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_date
とknown_itineraries
の両方を提供します。パートナーは、内部データベースで詳細な検索を行い、想定される旅行プランの正確な料金を設定できます。リクエストされたknown_itineraries
はすべてユーザーに表示されるため、パートナー様は料金と予約リンクが表示される旅行プランの数を最大化できます。パートナーは、Google が自社の(プロモーション)広告枠をより適切に照合できるように、追加の旅程を返すこともできます。
エラー報告
エラーはルートごとに個別に報告する必要があります。したがって、推奨されるレスポンスは BulkTripOptionsResult
(HTTP 200)で、bulk_trip_options_result.itinerary_responses[i].trip_options_error
の乗車ごとのエラーを示します。リクエスト全体が予期せず失敗した場合は、BulkTripOptionsErrorType.INTERNAL_ERROR
(HTTP 500)で bulk_trip_options_error
を使用します。
詳しくは、TripOptionsErrorType
をご覧ください。
HTTP レスポンスで返されるステータス コードについては、ステータス コードとエラー処理を参照してください。
備考
MarketDate.departure_date
はカレンダーの日を指定します。オペレーター API との整合性を高めるため、オリジンのタイムゾーンが使用されます。ただし、GetTripOptions
との整合性を保つため、SegmentKey では引き続き UTC を使用して搭乗時間と到着時間を指定します。