Tool description (what the LLM sees)
Tool description (what the LLM sees)
Create and manage a trip: add flight, hotel, or car items, remove items, set traveler details, and select ancillaries.
Operations:
- add_item: Add a flight, hotel, or car item to the trip. Pass trip_item_token from flight_search (offer__* tokens), offer_id from hotel_search (htl_* tokens) or car_search. Omit trip_id to create a new trip. MULTI-ROOM HOTEL: to book several rooms of the SAME hotel and stay as ONE booking with ONE reference, make ONE add_item call with rooms: [{trip_item_token: "htl_..."}, ...] (2-8 entries, one htl_* rate token per room, mutually exclusive with trip_item_token; not every hotel rate can be booked this way), do NOT add the same hotel twice as separate items.
- remove_item: Remove an existing item from the trip by item_id (from trip response items[].item_id). Requires an existing trip_id. Can be combined with add_item in a single call to swap an item, remove runs first, then add.
- upsert_travelers: Set traveler details and contact info on an existing trip_id.
- select_ancillaries: Select bags, seats, meals for a quoted trip item. Requires trip_id and item_id.
Returns trip_id for use with the checkout tool. Flights, hotels, and cars can coexist in the same trip (single Stripe checkout).
IMPORTANT, TRAVELER DATA:
NEVER invent or fabricate traveler data. Before calling upsert_travelers, you MUST ask the user for the required fields:
- Always: first_name, last_name, passenger_type
- Flights only: date_of_birth (YYYY-MM-DD), gender (MALE/FEMALE), required when the trip contains a flight, optional for hotel-only trips
- Contact: email, phone in international format with a leading + and the country code (e.g. +12025550147); a number without the + is rejected with INVALID_PHONE_NUMBER
If a required field is missing, ASK the user. Do not use placeholder or default values.
ANCILLARY FLOW:
Ancillaries (bags, seats) appear as available_ancillaries on trip items once checkout has quoted the trip; offer them to the user before they pay.
Use select_ancillaries with offer_ids from available_ancillaries. Full replacement, send every desired selection (bags and seats) in each call.
SEATS (flights):
1. get_trip after checkout: each available_ancillaries entry with type "seat" covers one segment (segment_ref_ids) and lists seat_map.seats[] {seat_number, available, chargeable, price_money}.
2. Take each passenger's pax_ref_id from the trip's travelers[].pax_ref_id.
3. Send one selection per passenger per segment: {offer_id, pax_ref_id, segment_ref_ids: [that offer's segment], seat_number}. Pick only available seats; no two passengers share a seat.
Read price_money for the exact seat price. Chargeable seats add their price to the trip total (the server sets the price); call checkout again to pay it. Ask before choosing a paid seat.
Flows:
- Flights: flight_calendar → flight_search → trip(add_item) → trip(upsert_travelers) → [checkout → trip(select_ancillaries)] → checkout
- Hotels: hotel_search → trip(add_item) → trip(upsert_travelers) → checkout
- Cars: car_search → trip(add_item) → trip(upsert_travelers) → checkout
- Mixed: supported item kinds in the same trip, one cart, one checkout
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
trip_id | string | No | Existing trip ID returned by trip or get_trip. Pass it back exactly as returned; omit it to create a new trip. |
add_item | object | No | Add a flight, hotel, or car item to the trip. For MULTIPLE ROOMS of the same hotel stay, make ONE add_item call with the rooms array (2-8 htl_* tokens), do NOT add the same hotel twice as separate items. |
add_item.trip_item_token | string | No | Token identifying the thing to add. One of: flight_search -> trip_item_token (offer__* format); hotel_search -> offer_id (htl_* format); car_search -> offer_id. Mutually exclusive with rooms, provide exactly one of the two. |
add_item.rooms | array<object> | No | MULTI-ROOM HOTEL ONLY: book 2-8 rooms of the SAME hotel and SAME stay as ONE booking with ONE reference. One entry per room, each with its own htl_* rate token from hotel_search (e.g. one rate per occupancy). Mutually exclusive with trip_item_token; for a single room use trip_item_token instead. Not every hotel rate can be booked this way; one that cannot is refused when it is added. |
add_item.rooms[].trip_item_token | string | Yes | Hotel rate token (htl_*) from hotel_search for THIS room. All rooms must come from the same hotel and the same stay (same check-in/check-out dates). |
add_item.special_requests | array<string> | No | HOTEL ONLY. Free-text special requests for the property, one per entry, e.g. “Expected arrival around 11:30 PM”, “Quiet room on a high floor, if available”, “Baby cot requested”, “Non-smoking room”. Forwarded to the hotel supplier with the booking as REQUESTS ONLY: neither Jinko nor the hotel guarantees them, and a confirmed booking does not mean they will be honoured, tell the user so. Applies to the whole stay (every room). At most 10 entries of 500 characters each and 1500 characters in total; blank entries are dropped. Ignored on any item that is not a hotel. |
remove_item | object | No | Remove an existing item from the trip. Requires an existing trip_id, you cannot remove from a trip that has not been created yet. Can be combined with add_item in a single call to swap an item (remove runs first, then add). |
remove_item.item_id | string | Yes | ID of the trip item to remove. Matches the value returned in the trip response items[].item_id field. |
upsert_travelers | object | No | Set or update travelers and contact info on the trip. Optional per call (you can add_item while building the cart), but travelers and a contact must be present before booking. |
upsert_travelers.travelers | array<object> | Yes | List of travelers (replaces all). Required to complete a booking; the first traveler also supplies the booking contact name. |
upsert_travelers.travelers[].first_name | string | Yes | First name as on travel document |
upsert_travelers.travelers[].last_name | string | Yes | Last name as on travel document |
upsert_travelers.travelers[].date_of_birth | string | No | Date of birth (YYYY-MM-DD). Required for flights; optional for hotel-only trips. |
upsert_travelers.travelers[].gender | enum ("MALE" | "FEMALE") | No | Gender as on travel document. Required for flights; optional for hotel-only trips. |
upsert_travelers.travelers[].passenger_type | enum ("ADULT" | "CHILD" | "INFANT") | Yes | ADULT (12+), CHILD (2-11), INFANT (under 2) |
upsert_travelers.travelers[].nationality | string | No | ISO 3166-1 alpha-2 country code |
upsert_travelers.travelers[].passport_number | string | No | Passport number |
upsert_travelers.travelers[].passport_expiry | string | No | Passport expiry date (YYYY-MM-DD) |
upsert_travelers.travelers[].passport_country | string | No | Passport issuing country (ISO 3166-1 alpha-2) |
upsert_travelers.travelers[].frequent_flyer | object | No | Frequent-flyer / loyalty membership. airline = IATA carrier that issued the membership (e.g. LH); number = membership number. |
upsert_travelers.travelers[].known_traveler_number | string | No | US trusted-traveler Known Traveler Number (TSA PreCheck / Global Entry). Flights only; sent to the airline as Secure Flight data so PreCheck prints on the boarding pass. |
upsert_travelers.travelers[].known_traveler_issuing_country | string | No | ISO 3166-1 alpha-2 country that issued the Known Traveler Number. Defaults to US downstream; ignored without known_traveler_number. |
upsert_travelers.travelers[].redress_number | string | No | DHS redress control number (TRIP program). Flights only. |
upsert_travelers.travelers[].redress_issuing_country | string | No | ISO 3166-1 alpha-2 country that issued the redress number. Defaults to US downstream; ignored without redress_number. |
upsert_travelers.contact | object | Yes | Booking contact (email + phone, both required). Required before the trip can be booked. |
upsert_travelers.contact.email | string | Yes | Contact email for booking confirmation |
upsert_travelers.contact.phone | string | Yes | Contact phone in international format: a leading + and the country code, e.g. “+12025550147”. Spaces, hyphens, dots and parentheses are tolerated and removed. A number without the leading + is rejected with INVALID_PHONE_NUMBER. Required. The platform rejects bookings without it. |
upsert_travelers.contact.title | string | No | Honorific of the person paying (e.g. “mr”, “ms”, “mx”). Required by some carriers, and by EVERY car rental, a car booking is refused without one. Matched against the provider’s own title vocabulary, so an unusual value may not resolve. |
upsert_travelers.contact.street_and_number | string | No | Billing street and number. Required by some carriers. |
upsert_travelers.contact.city | string | No | Billing city. Required by some carriers. |
upsert_travelers.contact.zip_code | string | No | Billing postal code. Required by some carriers. |
upsert_travelers.contact.country_code | string | No | Billing country as an ISO 3166-1 alpha-2 code (e.g. “FR”). |
upsert_travelers.contact.terms_accepted | boolean | No | Whether the traveller accepted the CARRIER’s terms and conditions, which are separate from Jinko’s. Send true only if they were actually shown and accepted. |
select_ancillaries | object | No | Select ancillaries (bags, seats, meals) for a quoted trip item. Uses full-replacement semantics, send all desired selections. |
select_ancillaries.item_id | string | Yes | ID of the trip item to select ancillaries for. Get from trip response items[].item_id |
select_ancillaries.selections | array<object> | Yes | Ancillary selections. Full replacement, send all desired selections each time. Get offer_ids from trip_item.available_ancillaries[].offer_id |
select_ancillaries.selections[].offer_id | string | Yes | Ancillary offer_id from available_ancillaries on the trip item |
select_ancillaries.selections[].category | string | No | Ancillary category (BAGGAGE, SEAT, MEAL, etc.) |
select_ancillaries.selections[].pax_ref_id | string | No | Passenger reference from the trip’s travelers[].pax_ref_id (e.g. “pax_1”). Required for per-passenger ancillaries such as seats. |
select_ancillaries.selections[].seat_number | string | No | Seat to assign, e.g. “14A” (seat offers only; required for them). From seat_map.seats[].seat_number of that offer; one seat per passenger per segment. |
select_ancillaries.selections[].segment_ref_ids | array<string> | No | Segment reference IDs (for segment-scoped ancillaries) |
select_ancillaries.selections[].journey_ref_id | string | No | Journey reference ID (for journey-scoped ancillaries) |
select_ancillaries.selections[].quantity | integer | No | Quantity (defaults to 1) |
user_intent | string | No | The end user’s current request in their own words, e.g. “help me with my travel plans”. Pass it as-is when short; otherwise condense the goal and constraints into 1-2 sentences. Strip personal identifiers (names, emails, phone numbers, addresses, payment details), replace them with placeholders like “[name]”. Optional. Jinko uses it to understand demand, and hotel_search uses it to rank hotel results against what the user asked for (e.g. “quiet, with a gym, near Times Square”), so keep the user’s stated preferences in it. |
Examples
Create a new trip (add flight + set travelers in one call):{
"name": "trip",
"arguments": {
"add_item": {
"trip_item_token": "offer_abc123:fare_xyz"
},
"upsert_travelers": {
"travelers": [
{
"first_name": "Jane",
"last_name": "Doe",
"date_of_birth": "1990-01-15",
"gender": "FEMALE",
"passenger_type": "ADULT",
"frequent_flyer": { "airline": "LH", "number": "992100100" }
}
],
"contact": {
"email": "jane@example.com",
"phone": "+33612345678"
}
}
}
}
{
"name": "trip",
"arguments": {
"trip_id": "42",
"add_item": { "trip_item_token": "htl_abc..." }
}
}
{
"name": "trip",
"arguments": {
"trip_id": "42",
"upsert_travelers": {
"travelers": [
{ "first_name": "Jane", "last_name": "Doe", "date_of_birth": "1990-01-15", "gender": "FEMALE", "passenger_type": "ADULT", "frequent_flyer": { "airline": "LH", "number": "992100100" } },
{ "first_name": "John", "last_name": "Doe", "date_of_birth": "2015-05-20", "gender": "MALE", "passenger_type": "CHILD" }
],
"contact": { "email": "jane@example.com", "phone": "+33612345678" }
}
}
}
frequent_flyer object so miles are credited on the booking. airline is the IATA code of the program issuer (e.g. LH for Lufthansa Miles & More), not necessarily the operating carrier, since alliances credit miles on partner flights. Both airline and number are required when the object is present.
Include upsert_travelers.contact with every MCP traveler update, even when only adding a frequent-flyer number. Use the booking contact’s email and phone; the phone must be in international format with a leading + and country code, e.g. +12025550147.
{
"name": "trip",
"arguments": {
"trip_id": "42",
"upsert_travelers": {
"travelers": [
{
"first_name": "Jane",
"last_name": "Doe",
"date_of_birth": "1990-01-15",
"gender": "FEMALE",
"passenger_type": "ADULT",
"frequent_flyer": { "airline": "LH", "number": "992100100" }
}
],
"contact": {
"email": "jane@example.com",
"phone": "+33612345678"
}
}
}
}
Traveler details must match real travel documents, airlines enforce name / DOB matching and reject bookings where they don’t. Never let an agent fabricate these.
trip_id, the current item list, and totals. Use trip_id with checkout when you’re ready to check out.