{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://artifacts.apis.io/google-pay/json-schema/google-pay-loyalty-class-schema.json",
  "title": "LoyaltyClass",
  "x-generated": "2026-11-04",
  "x-method": "derived",
  "x-generator": "derive-json-schema.py",
  "x-source": "openapi/google-pay-wallet-openapi.yml#/components/schemas/LoyaltyClass",
  "type": "object",
  "properties": {
    "programLogo": {
      "$ref": "#/$defs/Image"
    },
    "localizedProgramName": {
      "$ref": "#/$defs/LocalizedString"
    },
    "version": {
      "type": "string",
      "format": "int64",
      "description": "Deprecated"
    },
    "infoModuleData": {
      "$ref": "#/$defs/InfoModuleData"
    },
    "localizedAccountNameLabel": {
      "$ref": "#/$defs/LocalizedString"
    },
    "callbackOptions": {
      "$ref": "#/$defs/CallbackOptions"
    },
    "locations": {
      "type": "array",
      "description": "Note: This field is currently not supported to trigger geo notifications.",
      "items": {
        "$ref": "#/$defs/LatLongPoint"
      }
    },
    "countryCode": {
      "type": "string",
      "description": "Country code used to display the card's country (when the user is not in that country), as well as to display localized content when content is not available in the user's locale."
    },
    "wideProgramLogo": {
      "$ref": "#/$defs/Image"
    },
    "hexBackgroundColor": {
      "type": "string",
      "description": "The background color for the card. If not set the dominant color of the hero image is used, and if no hero image is set, the dominant color of the logo is used. The format is #rrggbb where rrggbb is a hex RGB triplet, such as `#ffcc00`. You can also use the shorthand version of the RGB triplet which is #rgb, such as `#fc0`."
    },
    "id": {
      "type": "string",
      "description": "Required. The unique identifier for a class. This ID must be unique across all classes from an issuer. This value should follow the format issuer ID. identifier where the former is issued by Google and latter is chosen by you. Your unique identifier should only include alphanumeric characters, '.', '_', or '-'."
    },
    "secondaryRewardsTier": {
      "type": "string",
      "description": "The secondary rewards tier, such as \"Gold\" or \"Platinum.\""
    },
    "localizedAccountIdLabel": {
      "$ref": "#/$defs/LocalizedString"
    },
    "accountIdLabel": {
      "type": "string",
      "description": "The account ID label, such as \"Member ID.\" Recommended maximum length is 15 characters to ensure full string is displayed on smaller screens."
    },
    "kind": {
      "type": "string",
      "description": "Identifies what kind of resource this is. Value: the fixed string `\"walletobjects#loyaltyClass\"`."
    },
    "rewardsTier": {
      "type": "string",
      "description": "The rewards tier, such as \"Gold\" or \"Platinum.\" Recommended maximum length is 7 characters to ensure full string is displayed on smaller screens."
    },
    "securityAnimation": {
      "$ref": "#/$defs/SecurityAnimation"
    },
    "homepageUri": {
      "$ref": "#/$defs/Uri"
    },
    "linksModuleData": {
      "$ref": "#/$defs/LinksModuleData"
    },
    "reviewStatus": {
      "type": "string",
      "description": "Required. The status of the class. This field can be set to `draft` or `underReview` using the insert, patch, or update API calls. Once the review state is changed from `draft` it may not be changed back to `draft`. You should keep this field to `draft` when the class is under development. A `draft` class cannot be used to create any object. You should set this field to `underReview` when you believe the class is ready for use. The platform will automatically set this field to `approved` and it can be immediately used to create or migrate objects. When updating an already `approved` class you should keep setting this field to `underReview`.",
      "enum": [
        "REVIEW_STATUS_UNSPECIFIED",
        "UNDER_REVIEW",
        "underReview",
        "APPROVED",
        "approved",
        "REJECTED",
        "rejected",
        "DRAFT",
        "draft"
      ]
    },
    "merchantLocations": {
      "type": "array",
      "description": "Merchant locations. There is a maximum of ten on the class. Any additional MerchantLocations added beyond the 10 will be rejected. These locations will trigger a notification when a user enters within a Google-set radius of the point. This field replaces the deprecated LatLongPoints.",
      "items": {
        "$ref": "#/$defs/MerchantLocation"
      }
    },
    "localizedRewardsTierLabel": {
      "$ref": "#/$defs/LocalizedString"
    },
    "valueAddedModuleData": {
      "type": "array",
      "description": "Optional value added module data. Maximum of fifteen on the class. For a pass only fifteen will be displayed, prioritizing those from the object.",
      "items": {
        "$ref": "#/$defs/ValueAddedModuleData"
      }
    },
    "imageModulesData": {
      "type": "array",
      "description": "Image module data. The maximum number of these fields displayed is 1 from object level and 1 for class object level.",
      "items": {
        "$ref": "#/$defs/ImageModuleData"
      }
    },
    "enableSmartTap": {
      "type": "boolean",
      "description": "Identifies whether this class supports Smart Tap. The `redemptionIssuers` and one of object level `smartTapRedemptionLevel`, barcode.value`, or `accountId` fields must also be set up correctly in order for a pass to support Smart Tap."
    },
    "issuerName": {
      "type": "string",
      "description": "Required. The issuer name. Recommended maximum length is 20 characters to ensure full string is displayed on smaller screens."
    },
    "localizedIssuerName": {
      "$ref": "#/$defs/LocalizedString"
    },
    "localizedSecondaryRewardsTierLabel": {
      "$ref": "#/$defs/LocalizedString"
    },
    "classTemplateInfo": {
      "$ref": "#/$defs/ClassTemplateInfo"
    },
    "messages": {
      "type": "array",
      "description": "An array of messages displayed in the app. All users of this object will receive its associated messages. The maximum number of these fields is 10.",
      "items": {
        "$ref": "#/$defs/Message"
      }
    },
    "localizedSecondaryRewardsTier": {
      "$ref": "#/$defs/LocalizedString"
    },
    "notifyPreference": {
      "type": "string",
      "description": "Whether or not field updates to this class should trigger notifications. When set to NOTIFY, we will attempt to trigger a field update notification to users. These notifications will only be sent to users if the field is part of an allowlist. If not specified, no notification will be triggered. This setting is ephemeral and needs to be set with each PATCH or UPDATE request, otherwise a notification will not be triggered.",
      "enum": [
        "NOTIFICATION_SETTINGS_FOR_UPDATES_UNSPECIFIED",
        "NOTIFY_ON_UPDATE"
      ]
    },
    "accountNameLabel": {
      "type": "string",
      "description": "The account name label, such as \"Member Name.\" Recommended maximum length is 15 characters to ensure full string is displayed on smaller screens."
    },
    "heroImage": {
      "$ref": "#/$defs/Image"
    },
    "viewUnlockRequirement": {
      "type": "string",
      "description": "View Unlock Requirement options for the loyalty card.",
      "enum": [
        "VIEW_UNLOCK_REQUIREMENT_UNSPECIFIED",
        "UNLOCK_NOT_REQUIRED",
        "UNLOCK_REQUIRED_TO_VIEW"
      ]
    },
    "programName": {
      "type": "string",
      "description": "Required. The program name, such as \"Adam's Apparel\". The app may display an ellipsis after the first 20 characters to ensure full string is displayed on smaller screens."
    },
    "multipleDevicesAndHoldersAllowedStatus": {
      "type": "string",
      "description": "Identifies whether multiple users and devices will save the same object referencing this class.",
      "enum": [
        "STATUS_UNSPECIFIED",
        "MULTIPLE_HOLDERS",
        "ONE_USER_ALL_DEVICES",
        "ONE_USER_ONE_DEVICE",
        "multipleHolders",
        "oneUserAllDevices",
        "oneUserOneDevice"
      ]
    },
    "appLinkData": {
      "$ref": "#/$defs/AppLinkData"
    },
    "review": {
      "$ref": "#/$defs/Review"
    },
    "secondaryRewardsTierLabel": {
      "type": "string",
      "description": "The secondary rewards tier label, such as \"Rewards Tier.\""
    },
    "wordMark": {
      "$ref": "#/$defs/Image"
    },
    "redemptionIssuers": {
      "type": "array",
      "description": "Identifies which redemption issuers can redeem the pass over Smart Tap. Redemption issuers are identified by their issuer ID. Redemption issuers must have at least one Smart Tap key configured. The `enableSmartTap` and one of object level `smartTapRedemptionValue`, barcode.value`, or `accountId` fields must also be set up correctly in order for a pass to support Smart Tap.",
      "items": {
        "type": "string",
        "format": "int64"
      }
    },
    "textModulesData": {
      "type": "array",
      "description": "Text module data. If text module data is also defined on the class, both will be displayed. The maximum number of these fields displayed is 10 from the object and 10 from the class.",
      "items": {
        "$ref": "#/$defs/TextModuleData"
      }
    },
    "localizedRewardsTier": {
      "$ref": "#/$defs/LocalizedString"
    },
    "discoverableProgram": {
      "$ref": "#/$defs/DiscoverableProgram"
    },
    "allowMultipleUsersPerObject": {
      "type": "boolean",
      "description": "Deprecated. Use `multipleDevicesAndHoldersAllowedStatus` instead."
    },
    "rewardsTierLabel": {
      "type": "string",
      "description": "The rewards tier label, such as \"Rewards Tier.\" Recommended maximum length is 9 characters to ensure full string is displayed on smaller screens."
    }
  },
  "$defs": {
    "AppLinkData": {
      "type": "object",
      "properties": {
        "androidAppLinkInfo": {
          "$ref": "#/$defs/AppLinkDataAppLinkInfo"
        },
        "iosAppLinkInfo": {
          "$ref": "#/$defs/AppLinkDataAppLinkInfo"
        },
        "displayText": {
          "$ref": "#/$defs/LocalizedString"
        },
        "webAppLinkInfo": {
          "$ref": "#/$defs/AppLinkDataAppLinkInfo"
        }
      }
    },
    "AppLinkDataAppLinkInfo": {
      "type": "object",
      "properties": {
        "title": {
          "$ref": "#/$defs/LocalizedString"
        },
        "appTarget": {
          "$ref": "#/$defs/AppLinkDataAppLinkInfoAppTarget"
        },
        "appLogoImage": {
          "$ref": "#/$defs/Image"
        },
        "description": {
          "$ref": "#/$defs/LocalizedString"
        }
      }
    },
    "AppLinkDataAppLinkInfoAppTarget": {
      "type": "object",
      "properties": {
        "packageName": {
          "type": "string",
          "description": "Package name for AppTarget. For example: com.google.android.gm"
        },
        "targetUri": {
          "$ref": "#/$defs/Uri"
        }
      }
    },
    "BarcodeSectionDetail": {
      "type": "object",
      "properties": {
        "fieldSelector": {
          "$ref": "#/$defs/FieldSelector"
        }
      }
    },
    "CallbackOptions": {
      "type": "object",
      "properties": {
        "url": {
          "type": "string",
          "description": "The HTTPS url configured by the merchant. The URL should be hosted on HTTPS and robots.txt should allow the URL path to be accessible by UserAgent:Googlebot."
        },
        "updateRequestUrl": {
          "type": "string",
          "description": "URL for the merchant endpoint that would be called to request updates. The URL should be hosted on HTTPS and robots.txt should allow the URL path to be accessible by UserAgent:Googlebot. Deprecated."
        }
      }
    },
    "CardBarcodeSectionDetails": {
      "type": "object",
      "properties": {
        "firstBottomDetail": {
          "$ref": "#/$defs/BarcodeSectionDetail"
        },
        "firstTopDetail": {
          "$ref": "#/$defs/BarcodeSectionDetail"
        },
        "secondTopDetail": {
          "$ref": "#/$defs/BarcodeSectionDetail"
        }
      }
    },
    "CardRowOneItem": {
      "type": "object",
      "properties": {
        "item": {
          "$ref": "#/$defs/TemplateItem"
        }
      }
    },
    "CardRowTemplateInfo": {
      "type": "object",
      "properties": {
        "twoItems": {
          "$ref": "#/$defs/CardRowTwoItems"
        },
        "threeItems": {
          "$ref": "#/$defs/CardRowThreeItems"
        },
        "oneItem": {
          "$ref": "#/$defs/CardRowOneItem"
        }
      }
    },
    "CardRowThreeItems": {
      "type": "object",
      "properties": {
        "endItem": {
          "$ref": "#/$defs/TemplateItem"
        },
        "middleItem": {
          "$ref": "#/$defs/TemplateItem"
        },
        "startItem": {
          "$ref": "#/$defs/TemplateItem"
        }
      }
    },
    "CardRowTwoItems": {
      "type": "object",
      "properties": {
        "endItem": {
          "$ref": "#/$defs/TemplateItem"
        },
        "startItem": {
          "$ref": "#/$defs/TemplateItem"
        }
      }
    },
    "CardTemplateOverride": {
      "type": "object",
      "properties": {
        "cardRowTemplateInfos": {
          "type": "array",
          "description": "Template information for rows in the card view. At most three rows are allowed to be specified.",
          "items": {
            "$ref": "#/$defs/CardRowTemplateInfo"
          }
        }
      }
    },
    "ClassTemplateInfo": {
      "type": "object",
      "properties": {
        "cardTemplateOverride": {
          "$ref": "#/$defs/CardTemplateOverride"
        },
        "listTemplateOverride": {
          "$ref": "#/$defs/ListTemplateOverride"
        },
        "cardBarcodeSectionDetails": {
          "$ref": "#/$defs/CardBarcodeSectionDetails"
        },
        "detailsTemplateOverride": {
          "$ref": "#/$defs/DetailsTemplateOverride"
        }
      }
    },
    "DateTime": {
      "type": "object",
      "properties": {
        "date": {
          "type": "string",
          "description": "An ISO 8601 extended format date/time. Offset may or may not be required (refer to the parent field's documentation). Time may be specified up to nanosecond precision. Offsets may be specified with seconds precision (even though offset seconds is not part of ISO 8601). For example: `1985-04-12T23:20:50.52Z` would be 20 minutes and 50.52 seconds after the 23rd hour of April 12th, 1985 in UTC. `1985-04-12T19:20:50.52-04:00` would be 20 minutes and 50.52 seconds after the 19th hour of April 12th, 1985, 4 hours before UTC (same instant in time as the above example). If the date/time is intended for a physical location in New York, this would be the equivalent of Eastern Daylight Time (EDT). Remember that offset varies in regions that observe Daylight Saving Time (or Summer Time), depending on the time of the year. `1985-04-12T19:20:50.52` would be 20 minutes and 50.52 seconds after the 19th hour of April 12th, 1985 with no offset information. Providing an offset makes this an absolute instant in time around the world. The date/time will be adjusted based on the user's time zone. For example, a time of `2018-06-19T18:30:00-04:00` will be 18:30:00 for a user in New York and 15:30:00 for a user in Los Angeles. Omitting the offset makes this a local date/time, representing several instants in time around the world. The date/time will always be in the user's current time zone. For example, a time of `2018-06-19T18:30:00` will be 18:30:00 for a user in New York and also 18:30:00 for a user in Los Angeles. This is useful when the same local date/time should apply to many physical locations across several time zones."
        }
      }
    },
    "DetailsItemInfo": {
      "type": "object",
      "properties": {
        "item": {
          "$ref": "#/$defs/TemplateItem"
        }
      }
    },
    "DetailsTemplateOverride": {
      "type": "object",
      "properties": {
        "detailsItemInfos": {
          "type": "array",
          "description": "Information for the \"nth\" item displayed in the details list.",
          "items": {
            "$ref": "#/$defs/DetailsItemInfo"
          }
        }
      }
    },
    "DiscoverableProgram": {
      "type": "object",
      "description": "Information about how a class may be discovered and instantiated from within the Google Wallet app. This is done by searching for a loyalty or gift card program and scanning or manually entering.",
      "properties": {
        "state": {
          "type": "string",
          "description": "Visibility state of the discoverable program.",
          "enum": [
            "STATE_UNSPECIFIED",
            "TRUSTED_TESTERS",
            "trustedTesters",
            "LIVE",
            "live",
            "DISABLED",
            "disabled"
          ]
        },
        "merchantSignupInfo": {
          "$ref": "#/$defs/DiscoverableProgramMerchantSignupInfo"
        },
        "merchantSigninInfo": {
          "$ref": "#/$defs/DiscoverableProgramMerchantSigninInfo"
        }
      }
    },
    "DiscoverableProgramMerchantSigninInfo": {
      "type": "object",
      "description": "Information about the merchant hosted signin flow for a program.",
      "properties": {
        "signinWebsite": {
          "$ref": "#/$defs/Uri"
        }
      }
    },
    "DiscoverableProgramMerchantSignupInfo": {
      "type": "object",
      "description": "Information about the merchant hosted signup flow for a program.",
      "properties": {
        "signupWebsite": {
          "$ref": "#/$defs/Uri"
        },
        "signupSharedDatas": {
          "type": "array",
          "description": "User data that is sent in a POST request to the signup website URL. This information is encoded and then shared so that the merchant's website can prefill fields used to enroll the user for the discoverable program.",
          "items": {
            "type": "string",
            "enum": [
              "SHARED_DATA_TYPE_UNSPECIFIED",
              "FIRST_NAME",
              "LAST_NAME",
              "STREET_ADDRESS",
              "ADDRESS_LINE_1",
              "ADDRESS_LINE_2",
              "ADDRESS_LINE_3",
              "CITY",
              "STATE",
              "ZIPCODE",
              "COUNTRY",
              "EMAIL",
              "PHONE"
            ]
          }
        }
      }
    },
    "FieldReference": {
      "type": "object",
      "description": "Reference definition to use with field overrides.",
      "properties": {
        "dateFormat": {
          "type": "string",
          "description": "Only valid if the `fieldPath` references a date field. Chooses how the date field will be formatted and displayed in the UI.",
          "enum": [
            "DATE_FORMAT_UNSPECIFIED",
            "DATE_TIME",
            "dateTime",
            "DATE_ONLY",
            "dateOnly",
            "TIME_ONLY",
            "timeOnly",
            "DATE_TIME_YEAR",
            "dateTimeYear",
            "DATE_YEAR",
            "dateYear",
            "YEAR_MONTH",
            "YEAR_MONTH_DAY"
          ]
        },
        "fieldPath": {
          "type": "string",
          "description": "Path to the field being referenced, prefixed with \"object\" or \"class\" and separated with dots. For example, it may be the string \"object.purchaseDetails.purchasePrice\"."
        }
      }
    },
    "FieldSelector": {
      "type": "object",
      "description": "Custom field selector to use with field overrides.",
      "properties": {
        "fields": {
          "type": "array",
          "description": "If more than one reference is supplied, then the first one that references a non-empty field will be displayed.",
          "items": {
            "$ref": "#/$defs/FieldReference"
          }
        }
      }
    },
    "FirstRowOption": {
      "type": "object",
      "properties": {
        "fieldOption": {
          "$ref": "#/$defs/FieldSelector"
        },
        "transitOption": {
          "type": "string",
          "enum": [
            "TRANSIT_OPTION_UNSPECIFIED",
            "ORIGIN_AND_DESTINATION_NAMES",
            "originAndDestinationNames",
            "ORIGIN_AND_DESTINATION_CODES",
            "originAndDestinationCodes",
            "ORIGIN_NAME",
            "originName"
          ]
        }
      }
    },
    "Image": {
      "type": "object",
      "description": "Wrapping type for Google hosted images.",
      "properties": {
        "privateImageId": {
          "type": "string",
          "description": "An ID for an already uploaded private image. Either this or source_uri should be set. Requests setting both or neither will be rejected. Please contact support to use private images."
        },
        "sourceUri": {
          "$ref": "#/$defs/ImageUri"
        },
        "kind": {
          "type": "string",
          "description": "Identifies what kind of resource this is. Value: the fixed string `\"walletobjects#image\"`."
        },
        "contentDescription": {
          "$ref": "#/$defs/LocalizedString"
        }
      }
    },
    "ImageModuleData": {
      "type": "object",
      "properties": {
        "id": {
          "type": "string",
          "description": "The ID associated with an image module. This field is here to enable ease of management of image modules."
        },
        "mainImage": {
          "$ref": "#/$defs/Image"
        }
      }
    },
    "ImageUri": {
      "type": "object",
      "properties": {
        "uri": {
          "type": "string",
          "description": "The location of the image. URIs must have a scheme."
        },
        "localizedDescription": {
          "$ref": "#/$defs/LocalizedString"
        },
        "description": {
          "type": "string",
          "description": "Additional information about the image, which is unused and retained only for backward compatibility."
        }
      }
    },
    "InfoModuleData": {
      "type": "object",
      "properties": {
        "labelValueRows": {
          "type": "array",
          "description": "A list of collections of labels and values. These will be displayed one after the other in a singular column.",
          "items": {
            "$ref": "#/$defs/LabelValueRow"
          }
        },
        "showLastUpdateTime": {
          "type": "boolean"
        }
      }
    },
    "LabelValue": {
      "type": "object",
      "description": "A pair of text strings to be displayed in the details view. Note we no longer display LabelValue/LabelValueRow as a table, instead a list of items.",
      "properties": {
        "label": {
          "type": "string",
          "description": "The label for a specific row and column. Recommended maximum is 15 characters for a two-column layout and 30 characters for a one-column layout."
        },
        "localizedLabel": {
          "$ref": "#/$defs/LocalizedString"
        },
        "localizedValue": {
          "$ref": "#/$defs/LocalizedString"
        },
        "value": {
          "type": "string",
          "description": "The value for a specific row and column. Recommended maximum is 15 characters for a two-column layout and 30 characters for a one-column layout."
        }
      }
    },
    "LabelValueRow": {
      "type": "object",
      "properties": {
        "columns": {
          "type": "array",
          "description": "A list of labels and values. These will be displayed in a singular column, one after the other, not in multiple columns, despite the field name.",
          "items": {
            "$ref": "#/$defs/LabelValue"
          }
        }
      }
    },
    "LatLongPoint": {
      "type": "object",
      "properties": {
        "longitude": {
          "type": "number",
          "format": "double",
          "description": "The longitude specified in the range -180.0 through +180.0, both inclusive. Values outside these bounds will be rejected."
        },
        "kind": {
          "type": "string",
          "description": "Identifies what kind of resource this is. Value: the fixed string `\"walletobjects#latLongPoint\"`."
        },
        "latitude": {
          "type": "number",
          "format": "double",
          "description": "The latitude specified as any value in the range of -90.0 through +90.0, both inclusive. Values outside these bounds will be rejected."
        }
      }
    },
    "LinksModuleData": {
      "type": "object",
      "properties": {
        "uris": {
          "type": "array",
          "description": "The list of URIs.",
          "items": {
            "$ref": "#/$defs/Uri"
          }
        }
      }
    },
    "ListTemplateOverride": {
      "type": "object",
      "properties": {
        "firstRowOption": {
          "$ref": "#/$defs/FirstRowOption"
        },
        "thirdRowOption": {
          "$ref": "#/$defs/FieldSelector"
        },
        "secondRowOption": {
          "$ref": "#/$defs/FieldSelector"
        }
      }
    },
    "LocalizedString": {
      "type": "object",
      "properties": {
        "kind": {
          "type": "string",
          "description": "Identifies what kind of resource this is. Value: the fixed string `\"walletobjects#localizedString\"`."
        },
        "translatedValues": {
          "type": "array",
          "description": "Contains the translations for the string.",
          "items": {
            "$ref": "#/$defs/TranslatedString"
          }
        },
        "defaultValue": {
          "$ref": "#/$defs/TranslatedString"
        }
      }
    },
    "MerchantLocation": {
      "type": "object",
      "description": "Locations of interest for this class or object. Currently, this location is used for geofenced notifications. When a user is within a set radius of this lat/long, and dwells there, Google will trigger a notification. When a user exits this radius, the notification will be hidden.",
      "properties": {
        "latitude": {
          "type": "number",
          "format": "double",
          "description": "The latitude specified as any value in the range of -90.0 through +90.0, both inclusive. Values outside these bounds will be rejected."
        },
        "longitude": {
          "type": "number",
          "format": "double",
          "description": "The longitude specified in the range -180.0 through +180.0, both inclusive. Values outside these bounds will be rejected."
        }
      }
    },
    "Message": {
      "type": "object",
      "description": "A message that will be displayed with a Valuable",
      "properties": {
        "messageType": {
          "type": "string",
          "description": "The message type.",
          "enum": [
            "MESSAGE_TYPE_UNSPECIFIED",
            "TEXT",
            "text",
            "EXPIRATION_NOTIFICATION",
            "expirationNotification",
            "TEXT_AND_NOTIFY"
          ]
        },
        "body": {
          "type": "string",
          "description": "The message body."
        },
        "id": {
          "type": "string",
          "description": "The ID associated with a message. This field is here to enable ease of management of messages. Notice ID values could possibly duplicate across multiple messages in the same class/instance, and care must be taken to select a reasonable ID for each message."
        },
        "kind": {
          "type": "string",
          "description": "Identifies what kind of resource this is. Value: the fixed string `\"walletobjects#walletObjectMessage\"`."
        },
        "displayInterval": {
          "$ref": "#/$defs/TimeInterval"
        },
        "localizedHeader": {
          "$ref": "#/$defs/LocalizedString"
        },
        "header": {
          "type": "string",
          "description": "The message header."
        },
        "localizedBody": {
          "$ref": "#/$defs/LocalizedString"
        }
      }
    },
    "ModuleViewConstraints": {
      "type": "object",
      "description": "Constraints that all must be met for the module to be shown.",
      "properties": {
        "displayInterval": {
          "$ref": "#/$defs/TimeInterval"
        }
      }
    },
    "Review": {
      "type": "object",
      "properties": {
        "comments": {
          "type": "string"
        }
      }
    },
    "SecurityAnimation": {
      "type": "object",
      "properties": {
        "animationType": {
          "type": "string",
          "description": "Type of animation.",
          "enum": [
            "ANIMATION_UNSPECIFIED",
            "FOIL_SHIMMER",
            "foilShimmer"
          ]
        }
      }
    },
    "TemplateItem": {
      "type": "object",
      "properties": {
        "predefinedItem": {
          "type": "string",
          "description": "A predefined item to display. Only one of `firstValue` or `predefinedItem` may be set.",
          "enum": [
            "PREDEFINED_ITEM_UNSPECIFIED",
            "FREQUENT_FLYER_PROGRAM_NAME_AND_NUMBER",
            "frequentFlyerProgramNameAndNumber",
            "FLIGHT_NUMBER_AND_OPERATING_FLIGHT_NUMBER",
            "flightNumberAndOperatingFlightNumber"
          ]
        },
        "firstValue": {
          "$ref": "#/$defs/FieldSelector"
        },
        "secondValue": {
          "$ref": "#/$defs/FieldSelector"
        }
      }
    },
    "TextModuleData": {
      "type": "object",
      "description": "Data for Text module. All fields are optional. Header will be displayed if available, different types of bodies will be concatenated if they are defined.",
      "properties": {
        "localizedHeader": {
          "$ref": "#/$defs/LocalizedString"
        },
        "id": {
          "type": "string",
          "description": "The ID associated with a text module. This field is here to enable ease of management of text modules and referencing them in template overrides. The ID should only include alphanumeric characters, '_', or '-'. It can not include dots, as dots are used to separate fields within FieldReference.fieldPaths in template overrides."
        },
        "localizedBody": {
          "$ref": "#/$defs/LocalizedString"
        },
        "body": {
          "type": "string",
          "description": "The body of the Text Module, which is defined as an uninterrupted string. Recommended maximum length is 500 characters to ensure full string is displayed on smaller screens."
        },
        "header": {
          "type": "string",
          "description": "The header of the Text Module. Recommended maximum length is 35 characters to ensure full string is displayed on smaller screens."
        }
      }
    },
    "TimeInterval": {
      "type": "object",
      "properties": {
        "kind": {
          "type": "string",
          "description": "Identifies what kind of resource this is. Value: the fixed string `\"walletobjects#timeInterval\"`."
        },
        "start": {
          "$ref": "#/$defs/DateTime"
        },
        "end": {
          "$ref": "#/$defs/DateTime"
        }
      }
    },
    "TranslatedString": {
      "type": "object",
      "properties": {
        "language": {
          "type": "string",
          "description": "Represents the BCP 47 language tag. Example values are \"en-US\", \"en-GB\", \"de\", or \"de-AT\"."
        },
        "value": {
          "type": "string",
          "description": "The UTF-8 encoded translated string."
        },
        "kind": {
          "type": "string",
          "description": "Identifies what kind of resource this is. Value: the fixed string `\"walletobjects#translatedString\"`."
        }
      }
    },
    "Uri": {
      "type": "object",
      "properties": {
        "kind": {
          "type": "string",
          "description": "Identifies what kind of resource this is. Value: the fixed string `\"walletobjects#uri\"`."
        },
        "id": {
          "type": "string",
          "description": "The ID associated with a uri. This field is here to enable ease of management of uris."
        },
        "localizedDescription": {
          "$ref": "#/$defs/LocalizedString"
        },
        "uri": {
          "type": "string",
          "description": "The location of a web page, image, or other resource. URIs in the `LinksModuleData` module can have different prefixes indicating the type of URI (a link to a web page, a link to a map, a telephone number, or an email address). URIs must have a scheme."
        },
        "description": {
          "type": "string",
          "description": "The URI's title appearing in the app as text. Recommended maximum is 20 characters to ensure full string is displayed on smaller screens. Note that in some contexts this text is not used, such as when `description` is part of an image."
        }
      }
    },
    "ValueAddedModuleData": {
      "type": "object",
      "description": "Data for Value Added module. Required fields are header and uri.",
      "properties": {
        "viewConstraints": {
          "$ref": "#/$defs/ModuleViewConstraints"
        },
        "body": {
          "$ref": "#/$defs/LocalizedString"
        },
        "header": {
          "$ref": "#/$defs/LocalizedString"
        },
        "sortIndex": {
          "type": "integer",
          "format": "int32",
          "description": "The index for sorting the modules. Modules with a lower sort index are shown before modules with a higher sort index. If unspecified, the sort index is assumed to be INT_MAX. For two modules with the same index, the sorting behavior is undefined."
        },
        "image": {
          "$ref": "#/$defs/Image"
        },
        "uri": {
          "type": "string",
          "description": "URI that the module leads to on click. This can be a web link or a deep link as mentioned in https://developer.android.com/training/app-links/deep-linking."
        }
      }
    }
  }
}