Par rapport à la méthode GetTripOptions, la méthode GetBulkTripOptions
présente les avantages suivants :
- Permet de remplir le cache Google plus efficacement, en utilisant moins de requêtes et en s'alignant mieux sur les API en amont des opérateurs, qui peuvent être utilisées par les partenaires pour acquérir eux-mêmes les données.
- Permet aux partenaires disposant d'un ensemble prédéterminé de trajets disponibles de fournir leurs données sans inspection détaillée de l'itinéraire.
- Pour les partenaires plus sophistiqués, il fournit toujours une liste d'itinéraires connus afin de maximiser la mise en correspondance de l'inventaire des partenaires et des itinéraires produits par le moteur de calcul d'itinéraire de Google, ce qui permet d'afficher les prix des partenaires pour le plus grand nombre d'itinéraires possible.
- Permet d'ingérer des itinéraires que Google ne propose pas encore, afin d'ajuster potentiellement le moteur de routage de Google pour mieux correspondre à l'inventaire des partenaires à l'avenir.
GetBulkTripOptionsRequest
Définition 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; }
Exemple 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
Définition 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; }
Exemple 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 } } } ] } } ] } }
Exemple d'erreur JSON
{ "bulk_trip_options_error": { "error_type": "INTERNAL_ERROR", "error_message": "Unexpected RoutingException during trip lookup." } }
Erreur JSON partielle
{ "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" } } ] } }
Scénarios typiques
Nous imaginons les scénarios suivants avec des formes de requête particulières pour l'API :
Pour les partenaires moins expérimentés sur le plan technique, ne fournissez qu'un
market_date
. Ces partenaires peuvent utiliser une requête basée surmarket_date
pour leurs données en amont et renvoyer tous les résultats mappés à notre format de données. Google peut filtrer les résultats pour n'afficher que les itinéraires attendus.Pour les partenaires plus sophistiqués sur le plan technique, fournissez à la fois un
market_date
et unknown_itineraries
. Le partenaire peut effectuer une recherche détaillée dans les bases de données internes pour pouvoir tarifer exactement les itinéraires attendus. Tous lesknown_itineraries
demandés seront affichés aux utilisateurs. Les partenaires pourront ainsi maximiser le nombre de voyages pour lesquels leur prix et leur lien de réservation sont affichés. Les partenaires ont toujours la possibilité de renvoyer des itinéraires supplémentaires pour aider Google à mieux faire correspondre leur propre inventaire (promu).
Création de rapports d'erreur
Les erreurs doivent être signalées individuellement pour chaque trajet. Par conséquent, la réponse recommandée est BulkTripOptionsResult
(HTTP 200), qui indique les erreurs par trajet dans bulk_trip_options_result.itinerary_responses[i].trip_options_error
. Si l'ensemble de la requête a échoué de manière inattendue, utilisez bulk_trip_options_error
avec BulkTripOptionsErrorType.INTERNAL_ERROR
(HTTP 500).
Pour en savoir plus, consultez TripOptionsErrorType
.
Pour les codes d'état renvoyés dans les réponses HTTP, consultez Codes d'état et gestion des erreurs.
Remarques
MarketDate.departure_date
spécifie un jour civil. Pour mieux correspondre aux API d'opérateur, le fuseau horaire de l'origine sera utilisé. Toutefois, SegmentKey continuera de spécifier les heures d'embarquement et d'arrivée en UTC pour assurer la cohérence avec GetTripOptions
.