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

Book a locked rate

Books the offer locked by pre_book and confirms it: there is no hold or pay-later option for API keys, and your agency is debited as part of the booking, when it is confirmed (the sandbox debits nothing).

POST/api/v1/hotels/book_hotel

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

Send the booking_id (the partnerOrderId of pre_book), the guests of each room and the contact of the booker; the price, the hotel and the dates come from the locked offer, and the pre-booked rate and hotel are always the ones booked: a book_hash or hotel_id in the body is optional and never an error (a value that is not the offer's is ignored, with an ignored_field warning). The answer is pending: the supplier confirms in the background, usually 4 to 14 seconds later. Read GET /bookings/{booking_id}?product=hotels every 2 seconds until status is confirmed (or failed), then fetch the voucher. FX-Port sends no webhooks. Call book_hotel once per booking_id: a second call answers 409 duplicate_booking and does not reach the supplier. After a timeout or a 5xx, read the booking before you do anything else. A child must be a guest with is_child true and an age. commission_override sets your commission for this booking. In the sandbox every booking is a real order on the supplier's test contract: cancel it.

curl https://api.fx-port.com/api/v1/hotels/book_hotel \
  -H "Authorization: Bearer fxp_test_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "booking_id": "HMVXX4ZQ3",
  "rooms": [
    {
      "guests": [
        {
          "first_name": "Jane",
          "last_name": "Smith"
        },
        {
          "first_name": "John",
          "last_name": "Smith"
        }
      ]
    }
  ],
  "user": {
    "email": "[email protected]",
    "phone": "+15555550123"
  },
  "send_email": false
}'
Response200
{
  "environment": "sandbox",
  "success": true,
  "status": "pending",
  "bookingId": "HMVXX4ZQ3",
  "partnerOrderId": "HMVXX4ZQ3",
  "hotelId": "test_hotel_do_not_book",
  "checkinDate": "2026-12-01",
  "checkoutDate": "2026-12-04",
  "pricing": {
    "totalPrice": 1484.97,
    "agencyCommission": 2.97,
    "currency": "DZD",
    "supplierCurrency": "EUR",
    "originalPrice": 3
  },
  "postProcessing": {
    "bookingDbId": "24fec1e5-a09f-48ec-8050-1adaab0a8de1",
    "webhookSent": false,
    "bucketLink": null
  },
  "processingTime": 5.449,
  "balanceDebited": false,
  "transactionCreated": false,
  "payoutCreated": false
}

Request

Body

Required, JSON.

booking_idstringrequired

The id of the booking: the partnerOrderId that pre_book returned. Book it once.

roomsarray of objectrequired

The guests of each room, in the same order and with the same occupancy as the search: one object per room, one entry per adult and per child.

ShowHide 1 attribute
guestsarray of objectrequired

Every guest of the room, adults and children, as many as you searched (one object per adult and per child).

ShowHide 4 attributes
first_namestringrequired

Given name of the guest. Letters of any script, spaces, -, ,, . and ' are kept; digits and other symbols are replaced by a space.

last_namestringrequired

Family name of the guest, same rules as first_name.

is_childboolean

true for a child. A child must carry is_child and age, or the supplier refuses the booking with incorrect_guests_number. The numbers 1 and 0, and the texts true, false, yes, no, on, off, 1 and 0, are read as the boolean (a text with a coerced_value warning); null or an empty text means not set (an adult); any other value is 400 invalid_is_child.

ageinteger

Age of the child in years at check-in, 0 to 17. Required with is_child. A number written as text ("8") is read as the number, with a coerced_value warning.

Between 0 and 17.

userobjectrequired

The person who makes the booking.

ShowHide 3 attributes
emailstringrequired

E-mail address of the booker. FX-Port sends its confirmation here (unless send_email is false); the supplier gets an address of FX-Port's own.

phonestring

Phone number of the booker, with country code.

commentstring

Free text for the hotel, forwarded to the supplier.

languagestring

Language of the confirmation e-mail and of the voucher.

Default en.

send_emailboolean

false to stop FX-Port from sending its confirmation e-mail to user.email. Use it when you test. The numbers 1 and 0, and the texts true, false, yes, no, on, off, 1 and 0, are read as the boolean (a text with a coerced_value warning); null means the default; any other value is 400 invalid_send_email.

Default true.

commission_overrideobject

Sets your commission for this booking instead of your default one. The traveler price becomes the price you pay plus this commission; what you are debited does not change.

ShowHide 2 attributes
typestringrequired

fixed: value is your commission per room, in your agency currency. percentage: value is a percentage of the price you pay.

One of fixed, percentage.

valuenumberrequired

The amount or the percentage, 0 or more. A negative value is ignored.

At least 0.

book_hashstring

Do not send it: FX-Port keeps the rate you locked with pre_book under booking_id and always books that rate. A hash the offer was made from (the bookHash of pre_book, the bookHash of get_rates, a match hash) is accepted silently; any other value is ignored, with an ignored_field warning, and the pre-booked rate is booked. It is never an error.

hotel_idstring

Do not send it: FX-Port keeps the hotel you locked with pre_book under booking_id and always books that hotel. The same hotel (in another case, its numeric supplier id, the id get_rates was called with) is accepted silently; any other value is ignored, with an ignored_field warning, and the pre-booked hotel is booked. It is never an error.

partner_order_idstringdeprecated

Legacy name, still accepted. Use booking_id instead.

The booking id, in its older spelling. Use booking_id.

partnerOrderIdstringdeprecated

Legacy name, still accepted. Use booking_id instead.

The booking id, in its older spelling. Use booking_id.

bookingIdstringdeprecated

Legacy name, still accepted. Use booking_id instead.

The booking id, in its older spelling. Use booking_id.

bookHashstringdeprecated

Legacy name, still accepted. Use book_hash instead.

The rate token, in its older spelling. Do not send it: see book_hash.

hotelIdstringdeprecated

Legacy name, still accepted. Use hotel_id instead.

The hotel id, in its older spelling. Do not send it: see hotel_id.

Response

200The supplier accepted the booking: it is pending.

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 supplier accepted the booking.

statusstring

Always pending: the supplier confirms in the background. Poll the booking until it is confirmed.

Always pending.

bookingIdstringdeprecated

Legacy name, still accepted. Use booking_id instead.

The id of the booking. The same value as partnerOrderId and as the booking_id you sent.

booking_idstring

The id of the booking. The same value as partnerOrderId and as the booking_id you sent. The snake_case twin of bookingId, with the same value: use this name.

partnerOrderIdstringdeprecated

Legacy name, still accepted. Use partner_order_id instead.

The id of the booking, as the supplier knows it.

partner_order_idstring

The id of the booking, as the supplier knows it. The snake_case twin of partnerOrderId, with the same value: use this name.

hotelIdstringdeprecated

Legacy name, still accepted. Use hotel_id instead.

The id of the hotel that was booked.

hotel_idstring

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

checkinDatestringdeprecated

Legacy name, still accepted. Use checkin instead.

Check-in date, YYYY-MM-DD, taken from the locked offer.

checkinstring

Check-in date, YYYY-MM-DD, taken from the locked offer. The snake_case twin of checkinDate, with the same value: use this name.

checkoutDatestringdeprecated

Legacy name, still accepted. Use checkout instead.

Check-out date, YYYY-MM-DD.

checkoutstring

Check-out date, YYYY-MM-DD. The snake_case twin of checkoutDate, with the same value: use this name.

pricingobject

The price of the booking as it was locked by pre_book.

ShowHide 9 attributes
totalPricenumberdeprecated

Legacy name, still accepted. Use total_price instead.

What the traveler pays, in currency.

total_pricenumber

What the traveler pays, in currency. The snake_case twin of totalPrice, with the same value: use this name.

agencyCommissionnumberdeprecated

Legacy name, still accepted. Use agency_commission instead.

Your commission, in currency. You are debited totalPrice - agencyCommission.

agency_commissionnumber

Your commission, in currency. You are debited totalPrice - agencyCommission. The snake_case twin of agencyCommission, with the same value: use this name.

currencystringdeprecated

Legacy name, still accepted. Use agency_currency instead.

The currency of your agency.

agency_currencystring

The currency of your agency. The snake_case twin of currency, with the same value: use this name.

supplierCurrencystringdeprecated

Legacy name, still accepted. Use supplier_currency instead.

The currency the supplier priced in: EUR.

supplier_currencystring

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

originalPricenumber

The supplier's price in supplierCurrency, for information.

postProcessingobject

Internal progress of the booking. Poll the booking instead of reading it.

ShowHide 4 attributes
bookingDbIdstring

The internal id of the booking row (a UUID). The booking detail calls it id.

webhookSentboolean

Describes an internal step of FX-Port (the voucher rendering), not a message to you: FX-Port sends no webhooks to customers.

bucketLinkstringnullabledeprecated

Legacy name, still accepted. Use voucher_url instead.

The voucher link. Always null here: the voucher is made after the call; read it with get_voucher.

voucher_urlstringnullable

The voucher link. Always null here: the voucher is made after the call; read it with get_voucher. The snake_case twin of bucketLink, with the same value: use this name.

processingTimenumberdeprecated

Legacy name, still accepted. Use processing_time instead.

Seconds the call took.

processing_timenumber

Seconds the call took. The snake_case twin of processingTime, with the same value: use this name.

balanceDebitedbooleandeprecated

Legacy name, still accepted. Use balance_debited instead.

Sandbox only: false, nothing was debited. The key is absent on live.

balance_debitedboolean

Sandbox only: false, nothing was debited. The key is absent on live. The snake_case twin of balanceDebited, with the same value: use this name.

transactionCreatedbooleandeprecated

Legacy name, still accepted. Use transaction_created instead.

Sandbox only: false. Absent on live.

transaction_createdboolean

Sandbox only: false. Absent on live. The snake_case twin of transactionCreated, with the same value: use this name.

payoutCreatedbooleandeprecated

Legacy name, still accepted. Use payout_created instead.

Sandbox only: false. Absent on live.

payout_createdboolean

Sandbox only: false. Absent on live. The snake_case twin of payoutCreated, with the same value: use this name.

Errors

StatusCodeExample message
400missing_fieldMissing required field: rooms
400invalid_rooms'rooms' must be a non-empty list: one {guests: [...]} object per room.
400invalid_send_email'send_email' must be true or false (got 'maybe').
400invalid_is_child'rooms[0].guests[1].is_child' must be true or false (got 'maybe').
400invalid_request'partner.partner_order_id' differs from 'booking_id': send the booking id once, or the same value twice.
400incorrect_guests_numberIncorrect guests number
400order_not_foundOrder not found
402insufficient_balanceThe agency balance is lower than the amount to debit.
403read_write_permission_requiredThis endpoint requires an API key with read_write permission.
409duplicate_bookingA booking already exists for this partner_order_id: do not call book_hotel again, read its status with GET /api/v1/bookings/{booking_id}?product=hotels.
409cached_offer_requiredTrusted cached hotel offer not found. Re-run pre_book before booking so the backend can verify the exact debit amount.
500post_booking_failedThe booking was accepted but its post-processing failed; read its status with GET /api/v1/bookings/{booking_id}?product=hotels.
502supplier_invalid_responseThe hotel supplier returned an unreadable answer to the booking request, so the booking may or may not have been made: read its status with GET /api/v1/bookings/{booking_id}?product=hotels before you retry.
503balance_lock_timeoutAnother booking of this agency is still being processed; retry in a few seconds.
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

  • Book a hotel
  • Guests and rooms
  • Get a hotel booking
PreviousLock a rate before bookingNext Get the voucher PDF links of a booking

© 2026 FX-Port

TermsPrivacy[email protected]