> ## Documentation Index
> Fetch the complete documentation index at: https://demo-travel.webbinghub.io/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Hotelbeds integration: rules, flow and mapping

> The Hotelbeds APItude rules Omnibeds follows: signature auth, one search filter, child ages, rateKeys, the 40-call daily stop, booking, cancelling and how its data maps to ours.

Omnibeds connects to Hotelbeds APItude in its test environment, over REST and JSON. Hotelbeds is a confidential supplier: it is only searched, booked and shown in presenter mode, and its data is never committed or shown publicly. The adapter is in `lib/suppliers/hotelbeds/` and is built only from Hotelbeds' public documentation.

## At a glance

| | |
| - | - |
| Environment | Test (`api.test.hotelbeds.com`) |
| Authentication | API key plus `X-Signature` = SHA-256 of key + secret + Unix seconds, renewed on every call |
| How it keeps state | Offer token: every rate carries a `rateKey` |
| Offer validity | Not stated by Hotelbeds. We assume 30 minutes and label it "our estimate" |
| Daily calls | We stop at 40 a day (UTC), below what the test key allows |
| Search time limit | 4 s (our default) |
| Presenter mode | Required for everything |

## Their flow and ours

| Our step | Hotelbeds call | What Omnibeds does with it |
| - | - | - |
| Search | `POST /hotel-api/1.0/hotels` | Normalises each hotel and rate; adds photos and addresses from our stored content |
| Price check | `POST /hotel-api/1.0/checkrates` with the `rateKey` | Reads the price Hotelbeds will honour now and compares it with the searched one |
| Book | `POST /hotel-api/1.0/bookings` | Sends the holder and every guest by room; Hotelbeds confirms in the same answer |
| Live view and reconciliation | `GET /hotel-api/1.0/bookings/{reference}` | Shows how Hotelbeds holds the booking; `CANCELLED` closes it as failed |
| Cancel | `DELETE /hotel-api/1.0/bookings/{reference}?cancellationFlag=CANCELLATION` | Cancelled when Hotelbeds answers `CANCELLED` |
| Hotel content | `GET /hotel-content-api/1.0/hotels` | Photos, address, country, position and stars, stored in our database |
| Traveller change | None | There is no name-change call; a change is saved and marked as needing a supplier update |

## Must do

**1. Sign every request**

The signature changes every second, so it is computed for each call on the server. The key and secret never reach the browser and are masked in every log.

**2. Send exactly one search filter**

A destination code, a circle around a place (radius in km), or a list of hotel codes. Both a place and hotel codes at once are refused with HTTP 400 ("The request must have unique filter").

**3. Give every child's age**

One occupancy per room, and with children a `paxes` entry per child (`type: CH` and the age). Without it Hotelbeds refuses the search with HTTP 400.

**4. Check the rate before booking**

Every booking is preceded by `checkrates` with the offer's `rateKey`.

**5. Name every guest at booking**

The holder's name and surname, then a `paxes` list with each guest's room number, `AD` or `CH` (children with their age), name and surname. Each booking carries our own `clientReference`.

**6. Count every call**

Each live call reserves one unit of the daily allowance first, in one atomic statement in Postgres shared by every server. At 40 the call isn't made.

## Never do

> [!WARNING]
>
> * Never commit, publish or show Hotelbeds payloads, fixtures or content outside presenter mode. Replay mode uses synthetic fixtures, never recorded real data.
> * Never book in Replay mode. Bookings are real bookings in the test environment, so they run only in Live mode; Replay says so instead of pretending.
> * Never use Hotelbeds' logo or call it a partner. It may be named as a test environment.
> * Never spend the daily allowance on content: at most one Content API call follows a search, for at most 100 hotels, cheapest first.

## How its data becomes ours

| Hotelbeds | Omnibeds |
| - | - |
| `net` | The price. It already includes the taxes marked included |
| Taxes not included | Added to the price and shown as payable at the hotel |
| A tax in another currency (for example a tourism fee in AED on a EUR price) | Shown in its own currency, never added to the total |
| `rateClass: NRF` | Non-refundable. With no cancellation policies, 100% is charged from check-in |
| `cancellationPolicies` | Cancellation timeline: from each date, the amount and its percentage of the price |
| `boardCode` (RO, SC, BB, HB, FB...) | One of our five boards. A rate with a code we can't map is left out, not the whole answer |
| `rateType` | Kept as `BOOKABLE` or `RECHECK` |
| `rateKey` | The offer's supplier reference, valid for our assumed 30 minutes |
| A hotel described oddly | That hotel is left out, never the whole answer |
| Country, position | Never guessed: the availability answer doesn't give a country, and a missing position stays missing |

## When something goes wrong

| Hotelbeds answers | Omnibeds |
| - | - |
| HTTP 400, 404, 409, 410 or 422 to `checkrates` or a booking | The `rateKey` is no longer accepted: the offer counts as expired, Omnibeds searches the same product again, and the agent confirms the new price |
| HTTP 401, 403, 429 or a server error | An ordinary error, shown with Hotelbeds' own sentence and a link to the log |
| The daily stop is reached | No call is made; the agent is told the allowance is used up |


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.