htl_* offer token you can hand to the trip tool to start a booking.
Tool description (what the LLM sees)
Tool description (what the LLM sees)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
destination | object | Yes | Destination — provide exactly one shape. Two distinct modes: MODE A (rate lookup — you know which hotel): • { hotel_ids } to re-shop a known set. • { hotel_name, country_code?, city_name? } when the user named a specific property. Server resolves via fuzzy lookup; returns 422 HOTEL_NAME_LOW_CONFIDENCE if no candidate scores ≥ 0.7. MODE B (hotel search — you’re exploring): • { query } for unambiguous cities/POIs only (“Paris”, “Times Square”). Provider AI search returns 0 for islands/regions/countries/archipelagos. • { city_name + country_code } for ambiguous city names or when the user named a primary city (“Mahón, ES” for Menorca). • { latitude + longitude + radius_km } for islands, regions, neighborhoods — anywhere { query } returns 0. • { place_id } when you already have an upstream Place ID. In Mode A, filters (min_rating / star / facility / chain / hotel_type / max_results) are ignored — the user already named the property. Best practice: don’t combine filters with hotel_ids or hotel_name. |
destination.query | string | No | Free-text destination — use ONLY for unambiguous cities or well-known POIs (e.g. “Paris”, “Times Square”). Provider-side AI search reliably returns 0 results for islands (“Menorca”, “Santorini”), regions (“Tuscany”, “Provence”), countries, archipelagos, and other non-city geographies. For those: prefer { city_name + country_code } when a primary city is implied (e.g. “Mahón, ES” for Menorca), or { latitude + longitude + radius_km } to cover an area. Max 200 chars. |
destination.city_name | string | No | City name (e.g. “Paris”). In Mode B: pair with country_code as the destination. In Mode A (with hotel_name): pair with hotel_name to narrow the fuzzy-lookup scope. |
destination.country_code | string | No | ISO 3166-1 alpha-2 country code (lowercase preferred, e.g. “fr”). Must be paired with city_name OR hotel_name. In Mode B it disambiguates the city; in Mode A it narrows the fuzzy lookup. |
destination.latitude | number | No | Latitude for geo-radius search. Pair with longitude. |
destination.longitude | number | No | Longitude for geo-radius search. Pair with latitude. |
destination.radius_km | number | No | Geo-radius in km (default 5, max 50). Requires latitude+longitude — ignored with other destination shapes. |
destination.place_id | string | No | Google Places ID or upstream place identifier. |
destination.hotel_ids | array<string> | No | Mode A — re-shop a known set of hotel IDs (skips destination resolution). |
destination.hotel_name | string | No | Mode A — free-text hotel name when the user named a specific property they want to book (e.g. “Hotel Calimala”, “The St. Regis Rome”, “Hôtel Costes”). Server runs a fuzzy trigram match over the 1.74M-hotel catalog; uses the top hit when its confidence is ≥ 0.7 (auto-pick safe). If no candidate clears that threshold, returns HTTP 422 with error.code = HOTEL_NAME_LOW_CONFIDENCE + top_candidates + suggested_retry — the agent should confirm a candidate with the user or fall back to the suggested city destination. ALWAYS pair with country_code and city_name when known; lookup precision drops sharply on common names without scope. |
checkin | string | Yes | Check-in date (YYYY-MM-DD). |
checkout | string | Yes | Check-out date (YYYY-MM-DD). |
occupancies | array<object> | No | One entry per room (structured). PREFERRED whenever the party is larger than 2 adults or has children — it removes ambiguity about how guests are split across rooms. Example: [{ “adults”: 2 }, { “adults”: 1, “children_ages”: [5] }]. Do NOT combine with the shorthand fields (adults/children/rooms) — use one or the other. |
adults | integer | No | Shorthand: total adults across all rooms. Use ONLY when there is no ambiguity (1 or 2 adults = single room). For 3+ adults, or odd splits, ask the user how they want to split rooms and pass occupancies[] instead — e.g. 4 adults → [{adults:2},{adults:2}] (double + double) vs a single 4-sleeper is a meaningfully different search. If the user does not clarify, the server defaults to 2-adults-per-room (remainder in the last room), so every 4-adult request becomes two double rooms. Do NOT combine with occupancies[] — use one or the other. |
children | array<integer> | No | Shorthand: ages of all children across all rooms. If children are present, prefer occupancies[] so the caller controls which room each child goes in (ages affect pricing and some providers reject invalid age/room combinations). |
rooms | integer | No | Shorthand: number of rooms (BFF auto-distributes adults + children). Use when the user named a room count but not the per-room split. |
currency | string | No | ISO 4217 currency code (e.g. “EUR”, “USD”, “GBP”, “JPY”). ALWAYS set this — omitting it falls back to USD which is rarely what users actually want. Infer from the strongest signal available: (1) the user’s explicit ask (“show me prices in pounds”), (2) the conversation language/locale (French → EUR, Japanese → JPY, German → EUR, Spanish/Catalan/Italian/Portuguese → EUR, English UK → GBP, English US → USD), (3) the destination country (Italy/France/Germany → EUR, UK → GBP, Japan → JPY, US → USD). When in doubt between two plausible currencies, prefer the one matching the user’s likely home country. |
guest_nationality | string | No | Guest nationality (ISO 3166-1 alpha-2, uppercase, e.g. “FR”). Affects rate availability + tax handling at search time. Separate from traveler nationality used for booking documents. |
filters | object | No | Optional filter overrides applied on top of the tenant default filter set. |
filters.min_rating | number | No | Minimum guest review rating (0-10 scale). |
filters.min_star_rating | integer | No | Minimum star rating (1-5). Pair with max_star_rating to bound a range. |
filters.max_star_rating | integer | No | Maximum star rating (1-5). Pair with min_star_rating to bound a range. |
filters.min_reviews | integer | No | Minimum number of guest reviews. |
filters.hotel_type_ids | array<string> | No | Filter by hotel type IDs (e.g. boutique, resort). |
filters.chain_ids | array<string> | No | Filter by hotel chain IDs (e.g. “hilton”, “marriott”, “accor”, “ihg”). |
filters.facility_ids | array<string> | No | Filter by facility IDs (e.g. pool, gym, spa). Applied at connector search time, not post-filtered. |
filters.max_results | integer | No | Maximum number of hotels to return per page (default 50). |
filters.offset | integer | No | Pagination offset — skip this many hotels at the upstream search (default 0). |
trip_id | string | No | Existing trip_id to associate this search with. Unified (cart-widget) tool only — the DevPlatform variant accepts the field for schema consistency but ignores it (no widget surface). Forward whenever the user is mid-trip-build (you have seen a trip_id in a recent trip(…) tool result and the user has NOT pivoted to a different trip context, e.g. a new origin OR destination city or unrelated request). Drop on pivot. Echoed back in the result so the cart widget can append the next selection to the same trip. |
Examples
Simple city search, 2 adults, 3 nights in Paris:rooms[].rates[] includes a offer_id starting with htl_. Pass it as a trip_item_token to trip(add_item), hotels coexist with flight items in the same trip.