Skip to content
FX-Port/Docs
GuidesAPI referenceChangelog
Get API keys
  • Overview
  • Error object

Search

  • Geo searchPOST
  • Locations and coordinatesGET
  • Name searchGET
  • Name search (JSON body)POST

Hotel content

  • Cards of many hotelsPOST
  • One hotel, for its pagePOST
  • Raw hotel documentsPOST

Rates and booking

  • Rates of a hotelPOST
  • Pre-book a ratePOST
  • BookPOST

After booking

  • VoucherGET
  • CancelPOST

Objects

  • Hotel mini
  • Hotel full

Hotels · Rates and booking

Lock a rate before booking

Locks the rate you chose: the supplier re-checks the price and opens an order, and FX-Port keeps the priced offer for one hour under the partnerOrderId of the answer.

POST/api/v1/hotels/pre_book

Requires an API key with Read+Write permission: a Read key is refused with read_write_permission_required.

Book it with book_hotel, passing that id as booking_id. If the price rose since get_rates by more than price_increase_percent the call fails with rate_not_found: call get_rates again. If it rose by less, priceChanged is true and data holds the new price. Calling pre_book again with the same rate and the same price_increase_percent within a minute returns the same answer (the same partnerOrderId, no second order at the supplier); another percentage is a new request. Take 4 to 5 seconds. Always check formData.orderId: null means the supplier opened no order. In the sandbox a hotel other than a supplier test hotel answers 409 hotel_not_bookable_in_sandbox with the list of test hotels.

curl https://api.fx-port.com/api/v1/hotels/pre_book \
  -H "Authorization: Bearer fxp_test_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "book_hash": "h-14574656-7ce9-5a21-b673-8654c5ebd416",
  "price_increase_percent": 0
}'
Response200
{
  "environment": "sandbox",
  "success": true,
  "status": "ok",
  "partnerOrderId": "HMVXX4ZQ3",
  "priceChanged": false,
  "data": {
    "hotelId": "test_hotel_do_not_book",
    "hid": 8473727,
    "rates": [
      {
        "bookHash": "p-58bfbfa0-fd1c-4be9-8a2a-54942cae6627",
        "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
      }
    ]
  },
  "formData": {
    "partnerOrderId": "HMVXX4ZQ3",
    "orderId": 757581298,
    "itemId": 232430616,
    "paymentTypes": [
      {
        "amount": "3.00",
        "currencyCode": "EUR",
        "isNeedCreditCard": false,
        "isNeedCvc": false,
        "type": "deposit"
      },
      {
        "amount": "3.00",
        "currencyCode": "USD",
        "isNeedCreditCard": true,
        "isNeedCvc": true,
        "type": "now"
      }
    ]
  }
}

Request

Body

Required, JSON.

book_hashstringrequired

The bookHash of the rate you chose, from get_rates (it starts with h-). Valid for 30 minutes. The matchHash of a rate is not a booking token and is not read as one: a call that sends only a match_hash fails with missing_field.

price_increase_percentnumber

The price rise, in percent, you accept if the supplier raised the price since get_rates. 0 means none: the call fails if the price moved; null means not set (0). A repeated call within a minute with the same book_hash and the same percentage gets the same answer; another percentage is a new request. A number written as text ("5") is read as the number, with a coerced_value warning.

Between 0 and 100. Default 0.

languagestring

Language of the hotel name in the answer.

Default en.

hashstringdeprecated

Legacy name, still accepted. Use book_hash instead.

The rate token, in its older spelling. Use book_hash.

bookHashstringdeprecated

Legacy name, still accepted. Use book_hash instead.

The rate token, in its older spelling. Use book_hash.

Response

200The rate is locked. Keep partnerOrderId.

environmentstring

The environment of the key that made the call: sandbox for fxp_test_ keys, live for fxp_live_ keys. Present in every JSON body.

One of sandbox, live.

request_idstring

The id of the request, also in the X-Request-Id header.

warningsarray of object

Present only when the request used a previous spelling of a field or something the endpoint ignored.

ShowHide 5 attributes
codestring

What the warning is about.

One of deprecated_field, ignored_field, coerced_value, deprecated_value, deprecated_endpoint.

fieldstring

The request field the warning is about.

replacementstring

The name to use instead, for deprecated_* warnings.

messagestring

A sentence that says what happened and what to do.

documentation_urlstring

Where the naming rules are explained.

successboolean

true when the rate was locked.

statusstring

Always ok.

Always ok.

partnerOrderIdstringdeprecated

Legacy name, still accepted. Use booking_id instead.

The id of the booking you are about to make. Send it as booking_id to book_hotel, then to GET /bookings/{id}, get_voucher and cancel_hotel.

booking_idstring

The id of the booking you are about to make. Send it as booking_id to book_hotel, then to GET /bookings/{id}, get_voucher and cancel_hotel. The snake_case twin of partnerOrderId, with the same value: use this name.

partner_order_idstring

The id of the booking you are about to make. Send it as booking_id to book_hotel, then to GET /bookings/{id}, get_voucher and cancel_hotel. The snake_case twin of partnerOrderId, with the same value: use this name.

priceChangedbooleandeprecated

Legacy name, still accepted. Use price_changed instead.

true when the supplier's price moved since get_rates (within price_increase_percent). data holds the new price.

price_changedboolean

true when the supplier's price moved since get_rates (within price_increase_percent). data holds the new price. The snake_case twin of priceChanged, with the same value: use this name.

dataobject

The locked rate.

ShowHide 4 attributes
hotelIdstringdeprecated

Legacy name, still accepted. Use hotel_id instead.

The id of the hotel.

hotel_idstring

The id of the hotel. The snake_case twin of hotelId, with the same value: use this name.

hidinteger

The supplier's numeric hotel id.

ratesarray of object

The one rate you locked, with a new bookHash that starts with p-. Do not reuse it.

ShowHide 17 attributes
bookHashstringdeprecated

Legacy name, still accepted. Use book_hash instead.

The token of this rate. Send it as book_hash to pre_book. It stays valid for 30 minutes.

book_hashstring

The token of this rate. Send it as book_hash to pre_book. It stays valid for 30 minutes. The snake_case twin of bookHash, with the same value: use this name.

matchHashstringdeprecated

Legacy name, still accepted. Use match_hash instead.

A second identifier of the rate. You do not need it to book: send bookHash.

match_hashstring

A second identifier of the rate. You do not need it to book: send bookHash. The snake_case twin of matchHash, with the same value: use this name.

roomobject

The room of a rate. Match it with the hotel content by room name; the document of get_hotel_info lists every room type with photos and amenities.

ShowHide 16 attributes
namestring

Name of the room as the supplier sells it, in the language of the request.

beddingTypestringnullable

The bedding as a phrase: single bed, full double bed, twin beds ...

miscRoomTypestringnullable

Another description of the bed or room, when the supplier gives one (king size bed).

capacityintegernullable

Number of guests the room is made for; null when unknown.

bathroomstringnullable

private-bathroom or shared-bathroom.

hasPrivateBathroomboolean

true when the bathroom is private.

balconyboolean

true when the room has a balcony.

roomClassstringnullable

Class of the room: room, suite, junior-suite, apartment, studio, cottage, dorm ...

qualitystringnullable

Quality of the room: economy, standard, classic, superior, deluxe, executive, business ...

viewstringnullable

View of the room (city-view, garden-view ...); null when there is none.

floorstringnullable

Floor of the room, when it is special (attic).

bedroomsintegernullable

Number of bedrooms; null when unknown.

isFamilyboolean

true for a family room.

isClubboolean

true for a club room.

genderRestrictionstringnullable

Gender the room is reserved for (hostel dorms); null when there is no restriction.

nonSmokingboolean

true when the room is non-smoking.

mealobject

The meal plan of a rate.

ShowHide 3 attributes
typestring

The meal included in the rate. nomeal is room only.

One of nomeal, breakfast, lunch, dinner, half-board, half-board-lunch, half-board-dinner, full-board, all-inclusive, ultra-all-inclusive.

includedboolean

true when a meal is included (type is not nomeal).

childMealIncludedboolean

true when the meal of the children is included too.

dailyPricesarray of numberdeprecated

Legacy name, still accepted. Use daily_prices instead.

The supplier's price of each night of the stay (first room), in supplierCurrency.

daily_pricesarray of number

The supplier's price of each night of the stay (first room), in supplierCurrency. The snake_case twin of dailyPrices, with the same value: use this name.

allotmentinteger

How many rooms of this type are left at this rate.

isPackageboolean

true when the rate is part of a package.

anyResidencyboolean

false when the rate is reserved for some residencies: it exists for the residency of your request only.

depositobjectnullable

Reserved for deposit terms of the rate. null today.

noShowobjectnullable

Reserved for no-show terms of the rate. null today.

cancellationPolicyobject

When and at what price a booking of the rate can be cancelled. The amounts are the supplier's (originalAmount, in originalCurrency); what is refunded to your agency is in the answer of cancel_hotel.

ShowHide 3 attributes
freeCancellationBeforestringnullabledeprecated

Legacy name, still accepted. Use free_cancellation_before instead.

UTC date and time (no zone suffix) until which the booking can be cancelled for free. null means the rate is non-refundable.

free_cancellation_beforestringnullable

UTC date and time (no zone suffix) until which the booking can be cancelled for free. null means the rate is non-refundable. The snake_case twin of freeCancellationBefore, with the same value: use this name.

policiesarray of object

The schedule of penalties from now to check-in: the free window first, then the windows with a penalty.

ShowHide 5 attributes
fromstringnullable

Start of the window, a UTC date and time without zone suffix; null for the first window (from now).

untilstringnullable

End of the window, a UTC date and time without zone suffix; null for the last window (to check-in and after).

originalAmountnumber

The penalty charged by the supplier in this window, in originalCurrency. 0 in the free window.

originalCurrencystring

Currency of originalAmount, the supplier's: EUR.

currencystring

Your agency currency, as a label. originalAmount is NOT in this currency.

pricingobject

The prices of a rate or of an offer. There is no b2bPrice in this block: the amount debited from your agency is totalPrice - agencyCommission (see Hotel pricing).

ShowHide 10 attributes
supplierCurrencystringdeprecated

Legacy name, still accepted. Use supplier_currency instead.

Currency the supplier prices in: EUR.

supplier_currencystring

Currency the supplier prices in: EUR. The snake_case twin of supplierCurrency, with the same value: use this name.

agencyCurrencystringdeprecated

Legacy name, still accepted. Use agency_currency instead.

The currency of your agency. Every amount below except originalPrice and taxes is in it.

agency_currencystring

The currency of your agency. Every amount below except originalPrice and taxes is in it. The snake_case twin of agencyCurrency, with the same value: use this name.

originalPricenumber

The supplier's price for the whole stay and all rooms, in supplierCurrency. For information: it is not the base of what you pay.

agencyCommissionnumberdeprecated

Legacy name, still accepted. Use agency_commission instead.

Your commission, in agencyCurrency. The agency price is totalPrice minus this amount.

agency_commissionnumber

Your commission, in agencyCurrency. The agency price is totalPrice minus this amount. The snake_case twin of agencyCommission, with the same value: use this name.

totalPricenumberdeprecated

Legacy name, still accepted. Use total_price instead.

What the traveler pays: the whole stay, all rooms, in agencyCurrency. You are debited totalPrice - agencyCommission.

total_pricenumber

What the traveler pays: the whole stay, all rooms, in agencyCurrency. You are debited totalPrice - agencyCommission. The snake_case twin of totalPrice, with the same value: use this name.

taxesobject

Taxes and fees by name (cityTax, cleaningFee, electricityFee, occupancyTax, resortFee, serviceFee, vat ...), only the ones the rate has.

exchangeRatenumberdeprecated

Legacy name, still accepted. Use exchange_rate instead.

The rate of exchange from supplierCurrency to agencyCurrency that was used (285.0 in the sandbox).

exchange_ratenumber

The rate of exchange from supplierCurrency to agencyCurrency that was used (285.0 in the sandbox). The snake_case twin of exchangeRate, with the same value: use this name.

formDataobject

The supplier's booking form for the order that book_hotel finishes.

ShowHide 5 attributes
partnerOrderIdstringnullabledeprecated

Legacy name, still accepted. Use partner_order_id instead.

The order id again. null when the supplier opened no order.

partner_order_idstringnullable

The order id again. null when the supplier opened no order. The snake_case twin of partnerOrderId, with the same value: use this name.

orderIdintegernullable

The supplier's order number. null means the supplier opened no order and the hotel cannot be booked.

itemIdintegernullable

The supplier's item number inside the order.

paymentTypesarray of object

The ways to pay the supplier offers: one deposit and one now option per card currency (about 40 entries).

ShowHide 5 attributes
amountstring

The amount as a decimal string, in currencyCode.

currencyCodestring

ISO 4217 currency of amount.

isNeedCreditCardboolean

true when the option needs a card. FX-Port never does: it pays with the deposit option.

isNeedCvcboolean

true when the option needs a card security code.

typestring

deposit pays from the supplier deposit of FX-Port (the one FX-Port uses); now is a card payment.

One of deposit, now.

Errors

StatusCodeExample message
400missing_fieldMissing required field: hash
400invalid_rate_hash'book_hash' must be a rate hash taken from get_rates (got 'abc').
400rate_not_foundRate not found
403read_write_permission_requiredThis endpoint requires an API key with read_write permission.
409hotel_not_bookable_in_sandboxOnly the supplier test hotels can be booked in sandbox: test_hotel_do_not_book (any residency) or test_hotel (residency dz, ru or us).
502supplier_invalid_responseThe hotel supplier returned an answer that could not be used. Retry in a few minutes.
503supplier_busyThe supplier is temporarily at capacity; retry after the time given in the Retry-After header.

The shape of the error body depends on the endpoint. See Errors for every shape and code.

Related guides

  • Pre-book a rate
  • Sandbox testing
PreviousGet the rooms and rates of one hotelNext Book a locked rate

© 2026 FX-Port

TermsPrivacy[email protected]