JSON 架构

图书:/actions-center/verticals/things-to-do/_book.yaml 项目:/actions-center/verticals/things-to-do/_project.yaml

JSON 架构可用于在开发期间排查 Feed 问题。

{
  "title": "travel.ttd.proto.feeds.v1.ProductFeed",
  "type": [
    "object"
  ],
  "properties": {
    "feed_metadata": {
      "title": "feed_metadata",
      "description": "Metadata for this feed.\n Required.",
      "$ref": "#/definitions/travel.ttd.proto.feeds.v1.FeedMetadata"
    },
    "products": {
      "title": "products",
      "description": "List of the products.\n Optional. When unset in all shards, all products will be deleted.",
      "type": [
        "array",
        "null"
      ],
      "items": {
        "$ref": "#/definitions/travel.ttd.proto.feeds.v1.Product"
      }
    }
  },
  "additionalProperties": true,
  "required": [ "feed_metadata", "products" ],
  "definitions": {
    "travel.ttd.proto.feeds.v1.FeedMetadata": {
      "title": "travel.ttd.proto.feeds.v1.FeedMetadata",
      "type": [
        "object"
      ],
      "properties": {
        "shard_id": {
          "title": "shard_id",
          "description": "The current shard ID, zero-based. Shards do not need to be transferred in\n order. Processing will start only after a full set of shards was uploaded.\n Required when total_shards_count \u003e 1.",
          "type": [
            "integer"
          ],
          "minimum": 0,
          "maximum": 4294967295
        },
        "total_shards_count": {
          "title": "total_shards_count",
          "description": "Total number of shards in this transfer.\n Required. Must be \u003e\u003d 1.",
          "type": [
            "integer"
          ],
          "minimum": 1,
          "maximum": 4294967295
        },
        "nonce": {
          "title": "nonce",
          "description": "An arbitrary number used to link multiple shards to the same transfer.\n Required when total_shards_count \u003e 1.\n Must be the same for all shards within the transfer.",
          "type": [
            "integer"
          ],
          "minimum": 0
        },
        "processing_instruction": {
          "title": "processing_instruction",
          "description": "Processing instruction for this upload.\n Required.",
          "$ref": "#/definitions/travel.ttd.proto.feeds.v1.FeedMetadata.ProcessingInstruction"
        },
        "max_removal_share": {
          "title": "max_removal_share",
          "description": "Maximal share of currently active products that are allowed to be removed\n by an upload. If more products will be removed by this transfer, the whole\n transfer will be rejected.\n This is a safeguard against unintentional take down of a significant part\n of the inventory. Can be set to 1.0 to allow complete inventory take down.\n Optional.",
          "type": [
            "number"
          ]
        }
      },
      "additionalProperties": true,
      "required": [ "total_shards_count", "processing_instruction" ]
    },
    "google.type.LocalizedText": {
      "title": "google.type.LocalizedText",
      "type": [
        "object"
      ],
      "properties": {
        "text": {
          "title": "text",
          "description": "Localized string in the language corresponding to `language_code\u0027 below.",
          "type": [
            "string"
          ]
        },
        "language_code": {
          "title": "language_code",
          "description": "The text\u0027s BCP-47 language code, such as \"en-US\" or \"sr-Latn\".\n\n For more information, see\n http://www.unicode.org/reports/tr35/#Unicode_locale_identifier.\n\n (-- In google3, convert to/from the go/iii `LanguageCode` class for\n processing. Do not use the deprecated `Language` enum. --)",
          "type": [
            "string"
          ]
        }
      },
      "additionalProperties": true,
      "required": [ "text", "language_code" ]
    },
    "travel.ttd.proto.feeds.v1.LocalizedTextSet": {
      "title": "travel.ttd.proto.feeds.v1.LocalizedTextSet",
      "type": [
        "object"
      ],
      "properties": {
        "localized_texts": {
          "title": "localized_texts",
          "description": "Per-locale LocalizedText values.",
          "type": [
            "array"
          ],
          "items": {
            "$ref": "#/definitions/google.type.LocalizedText"
          },
          "minItems": 1
        }
      },
      "additionalProperties": true
    },
    "travel.ttd.proto.feeds.v1.TextFeature": {
      "title": "travel.ttd.proto.feeds.v1.TextFeature",
      "type": [
        "object"
      ],
      "properties": {
        "feature_type": {
          "title": "feature_type",
          "description": "Feature type.\n Required.",
          "$ref": "#/definitions/travel.ttd.proto.feeds.v1.TextFeature.TextFeatureType"
        },
        "value": {
          "title": "value",
          "description": "LocalizedTextSet content of the feature. Values support both plain-text\n and HTML-like text for basic formatting. Supported HTML formatting tags:\n\n Phrase tags: \u003cbr\u003e, \u003cstrong\u003e, \u003cem\u003e, \u003ci\u003e:\n   Only the four tags mentioned above are supported. \u003cbr\u003e can be used to\n   break lines in paragraphs, and \u003cstrong\u003e/\u003cem\u003e/\u003ci\u003e can be used to highlight\n   important text. Any other phrase tags will be ignored.\n\n All other tags and custom styles are not allowed and will be removed. Any\n URLs, anchors, and links will be stripped, and will never be displayed to\n end-users.\n Recommended to not exceed length of 1000 in any language. Max length: 2000.\n Required.",
          "$ref": "#/definitions/travel.ttd.proto.feeds.v1.LocalizedTextSet"
        }
      },
      "additionalProperties": true,
      "required": [ "feature_type", "value" ]
    },
    "travel.ttd.proto.feeds.v1.Rating": {
      "title": "travel.ttd.proto.feeds.v1.Rating",
      "type": [
        "object"
      ],
      "properties": {
        "averageValue": {
          "title": "averageValue",
          "description": "Average rating value.\n The value must be in the range of [1, 5] and can be omitted if and only if\n the rating_count is zero.",
          "type": [
            "number"
          ]
        },
        "rating_count": {
          "title": "rating_count",
          "description": "Number of ratings used in calculating the value.\n Required.",
          "type": [
            "integer"
          ],
          "minimum": 0,
          "maximum": 9007199254740991
        }
      },
      "additionalProperties": true,
      "required": [ "rating_count" ]
    },
    "travel.ttd.proto.feeds.v1.Media": {
      "title": "travel.ttd.proto.feeds.v1.Media",
      "type": [
        "object"
      ],
      "properties": {
        "url": {
          "title": "url",
          "description": "URL of this media source. Google will crawl the media hosted at this URL.\n Max length: 2000.\n Required.",
          "type": [
            "string"
          ]
        },
        "type": {
          "title": "type",
          "description": "Type of this media source.\n Required.",
          "$ref": "#/definitions/travel.ttd.proto.feeds.v1.Media.MediaType"
        },
        "attribution": {
          "title": "attribution",
          "description": "Attribution information about the source of the media. Note that if\n the attribution is required to display with the media to give credit to\n photographer or agency, this field must be set.\n Recommended to not exceed length of 1000 in any language.\n Max length: 2000.\n Optional.",
          "$ref": "#/definitions/travel.ttd.proto.feeds.v1.LocalizedTextSet"
        }
      },
      "additionalProperties": true,
      "required": [ "url", "type" ]
    },
    "travel.ttd.proto.feeds.v1.DeepLink": {
      "title": "travel.ttd.proto.feeds.v1.DeepLink",
      "type": [
        "object"
      ],
      "properties": {
        "url": {
          "title": "url",
          "description": "Landing page URL template for desktop. If both `url` and `localized_url`\n are provided, the former is used as a fallback in case\n no URL matches the user’s locale.\n Max length: 2000.\n Either `url` or `localized_url` is required.",
          "type": [
            "string"
          ]
        },
        "mobile_url": {
          "title": "mobile_url",
          "description": "Landing page URL template for mobile. If omitted, it defaults to the `url`\n value.\n Max length: 2000.\n Optional.",
          "type": [
            "string"
          ]
        },
        "localized_url": {
          "title": "localized_url",
          "description": "Localized landing page URL template for desktop. If both `url` and\n `localized_url` are provided, the former is used as a fallback in case\n no URL matches the user’s locale.\n Max length: 2000.\n Max number of locales: 50.\n Either `url` or `localized_url` is required.",
          "$ref": "#/definitions/travel.ttd.proto.feeds.v1.LocalizedTextSet"
        },
        "localized_mobile_url": {
          "title": "localized_mobile_url",
          "description": "Localized landing page URL template for mobile.\n Max length: 2000.\n Max number of locales: 50.\n Optional.",
          "$ref": "#/definitions/travel.ttd.proto.feeds.v1.LocalizedTextSet"
        }
      },
      "additionalProperties": true,
      "anyOf": [
        {"required": ["url"]},
	{"required": ["localized_url"]}
      ]
    },
    "google.type.Money": {
      "title": "google.type.Money",
      "description": "Represents an amount of money with its currency type.",
      "type": [
        "object"
      ],
      "properties": {
        "currency_code": {
          "title": "currency_code",
          "description": "The three-letter currency code defined in ISO 4217.",
          "type": [
            "string"
          ]
        },
        "units": {
          "title": "units",
          "description": "The whole units of the amount.\n For example if `currencyCode` is `\"USD\"`, then 1 unit is one US dollar.",
          "type": [
            "integer"
          ],
          "minimum": -9007199254740991,
          "maximum": 9007199254740991
        },
        "nanos": {
          "title": "nanos",
          "description": "Number of nano (10^-9) units of the amount.\n The value must be between -999,999,999 and +999,999,999 inclusive.\n If `units` is positive, `nanos` must be positive or zero.\n If `units` is zero, `nanos` can be positive, zero, or negative.\n If `units` is negative, `nanos` must be negative or zero.\n For example $-1.75 is represented as `units`\u003d-1 and `nanos`\u003d-750,000,000.",
          "type": [
            "integer"
          ],
          "minimum": -999999999,
          "maximum": 999999999
        }
      },
      "additionalProperties": true,
      "required": [ "currency_code" ]
    },
    "travel.ttd.proto.feeds.v1.CancellationPolicy.RefundCondition": {
      "title": "travel.ttd.proto.feeds.v1.CancellationPolicy.RefundCondition",
      "description": "Defines a single refund condition. Multiple refund conditions could be\n used together to describe \"refund steps\" as various durations before the\n service start time.",
      "type": [
        "object"
      ],
      "properties": {
        "min_duration_before_start_time_sec": {
          "title": "min_duration_before_start_time_sec",
          "description": "Duration in seconds before the start time, until when the customer can\n receive a refund for part of the service\u0027s cost specified in\n `refund_percent`.\n When unset or set to 0 the service can be cancelled at any time.\n Optional.",
          "type": [
            "integer"
          ],
          "minimum": 0,
          "maximum": 4294967295
        },
        "refund_percent": {
          "title": "refund_percent",
          "description": "The percent that can be refunded, as long as the service booking is\n cancelled at least `min_duration_before_start_time` before the service\n start time, in the range of [0, 100].\n When unset or set to 0, the service is not refundable. When set to 100\n this service is fully refundable.\n Optional.",
          "type": [
            "integer"
          ],
          "minimum": 0,
          "maximum": 4294967295
        },
        "refundFee": {
          "title": "refund_fee",
          "description": "A flat fee deducted on refund. Could be used separately, or in\n combination with the refund_percent above. In the latter case, refund\n percent applies first, then the fee is deducted.\n Optional.",
          "$ref": "#/definitions/google.type.Money"
        }
      },
      "additionalProperties": true
    },
    "travel.ttd.proto.feeds.v1.CancellationPolicy": {
      "title": "travel.ttd.proto.feeds.v1.CancellationPolicy",
      "type": [
        "object"
      ],
      "properties": {
        "refund_conditions": {
          "title": "refund_conditions",
          "description": "Zero or more refund conditions applicable to the policy.\n Max number of refund conditions: 10.",
          "type": [
            "array"
          ],
          "items": {
            "$ref": "#/definitions/travel.ttd.proto.feeds.v1.CancellationPolicy.RefundCondition"
          }
        }
      },
      "additionalProperties": true
    },
    "travel.ttd.proto.feeds.v1.Category": {
      "title": "travel.ttd.proto.feeds.v1.Category",
      "type": [
        "object"
      ],
      "properties": {
        "label": {
          "title": "label",
          "description": "Refer to the documentation for the valid values list.\n Required.",
          "type": [
            "string"
          ]
        }
      },
      "additionalProperties": true
    },
    "travel.ttd.proto.feeds.v1.StructuredAddress": {
      "title": "travel.ttd.proto.feeds.v1.StructuredAddress",
      "description": "Object Street address, including house number and any other components.",
      "type": [
        "object"
      ],
      "properties": {
        "street_address": {
          "title": "street_address",
          "description": "Street address, including house number",
          "type": [
            "string"
          ]
        },
        "locality": {
          "title": "locality",
          "description": "Locality, generally referring to the city/town portion of an address.",
          "type": [
            "string"
          ]
        },
        "administrative_area": {
          "title": "administrative_area",
          "description": "Highest administrative subdivision used for postal addresses of the specific country or region. This can be a state, a region, a province, an oblast, a prefecture, etc.Website URL shown on Google for the place, preferably the URL linked from the business listing in Google Maps or Search for the place.",
          "type": [
            "string"
          ]
        },
        "postal_code": {
          "title": "postal_code",
          "description": "The postal code or zip code.",
          "type": [
            "string"
          ]
        },
        "country_code": {
          "title": "country_code",
          "description": "Country code, as defined by Unicode's CLDR, itself based on the ISO 3166 alpha-2 standard.",
          "type": [
            "string"
          ]
        }
      },
      "additionalProperties": true,
      "required": [ "street_address", "country_code" ]
    },
    "travel.ttd.proto.feeds.v1.PlaceInfo": {
      "title": "travel.ttd.proto.feeds.v1.PlaceInfo",
      "description": "Object containing information about a location",
      "type": [
        "object"
      ],
      "properties": {
        "name": {
          "title": "name",
          "description": "Place or business name.",
          "type": [
            "string"
          ]
        },
        "phone_number": {
          "title": "phone_number",
          "description": "Phone number, including the international prefix.",
          "type": [
            "string"
          ]
        },
        "website_url": {
          "title": "website_url",
          "description": "Website URL shown on Google for the place, preferably the URL linked from the business listing in Google Maps or Search for the place.",
          "type": [
            "string"
          ]
        },
        "coordinates": {
          "title": "coordinates",
          "description": "Geographic coordinates of the place.",
          "$ref": "#/definitions/google.type.LatLng"
        },
        "structured_address": {
          "title": "structured_address",
          "description": "Structured address",
          "$ref": "#/definitions/travel.ttd.proto.feeds.v1.StructuredAddress"
        },
        "unstructured_address": {
          "title": "unstructured_address",
          "description": "Unstructured address",
          "type": [
            "string"
          ]
        }
      },
      "additionalProperties": true,
      "required": [ "name" ],
      "anyOf": [
        {"required": ["coordinates"]},
        { "oneOf": [
          {"required": ["structured_address"]},
          {"required": ["unstructured_address"]}
        ]}
      ]
    },
    "google.type.LatLng": {
      "title": "google.type.LatLng",
      "description": "An object that represents a latitude/longitude pair. This is expressed as a\n pair of doubles to represent degrees latitude and degrees longitude. Unless\n specified otherwise, this object must conform to the\n \u003ca href\u003d\"https://en.wikipedia.org/wiki/World_Geodetic_System#1984_version\"\u003e\n WGS84 standard\u003c/a\u003e. Values must be within normalized ranges.\n (-- An API may allow wider ranges in which case it must convert them to\n  normalized values.\n\n Example of normalization code in Python:\n\n     def normalize_longitude(longitude):\n       \"\"\"Wraps decimal degrees longitude to [-180.0, 180.0].\"\"\"\n       q, r \u003d divmod(longitude, 360.0)\n       if r \u003e 180.0 or (r \u003d\u003d 180.0 and q \u003c\u003d -1.0):\n         return r - 360.0\n       return r\n\n     def normalize_lat_lng(latitude, longitude):\n       \"\"\"Wraps decimal degrees latitude and longitude to\n       [-90.0, 90.0] and [-180.0, 180.0], respectively.\n       \"\"\"\n       r \u003d latitude % 360.0\n       if r \u003c\u003d 90.0:\n         return r, normalize_longitude(longitude)\n       elif r \u003e\u003d 270.0:\n         return r - 360, normalize_longitude(longitude)\n       else:\n         return 180 - r, normalize_longitude(longitude + 180.0)\n\n     assert 180.0 \u003d\u003d normalize_longitude(180.0)\n     assert -180.0 \u003d\u003d normalize_longitude(-180.0)\n     assert -179.0 \u003d\u003d normalize_longitude(181.0)\n     assert (0.0, 0.0) \u003d\u003d normalize_lat_lng(360.0, 0.0)\n     assert (0.0, 0.0) \u003d\u003d normalize_lat_lng(-360.0, 0.0)\n     assert (85.0, 180.0) \u003d\u003d normalize_lat_lng(95.0, 0.0)\n     assert (-85.0, -170.0) \u003d\u003d normalize_lat_lng(-95.0, 10.0)\n     assert (90.0, 10.0) \u003d\u003d normalize_lat_lng(90.0, 10.0)\n     assert (-90.0, -10.0) \u003d\u003d normalize_lat_lng(-90.0, -10.0)\n     assert (0.0, -170.0) \u003d\u003d normalize_lat_lng(-180.0, 10.0)\n     assert (0.0, -170.0) \u003d\u003d normalize_lat_lng(180.0, 10.0)\n     assert (-90.0, 10.0) \u003d\u003d normalize_lat_lng(270.0, 10.0)\n     assert (90.0, 10.0) \u003d\u003d normalize_lat_lng(-270.0, 10.0) --)\n\n (-- The code in logs/storage/validator/logs_validator_traits.cc treats this\n type as if it were annotated as ST_LOCATION. --)",
      "type": [
        "object"
      ],
      "properties": {
        "latitude": {
          "title": "latitude",
          "description": "The latitude in degrees. It must be in the range [-90.0, +90.0].\n (-- An API may allow a wider range and must convert them to normalized\n  values. --)",
          "type": [
            "number"
          ]
        },
        "longitude": {
          "title": "longitude",
          "description": "The longitude in degrees. It must be in the range [-180.0, +180.0].\n (-- An API may allow a wider range and must convert them to normalized\n  values. --)",
          "type": [
            "number"
          ]
        }
      },
      "additionalProperties": true,
      "required": [ "latitude", "longitude" ]
    },
    "travel.ttd.proto.feeds.v1.GeoLocation": {
      "title": "travel.ttd.proto.feeds.v1.GeoLocation",
      "type": [
        "object"
      ],
      "properties": {
        "place_id": {
          "title": "place_id [oneof#value]",
          "description": "PlaceId as defined by The Places API:\n   https://developers.google.com/places/web-service/place-id\n\n This is the most preferred option as it is the most accurate and do not\n contain any ambiguity as to the point of interest.",
          "type": [
            "string"
          ]
        },
        "address": {
          "title": "address [oneof#value]",
          "description": "Location as an address suitable for machine processing.\n Max length: 200.\n\n This is the next preferred option outside of place_id.",
          "type": [
            "string"
          ]
        },
        "lat_lng": {
          "title": "lat_lng [oneof#value]",
          "description": "When place ID and address are not available, the lat_lng field could be\n used to specify the coordinates.\n\n This is the least preferred option as it is the most ambiguous when used\n to describe the POI. lat_lng will only be used to determine the city and\n geographic region the POI is in.",
          "$ref": "#/definitions/google.type.LatLng"
        },
        "place_info": {
          "title": "place_id [oneof#value]",
          "description": "Structured place information",
          "$ref": "#/definitions/travel.ttd.proto.feeds.v1.PlaceInfo"
        }
      },
      "additionalProperties": true,
      "oneOf": [
        {"required": ["place_info"]},
        {"required": ["place_id"]},
        {"required": ["address"]},
        {"required": ["lat_lng"]}
      ]
    },
    "travel.ttd.proto.feeds.v1.Location": {
      "title": "travel.ttd.proto.feeds.v1.Location",
      "type": [
        "object"
      ],
      "properties": {
        "location": {
          "title": "location",
          "description": "At least one of (location, description) must be set, and we highly\n recommend populating location wherever possible.\n\n To emphasize, both fields can be populated together, e.g. you can set\n Central Park New York for the location and \"In front of the 72 Street\n Station\" for the description.",
          "$ref": "#/definitions/travel.ttd.proto.feeds.v1.GeoLocation"
        },
        "description": {
          "title": "description",
          "description": "Additional description in human-readable form, e.g.\n     \"On the left side of the fountain on the Palace square\".\n At least one of (location, description) must be set.\n Recommended to not exceed length of 1000 in any language. Max length: 2000.",
          "$ref": "#/definitions/travel.ttd.proto.feeds.v1.LocalizedTextSet"
        }
      },
      "additionalProperties": true,
      "anyOf": [
        {"required": ["location"]},
        {"required": ["description"]}
      ]
    },
    "travel.ttd.proto.feeds.v1.RelatedLocation": {
      "title": "travel.ttd.proto.feeds.v1.RelatedLocation",
      "type": [
        "object"
      ],
      "properties": {
        "location": {
          "title": "location",
          "description": "Location related to an option. Can be a POI (e.g. Eiffel tower),\n neighbourhood (e.g. Old Town) or an address / arbitrary map point.\n Required.",
          "$ref": "#/definitions/travel.ttd.proto.feeds.v1.Location"
        },
        "relation_type": {
          "title": "relation_type",
          "description": "Relation type of an option for the given location.\n Required.",
          "$ref": "#/definitions/travel.ttd.proto.feeds.v1.RelatedLocation.RelationType"
        }
      },
      "additionalProperties": true,
      "required": [ "location", "relation_type" ]
    },
    "travel.ttd.proto.feeds.v1.GeoCriterion": {
      "title": "travel.ttd.proto.feeds.v1.GeoCriterion",
      "type": [
        "object"
      ],
      "properties": {
        "country_code": {
          "title": "country_code",
          "description": "2-letter country code as defined in ISO 3166-1.\n Required.",
          "type": [
            "string"
          ],
          "minLength": 2,
          "maxLength": 3
        },
        "is_negative": {
          "title": "is_negative",
          "description": "If true, criterion is negative (the country code is excluded).",
          "type": [
            "boolean"
          ]
        }
      },
      "additionalProperties": true,
      "required": [ "country_code" ]
    },
    "travel.ttd.proto.feeds.v1.PriceFeesAndTaxes": {
      "title": "travel.ttd.proto.feeds.v1.PriceFeesAndTaxes",
      "type": [
        "object"
      ],
      "properties": {
        "per_ticket_fee": {
          "title": "per_ticket_fee",
          "description": "Booking fees included in the final product price for a single ticket.\n Optional.",
          "$ref": "#/definitions/google.type.Money"
        },
        "per_ticket_tax": {
          "title": "per_ticket_tax",
          "description": "State taxes included in the final product price for a single ticket.\n Optional.",
          "$ref": "#/definitions/google.type.Money"
        }
      },
      "additionalProperties": true
    },
    "travel.ttd.proto.feeds.v1.PriceOption": {
      "title": "travel.ttd.proto.feeds.v1.PriceOption",
      "type": [
        "object"
      ],
      "properties": {
        "id": {
          "title": "id",
          "description": "Unique ID within the price set.\n Max length: 255.\n Required.",
          "type": [
            "string"
          ]
        },
        "title": {
          "title": "title",
          "description": "Short description of the price option, e.g. \"Adult weekday\".\n Max length: 150.\n Required.",
          "type": [
            "string"
          ]
        },
        "price": {
          "title": "price",
          "description": "Price value, must match the final price on the checkout page, including all\n taxes and charges, see price policy. Currency will be converted to the user\n currency on rendering.\n Required when is_free is false.",
          "$ref": "#/definitions/google.type.Money"
        },
        "is_free": {
          "title": "is_free",
          "description": "Admission or ticket is free. Must be set to true for zero-price options.\n Optional, default is false.",
          "type": [
            "boolean"
          ]
        },
        "geo_criteria": {
          "title": "geo_criteria",
          "description": "List of geographical regions this price is applicable to. If empty,\n applicable to all locations.\n Optional.",
          "type": [
            "array"
          ],
          "items": {
            "$ref": "#/definitions/travel.ttd.proto.feeds.v1.GeoCriterion"
          }
        },
        "fees_and_taxes": {
          "title": "fees_and_taxes",
          "description": "Break down of fees and taxes included in the price above.\n Optional.",
          "$ref": "#/definitions/travel.ttd.proto.feeds.v1.PriceFeesAndTaxes"
        }
      },
      "additionalProperties": true,
      "required": [ "id", "title" ],
      "if": {
        "not": {
          "properties": {
            "is_free": {
              "enum": [ true ]
            }
          }
        }
      },
      "then": {
        "required": [
         "price"
        ]
      }
    },
    "travel.ttd.proto.feeds.v1.Language": {
      "title": "travel.ttd.proto.feeds.v1.Language",
      "type": [
        "object"
      ],
      "properties": {
        "code": {
          "title": "code",
          "description": "A BCP 47 compliant language code such as \"en\" or \"de-CH\".",
          "type": [
            "string"
          ]
        }
      },
      "additionalProperties": true
    },
    "travel.ttd.proto.feeds.v1.Option": {
      "title": "travel.ttd.proto.feeds.v1.Option",
      "type": [
        "object"
      ],
      "properties": {
        "id": {
          "title": "id",
          "description": "Option ID. Must be unique within a product.\n Required.",
          "type": [
            "string"
          ]
        },
        "title": {
          "title": "title",
          "description": "The title of the option in plain text, e.g. \"Sunset tour\".\n\n If there is only a single option, the option title may be the same as the\n product title. If multiple product options are presented, the title must be\n unique to the option.\n Recommended to not exceed length of 80 in any language.\n Max length: 150.\n Required.",
          "$ref": "#/definitions/travel.ttd.proto.feeds.v1.LocalizedTextSet"
        },
        "description": {
          "title": "description",
          "description": "The description of the option. Limited formatting options are allowed in\n the HTML format, see product description field for more details.\n Recommended to not exceed length of 10000 in any language.\n Max length: 16000.\n Recommended.",
          "$ref": "#/definitions/travel.ttd.proto.feeds.v1.LocalizedTextSet"
        },
        "landing_page": {
          "title": "landing_page",
          "description": "Landing page URL for this option. The page should include a button to start\n the booking/checkout flow.\n Required.",
          "$ref": "#/definitions/travel.ttd.proto.feeds.v1.DeepLink"
        },
        "landing_page_list_view": {
          "title": "landing_page_list_view",
          "description": "Link to a list view at a higher level of available tickets and tours,\n prominently showing this option possibly among other options.\n Recommended.",
          "$ref": "#/definitions/travel.ttd.proto.feeds.v1.DeepLink"
        },
        "option_features": {
          "title": "option_features",
          "description": "Additional structured details about the option features. Should not\n duplicate the details from the product level.\n Max number of features: 100.\n Optional.",
          "type": [
            "array"
          ],
          "items": {
            "$ref": "#/definitions/travel.ttd.proto.feeds.v1.TextFeature"
          },
          "maxItems": 100
        },
        "cancellation_policy": {
          "title": "cancellation_policy",
          "description": "Cancellation policy for this option.\n Recommended.",
          "$ref": "#/definitions/travel.ttd.proto.feeds.v1.CancellationPolicy"
        },
        "option_categories": {
          "title": "option_categories",
          "description": "Relevant categories for this Option. Refer to the documentation for valid\n and mutually exclusive values.\n Max number of categories: 100.\n Optional.",
          "type": [
            "array"
          ],
          "items": {
            "$ref": "#/definitions/travel.ttd.proto.feeds.v1.Category"
          },
          "maxItems": 100
        },
        "related_locations": {
          "title": "related_locations",
          "description": "List of locations related to this option.\n Max number of locations: 100.\n Recommended.",
          "type": [
            "array"
          ],
          "items": {
            "$ref": "#/definitions/travel.ttd.proto.feeds.v1.RelatedLocation"
          },
          "maxItems": 100
        },
        "base_ticket": {
          "title": "base_ticket",
          "description": "If true, the option is a *typical ticket* that a user would expect to buy\n to participate in the experience, whether it\u0027s an attraction admission or\n a slot in a tour.\n Optional, default is false.",
          "type": [
            "boolean"
          ]
        },
        "price_options": {
          "title": "price_options",
          "description": "All possible prices for this option.\n Note: With Feed Spec v1 only single Adult price is supported. If multiple\n price options were provided, the lowest price, possibly with notion\n \"from ...\" would be displayed.\n At least one is required.",
          "type": [
            "array"
          ],
          "items": {
            "$ref": "#/definitions/travel.ttd.proto.feeds.v1.PriceOption"
          },
          "minItems": 1
        },
        "duration_sec": {
          "title": "duration_sec",
          "description": "Duration of the option in seconds, where applicable, e.g. for guided tours,\n boat trips etc. This should reflect the duration of experience (not\n validity time).\n Optional.",
          "type": [
            "integer"
          ]
        },
        "languages": {
          "title": "languages",
          "description": "Languages of the option. Only where relevant -- when it\u0027s important for\n the end user to understand and/or read in the language to enjoy the\n experience. E.g. relevant for a guided tour, but not for a mini-golf pass.\n Max number of languages: 100.\n Recommended.",
          "type": [
            "array"
          ],
          "items": {
            "$ref": "#/definitions/travel.ttd.proto.feeds.v1.Language"
          },
          "maxItems": 100
        },
        "meeting_point": {
          "title": "meeting_point",
          "description": "Meeting point -- the start location. Only add where relevant and\n beneficial, e.g. the place where participant will meet the tour guide to\n start a walking tour, the place where participant will be picked up for a\n city tour, the dock where a cruise trip will start.\n Optional.",
          "$ref": "#/definitions/travel.ttd.proto.feeds.v1.Location"
        }
      },
      "additionalProperties": true,
      "required": [ "id", "title", "landing_page", "price_options" ]
    },
    "travel.ttd.proto.feeds.v1.Operator": {
      "title": "travel.ttd.proto.feeds.v1.Operator",
      "type": [
        "object"
      ],
      "properties": {
        "name": {
          "title": "name",
          "description": "Operator name.\n Recommended to not exceed length of 50 in any language. Max length: 100.\n Required.",
          "$ref": "#/definitions/travel.ttd.proto.feeds.v1.LocalizedTextSet"
        },
        "google_business_profile_name": {
          "title": "google_business_profile_name",
          "description": "Operator business name as it is registered in Google Business Profile and appearing on Google Maps",
          "$ref": "#/definitions/travel.ttd.proto.feeds.v1.LocalizedTextSet"
        },
        "phone_number": {
          "title": "phone_number",
          "description": "Operator phone number. Prefer full international phone number format.\n Max length: 64.\n Optional.",
          "type": [
            "string"
          ],
      	  "maxLength": 64
        },
        "locations": {
          "title": "locations",
          "description": "List of operator locations.\n Max number of locations: 1.\n Optional.",
          "type": [
            "array"
          ],
          "items": {
            "$ref": "#/definitions/travel.ttd.proto.feeds.v1.Location"
          },
          "maxItems": 1
        }
      },
      "additionalProperties": true,
      "oneOf": [
        {"required": [ "name" ]},
        {"required": [ "google_business_profile_name" ]}
      ]
    },
    "travel.ttd.proto.feeds.v1.Product.FulfillmentType": {
      "title": "travel.ttd.proto.feeds.v1.Product.FulfillmentType",
      "description": "Possible fulfillment types -- ways to obtain a document to confirm the\n booking. Combinations are possible, e.g. mobile + printed, or\n printed at home + in-person pickup is available.\n At least one field must be true.",
      "type": [
        "object"
      ],
      "properties": {
        "mobile": {
          "title": "mobile",
          "description": "Confirmation on a mobile phone, e.g. with a QR code.",
          "type": [
            "boolean"
          ]
        },
        "print_at_home": {
          "title": "print_at_home",
          "description": "Printable confirmation.",
          "type": [
            "boolean"
          ]
        },
        "pickup": {
          "title": "pickup",
          "description": "Admission documents to be picked up in person.",
          "type": [
            "boolean"
          ]
        }
      },
      "additionalProperties": true
    },
    "travel.ttd.proto.feeds.v1.Product": {
      "title": "travel.ttd.proto.feeds.v1.Product",
      "type": [
        "object"
      ],
      "properties": {
        "id": {
          "title": "id",
          "description": "An opaque string from the partner which uniquely identifies the product.\n Allowed characters are alphanumeric, _, and -. Max length: 255.\n Required.",
          "type": [
            "string"
          ],
          "maxLength": 255
        },
        "title": {
          "title": "title",
          "description": "The title of the product in plain text, e.g. \"Horseback riding on the\n moon\". See definition of \"LocalizedTextSet\" message for the details on the\n localization.\n Recommended to not exceed length of 80 in any language. Max length: 150.\n Required.",
          "$ref": "#/definitions/travel.ttd.proto.feeds.v1.LocalizedTextSet"
        },
        "description": {
          "title": "description",
          "description": "The description of the product. Limited formatting options are allowed in\n the HTML format. Supported tags:\n   * h1-h5\n   * ul, ol, li\n   * strong, italic, em\n   * p, br\n Other tags are not supported and will be removed. CSS, tables, style\n property, `a` links are not supported. Images are not allowed, use the\n related_media field instead.\n Important notes:\n   * Try not to use other tags except for the supported ones mentioned\n     above, because the contents within unsupported tags will be stripped,\n     and may lead to an undesirable user experience.\n   * Try avoid deep nested structures like more than 3 different heading\n     levels or nested lists. Keeping the structure flat, simple, and\n     straightforward, helps to create a better user experience.\n   * Do not duplicate info from the product_features field below in the\n     description as both would normally be shown side by side.\n Recommended to not exceed length of 10000 in any language. Max length:\n 16000.\n Recommended.",
          "$ref": "#/definitions/travel.ttd.proto.feeds.v1.LocalizedTextSet"
        },
        "product_features": {
          "title": "product_features",
          "description": "Structured details about the product features.\n Max number of features: 100.\n Recommended.",
          "type": [
            "array"
          ],
          "items": {
            "$ref": "#/definitions/travel.ttd.proto.feeds.v1.TextFeature"
          }
        },
        "rating": {
          "title": "rating",
          "description": "Aggregated product rating.\n Recommended.",
          "$ref": "#/definitions/travel.ttd.proto.feeds.v1.Rating"
        },
        "related_media": {
          "title": "related_media",
          "description": "Related media such as photos or videos.\n Max number of media: 30.\n Recommended.",
          "type": [
            "array"
          ],
          "items": {
            "$ref": "#/definitions/travel.ttd.proto.feeds.v1.Media"
          }
        },
        "use_media_order": {
          "title": "use_media_order",
          "description": "Whether Google should make use of the order in which related media are\n listed in the feed or not. The media order would be used to influence\n the final image order for the product in the UI.\n Optional, default is false.",
          "type": [
            "boolean"
          ]
        },
        "options": {
          "title": "options",
          "description": "Options available for this product.\n Max number of options: 20.\n At least one is required.",
          "type": [
            "array"
          ],
          "items": {
            "$ref": "#/definitions/travel.ttd.proto.feeds.v1.Option"
          },
          "minItems": 1,
          "maxItems": 20
        },
        "operator": {
          "title": "operator",
          "description": "Operator details.\n Optional.",
          "$ref": "#/definitions/travel.ttd.proto.feeds.v1.Operator"
        },
        "inventory_type": {
          "title": "inventory_type",
          "description": "Optional.",
          "$ref": "#/definitions/travel.ttd.proto.feeds.v1.Product.InventoryType"
        },
        "inventory_types": {
          "title": "inventory_types",
          "description": "Should contain only distinct values of InventoryType.\n Max number of inventory types: 2.\n Optional.",
          "type": [
            "array"
          ],
          "items": {
            "$ref": "#/definitions/travel.ttd.proto.feeds.v1.Product.InventoryType"
          },
          "maxItems": 2
        },
        "confirmation_type": {
          "title": "confirmation_type",
          "description": "Optional.",
          "$ref": "#/definitions/travel.ttd.proto.feeds.v1.Product.ConfirmationType"
        },
        "fulfillment_type": {
          "title": "fulfillment_type",
          "description": "Recommended.",
          "$ref": "#/definitions/travel.ttd.proto.feeds.v1.Product.FulfillmentType"
        },
        "brand_name": {
          "title": "brand_name",
          "description": "Provider brand name",
          "$ref": "#/definitions/travel.ttd.proto.feeds.v1.LocalizedTextSet"
        }
      },
      "additionalProperties": true,
      "required": [ "id", "title", "options" ]
    },
    "travel.ttd.proto.feeds.v1.FeedMetadata.ProcessingInstruction": {
      "title": "travel.ttd.proto.feeds.v1.FeedMetadata.ProcessingInstruction",
      "enum": [
        "PROCESS_AS_UNSPECIFIED",
        "PROCESS_AS_SNAPSHOT",
        "PROCESS_AS_UPSERT"
      ]
    },
    "travel.ttd.proto.feeds.v1.TextFeature.TextFeatureType": {
      "title": "travel.ttd.proto.feeds.v1.TextFeature.TextFeatureType",
      "enum": [
        "TEXT_FEATURE_UNKNOWN",
        "TEXT_FEATURE_INCLUSION",
        "TEXT_FEATURE_EXCLUSION",
        "TEXT_FEATURE_HIGHLIGHT",
        "TEXT_FEATURE_MUST_KNOW",
        "TEXT_FEATURE_SAFETY_INFORMATION"
      ]
    },
    "travel.ttd.proto.feeds.v1.Media.MediaType": {
      "title": "travel.ttd.proto.feeds.v1.Media.MediaType",
      "enum": [
        "MEDIA_TYPE_UNSPECIFIED",
        "MEDIA_TYPE_PHOTO"
      ]
    },
    "travel.ttd.proto.feeds.v1.RelatedLocation.RelationType": {
      "title": "travel.ttd.proto.feeds.v1.RelatedLocation.RelationType",
      "enum": [
        "RELATION_TYPE_RELATED_NO_ADMISSION",
        "RELATION_TYPE_ADMISSION_TICKET",
        "RELATION_TYPE_SUPPLEMENTARY_ADDON"
      ]
    },
    "travel.ttd.proto.feeds.v1.Product.InventoryType": {
      "title": "travel.ttd.proto.feeds.v1.Product.InventoryType",
      "description": "Inventory type of this product.",
      "enum": [
        "INVENTORY_TYPE_DEFAULT",
        "INVENTORY_TYPE_OFFICIAL",
        "INVENTORY_TYPE_OPERATOR_DIRECT"
      ]
    },
    "travel.ttd.proto.feeds.v1.Product.ConfirmationType": {
      "title": "travel.ttd.proto.feeds.v1.Product.ConfirmationType",
      "description": "Confirmation type of this product.",
      "enum": [
        "CONFIRMATION_TYPE_UNKNOWN",
        "CONFIRMATION_TYPE_INSTANT",
        "CONFIRMATION_TYPE_24HRS",
        "CONFIRMATION_TYPE_48HRS"
      ]
    }
  }
}