Travel To Discover

Loading documentation…

3. API Reference

Export .md

HotelList

POST /api/search/hotelList

Returns hotels matching a set of search criteria — destination, stay dates and guest configuration — with optional per-hotel room availability and pricing.

Three ways to drive the search are supported:

  1. By specific SupplierHotelList — pass explicit hotel IDs to fetch detail for exactly those properties.
  2. By destination — search within a region, addressed either by destinationId or by destinationName.
  3. By location — return hotels near a point, ranked by distance.

Required parameters

  • checkIn / checkOut — the stay dates.
  • roomOccupancies — one entry per room, each carrying adultCount and optional childrenAges. At least one entry is required.
  • at least one of destinationId, destinationName or hotelIds — how the search is scoped. A body carrying none of the three is rejected.

Optional parameters

  • destinationId — region identifier for a location-scoped search.
  • destinationName — region name; the server resolves it to an ID.
  • hotelIds — explicit hotel IDs to retrieve.
  • maxRatesPerHotel — cap on room rates returned per hotel; 0 (the default) is uncapped.
  • sortBy — result ordering (price-asc, price-desc, rating-desc, distance-asc).
  • pageNum / pageSize / cursor — pagination controls. They are flat top-level fields on this endpoint; the nested page object belongs to HotelsMetadata, not here. pageSize defaults to 50 and is capped at 200; a larger value is rejected rather than clamped.

What comes back

  • A hotel list carrying core property information.
  • Room availability and pricing, when requested.
  • Pagination metadata for large result sets.
  • A session identifier that ties the search context together.
  • basic.statusRemark / basic.notices / basic.emptyReason — why a result is empty or incomplete. See "Empty results" below.

Empty results

{ "list": [], "total": 0 } has two causes that need opposite responses, and on its own it cannot tell you which you have hit:

  1. The suppliers were asked and had nothing. Genuine zero availability — try other dates or another property. basic.emptyReason is ABSENT.
  2. No supplier answered, or none was asked at all. A configuration state on our side. Retrying the same request, or changing the dates or the destination, cannot change it. basic.emptyReason.code is present and says which.

basic.emptyReason.code is one of:

  • NO_SUPPLIER_ENABLED — no supplier is currently enabled for hotel search.
  • NO_SUPPLIER_PERMITTED — suppliers are enabled, but none may serve your account on this search.
  • ALL_SUPPLIERS_EXCLUDED — every candidate was excluded before the search ran, by a market, currency, language or inventory restriction.
  • NO_SUPPLIER_ANSWERED — suppliers were called and every one of them failed. This is the only one of the four worth retrying.

basic.statusRemark carries the same thing as one human-readable sentence, suitable for a log line or an operator-facing message.

basic.emptyReason.suppliers — WHICH supplier failed and why — is disclosed only to accounts entitled to the supplier breakdown. Most integrations will never see it, and its absence is not an error: the code and the statusRemark are complete without it.

basic.notices is separate and belongs to a search that WORKED: it lists what the response does not contain when the result is real but not complete (a destination expansion that hit its cap, properties dropped because they could not be priced in the requested currency). It is not emitted alongside emptyReason — on an empty response there is no partial result for it to qualify, and statusRemark already carries the explanation.

All four fields are additive and optional. A client that ignores them behaves exactly as it did before they existed.

Typical uses

  • Powering a hotel booking search UI.
  • Browsing the inventory of a destination.
  • Looking up one or more known properties.
  • Suggesting hotels near a given point.

Request headers

Header Required Description
Client-Request-Timestamp No Unix timestamp recorded by the client at the moment it begins sending the request.
Currency No Currency the rates should be quoted in, expressed as an ISO 4217 code (https://en.wikipedia.org/wiki/ISO_4217).
IP No Client IP address; both IPv4 and IPv6 are accepted.
Language No IETF BCP 47 language tag (https://masonreview.com/posts/ietf-bcp-47-language-tags/), for example "en" or "en-US". Defaults to "en-US".
Market No Point-of-sale market for this call, as an ISO 3166-1 alpha-2 country code. Required only when your account carries a market restriction: an allow-list cannot admit a market you have not stated, so such an account refuses calls that omit it.
Request-Id No Identifies this individual request; values must not repeat.
Session-Id Yes Recommended to be supplied by the client on every call, and mandatory throughout the booking flow.
Test No Test switches, given as key-value pairs — for example "hotel=HC1&scenario=priceChange". A value the server does not recognise is ignored, and the call proceeds exactly as if no "Test" header had been sent.
Timeout-Milliseconds No Client-imposed timeout; the server makes a best effort to respond within it.
Trace-Id No Correlates a group of related requests for tracing.
User-Ref No Your own identifier for the person on whose behalf this call is made. Required only once named users have been authorised on your account, after which every call must identify one and is authorised against that user's scopes as well as the key's.
Authorization Yes Must begin with "Bearer ". The token is obtained from the Ticket response; the Ticket call itself does not require this header.

Request body

Field Type Required Description
hotelIds[] array No Explicit hotel IDs to search for; at most 1,000 entries. These are OUR ids — the hotelId values a previous HotelList or HotelsMetadata response returned to this account. Ids issued by another platform name nothing here and come back as a successful, empty list; see the migration guide. A connection with a visibility band (hotel or rate filters) takes at most 200 per request. A longer array is rejected with code 100000400 — split it across several requests.
maxRatesPerHotel integer No How many room rates to return for each hotel, ordered by price with the cheapest first. 0 (the default) returns every rate uncapped; use 1 to return only the cheapest rate per hotel, which suits listing pages.
checkIn string Yes Check-in date; defaults to the current date.
checkOut string Yes Check-out date; defaults to seven days from now.
countryCode string No Country code of the booker's point of sale, in ISO 3166-1 alpha-2 form (e.g. "US"). Accepted for compatibility and validated, but it does NOT select the market your search is priced in: pricing always uses the point of sale configured on your connection, so this field cannot change the rates you are quoted. Ask us to change your configured point of sale if the one you trade in is wrong.
residencyCode string No Booker's residency code, in ISO 3166-1 alpha-2 form (e.g. "US").
nationalityCode string No Booker's nationality code, in ISO 3166-1 alpha-2 form (e.g. "US").
roomOccupancies[] array<hotel.supplier.domain.GuestPerRoom> Yes
roomOccupancies[].adultCount integer Yes AdultCount is the number of adults
roomOccupancies[].childrenAges[] array No ChildrenAges contains ages of children
destinationId string No Region identifier — the id of a node returned by Destinations, which is a UUID rather than a numeric code. Required when destinationName is not supplied.
destinationName string No Region name. Required when destinationId is not supplied; the system automatically looks up cities matching this name.
pageNum integer No Page number. The first page is 1; values below 1 are rejected.
pageSize integer No Page size. Defaults to 50 when omitted, and may not exceed 200 — a larger value is rejected with code 100000400 rather than being silently clamped.
cursor integer No Cursor pointing at the next page.
sortBy string No Result ordering. Documented values: price-asc, price-desc, rating-desc, distance-asc. (The source types this as a free-form string — no enum constraint is declared.)

Example request

json
{
  "hotelIds": [
    "461850557",
    "118062388"
  ],
  "maxRatesPerHotel": 3,
  "checkIn": "2026-01-01",
  "checkOut": "2026-01-03",
  "countryCode": "US",
  "residencyCode": "US",
  "nationalityCode": "US",
  "roomOccupancies": [
    {
      "adultCount": 2,
      "childrenAges": [
        2
      ]
    }
  ],
  "destinationId": "0192f3a7-5c41-7e88-b3d2-9a1c4e6f0b57",
  "destinationName": "Dubai",
  "pageNum": 1,
  "pageSize": 50,
  "cursor": 0,
  "sortBy": "price-desc"
}

Response

Successful calls return the standard envelope. code is 0 on success — check it rather than the HTTP status alone, because some business failures are delivered with HTTP 200.

Field Type Required Description
code integer No
msg string No
data hotel.search.protocol.HotelListResp No
data.list[] array Yes The hotels matched by the search.
data.list[].id string No Identifier of this property as the source that served it names it. It is accepted back on hotelIds, but it is not stable across searches — where several sources sell the same property, this is whichever one served this result. Key your catalogue on ttdHotelId instead.
data.list[].ttdHotelId string No The platform's stable, client-facing property code — the same value the hotel-catalogue file publishes as ttdHotelId. One property is one code, and unlike id it does not change with the supplier that served this result, so it is the id to key your catalogue on. Present whenever the property is matched to our master catalogue. Accepted anywhere a hotel id is sent.
data.list[].destinationId string No index
data.list[].name I18N No Hotel name.
data.list[].name.en string No English; the default system language.
data.list[].name.zh string No Chinese (中文).
data.list[].name.ar string No Arabic (اللغة العربية).
data.list[].rating number No Hotel rating, on a scale from 0.0 to 5.0. (The range is documented in prose only; the source declares no minimum/maximum keywords.)
data.list[].address I18N No Localised string set. Keys are fixed language codes.
data.list[].address.en string No English; the default system language.
data.list[].address.zh string No Chinese (中文).
data.list[].address.ar string No Arabic (اللغة العربية).
data.list[].latlngCoordinator LatlngCoordinator No
data.list[].latlngCoordinator.google Latlng Yes
data.list[].latlngCoordinator.gaode Latlng No
data.list[].logoURL string No
data.list[].minPrice Money No The lowest price satisfying the search criteria.
data.list[].minPrice.currency string Yes Currency code, e.g. "USD".
data.list[].minPrice.amount number Yes Monetary amount, e.g. "14.50".
data.list[].minPricesByCurrency[] array No Lowest prices expressed in a range of currencies.
data.list[].minPricesByCurrency[].currency string Yes Currency code, e.g. "USD".
data.list[].minPricesByCurrency[].amount number Yes Monetary amount, e.g. "14.50".
data.list[].isAvailable boolean No
data.list[].rooms[] array No
data.list[].rooms[].roomTypeId string Yes Standardized room type ID, e.g. "R001".
data.list[].rooms[].roomTypeName I18N Yes Standardized room type name. When the supplier's type cannot be recognised, a fallback such as "Standard Room" is returned.
data.list[].rooms[].hotelId string Yes Hotel ID. Repeats the parent hotel's ID so the room can be identified on its own.
data.list[].rooms[].rates[] array<hotel.supplier.domain.RoomRatePkg> No The core structure — the room offers available for this room.
data.basic HotelListBasicInfo Yes Contextual information about the search itself.
data.basic.destination Destination No Details of the region the search covered.
data.basic.destination.id string No
data.basic.destination.type hotel.geography.domain.DestinationType No Classification of a destination record. - DestinationType_Unknown (0): no description supplied in the source. - DestinationType_Continent (1): a large landmass such as Europe, Asia or South America. The region summary section lists the continents. - DestinationType_Country (2): a nation-state such as the United States, Australia or Germany. Countries/regions here are drawn geographically rather than politically - Guadeloupe, for instance, is a French department in the Caribbean that belongs politically to France yet forms its own geographic entity. The region summary section lists the countries/regions. - DestinationType_ProvinceState (3): an administrative division inside a country, such as California or New South Wales. Lower-level administrative divisions - counties and provinces within a country/region - fall under this type too. - DestinationType_HighLevelRegion (4): a tourist region, such as the Upper Rhine in Germany or the wine country in California. - DestinationType_MultiCityVicinity (5): a large metropolitan area covering a major city together with its surrounding suburbs, such as Cairo and the areas around it. Polygon boundaries for these are drawn broadly according to tourist value. - DestinationType_City (6): an urban area, such as Bellevue and Washington. A large metropolitan area can contain a city - London, for example - in which case the city covers a smaller footprint than the corresponding multi_city_vicinity. Each accommodation contracted with Expedia must be tied to a city, since the city is the base unit of geographic coverage. City polygon boundaries follow official administrative sources. - DestinationType_Neighborhood (7): a geographic area smaller than a city, such as the old town in Bonn, Germany. Neighborhood polygon boundaries are drawn by tourist value rather than by administrative definition. - DestinationType_Airport (8): an airport, such as LHR (London Heathrow). - DestinationType_PointOfInterest (9): a place such as a museum, convention center, beach or park. The list covers not only well-known tourist attractions but a broader set of venues, such as the Shanghai Exhibition Center, the Texas State Capitol or the Prague Zoo. - DestinationType_TrainStation (10): a train station, such as Grand Central Terminal in New York. - DestinationType_MetroStation (11): a subway station, such as Avtovo Station in St. Petersburg, Russia. - DestinationType_BusStation (12): a bus station, such as the Port Authority Bus Terminal in New York State, USA. Allowed: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12.
data.basic.destination.name I18N No Localised name.
data.basic.destination.nameFull I18N No Fully qualified localised name, for example "Springfield, Missouri, United States of America".
data.basic.destination.countryCode string No ISO 3166-1 alpha-2 country code. Reference: https://www.iso.org/obp/ui/#search
data.basic.destination.coordinates Coordinates No Location descriptor.
data.basic.destination.extra hotel.geography.domain.DestinationExtra No
data.basic.destination.countryName I18N No Localised string set. Keys are fixed language codes.
data.basic.destination.destinationName I18N No Localised string set. Keys are fixed language codes.
data.basic.destination.parentDestinationName I18N No Localised string set. Keys are fixed language codes.
data.basic.destination.parentDestinationId string No Code of the parent region: for a city this is the province code, for a province it is the country code.
data.basic.sessionId string No The session ID.
data.basic.statusRemark string No One human-readable sentence explaining a result that is empty or incomplete. Uses the same field name the contract already gives the advisory text beside status on CheckAvail and on every order. Absent when there is nothing to explain. Additive and optional.
data.basic.notices[] array No What this response does NOT contain, when the search succeeded but is not complete — a destination expansion that hit its cap, properties dropped because they could not be priced in the requested currency. Belongs to a result that HAS content; never emitted alongside emptyReason. Additive and optional.
data.basic.emptyReason HotelListEmptyReason No Machine-readable diagnosis of an empty list. Present ONLY when the emptiness is a platform or configuration state; absent when the suppliers were asked and simply had nothing. Additive and optional.
data.basic.emptyReason.code enum Yes NO_SUPPLIER_ENABLED — nothing is enabled for hotel search. NO_SUPPLIER_PERMITTED — suppliers exist, but none may serve your account on this search. ALL_SUPPLIERS_EXCLUDED — every candidate was excluded before the search ran. NO_SUPPLIER_ANSWERED — suppliers were called and all of them failed; this is the only one of the four worth retrying. Published to every caller — it names no supplier. Allowed: NO_SUPPLIER_ENABLED, NO_SUPPLIER_PERMITTED, ALL_SUPPLIERS_EXCLUDED, NO_SUPPLIER_ANSWERED.
data.basic.emptyReason.suppliers[] array No Per-supplier detail — which supplier produced nothing, and why. Disclosed ONLY to accounts entitled to the supplier breakdown; most integrations will never receive this property, and its absence is not an error. code and statusRemark are complete without it.
data.total integer No Total number of items. A value of 0 means either that there are no items or that totals are not supported for this query.
data.hasMore boolean No Whether further items remain to be fetched.

Example response

json
{
  "code": 0,
  "msg": "string",
  "data": {
    "list": [
      {
        "id": "461850557",
        "ttdHotelId": "TTD-1000001",
        "destinationId": "0192f3a7-5c41-7e88-b3d2-9a1c4e6f0b57",
        "name": {
          "en": "Jumeirah Beach Hotel"
        },
        "rating": 4.5,
        "address": {
          "en": "Millenium Al Barsha"
        },
        "latlngCoordinator": {
          "google": {
            "lat": 0,
            "lng": 0
          },
          "gaode": {
            "lat": 0,
            "lng": 0
          }
        },
        "logoURL": "https://cdn.example.com/hotel/461850557_1.jpg",
        "minPrice": {
          "amount": 100,
          "currency": "USD"
        },
        "minPricesByCurrency": [
          {
            "amount": 700,
            "currency": "CNY"
          },
          {
            "amount": 85,
            "currency": "EUR"
          }
        ],
        "isAvailable": true,
        "rooms": [
          {
            "roomTypeId": "string",
            "roomTypeName": {},
            "hotelId": "string",
            "rates": []
          }
        ]
      }
    ],
    "basic": {
      "destination": {
        "id": "0192f3a7-5c41-7e88-b3d2-9a1c4e6f0b57",
        "name": {
          "en": "Dubai"
        }
      },
      "sessionId": "374337a797454a344ad999c7730da01c",
      "statusRemark": "No supplier was searched for this request: no supplier is currently enabled for hotel search. This is a configuration state, not an absence of availability — retrying, or changing the dates or destination, will not change it. Contact your account manager.",
      "notices": [
        "Showing the first 200 of 4318 properties matching \"United Arab Emirates\". Narrow to a city or area for full coverage."
      ],
      "emptyReason": {
        "code": "NO_SUPPLIER_ENABLED",
        "suppliers": [
          {
            "supplierCode": "MOCK",
            "reason": "TIMEOUT: supplier did not respond within 20000 ms"
          }
        ]
      }
    },
    "total": 100,
    "hasMore": true
  }
}

Failure responses

HTTP Meaning
400 Bad Request
401 Unauthorized
403 Forbidden
429 Too Many Requests

Every failure uses the { code, msg } envelope. See Error handling for the full business-code table.

Code samples

bash
curl -X POST https://api-test.ttdbooking.com/api/search/hotelList \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $TICKET" \
  -H "Request-Id: $(uuidgen)" \
  -d '{
    "hotelIds": [
      "461850557",
      "118062388"
    ],
    "maxRatesPerHotel": 3,
    "checkIn": "2026-01-01",
    "checkOut": "2026-01-03",
    "countryCode": "US",
    "residencyCode": "US",
    "nationalityCode": "US",
    "roomOccupancies": [
      {
        "adultCount": 2,
        "childrenAges": [
          2
        ]
      }
    ],
    "destinationId": "0192f3a7-5c41-7e88-b3d2-9a1c4e6f0b57",
    "destinationName": "Dubai",
    "pageNum": 1,
    "pageSize": 50,
    "cursor": 0,
    "sortBy": "price-desc"
  }'

Try it

Try it

POST /api/search/hotelList
A ticket will be fetched with ttdbooking_api_demo.