Feed proto bundle

// Feeds declaration
syntax = "proto2";

package ext.travel.ttd.proto.feeds.v1;

message ProductFeed {
  // Metadata for this feed.
  // Required.
  FeedMetadata feed_metadata = 1;

  // List of the products.
  // Optional. When unset in all shards, all products will be deleted.
  repeated Product products = 2;
}

message FeedMetadata {
  // The current shard ID, zero-based. Shards do not need to be transferred in
  // order. Processing will start only after a full set of shards was uploaded.
  // Required when total_shards_count > 1.
  uint32 shard_id = 1;

  // Total number of shards in this transfer.
  // Required. Must be >= 1.
  uint32 total_shards_count = 2;

  // An arbitrary number used to link multiple shards to the same transfer.
  // Required when total_shards_count > 1.
  // Must be the same for all shards within the transfer.
  uint64 nonce = 3;

  enum ProcessingInstruction {
    // For compatibility, don't use.
    PROCESS_AS_UNSPECIFIED = 0;

    // This Feed upload should be processed as a complete snapshot replacing any
    // previously uploaded data of this type.
    // Supported feed types: product.
    PROCESS_AS_SNAPSHOT = 1;

    // This Feed upload should be processed as an upsert, updating or adding
    // data to the previous uploads. Supported feed types: reviews,
    // availability.
    PROCESS_AS_UPSERT = 2;
  }
  // Processing instruction for this upload.
  // Required.
  ProcessingInstruction processing_instruction = 4;

  // Maximal share of currently active products that are allowed to be removed
  // by an upload. If more products will be removed by this transfer, the whole
  // transfer will be rejected.
  // This is a safeguard against unintentional take down of a significant part
  // of the inventory. Can be set to 1.0 to allow complete inventory take down.
  // Optional.
  double max_removal_share = 5;
}

message Product {
  // An opaque string from the partner which uniquely identifies the product.
  // Allowed characters are alphanumeric, _, and -. Max length: 255.
  // Required.
  string id = 1;

  // The title of the product in plain text, e.g. "Horseback riding on the
  // moon". See definition of "LocalizedTextSet" message for the details on the
  // localization.
  // Recommended to not exceed length of 80 in any language. Max length: 150.
  // Required.
  LocalizedTextSet title = 2;

  // The description of the product. Limited formatting options are allowed in
  // the HTML format. Supported tags:
  //   * h1-h5
  //   * ul, ol, li
  //   * strong, italic, em
  //   * p, br
  // Other tags are not supported and will be removed. CSS, tables, style
  // property, `a` links are not supported. Images are not allowed, use the
  // related_media field instead.
  // Important notes:
  //   * Try not to use other tags except for the supported ones mentioned
  //     above, because the contents within unsupported tags will be stripped,
  //     and may lead to an undesirable user experience.
  //   * Try avoid deep nested structures like more than 3 different heading
  //     levels or nested lists. Keeping the structure flat, simple, and
  //     straightforward, helps to create a better user experience.
  //   * Do not duplicate info from the product_features field below in the
  //     description as both would normally be shown side by side.
  // Recommended to not exceed length of 10000 in any language. Max length:
  // 16000.
  // Recommended.
  LocalizedTextSet description = 3;

  // Structured details about the product features.
  // Max number of features: 100.
  // Recommended.
  repeated TextFeature product_features = 4;

  // Aggregated product rating.
  // Recommended.
  Rating rating = 5;

  // Related media such as photos or videos.
  // Max number of media: 30.
  // Recommended.
  repeated Media related_media = 6;

  // Options available for this product.
  // Max number of options: 20.
  // At least one is required.
  repeated Option options = 7;

  // Operator details.
  // Optional.
  Operator operator = 8;

  // Inventory type of this product.
  enum InventoryType {
    // Default inventory type.
    INVENTORY_TYPE_DEFAULT = 0;
    // Product is an official ticket to a point of interest. To learn what
    // qualifies as official inventory, refer to the policy doc.
    INVENTORY_TYPE_OFFICIAL = 1;
  }
  // Optional.
  InventoryType inventory_type = 9;

  // Confirmation type of this product.
  enum ConfirmationType {
    // Type of confirmation is unknown.
    CONFIRMATION_TYPE_UNKNOWN = 0;
    // Booking is confirmed to the end user immediately.
    CONFIRMATION_TYPE_INSTANT = 1;
    // Booking is confirmed to the end user within 24 hours.
    CONFIRMATION_TYPE_24HRS = 2;
    // Booking is confirmed to the end user within 48 hours.
    CONFIRMATION_TYPE_48HRS = 3;
  }
  // Optional.
  ConfirmationType confirmation_type = 10;

  // Possible fulfillment types -- ways to obtain a document to confirm the
  // booking. Combinations are possible, e.g. mobile + printed, or
  // printed at home + in-person pickup is available.
  // At least one field must be true.
  message FulfillmentType {
    // Confirmation on a mobile phone, e.g. with a QR code.
    bool mobile = 1;
    // Printable confirmation.
    bool print_at_home = 2;
    // Admission documents to be picked up in person.
    bool pickup = 3;
  }
  // Recommended.
  FulfillmentType fulfillment_type = 11;
}

message Option {
  // Option ID. Must be unique within a product.
  // Required.
  string id = 1;

  // The title of the option in plain text, e.g. "Sunset tour".
  //
  // If there is only a single option, the option title may be the same as the
  // product title. If multiple product options are presented, the title must be
  // unique to the option.
  // Recommended to not exceed length of 80 in any language. Max length: 150.
  //
  // Required.
  LocalizedTextSet title = 2;

  // The description of the option. Limited formatting options are allowed in
  // the HTML format, see product description field for more details.
  // Recommended to not exceed length of 10000 in any language. Max length:
  // 16000.
  // Recommended.
  LocalizedTextSet description = 3;

  // Landing page URL for this option. The page should include a button to start
  // the booking/checkout flow.
  // Required.
  DeepLink landing_page = 5;

  // Link to a list view at a higher level of available tickets and tours,
  // prominently showing this option possibly among other options.
  // Recommended.
  DeepLink landing_page_list_view = 6;

  // Additional structured details about the option features. Should not
  // duplicate the details from the product level.
  // Max number of features: 100.
  // Optional.
  repeated TextFeature option_features = 7;

  // Cancellation policy for this option.
  // Recommended.
  CancellationPolicy cancellation_policy = 8;

  // Relevant categories for this Option. Refer to the documentation for valid
  // and mutually exclusive values.
  // Max number of categories: 100.
  // Optional.
  repeated Category option_categories = 9;

  // List of locations related to this option.
  // Max number of locations: 100.
  // Recommended.
  repeated RelatedLocation related_locations = 10;

  // If true, the option is a *typical ticket* that a user would expect to buy
  // to participate in the experience, whether it's an attraction admission or
  // a slot in a tour.
  // Optional, default is false.
  bool base_ticket = 11;

  // All possible prices for this option.
  // Note: With Feed Spec v1 only single Adult price is supported. If multiple
  // price options were provided, the lowest price, possibly with notion
  // "from ..." would be displayed.
  // At least one is required.
  repeated PriceOption price_options = 12;

  // Duration of the option in seconds, where applicable, e.g. for guided tours,
  // boat trips etc. This should reflect the duration of experience (not
  // validity time).
  // Optional.
  uint32 duration_sec = 16;

  // Languages of the option. Only where relevant -- when it's important for
  // the end user to understand and/or read in the language to enjoy the
  // experience. E.g. relevant for a guided tour, but not for a mini-golf pass.
  // Max number of languages: 100.
  // Recommended.
  repeated Language languages = 14;

  // Meeting point -- the start location. Only add where relevant and
  // beneficial, e.g. the place where participant will meet the tour guide to
  // start a walking tour, the place where participant will be picked up for a
  // city tour, the dock where a cruise trip will start.
  // Optional.
  Location meeting_point = 15;
}

message TextFeature {
  enum TextFeatureType {
    // Don't use, for backwards compatibility only.
    TEXT_FEATURE_UNKNOWN = 0;
    // Feature is an inclusion.
    TEXT_FEATURE_INCLUSION = 1;
    // Feature is an exclusion.
    TEXT_FEATURE_EXCLUSION = 2;
    // Feature is a highlight.
    TEXT_FEATURE_HIGHLIGHT = 3;
    // Feature is a "must know".
    TEXT_FEATURE_MUST_KNOW = 4;
    // Feature represents information about safety measures.
    TEXT_FEATURE_SAFETY_INFORMATION = 5;
  }
  // Feature type.
  // Required.
  TextFeatureType feature_type = 1;

  // LocalizedTextSet content of the feature. Values support both plain-text
  // and HTML-like text for basic formatting. Supported HTML formatting tags:
  //
  // Phrase tags: <br>, <strong>, <em>, <i>:
  //   Only the four tags mentioned above are supported. <br> can be used to
  //   break lines in paragraphs, and <strong>/<em>/<i> can be used to highlight
  //   important text. Any other phrase tags will be ignored.
  //
  // All other tags and custom styles are not allowed and will be removed. Any
  // URLs, anchors, and links will be stripped, and will never be displayed to
  // end-users.
  // Recommended to not exceed length of 1000 in any language. Max length: 2000.
  // Required.
  LocalizedTextSet value = 2;
}

message Rating {
  // Average rating value.
  // The value must be in the range of [1, 5] and can be omitted if and only if
  // the rating_count is zero.
  double average_value = 1;

  // Number of ratings used in calculating the value.
  // Required.
  uint64 rating_count = 2;
}

message Media {
  // URL of this media source. Google will crawl the media hosted at this URL.
  // Max length: 2000.
  // Required.
  string url = 1;

  enum MediaType {
    // Don't use, for backwards compatibility only.
    MEDIA_TYPE_UNSPECIFIED = 0;
    // Indicates the media provided by the url is a photo.
    MEDIA_TYPE_PHOTO = 1;
  }
  // Type of this media source.
  // Required.
  MediaType type = 2;

  // Attribution information about the source of the media. Note that if
  // the attribution is required to display with the media to give credit to
  // photographer or agency, this field must be set.
  // Recommended to not exceed length of 1000 in any language. Max length: 2000.
  // Optional.
  LocalizedTextSet attribution = 3;
}

message Category {
  // Refer to the documentation for the valid values list.
  // Required.
  string label = 1;
}

// Defines relation between an option and a location.
message RelatedLocation {
  // Location related to an option. Can be a POI (e.g. Eiffel tower),
  // neighbourhood (e.g. Old Town) or an address / arbitrary map point.
  // Required.
  Location location = 1;

  enum RelationType {
    // Location is related but relation does not allow admission or admission is
    // irrelevant, e.g. location is a square highlighted in a city tour.
    RELATION_TYPE_RELATED_NO_ADMISSION = 0;
    // Relation grants admission to this related location.
    RELATION_TYPE_ADMISSION_TICKET = 1;
    // Relation declares an additional service which doesn't get the user into
    // the related location, e.g. a parking ticket, a temporary exhibition, etc.
    RELATION_TYPE_SUPPLEMENTARY_ADDON = 2;
  }
  // Relation type of an option for the given location.
  // Required.
  RelationType relation_type = 2;
}

// Deep link definition. Can include value parameters that will be expanded on
// serve time.
message DeepLink {
  // Landing page URL template for desktop.
  // Max length: 2000.
  // Required.
  string url = 1;

  // Landing page URL template for mobile. If omitted, it defaults to the `url`
  // value.
  // Max length: 2000.
  // Optional.
  string mobile_url = 2;
}

message Operator {
  // Operator name.
  // Recommended to not exceed length of 50 in any language. Max length: 100.
  // Required.
  LocalizedTextSet name = 1;

  // Operator phone number. Prefer full international phone number format.
  // Max length: 64.
  // Optional.
  string phone_number = 2;
}

message Language {
  // A BCP 47 compliant language code such as "en" or "de-CH".
  string code = 1;
}

message PriceOption {
  // Unique ID within the price set.
  // Max length: 255.
  // Required.
  string id = 1;

  // Short description of the price option, e.g. "Adult weekday".
  // Max length: 150.
  // Required.
  string title = 2;

  // Price value, must match the final price on the checkout page, including all
  // taxes and charges, see price policy. Currency will be converted to the user
  // currency on rendering.
  // Required when is_free is false.
  google.type.Money price = 3;

  // Admission or ticket is free. Must be set to true for zero-price options.
  // Optional, default is false.
  bool is_free = 4;

  // List of geographical regions this price is applicable to. If empty,
  // applicable to all locations.
  // Optional.
  repeated GeoCriterion geo_criteria = 5;

  // Break down of fees and taxes included in the price above.
  // Optional.
  PriceFeesAndTaxes fees_and_taxes = 6;
}

message GeoCriterion {
  // 2-letter country code as defined in ISO 3166-1.
  // Required.
  string country_code = 1;

  // If true, criterion is negative (the country code is excluded).
  bool is_negative = 2;
}

message PriceFeesAndTaxes {
  // Booking fees included in the final product price for a single ticket.
  // Optional.
  google.type.Money per_ticket_fee = 1;

  // State taxes included in the final product price for a single ticket.
  // Optional.
  google.type.Money per_ticket_tax = 2;
}

message Location {
  // At least one of (location, description) must be set, and we highly
  // recommend populating location wherever possible.
  //
  // To emphasize, both fields can be populated together, e.g. you can set
  // Central Park New York for the location and "In front of the 72 Street
  // Station" for the description.
  GeoLocation location = 1;

  // Additional description in human-readable form, e.g.
  //     "On the left side of the fountain on the Palace square".
  // At least one of (location, description) must be set.
  // Recommended to not exceed length of 1000 in any language. Max length: 2000.
  LocalizedTextSet description = 2;
}

message GeoLocation {
  // Required (exactly one variant from oneof).
  oneof value {
    // PlaceId as defined by The Places API:
    //   https://developers.google.com/places/web-service/place-id
    //
    // This is the most preferred option as it is the most accurate and do not
    // contain any ambiguity as to the point of interest.
    string place_id = 1;

    // Location as an address suitable for machine processing.
    // Max length: 150.
    //
    // This is the next preferred option outside of place_id.
    string address = 3;

    // When place ID and address are not available, the lat_lng field could be
    // used to specify the coordinates.
    //
    // This is the least preferred option as it is the most ambiguous when used
    // to describe the POI. lat_lng will only be used to determine the city and
    // geographic region the POI is in.
    google.type.LatLng lat_lng = 2;
  }
}

// Values of the localized fields.
message LocalizedTextSet {
  // Per-locale LocalizedText values.
  repeated google.type.LocalizedText localized_texts = 1;
}

// Cancellation policy for a product.
message CancellationPolicy {
  // Defines a single refund condition. Multiple refund conditions could be
  // used together to describe "refund steps" as various durations before the
  // service start time.
  message RefundCondition {
    // Duration in seconds before the start time, until when the customer can
    // receive a refund for part of the service's cost specified in
    // `refund_percent`.
    // When unset or set to 0 the service can be cancelled at any time.
    // Optional.
    uint32 min_duration_before_start_time_sec = 1;

    // The percent that can be refunded, as long as the service booking is
    // cancelled at least `min_duration_before_start_time` before the service
    // start time, in the range of [0, 100].
    // When unset or set to 0, the service is not refundable. When set to 100
    // this service is fully refundable.
    // Optional.
    uint32 refund_percent = 2;

    // A flat fee deducted on refund. Could be used separately, or in
    // combination with the refund_percent above. In the latter case, refund
    // percent applies first, then the fee is deducted.
    // Optional.
    google.type.Money refund_fee = 3;
  }
  // Zero or more refund conditions applicable to the policy.
  // Max number of refund conditions: 5.
  repeated RefundCondition refund_conditions = 1;
}

// A Duration represents a signed, fixed-length span of time represented
// as a count of seconds and fractions of seconds at nanosecond
// resolution. It is independent of any calendar and concepts like "day"
// or "month". It is related to Timestamp in that the difference between
// two Timestamp values is a Duration and it can be added or subtracted
// from a Timestamp. Range is approximately +-10,000 years.
//
// # JSON Mapping
//
// In JSON format, the Duration type is encoded as a string rather than an
// object, where the string ends in the suffix "s" (indicating seconds) and
// is preceded by the number of seconds, with nanoseconds expressed as
// fractional seconds. For example, 3 seconds with 0 nanoseconds should be
// encoded in JSON format as "3s", while 3 seconds and 1 nanosecond should
// be expressed in JSON format as "3.000000001s", and 3 seconds and 1
// microsecond should be expressed in JSON format as "3.000001s".
//
message Duration {
  // Signed seconds of the span of time. Must be from -315,576,000,000
  // to +315,576,000,000 inclusive. Note: these bounds are computed from:
  // 60 sec/min * 60 min/hr * 24 hr/day * 365.25 days/year * 10000 years
  int64 seconds = 1;

  // Signed fractions of a second at nanosecond resolution of the span
  // of time. Durations less than one second are represented with a 0
  // `seconds` field and a positive or negative `nanos` field. For durations
  // of one second or more, a non-zero value for the `nanos` field must be
  // of the same sign as the `seconds` field. Must be from -999,999,999
  // to +999,999,999 inclusive.
  int32 nanos = 2;
}

// Represents an amount of money with its currency type.
message Money {
  // The three-letter currency code defined in ISO 4217.
  string currency_code = 1;

  // The whole units of the amount.
  // For example if `currencyCode` is `"USD"`, then 1 unit is one US dollar.
  int64 units = 2;

  // Number of nano (10^-9) units of the amount.
  // The value must be between -999,999,999 and +999,999,999 inclusive.
  // If `units` is positive, `nanos` must be positive or zero.
  // If `units` is zero, `nanos` can be positive, zero, or negative.
  // If `units` is negative, `nanos` must be negative or zero.
  // For example $-1.75 is represented as `units`=-1 and `nanos`=-750,000,000.
  int32 nanos = 3;
}

// An object that represents a latitude/longitude pair. This is expressed as a
// pair of doubles to represent degrees latitude and degrees longitude. Unless
// specified otherwise, this must conform to the
// <a href="http://www.unoosa.org/pdf/icg/2012/template/WGS_84.pdf">WGS84
// standard</a>. Values must be within normalized ranges.
message LatLng {
  // The latitude in degrees. It must be in the range [-90.0, +90.0].
  double latitude = 1;

  // The longitude in degrees. It must be in the range [-180.0, +180.0].
  double longitude = 2;
}

message LocalizedText {
  // Localized string in the language corresponding to `language_code' below.
  string text = 1;

  // The text's BCP-47 language code, such as "en-US" or "sr-Latn".
  //
  // For more information, see
  // http://www.unicode.org/reports/tr35/#Unicode_locale_identifier.
  string language_code = 2;
}