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 ยท Rates and booking

Get hotel rates

Every room and rate combination for a specific hotel, with cancellation policies. Required before pre_book.

POST/api/v1/hotels/get_rates

Get every room and rate of one hotel for a stay: each with its meal plan, its cancellation schedule, its taxes and its price. The bookHash of the rate the user chooses is what you send to pre_book.

Permission: Read

Sandbox: any hotel is priced, only the test hotels can be booked

get_rates returns the real rates of any hotel in the sandbox. A rate of another hotel than the supplier test hotels cannot be booked there: see Sandbox testing. test_hotel has rates for the residencies dz, ru and us only.

Request body

POST /api/v1/hotels/get_rates

FieldTypeRequiredDefaultDescription
hotel_idstringYesThe FX-Port id of the hotel: hotels_details[].id of a search, or a hit of the name search.
checkinstringYesCheck-in date, YYYY-MM-DD. From yesterday to 400 days ahead.
checkoutstringYesCheck-out date, after checkin. A stay is 1 to 30 nights.
guestsarrayYesOne { adults, children } object per room. See Guests and rooms.
residencystringNogbResidency of the guests, a two-letter country code. Some rates exist for some residencies only.
languagestringNoenLanguage of the room names (fr gives Standard chambre).

Do not send a currency field: it is refused with 400. Prices come in the currency of your agency.

Send the same guests and residency as in the search, or the rates and prices will differ. A value written in another well-defined way (a number as text, a date with a midnight time, GB-SCT as residency ...) is read like in search_advanced, and a number sent as hotel_id is not looked up as a supplier hid here. Identical calls of your agency that arrive at the same moment are merged into one supplier call; each caller still gets its own request_id and headers.

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
id, hotelIdhotel_id
check_in, checkinDate, checkin_datecheckin
check_out, checkoutDate, checkout_datecheckout

Request examples

curl https://api.fx-port.com/api/v1/hotels/get_rates \
  -H "Authorization: Bearer fxp_test_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "hotel_id": "test_hotel_do_not_book",
  "checkin": "2026-12-01",
  "checkout": "2026-12-04",
  "residency": "gb",
  "language": "en",
  "guests": [
    {
      "adults": 2,
      "children": []
    }
  ]
}'
curl https://api.fx-port.com/api/v1/hotels/get_rates \
  -H "Authorization: Bearer fxp_test_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "hotel_id": "test_hotel_do_not_book",
  "checkin": "2026-12-10",
  "checkout": "2026-12-12",
  "residency": "gb",
  "language": "en",
  "guests": [
    {
      "adults": 2,
      "children": [
        8
      ]
    },
    {
      "adults": 1,
      "children": []
    }
  ]
}'
curl https://api.fx-port.com/api/v1/hotels/get_rates \
  -H "Authorization: Bearer fxp_test_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "hotel_id": "test_hotel",
  "checkin": "2026-12-01",
  "checkout": "2026-12-04",
  "residency": "dz",
  "language": "en",
  "guests": [
    {
      "adults": 2,
      "children": []
    }
  ]
}'

Response

A real answer of the sandbox, cut to the cheapest of the 14 rates of the test hotel (0.5 to 1.4 s, 23 KB for the 14 rates):

{
  "environment": "sandbox",
  "success": true,
  "data": {
    "hotelId": "test_hotel_do_not_book",
    "hid": 8473727,
    "rates": [
      {
        "bookHash": "h-14574656-7ce9-5a21-b673-8654c5ebd416",
        "matchHash": "m-a1f40b22-c086-57c9-b2b5-70c8e59cb27c",
        "room": {
          "name": "Standard room",
          "beddingType": "single bed",
          "miscRoomType": null,
          "capacity": null,
          "bathroom": "private-bathroom",
          "hasPrivateBathroom": true,
          "balcony": false,
          "roomClass": "room",
          "quality": "standard",
          "view": null,
          "floor": null,
          "bedrooms": null,
          "isFamily": false,
          "isClub": false,
          "genderRestriction": null,
          "nonSmoking": true
        },
        "meal": {
          "type": "nomeal",
          "included": false,
          "childMealIncluded": false
        },
        "dailyPrices": [
          1,
          1,
          1
        ],
        "allotment": 77,
        "isPackage": false,
        "anyResidency": true,
        "deposit": null,
        "noShow": null,
        "cancellationPolicy": {
          "freeCancellationBefore": "2026-12-01T21:00:00",
          "policies": [
            {
              "from": null,
              "until": "2026-12-01T21:00:00",
              "originalAmount": 0,
              "originalCurrency": "EUR",
              "currency": "DZD"
            },
            {
              "from": "2026-12-01T21:00:00",
              "until": null,
              "originalAmount": 3,
              "originalCurrency": "EUR",
              "currency": "DZD"
            }
          ]
        },
        "pricing": {
          "supplierCurrency": "EUR",
          "agencyCurrency": "DZD",
          "originalPrice": 3,
          "agencyCommission": 2.97,
          "totalPrice": 1484.97,
          "taxes": {
            "cityTax": {
              "includedInPrice": false,
              "amount": 23.1,
              "currency": "HNL"
            },
            "electricityFee": {
              "includedInPrice": true,
              "amount": 0.6,
              "currency": "EUR"
            },
            "resortFee": {
              "includedInPrice": true,
              "amount": 0.68,
              "currency": "EUR"
            }
          }
        },
        "exchangeRate": 285
      }
    ]
  },
  "processingTime": 0.335
}
FieldDescription
data.hotelId, data.hidThe hotel, by FX-Port id and by the supplier's numeric id.
data.rates[]The rates, in no particular order: sort them by pricing.totalPrice yourself.
bookHashThe token of the rate. Send it as book_hash to pre_book. Valid for 30 minutes: after that, ask for the rates again.
matchHashA second identifier of the rate. It is not a booking token: pre_book does not read it. Send bookHash.
roomThe room: name (in your language), bedding, bathroom, class, quality, view, size flags. The full room types, with photos, are in the content of the hotel (get_hotel_info, roomGroups): match them by room name.
mealtype, included and childMealIncluded. The types are nomeal, breakfast, lunch, dinner, half-board, half-board-lunch, half-board-dinner, full-board, all-inclusive and ultra-all-inclusive.
dailyPricesThe supplier's price of each night, in the supplier's currency (EUR). For information.
allotmentHow many rooms of this type are left at this rate.
anyResidencyfalse when the rate is reserved for some residencies: it exists for the residency of your request only.
isPackagetrue when the rate is part of a package.
cancellationPolicyWhen the booking can be cancelled for free, and the penalty windows after that. See below.
pricing, exchangeRateThe price of the rate, for the whole stay and all rooms, and the exchange rate used. See Hotel pricing.
processingTimeSeconds the call took.

The keys you feed back or compute with also come with a snake_case twin: book_hash, match_hash, daily_prices, exchange_rate, pricing.total_price, pricing.agency_commission, pricing.agency_currency, pricing.supplier_currency, cancellationPolicy.free_cancellation_before, data.hotel_id and processing_time. See Legacy names.

Choosing a rate

  • A room type appears many times: one rate per meal plan and per cancellation condition. Group the rates by room.name and show the cheapest of each, with what differs (meal, cancellation).
  • Show what is paid at the hotel. pricing.taxes lists taxes and fees; those with includedInPrice: false are paid by the traveler at the property, on top of totalPrice, in the currency the supplier states (it can be the local currency, such as HNL).
  • Only prepaid rates are returned. Rates that are paid at the hotel are not offered, because FX-Port bookings are paid from your agency balance. The price of the search is the cheapest rate of the supplier, so in rare cases the cheapest rate here is a little higher.
  • A rate is for one occupancy and one residency. If the user changes a guest or the country, call again.

Cancellation policy

cancellationPolicy says what a cancellation costs, window after window:

  • freeCancellationBefore is the moment until which the booking can be cancelled for free, in UTC, without a zone suffix (2026-12-01T21:00:00). null means the rate is non-refundable.
  • policies[] is the schedule from now to the check-in and after: the free window first (originalAmount: 0), then the windows with a penalty.
  • The amounts are the supplier's: originalAmount is in originalCurrency (EUR). The currency field only labels your agency currency, and no amount in your currency is given: see Cancellation penalties. What is refunded is in the answer of cancel_hotel.

No rate is not an error

A hotel that is unknown, closed, not available for the dates or not available for the residency answers 200 with hotelId: null and an empty list. Check rates.length; do not wait for a 404:

{
  "environment": "sandbox",
  "success": true,
  "data": {
    "hotelId": null,
    "hid": null,
    "rates": []
  },
  "processingTime": 0.16
}

If you expected rates, check the dates, the occupancy, the residency (test_hotel has none for gb or fr) and isClosed in the content of the hotel.

Errors

HTTPCodeCause
400missing_fieldhotel_id, checkin, checkout or guests is missing. errors[0].field names the first missing field and errors[0].details.missing_fields lists all of them when several are missing. The message is the older sentence (Missing required fields: ['guests']).
400bad_requestYou sent a currency field.
400invalid_date, date_in_past, date_too_far, checkout_before_checkin, stay_too_longThe dates are not a real stay.
400invalid_guests, invalid_adult_count, too_many_children, invalid_child_age, too_many_guests, too_many_roomsThe rooms break the rules.
400invalid_residency, invalid_language, invalid_hotel_idThe code is not valid.
502supplier_invalid_responseThe supplier answered in a form that could not be used. Retry in a few minutes.
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.
429rate_limit_exceededToo many calls: Rate limits.

A search that the supplier itself refuses comes as 400 too, with the supplier's own code in errors[0].code and errors[0].type supplier_error.

Next step

Take the bookHash of the chosen rate and call pre_book to lock its price.

Related

Hotel pricingWhat totalPrice, agencyCommission and the taxes mean, and what you are debited.Pre-book a rateLock the price of the chosen rate.Guests and roomsThe occupancy of a request.API reference: Get the rooms and rates of one hotelEvery field and error.
PreviousHotel detailsNext Pre-book a rate

On this page

  • Request body
  • Legacy names
  • Request examples
  • Response
  • Choosing a rate
  • Cancellation policy
  • No rate is not an error
  • Errors
  • Next step
  • Related

ยฉ 2026 FX-Port

TermsPrivacy[email protected]