Skip to content
FX-Port/Docs
GuidesAPI referenceChangelog
Get API keys
  • Introduction
  • Quickstart
  • Security
  • Authentication
  • Environments and Postman
  • Sandbox
  • Conventions and naming
  • Legacy names and twins
  • Errors
  • Rate limits and fair use
  • Streaming search results

Concepts

  • Overview
  • Sandbox testing
  • Mini and full data
  • Guests and rooms
  • Pricing

Search

  • Geo search
  • Locations and coordinates
  • Name search
  • Hotel details

Rates and booking

  • Rates
  • Pre-book
  • Book

After booking

  • Get a booking
  • Voucher
  • Cancel
  • Use these docs with AI

Hotels · Search

Hotel details

The full page of one hotel, or its compact card with detail_level. Reads the cache and fetches an unknown hotel live.

POST/api/v1/hotels/get_hotel_info

Read one hotel for the page the user opens before checkout: the description, every room type, the photos, the policies, the facts and how to reach the hotel. It is the only content call that asks the supplier when FX-Port does not hold the hotel yet.

Permission: Read

Use the right size

This answer is the full document: 5 to 143 KB for one hotel (26 KB in the middle, 38 KB on average in our measurement). Ask for it for the one hotel the user opened. For a list of hotels use the compact card: search_advanced already returns it, and this call returns it too with detail_level: "minimal". See Mini and full hotel data.

Request body

POST /api/v1/hotels/get_hotel_info

FieldTypeRequiredDefaultDescription
hotel_idstring or integerOne of the twoOne hotel: its FX-Port id (hotels_details[].id, a hit of the name search) or its numeric supplier id (hid). The only form that asks the supplier when the hotel is not cached.
hotel_idsarrayOne of the twoSeveral hotels, at most 200. Cached hotels only: the others are left out. Wins over hotel_id when both are sent.
detail_levelstringNofullfull: the whole document, in camelCase. minimal (alias mini): the compact card, in snake_case.
images_limitintegerNoWith detail_level: "minimal": keep only the first N photos of each card, 0 to 30. With full it is ignored and the answer carries a coerced_value warning.
languagestringNoenLanguage of the live fetch of a hotel that is not cached. Cached content is English whatever you send.

Legacy names

These older spellings still work. The answer carries a deprecated_field warning that names the spelling to use (see Legacy names).

Older nameUse instead
hotelId, id, hidhotel_id
hotelIds, idshotel_ids
detailLeveldetail_level
imagesLimitimages_limit

Request examples

curl https://api.fx-port.com/api/v1/hotels/get_hotel_info \
  -H "Authorization: Bearer fxp_test_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "hotel_id": "test_hotel_do_not_book",
  "language": "en"
}'
curl https://api.fx-port.com/api/v1/hotels/get_hotel_info \
  -H "Authorization: Bearer fxp_test_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "hotel_id": "test_hotel_do_not_book",
  "detail_level": "minimal",
  "images_limit": 1
}'
curl https://api.fx-port.com/api/v1/hotels/get_hotel_info \
  -H "Authorization: Bearer fxp_test_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "hotel_ids": [
    "test_hotel_do_not_book",
    "hotel_honduras_maya_6"
  ],
  "detail_level": "minimal"
}'

How the hotel is found

  1. With hotel_id, FX-Port looks for the id in its cache of hotel content. A number (or a numeric string) is taken as the supplier's hid and looked up the same way.
  2. A single hotel_id that is not cached is fetched from the supplier (about 0.3 s), stored for every customer, and answered. This is how you get the card of a hotel listed in missing_hotel_ids of a search: see Hotels without content.
  3. With hotel_ids nothing is fetched: the hotels that are cached come back, the others are left out without an error, and the answer is {"data": []} when none is cached.

A single hotel_id that no source knows is 404 hotel_not_found.

Response

data is always a list, with one entry for a single hotel_id. The entry is the full document (camelCase), here shortened to one element per list:

{
  "environment": "sandbox",
  "data": [
    {
      "id": "test_hotel_do_not_book",
      "hid": 8473727,
      "name": "Test Hotel (Do Not Book) test",
      "kind": "Apartment",
      "hotelChain": "No chain",
      "isClosed": false,
      "isGenderSpecificationRequired": false,
      "address": "Avenida Roble, Frente al Mall Multiplaza, Tegucigalpa",
      "postalCode": null,
      "latitude": 14.079872,
      "longitude": -87.21677,
      "region": {
        "id": 3421,
        "name": "Tegucigalpa",
        "countryCode": "HN",
        "iata": "TGU",
        "type": "City"
      },
      "starRating": 0,
      "starCertificate": null,
      "contact": {
        "email": "[email protected]",
        "phone": "+15555550123"
      },
      "checkIn": "14:00:00",
      "checkOut": "12:00:00",
      "frontDeskHours": {
        "start": "00:00:00",
        "end": "00:00:00"
      },
      "images": [
        "https://cdn.worldota.net/t/{size}/extranet/b5/d3/b5d3d33394494c68321246882c1bd93a6832dcd5.jpeg"
      ],
      "amenityGroups": [
        {
          "groupName": "General",
          "amenities": [
            "24-hour reception",
            "Early check-in",
            "Late check-out"
          ],
          "paidAmenities": []
        }
      ],
      "serpFilters": [
        "has_internet",
        "has_parking",
        "kitchen"
      ],
      "descriptionStruct": [
        {
          "title": "Location",
          "paragraphs": [
            "A perfect fit for a big group of travellers: apartment «Test Hotel (Do Not Book)» ..."
          ],
          "html": "<h3>Location</h3><p>A perfect fit for a big group of travellers ...</p>"
        }
      ],
      "metapolicyExtraInfo": "Front desk is open 24/7.",
      "metapolicyStruct": {
        "internet": [
          {
            "inclusion": "included",
            "price": "0.00",
            "currency": null,
            "price_unit": "unspecified",
            "internet_type": "unspecified",
            "work_area": "hotel"
          }
        ],
        "pets": [
          {
            "inclusion": "not_included",
            "price": "560.00",
            "currency": "USD",
            "price_unit": "per_room_per_stay",
            "pets_type": "unspecified"
          }
        ],
        "children": [
          {
            "age_start": 0,
            "age_end": 3,
            "price": "500.00",
            "currency": "CHF",
            "extra_bed": "available"
          }
        ]
      },
      "roomGroups": [
        {
          "roomGroupId": 95,
          "name": "Standard Double room full double bed",
          "nameStruct": {
            "mainName": "Standard Double room",
            "beddingType": "full double bed",
            "bathroom": "shared bathroom"
          },
          "images": [
            "https://cdn.worldota.net/t/{size}/extranet/b5/d3/b5d3d33394494c68321246882c1bd93a6832dcd5.jpeg"
          ],
          "roomAmenities": [
            "bath",
            "heating"
          ],
          "roomClass": "room",
          "quality": "standard",
          "bathroom": "private-bathroom",
          "hasPrivateBathroom": true,
          "capacity": 2,
          "balcony": false,
          "view": null,
          "floor": null,
          "bedrooms": null,
          "beddingType": "double-bed",
          "isFamily": false,
          "isClub": false,
          "genderRestriction": null
        }
      ],
      "facts": {
        "floorsNumber": null,
        "roomsNumber": null,
        "yearBuilt": null,
        "yearRenovated": null,
        "electricity": {
          "voltage": [],
          "frequency": [
            60
          ],
          "sockets": [
            "a",
            "b"
          ]
        }
      },
      "paymentMethods": [
        "visa",
        "maestro",
        "cash"
      ],
      "keysPickup": {
        "type": "lockbox",
        "isContactless": true,
        "email": "[email protected]",
        "phone": "+15555550123",
        "officeAddress": null,
        "extraInfo": "The keys are in the box by the front door."
      }
    }
  ]
}

The reference describes every field: get_hotel_info for this camelCase form and The Hotel full object for the snake_case form of the same data. Things to know when you read it:

  • checkIn and checkOut are times of the day (14:00:00, local time), not dates.
  • images are URL templates with {size}: build the picture URL as described in Images. images can be null.
  • roomGroups is about 80% of the document. Each room type carries its own photos and amenities, with its properties decoded into words (roomClass, quality, beddingType, hasPrivateBathroom, balcony, view).
  • metapolicyStruct tells what is paid at the property (parking, extra beds, pets, deposits). Read children before you say a child stays free. Its entries keep snake_case keys (price_unit, age_start).
  • isClosed: true means the property is closed at the supplier: get_rates will find no rate.
  • The key style follows detail_level. full answers camelCase; minimal answers the snake_case card of The Hotel mini object. Do not mix them in one parser.

Eight keys of the full document come twice, as camelCase and as a snake_case twin, so that you can move to snake_case at your pace: hotelChain/hotel_chain, isClosed/is_closed, postalCode/postal_code, starRating/star_rating, starCertificate/star_certificate, checkIn/check_in_time, checkOut/check_out_time and region.countryCode/region.country_code. Add ?naming=snake to get every key in snake_case. See Conventions and naming.

Good practice

  • Cache the document by hotel id (not by language: the content is English). A day is a safe duration.
  • Call it once, when the user opens the hotel, not for every hotel of a list.
  • Fetch a missing hotel with one id per call, five calls at a time at most, and remember the failures for a few minutes. The supplier answers about 30 hotel content calls a minute for all of FX-Port. On a 503 supplier_busy wait the seconds of Retry-After: the call was refused before anything was sent.
  • Send "language": "en" when the hotel may not be cached: the fetched content is stored for every customer in the language of that call.

Errors

HTTPCodeCause
400missing_fieldNeither hotel_id nor hotel_ids is sent (Hotel IDs are required; errors[0].field is hotel_ids).
400invalid_hotel_id, invalid_hotel_idsAn id is not 1 to 128 characters (letters, digits and _ . : -; or a positive integer for a hid), or hotel_ids is not a list.
400too_many_idsMore than 200 ids in hotel_ids.
400invalid_detail_level, invalid_images_limit, invalid_languageThe value is not one of the documented ones.
404hotel_not_foundA single hotel_id that neither FX-Port nor the supplier knows.
429supplier_rate_limitedThe supplier is receiving too many content calls (only when FX-Port asks it for a single hotel). Retry after a minute.
502supplier_error, supplier_invalid_responseThe supplier could not process the request, or answered in a form that could not be used. Retry with backoff.
503supplier_unavailable, supplier_timeout, supplier_busyThe supplier could not be reached, did not answer in time, or is at capacity. With supplier_busy the call was refused before anything was sent: retry after the seconds in Retry-After. Otherwise retry with backoff.
401, 403The key is missing, wrong or not allowed: Authentication.

Related

Mini and full hotel dataWhen to use the compact card and when this document.Geo searchThe cards of the hotels around a point, with their prices.Get hotel ratesThe rooms, meals and cancellation terms of the hotel the user picked.API reference: Read one hotel for the hotel pageEvery field and error.
PreviousHotel name searchNext Get hotel rates

On this page

  • Request body
  • Legacy names
  • Request examples
  • How the hotel is found
  • Response
  • Good practice
  • Errors
  • Related

© 2026 FX-Port

TermsPrivacy[email protected]