GetBulkTripOptions 메서드

GetTripOptions 메서드와 비교할 때 GetBulkTripOptions 메서드에는 다음과 같은 이점이 있습니다.

  • 더 적은 요청을 사용하고 파트너가 데이터를 직접 획득하는 데 사용할 수 있는 운영자의 업스트림 API와 더 잘 정렬하여 Google 캐시를 더 효율적으로 채울 수 있습니다.
  • 파트너가 이용 가능한 여정의 사전 정의된 집합을 사용하여 자세한 여정 검사 없이 데이터를 제공할 수 있습니다.
  • 더 정교한 파트너의 경우 파트너 인벤토리와 Google 라우팅 엔진에서 생성된 숙박 일정의 일치율을 극대화하여 가능한 한 많은 숙박 일정에 파트너 가격을 표시할 수 있도록 알려진 숙박 일정 목록을 제공합니다.
  • 향후 파트너 인벤토리에 더 잘 맞도록 Google 라우팅 엔진을 조정하기 위해 Google에서 아직 제공하지 않는 여정을 수집할 수 있습니다.

GetBulkTripOptionsRequest

Proto 정의

// Request sent to partners.
message GetBulkTripOptionsRequest {
  // The MarketDates for which to return results.
  // Initially, only a single value will be supplied, representing one-way
  // trips.
  repeated MarketDate market_dates = 1;

  // List of itineraries matching market_dates that Google knows about and will
  // serve to end users. Partners should try to return results matching these
  // itineraries, as other itineraries will not be immediately useful other than
  // for analysis purposes.
  repeated ItineraryKey known_itineraries = 2;

  // If true, only the explicitly specified known_itineraries should be
  // returned. Not in use yet (always set to false).
  bool only_known_itineraries = 3;
}

message MarketDate {
  // ID of the stop where the traveler starts their journey.
  string origin_ticketing_stop_id = 1;

  // Stop ID of the ultimate journey destination of the traveler.
  string destination_ticketing_stop_id = 2;

  // Date of departure at the origin, in the timezone at the origin.
  .google.type.Date departure_date = 3;
}

// A full end-to-end journey for a traveler, including all vehicles used.
message ItineraryKey {
  // All segments together should form a single trip for which a ticket can be
  // booked.
  repeated ext.travel.transport.partner.SegmentKey segment_keys = 1;
}

JSON 샘플

{
  "market_dates": [
    {
      "origin_ticketing_stop_id": "ZRH-1234",
      "destination_ticketing_stop_id": "WOL-2455",
      "departure_date": {
        "year": 2023,
        "month": 5,
        "day": 15
      }
    }
  ],
  "known_itineraries": [
    {
      "segment_keys": [
        {
          "ticketing_trip_id": "123456",
          "from_ticketing_stop_time_id": "ZRH-1234",
          "to_ticketing_stop_time_id": "LUZ-1235",
          "service_date": {
            "year": 2023,
            "month": 5,
            "day": 15
          },
          "boarding_time": {
            "year": 2023,
            "month": 5,
            "day": 15,
            "hours": 14,
            "minutes": 25,
            "seconds": 0,
            "nanos": 0,
            "utc_offset": "0s"
          },
          "arrival_time": {
            "year": 2023,
            "month": 5,
            "day": 15,
            "hours": 16,
            "minutes": 25,
            "seconds": 0,
            "nanos": 0,
            "utc_offset": "0s"
          }
        },
        {
          "ticketing_trip_id": "988833",
          "from_ticketing_stop_time_id": "LUZ-1235",
          "to_ticketing_stop_time_id": "WOL-2455",
          "service_date": {
            "year": 2023,
            "month": 5,
            "day": 15
          },
          "boarding_time": {
            "year": 2023,
            "month": 5,
            "day": 15,
            "hours": 18,
            "minutes": 13,
            "seconds": 0,
            "nanos": 0,
            "utc_offset": "0s"
          },
          "arrival_time": {
            "year": 2023,
            "month": 5,
            "day": 15,
            "hours": 20,
            "minutes": 13,
            "seconds": 0,
            "nanos": 0,
            "utc_offset": "0s"
          }
        }
      ]
    },
    {
      "segment_keys": [
        {
          "ticketing_trip_id": "98765",
          "from_ticketing_stop_time_id": "ZRH-1234",
          "to_ticketing_stop_time_id": "ZUG-1235",
          "service_date": {
            "year": 2023,
            "month": 5,
            "day": 15
          },
          "boarding_time": {
            "year": 2023,
            "month": 5,
            "day": 15,
            "hours": 14,
            "minutes": 30,
            "seconds": 0,
            "nanos": 0,
            "utc_offset": "0s"
          },
          "arrival_time": {
            "year": 2023,
            "month": 5,
            "day": 15,
            "hours": 16,
            "minutes": 30,
            "seconds": 0,
            "nanos": 0,
            "utc_offset": "0s"
          }
        },
        {
          "ticketing_trip_id": "43210",
          "from_ticketing_stop_time_id": "ZUG-1235",
          "to_ticketing_stop_time_id": "WOL-2455",
          "service_date": {
            "year": 2023,
            "month": 5,
            "day": 15
          },
          "boarding_time": {
            "year": 2023,
            "month": 5,
            "day": 15,
            "hours": 18,
            "minutes": 13,
            "seconds": 0,
            "nanos": 0,
            "utc_offset": "0s"
          },
          "arrival_time": {
            "year": 2023,
            "month": 5,
            "day": 15,
            "hours": 20,
            "minutes": 13,
            "seconds": 0,
            "nanos": 0,
            "utc_offset": "0s"
          }
        }
      ]
    }
  ],
  "only_known_itineraries": false
}

GetBulkTripOptionsResponse

Proto 정의

// Response received from partners.
message GetBulkTripOptionsResponse {
  oneof response {
    BulkTripOptionsResult bulk_trip_options_result = 1;
    BulkTripOptionsError bulk_trip_options_error = 2;
  }
}

// A message representing a successful response.
message BulkTripOptionsResult {
  // One response per entry in known_itineraries in the request, plus any
  // additional ones partners choose to return if only_known_itineraries is
  // false.
  repeated ItineraryResponse itinerary_responses = 1;
}

// A message for errors affecting the whole request.
message BulkTripOptionsError {
  enum BulkTripOptionsErrorType {
    // An unexpected error happened during retrieval of this trip.
    // This indicates a bug that needs to be fixed by the partner.
    // This error is retriable.
    // Always returns HTTP 500 status code in response.
    INTERNAL_ERROR = 1;
  }

  BulkTripOptionsErrorType error_type = 1;

  // This is not user-visible and is for logging and debugging purposes only.
  string error_message = 2;
}

// A message container for an itinerary with a set of prices for that itinerary.
message ItineraryResponse {
  // A single itinerary that this response relates to.
  ItineraryKey itinerary = 1;

  oneof response {
    // A set of prices for this itinerary.
    TripOptionSet trip_option_set = 2;

    // Error information about the retrieval of this itinerary.
    TripOptionsError trip_options_error = 3;
  }
}

// A container for multiple trip options.
message TripOptionSet {
  // To reduce the amount of data transferred, segments.segment_key can be empty
  // inside these trip_options, since the segment_key is already present in
  // ItineraryResponse.itinerary.segment_keys. This requires the number of
  // segments in to each TripOption to match exactly the number of segments
  // inside ItineraryResponse.itinerary. We then assume that the n-th
  // trip_options.segments.segment_key matches the n-th itinerary.segment_key.
  repeated TripOption trip_options = 1;
}


// A travel option for users covering the whole end-to-end journey with the
// partner.
message TripOption {
  // A series of Segments that cover the whole trip option, one for each
  // SegmentKey in the request.
  repeated Segment segments = 1;

  // This is the lowest standard fare of all seats with the specified segments.
  // This field is optional if the series of segments is unavailable.
  // This "standard fare" should be the lowest seat price where no age or other
  // booking restrictions apply. The currency should be the local currency of
  // the origin of the first segment.
  Fare lowest_standard_fare = 2;

  // The availability status for bookings of this trip option at the
  // lowest_standard_fare.
  Availability availability = 3;

  // This is used to receive optional extra data via the Travel Transport API
  // and pass it into the ticketing deep link.
  // Booking links should still work without the booking token, but the token
  // can be used to ensure price consistency between Google Search results and
  // the partner booking page.
  string booking_token = 4 [features.field_presence = EXPLICIT];
}

// A segment traveled on a single vehicle in a given Service Class.
message Segment {
  SegmentKey segment_key = 1;

  // The service class used on this segment.
  ServiceClass service_class = 2;
}

JSON 샘플

{
  "bulk_trip_options_result": {
    "itinerary_responses": [
      {
        "itinerary": {
          "segment_keys": [
            {
              "ticketing_trip_id": "123456",
              "from_ticketing_stop_time_id": "ZRH-1234",
              "to_ticketing_stop_time_id": "LUZ-1235",
              "service_date": {
                "year": 2023,
                "month": 5,
                "day": 15
              },
              "boarding_time": {
                "year": 2023,
                "month": 5,
                "day": 15,
                "hours": 14,
                "minutes": 25,
                "seconds": 0,
                "nanos": 0,
                "utc_offset": "0s"
              },
              "arrival_time": {
                "year": 2023,
                "month": 5,
                "day": 15,
                "hours": 16,
                "minutes": 25,
                "seconds": 0,
                "nanos": 0,
                "utc_offset": "0s"
              }
            },
            {
              "ticketing_trip_id": "988833",
              "from_ticketing_stop_time_id": "LUZ-1235",
              "to_ticketing_stop_time_id": "WOL-2455",
              "service_date": {
                "year": 2023,
                "month": 5,
                "day": 15
              },
              "boarding_time": {
                "year": 2023,
                "month": 5,
                "day": 15,
                "hours": 18,
                "minutes": 13,
                "seconds": 0,
                "nanos": 0,
                "utc_offset": "0s"
              },
              "arrival_time": {
                "year": 2023,
                "month": 5,
                "day": 15,
                "hours": 20,
                "minutes": 13,
                "seconds": 0,
                "nanos": 0,
                "utc_offset": "0s"
              }
            }
          ]
        },
        "trip_option_set": {
          "trip_options": [
            {
              "segments": [
                {
                  "service_class": {
                    "type": "SECOND_CLASS"
                  }
                },
                {
                  "service_class": {
                    "type": "SECOND_CLASS"
                  }
                }
              ],
              "lowest_standard_fare": {
                "total_amount": {
                  "units": 10,
                  "nanos": 0,
                  "currency_code": "CHF"
                },
                "line_items": [
                  {
                    "line_item_type": "BASE_FARE",
                    "amount": {
                      "units": 9,
                      "nanos": 750000000,
                      "currency_code": "CHF"
                    }
                  },
                  {
                    "line_item_type": "SERVICE_CHARGE",
                    "amount": {
                      "units": 0,
                      "nanos": 250000000,
                      "currency_code": "CHF"
                    }
                  }
                ]
              },
              "availability": {
                "available": {
                  "available_seat_count": 44,
                  "total_seat_count": 200
                }
              }
            },
            {
              "segments": [
                {
                  "service_class": {
                    "type": "FIRST_CLASS"
                  }
                },
                {
                  "service_class": {
                    "type": "FIRST_CLASS"
                  }
                }
              ],
              "lowest_standard_fare": {
                "total_amount": {
                  "units": 15,
                  "nanos": 0,
                  "currency_code": "CHF"
                },
                "line_items": [
                  {
                    "line_item_type": "BASE_FARE",
                    "amount": {
                      "units": 13,
                      "nanos": 950000000,
                      "currency_code": "CHF"
                    }
                  },
                  {
                    "line_item_type": "SERVICE_CHARGE",
                    "amount": {
                      "units": 1,
                      "nanos": 50000000,
                      "currency_code": "CHF"
                    }
                  }
                ]
              },
              "availability": {
                "available": {
                  "available_seat_count": 10,
                  "total_seat_count": 100
                }
              }
            }
          ]
        }
      },
      {
        "itinerary": {
          "segment_keys": [
            {
              "ticketing_trip_id": "98765",
              "from_ticketing_stop_time_id": "ZRH-1234",
              "to_ticketing_stop_time_id": "ZUG-1235",
              "service_date": {
                "year": 2023,
                "month": 5,
                "day": 15
              },
              "boarding_time": {
                "year": 2023,
                "month": 5,
                "day": 15,
                "hours": 14,
                "minutes": 30,
                "seconds": 0,
                "nanos": 0,
                "utc_offset": "0s"
              },
              "arrival_time": {
                "year": 2023,
                "month": 5,
                "day": 15,
                "hours": 16,
                "minutes": 30,
                "seconds": 0,
                "nanos": 0,
                "utc_offset": "0s"
              }
            },
            {
              "ticketing_trip_id": "43210",
              "from_ticketing_stop_time_id": "ZUG-1235",
              "to_ticketing_stop_time_id": "WOL-2455",
              "service_date": {
                "year": 2023,
                "month": 5,
                "day": 15
              },
              "boarding_time": {
                "year": 2023,
                "month": 5,
                "day": 15,
                "hours": 18,
                "minutes": 13,
                "seconds": 0,
                "nanos": 0,
                "utc_offset": "0s"
              },
              "arrival_time": {
                "year": 2023,
                "month": 5,
                "day": 15,
                "hours": 20,
                "minutes": 13,
                "seconds": 0,
                "nanos": 0,
                "utc_offset": "0s"
              }
            }
          ]
        },
        "trip_option_set": {
          "trip_options": [
            {
              "segments": [
                {
                  "service_class": {
                    "type": "SECOND_CLASS"
                  }
                },
                {
                  "service_class": {
                    "type": "SECOND_CLASS"
                  }
                }
              ],
              "lowest_standard_fare": {
                "total_amount": {
                  "units": 9,
                  "nanos": 0,
                  "currency_code": "CHF"
                },
                "line_items": [
                  {
                    "line_item_type": "BASE_FARE",
                    "amount": {
                      "units": 8,
                      "nanos": 750000000,
                      "currency_code": "CHF"
                    }
                  },
                  {
                    "line_item_type": "SERVICE_CHARGE",
                    "amount": {
                      "units": 0,
                      "nanos": 250000000,
                      "currency_code": "CHF"
                    }
                  }
                ]
              },
              "availability": {
                "available": {
                  "available_seat_count": 30,
                  "total_seat_count": 150
                }
              }
            },
            {
              "segments": [
                {
                  "service_class": {
                    "type": "FIRST_CLASS"
                  }
                },
                {
                  "service_class": {
                    "type": "FIRST_CLASS"
                  }
                }
              ],
              "lowest_standard_fare": {
                "total_amount": {
                  "units": 14,
                  "nanos": 0,
                  "currency_code": "CHF"
                },
                "line_items": [
                  {
                    "line_item_type": "BASE_FARE",
                    "amount": {
                      "units": 12,
                      "nanos": 950000000,
                      "currency_code": "CHF"
                    }
                  },
                  {
                    "line_item_type": "SERVICE_CHARGE",
                    "amount": {
                      "units": 1,
                      "nanos": 50000000,
                      "currency_code": "CHF"
                    }
                  }
                ]
              },
              "availability": {
                "available": {
                  "available_seat_count": 15,
                  "total_seat_count": 60
                }
              }
            }
          ]
        }
      }
    ]
  }
}

JSON 오류 샘플

{
  "bulk_trip_options_error": {
    "error_type": "INTERNAL_ERROR",
    "error_message": "Unexpected RoutingException during trip lookup."
  }
}

JSON 부분 오류

{
  "bulk_trip_options_result": {
    "itinerary_responses": [
      {
        "itinerary": {
          "segment_keys": [
            {
              "ticketing_trip_id": "123456",
              "from_ticketing_stop_time_id": "ZRH-1234",
              "to_ticketing_stop_time_id": "LUZ-1235",
              "service_date": {
                "year": 2023,
                "month": 5,
                "day": 15
              },
              "boarding_time": {
                "year": 2023,
                "month": 5,
                "day": 15,
                "hours": 14,
                "minutes": 25,
                "seconds": 0,
                "nanos": 0,
                "utc_offset": "0s"
              },
              "arrival_time": {
                "year": 2023,
                "month": 5,
                "day": 15,
                "hours": 16,
                "minutes": 25,
                "seconds": 0,
                "nanos": 0,
                "utc_offset": "0s"
              }
            },
            {
              "ticketing_trip_id": "988833",
              "from_ticketing_stop_time_id": "LUZ-1235",
              "to_ticketing_stop_time_id": "WOL-2455",
              "service_date": {
                "year": 2023,
                "month": 5,
                "day": 15
              },
              "boarding_time": {
                "year": 2023,
                "month": 5,
                "day": 15,
                "hours": 18,
                "minutes": 13,
                "seconds": 0,
                "nanos": 0,
                "utc_offset": "0s"
              },
              "arrival_time": {
                "year": 2023,
                "month": 5,
                "day": 15,
                "hours": 20,
                "minutes": 13,
                "seconds": 0,
                "nanos": 0,
                "utc_offset": "0s"
              }
            }
          ]
        },
        "trip_option_set": {
          "trip_options": [
            {
              "segments": [
                {
                  "service_class": {
                    "type": "SECOND_CLASS"
                  }
                },
                {
                  "service_class": {
                    "type": "SECOND_CLASS"
                  }
                }
              ],
              "lowest_standard_fare": {
                "total_amount": {
                  "units": 10,
                  "nanos": 0,
                  "currency_code": "CHF"
                },
                "line_items": [
                  {
                    "line_item_type": "BASE_FARE",
                    "amount": {
                      "units": 9,
                      "nanos": 750000000,
                      "currency_code": "CHF"
                    }
                  },
                  {
                    "line_item_type": "SERVICE_CHARGE",
                    "amount": {
                      "units": 0,
                      "nanos": 250000000,
                      "currency_code": "CHF"
                    }
                  }
                ]
              },
              "availability": {
                "available": {
                  "available_seat_count": 44,
                  "total_seat_count": 200
                }
              }
            },
            {
              "segments": [
                {
                  "service_class": {
                    "type": "FIRST_CLASS"
                  }
                },
                {
                  "service_class": {
                    "type": "FIRST_CLASS"
                  }
                }
              ],
              "lowest_standard_fare": {
                "total_amount": {
                  "units": 15,
                  "nanos": 0,
                  "currency_code": "CHF"
                },
                "line_items": [
                  {
                    "line_item_type": "BASE_FARE",
                    "amount": {
                      "units": 13,
                      "nanos": 950000000,
                      "currency_code": "CHF"
                    }
                  },
                  {
                    "line_item_type": "SERVICE_CHARGE",
                    "amount": {
                      "units": 1,
                      "nanos": 50000000,
                      "currency_code": "CHF"
                    }
                  }
                ]
              },
              "availability": {
                "available": {
                  "available_seat_count": 10,
                  "total_seat_count": 100
                }
              }
            }
          ]
        }
      },
      {
        "itinerary": {
          "segment_keys": [
            {
              "ticketing_trip_id": "98765",
              "from_ticketing_stop_time_id": "ZRH-1234",
              "to_ticketing_stop_time_id": "ZUG-1235",
              "service_date": {
                "year": 2023,
                "month": 5,
                "day": 15
              },
              "boarding_time": {
                "year": 2023,
                "month": 5,
                "day": 15,
                "hours": 14,
                "minutes": 30,
                "seconds": 0,
                "nanos": 0,
                "utc_offset": "0s"
              },
              "arrival_time": {
                "year": 2023,
                "month": 5,
                "day": 15,
                "hours": 16,
                "minutes": 30,
                "seconds": 0,
                "nanos": 0,
                "utc_offset": "0s"
              }
            },
            {
              "ticketing_trip_id": "43210",
              "from_ticketing_stop_time_id": "ZUG-1235",
              "to_ticketing_stop_time_id": "WOL-2455",
              "service_date": {
                "year": 2023,
                "month": 5,
                "day": 15
              },
              "boarding_time": {
                "year": 2023,
                "month": 5,
                "day": 15,
                "hours": 18,
                "minutes": 13,
                "seconds": 0,
                "nanos": 0,
                "utc_offset": "0s"
              },
              "arrival_time": {
                "year": 2023,
                "month": 5,
                "day": 15,
                "hours": 20,
                "minutes": 13,
                "seconds": 0,
                "nanos": 0,
                "utc_offset": "0s"
              }
            }
          ]
        },
        "trip_options_error": {
          "error_type": "SEGMENT_KEY_NOT_FOUND",
          "error_message": "No matching segments found, no departures at 14:30"
        }
      }
    ]
  }
}

일반적인 시나리오

API의 특정 요청 형태와 관련된 시나리오를 다음과 같이 가정해 보겠습니다.

  • 기술적으로 정교하지 않은 파트너의 경우 market_date만 제공합니다. 이러한 파트너는 market_date 기반 쿼리를 업스트림 데이터에 사용하여 Google 데이터 형식에 매핑된 모든 결과를 반환할 수 있습니다. Google은 예상되는 여정만 표시되도록 결과를 필터링할 수 있습니다.

  • 기술적으로 정교한 파트너의 경우 market_dateknown_itineraries를 모두 제공합니다. 파트너는 내부 데이터베이스에서 자세히 조회하여 예상 운항 일정의 가격을 정확하게 책정할 수 있습니다. 요청된 모든 known_itineraries가 사용자에게 표시되므로 파트너는 가격과 예약 링크가 표시되는 운항 일정 수를 최대화할 수 있습니다. 파트너는 Google이 자체 (프로모션) 인벤토리를 더 잘 매칭할 수 있도록 추가 여정을 반환할 수 있습니다.

오류 보고

오류는 각 여정에 대해 개별적으로 보고해야 합니다. 따라서 기본 응답은 bulk_trip_options_result.itinerary_responses[i].trip_options_error에 여행별 오류를 나타내는 BulkTripOptionsResult (HTTP 200)입니다. 전체 요청이 예기치 않게 실패한 경우 BulkTripOptionsErrorType.INTERNAL_ERROR (HTTP 500)와 함께 bulk_trip_options_error를 사용합니다.

자세한 내용은 TripOptionsErrorType를 참고하세요.

HTTP 응답의 상태 코드 반환은 상태 코드 및 오류 처리를 참고하세요.

비고

MarketDate.departure_date는 캘린더 날짜를 지정합니다. 연산자 API와 더 잘 일치하도록 출처의 표준 시간대가 사용됩니다. 하지만 GetTripOptions와의 일관성을 위해 SegmentKey는 계속해서 UTC를 사용하여 탑승 및 도착 시간을 지정합니다.