
# Conventions

Every transaction in the Stays API follows the same wire rules. Learn them once here; the endpoint pages assume them throughout. This page mirrors the "generic conventions" chapter of the reference documentation this API is contract-compatible with, so an integrator moving across finds the same guarantees in the same places.

---

## Response envelope

Every response — success or failure — uses the same JSON envelope:

```json
{ "code": 0, "msg": "success", "data": {} }
```

| Field | Type    | Meaning                                                                                                                              |
| ----- | ------- | ------------------------------------------------------------------------------------------------------------------------------------ |
| code  | integer | Result code. `0` = success; anything else is a business error code (see [Error handling](/hotel-api/docs/guides/error-handling)). |
| msg   | string  | Human-readable result message.                                                                                                       |
| data  | object  | The business payload. Present on success; errors carry only `code` and `msg`.                                                        |

**The body `code` is authoritative.** Some business failures are delivered with HTTP 200, so check `code` rather than the transport status alone:

- A booking whose rate moved between [CheckAvail](/hotel-api/docs/api-reference/check-avail) and the commit returns HTTP 200 with `code` `100001111` (ARI Changed) — not an HTTP error.
- [CheckAvail](/hotel-api/docs/api-reference/check-avail) itself answers a sold-out room with `code` `0` and carries the outcome in `data.status`, never as an error code.

The inverse also holds: a 4xx/5xx does not by itself tell you which class of failure fired — read the `code` to distinguish a parameter error from a system error.

---

## Data formats

| Item                                                        | Format                | Example                         |
| ----------------------------------------------------------- | --------------------- | ------------------------------- |
| Dates (check-in, check-out)                                 | `yyyy-MM-dd` (ISO)    | `2026-01-01`                    |
| Timestamps (booking time, cancel time, windows)             | RFC 3339 / ISO 8601   | `2026-01-01T10:00:00Z`          |
| Webhook `eventTime`                                         | Unix **milliseconds** | `1704067200000`                 |
| `countryCode`, `residencyCode`, `nationalityCode`, `Market` | ISO 3166-1 alpha-2    | `AE`, `US`                      |
| Currency (body and `Currency` header)                       | ISO 4217              | `USD`                           |
| `Language` header                                           | IETF BCP 47           | `en`, `en-US` (default `en-US`) |

Every request is `POST` with a JSON body and `Content-Type: application/json`.

---

## Localised strings (I18N)

Human-readable text (names, addresses, board names) is returned as a localised object whose keys are the fixed language codes the contract declares:

```json
{
  "en": "Jumeirah Beach Hotel",
  "zh": "朱美拉海滩酒店",
  "ar": "فندق جميرا بيتش"
}
```

`en` is the default system language; `zh` (Chinese) and `ar` (Arabic) complete the set. The `Language` request header (BCP 47, default `en-US`) selects the content language where the API returns a single string.

---

## Occupancy semantics

`roomOccupancies` is one entry per room, each carrying `adultCount` and optional `childrenAges`:

```json
[{ "adultCount": 2, "childrenAges": [5, 7] }, { "adultCount": 1 }]
```

- **Children** are declared per room in `childrenAges`, one entry per child, accepted from age 0 with no upper bound. There is no fixed infant band — handling follows each hotel's and supplier's policy.
- **Multiple rooms with different occupancies:** submit the highest adult count across all rooms, applied to every room. Rooms with 1 adult and 2 adults → send `adultCount: 2` for both; children are always sent individually.

---

## Sessions

`HotelList` returns a `sessionId` in `data.basic.sessionId`. Carry it as the `Session-Id` header on every later call in the flow — it is required on [HotelList](/hotel-api/docs/api-reference/hotel-list), [HotelRates](/hotel-api/docs/api-reference/hotel-rates), [CheckAvail](/hotel-api/docs/api-reference/check-avail), [Book](/hotel-api/docs/api-reference/book) and [Cancel](/hotel-api/docs/api-reference/cancel).

The session carries context from search to booking, providing pricing consistency and availability stability. A `ratePkgId` is only resolvable inside the session that produced it; using a stale or mismatched session is one cause of `404 not found`.

---

## Idempotency

[Book](/hotel-api/docs/api-reference/book) is idempotent on `customerReferenceNo`: retrying with the same value returns the original order instead of creating a second one. A UUID is the usual choice. This is what makes timeout recovery safe — never re-issue a Book with a fresh reference to "try again"; reuse the original one and confirm via [QueryOrders](/hotel-api/docs/api-reference/query-orders).

---

## Need help?

Questions about these conventions or your integration: **integrations@ttdbooking.com**
Full documentation: **[developer.ttdbooking.com/hotel-api/docs](https://developer.ttdbooking.com/hotel-api/docs)**
