Hotels API overview
Geo search around a point, name search, hotel content, rates, pre-book, bookings that confirm at once, vouchers and cancellation.
Search, price and book hotels worldwide through one API. Hotel content comes as compact mini cards for result lists and as a full document for the hotel page: Mini and full hotel data.
For a summary of what the API covers, who it is for and how to get access, see the hotel booking API for travel agencies.
The flow: locations → geo search → rates → pre_book → book. Turn a typed city into coordinates, run a geo search (POST / with latitude, longitude and radius) to list the hotels around them with their prices, read the rooms and the cancellation terms of the hotel the user opens, lock the rate and book it. Then read the booking, get the voucher, or cancel. Booking a hotel 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).
- 1Your server to FX-Port API
GET /hotels/locations/search - 2FX-Port API to Your server
Coordinates of the destination - 3Your server to FX-Port API
POST /hotels/search_advanced (geo search) - 4FX-Port API to Your server
Mini hotel cards with prices - 5Your server to FX-Port API
POST /hotels/get_hotel_info (hotel page) - 6Your server to FX-Port API
POST /hotels/get_rates - 7FX-Port API to Your server
Rooms, rates, book_hash - 8Your server to FX-Port API
POST /hotels/pre_book - 9FX-Port API to Your server
Locked price, partnerOrderId - 10Your server to FX-Port API
POST /hotels/book_hotel - 11FX-Port API to Hotel supplier
Book the room - 12Your server to FX-Port API
GET /bookings/{id}?product=hotels - 13FX-Port API to Your server
Confirmed booking with the voucher
Endpoints
All paths are below https:/. Read works with any key; Read+Write needs a key with read_write permission (a read key answers 403 read_write_permission_required).
| Method | Path | Permission | What it does |
|---|---|---|---|
GET | / | Read | Turn a city, an area or an airport typed by a user into coordinates for the geo search. Search locations |
POST | / | Read | Geo search: the hotels around a point (or one hotel by id), as mini cards with prices. Geo search |
GET / POST | / / / | Read | Find a hotel by name. Hotel name search |
POST | /, / | Read | Content of up to 200 hotels by id, as mini cards or full documents. Mini and full hotel data |
POST | / | Read | The full content of one hotel for its page, and the content of a hotel FX-Port does not hold yet. Hotel details |
POST | / | Read | Every room and rate of a hotel for a stay, with cancellation terms. Get hotel rates |
POST | / | Read+Write | Lock the rate you chose. Pre-book a rate |
POST | / | Read+Write | Book the locked rate for the guests of each room. Book a hotel |
GET | / | Read | The status of a booking, with its price and voucher links. Get a hotel booking |
GET | / | Read | The hotel bookings of your agency, newest first. Booking history |
GET | / | Read | The links of the voucher PDFs. Get the hotel voucher |
POST | / | Read+Write | Cancel a confirmed booking. Cancel a hotel booking |
The API reference has every field, parameter and error of each call.
The flow, step by step
Find the place
locations/turns a typed city intosearch latitudeandlongitude, the input of the geo search.name-searchfinds a hotel by name and gives itsid.Geo search
search_advancedis the geo search: sendlatitude,longitudeand aradius(or ahotel_id) with the dates and the guests. It answers the mini cards inhotels_detailsand the price of each hotel inhotels_pricing. Join them by hotel id. Hotels that have a price but no card are inmissing_hotel_ids: see Mini and full hotel data.Show the hotel and its rooms
When the user opens a hotel, call
get_hotel_infofor its full page andget_ratesfor its rooms. Each rate has abookHashand a cancellation schedule.Lock the rate
pre_bookwith thebookHashre-checks the price with the supplier and answers apartnerOrderId: the id of the booking you are about to make.Book
book_hotelwith that id asbooking_id, the guests of each room and the contact. It answerspending.Wait for the confirmation
Poll
GET /every 2 seconds untilbookings/ {booking_id}?product=hotels statusisconfirmed(4 to 14 seconds). FX-Port sends no webhooks.Voucher, or cancel
get_vouchergives the voucher links.cancel_hotelcancels a confirmed booking.
What you carry from one call to the next:
| From | You keep | You send it to |
|---|---|---|
locations/ | latitude, longitude | search_advanced (the geo search) |
name-search, search_advanced | the hotel id | hotel_id of get_rates and get_hotel_info |
get_rates | rates[].bookHash (twin book_hash) | book_hash of pre_book |
pre_book | partnerOrderId (twin booking_id) | booking_id of book_hotel, get_voucher, cancel_hotel and the path of GET / |
Before you start
| Base URL and key | https:/. A key starting with fxp_test_ works on the sandbox and fxp_live_ on live: Authentication. |
| Permissions | Searches, content, rates, vouchers and booking reads need Read. pre_book, book_hotel and cancel_hotel need Read+Write. |
| Names | Fields you send are snake_case (hotel_id, book_hash, booking_id). The older spellings (id, hash, partner_order_id, hotelId ...) still work and are answered with a warnings array. Answers keep their keys, mostly camelCase after get_rates, and add snake_case twins of the keys you feed back; ?naming=snake returns snake_case only. See Conventions. |
| Currency | Prices come in the currency of your agency, resolved from your key. Never send currency: it is refused. See Hotel pricing. |
| Money | The traveler pays totalPrice; your agency is debited totalPrice - agencyCommission. There is no b2bPrice in the camelCase price blocks. |
| Stays | checkin and checkout as YYYY-MM-DD, 1 to 30 nights, check-in up to 400 days ahead. Guests and rooms: 9 rooms at most, one { adults, children } object per room. |
| Values | A value written in another well-defined way is read, and the answer says so in warnings (coerced_value): a number as text, a date with a midnight time, GB-SCT as residency, a radius outside 100 to 70,000 meters. Only what cannot be read is refused. See Values the API reads for you. |
| Rate limits | Per key and per minute: 6,000 for searches, rates, content and reads (a booking, a voucher), 1,200 for pre_book, book_hotel and cancel_hotel. Searches also have a ceiling on the calls that run at the same time. Rate limits. |
| Webhooks | None. Poll the booking. |
| Time | A search around a point takes 4 to 20 seconds, get_rates 0.5 to 5, pre_book 4 to 5, book_hotel 3 to 6, cancel_hotel 1 to 4. A booking is confirmed 4 to 14 seconds after book_hotel. |
Concepts
Errors
Every failed call answers one body, whatever the endpoint: errors[] with a stable code, next to the older keys. Branch on the code: see Errors. The ones you meet in the hotel flow:
| HTTP | Code | What to do |
|---|---|---|
400 | missing_field, invalid_date, stay_too_long, invalid_guests, invalid_residency ... | The request is wrong. A missing required field is missing_field: errors[0].field names it (the current name) and errors[0].details.missing_fields lists all of them when several are missing. Read errors[0].field and message, fix it. |
400 | invalid_status | The booking is not confirmed: wait, or it is already cancelled. |
400 | rate_not_found | The rate expired or its price rose: call get_rates again. |
403 | read_write_permission_required | Use a Read+Write key. |
404 | booking_not_found, pdf_not_found | No such booking of your agency; or the voucher is not made yet (get_voucher): ask again in 2 seconds. |
409 | hotel_not_bookable_in_sandbox | Sandbox: book test_hotel_do_not_book. |
409 | duplicate_booking | The booking exists. Do not call book_hotel again: read its status. |
409 | cached_offer_required | The offer of pre_book was not found (older than one hour on live, or locked by another agency): pre_book again. |
422 | supplier_rejected_request | The supplier refused well formed dates, guests, residency or radius (search_advanced): change them. |
429 | rate_limit_exceeded | Wait for Retry-After, then back off. |
502 | supplier_error, supplier_invalid_response, bad_gateway | The supplier could not answer, or answered in a form that could not be used. Retry a read with backoff. For book_hotel and cancel_hotel, read the booking first. |
503 | supplier_busy, service_overloaded | The supplier, or the service, is at capacity. The call was refused before anything was sent: nothing was searched, locked, booked or debited. Wait the seconds of Retry-After, then repeat the same call. |
503 | supplier_unavailable, supplier_timeout | The supplier could not be reached or did not answer. Retry a read with backoff. For cancel_hotel, read the booking first. |
A 200 is not always a hotel: get_rates answers 200 with an empty rates when a hotel is unknown, closed, not available for the dates or not available for the residency, and search_advanced answers 200 with no_hotels_found. Check the content of a 200.
What is safe to repeat
| Call | Safe to repeat? |
|---|---|
Locations, name search, search_advanced, content, get_rates, get_voucher, reading a booking | Yes. |
pre_book | Yes: the same rate and the same price_increase_percent within a minute get the same answer. |
book_hotel | No. A second call answers 409 duplicate_booking and does not reach the supplier. After a timeout or a 5xx (except 503 supplier_busy, which was refused before anything was sent), read GET /: if it exists, the booking was made. |
cancel_hotel | Yes after a timeout: a second call settles it, also when the supplier had already cancelled. Once the cancellation is recorded, a further call answers 400 invalid_status. |
Questions?
Email the FX-Port developer team at [email protected] for integration help, feature requests, or to report an API error. Quote the request_id of the failed call.