Sandbox testing
Which hotelId values are safe to test with in sandbox, and why booking any other hotel fails.
Sandbox only has live inventory for a small set of designated test hotels. The supplier
sandbox (WorldOTA/RateHawk test environment) does not carry real hotel inventory. Searching or
booking any hotelId other than the test hotels below will return no rates, or fail at
pre_book / book_hotel. This is expected — it is not an FX-Port bug.
Designated sandbox test hotel
Use this hotelId for sandbox integration testing:
hotelId = test_hotelPass it as the id field on search_advanced and get_rates:
{
"id": "test_hotel",
"checkin": "2026-11-15",
"checkout": "2026-11-18",
"residency": "gb",
"language": "en",
"guests": [{ "adults": 2, "children": [] }]
}Supplier sandbox inventory is not under FX-Port's control and can be inconsistent. The
supplier's own test/demo hotels are shared infrastructure across every partner testing against
their sandbox, and their available rates, dates, and even booking behaviour can change without
notice. If a request against test_hotel returns zero rates for a given date range, retry with a
different checkin/checkout window (2–3 nights, starting 2–8 weeks out tends to work best)
before assuming your integration is broken. This mirrors the same caveat documented for flight
suppliers in Sandbox notice.
If test_hotel returns zero rates for every date range you try, use test_hotel_do_not_book
as a fallback to validate your get_rates → pre_book → book_hotel request/response handling
end-to-end. It is the supplier's other standard sandbox property and has reliably returned
bookable rates in our own testing. Its name is the supplier's own label — bookings against it are
still safe test bookings (no balance is ever debited in sandbox), but the supplier's own sandbox
housekeeping can cancel/refund it shortly after booking, so don't build cancellation-timing
assumptions around it.
What to expect
| Step | Behaviour in sandbox |
|---|---|
search_advanced / get_rates | Returns whatever synthetic rates the supplier currently exposes for test_hotel. Empty results for some date ranges are a known supplier-side limitation — try another date window. |
pre_book | Locks the rate exactly like live; no charge occurs. |
book_hotel | Completes and returns a real bucket_link (voucher PDF) once the background finalization step runs — poll get-booking until status is confirmed. |
| Balance | Never debited. balanceDebited, transactionCreated, and payoutCreated are all false in every sandbox booking response. |
cancel_hotel | Works like live, but the supplier's own sandbox housekeeping can independently cancel/refund test bookings out of band. If cancel_hotel returns invalid_status with a booking already refunded or cancelled, that's the supplier sandbox — not your integration — and can be treated as a successful end state. |
| Webhooks | Still fire, to your configured sandbox webhook URL. |
Testing checklist
Before switching to a live key, verify in sandbox against test_hotel:
- Locations —
locations/searchresolves a city to usable coordinates - Name search —
name-searchreturns fuzzy matches for a real hotel name - Search —
search_advancedaccepts your geo or hotel-ID payload - Rates —
get_ratesreturns at least one rate with abookHash, for one room and for a multi-room guest configuration with children ages - Pre-book —
pre_bookwith thatbookHashreturns apartnerOrderId - Book —
book_hotelwith thepartnerOrderIdand guest names returnsstatus: "pending"then transitions toconfirmed - Get booking —
GET /api/v1/bookings/{id}?product=hotelsshowsstatus: "confirmed"and a populatedbucket_link(voucher PDF) - Voucher —
get_voucherreturns the same PDF URL - Cancel —
cancel_hotelsucceeds, or reports the booking was already cancelled/refunded by the supplier sandbox (see caveat above)
Once every step above passes against test_hotel, switch to a fxp_live_ key — the request shapes
are identical, only the key prefix changes.