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

# POST /bookings/reserve

> Create a temporary hold on a slot. Seyaha calls this when a customer initiates checkout.

Seyaha calls `POST /bookings/reserve` when a customer selects a slot and begins checkout.
The hold prevents the slot from being double-booked while the customer completes payment.

If your platform does not support holds (instant-confirmation only), you can still
implement this endpoint — just return a confirmation code and a far-future `expiresAt`.
Seyaha will call `POST /bookings/confirm` immediately after payment.

***

## Request

```http theme={null}
POST /bookings/reserve
Authorization: Bearer <auth_key>
Content-Type: application/json
```

### Request body

| Field               | Type   | Required | Description                                                         |
| ------------------- | ------ | -------- | ------------------------------------------------------------------- |
| `productId`         | string | **Yes**  | Your product `id`                                                   |
| `optionId`          | string | **Yes**  | Your option `id`                                                    |
| `availabilityId`    | string | **Yes**  | The `id` from the availability slot being booked                    |
| `unitItems`         | array  | **Yes**  | Guest counts by unit type (see below)                               |
| `contact`           | object | No       | Customer contact details                                            |
| `resellerReference` | string | No       | Seyaha's internal booking `_id` — store this to map to your records |
| `notes`             | string | No       | Optional booking notes                                              |

### Unit item object

| Field      | Type    | Description                                                                                                                                                 |
| ---------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `unitId`   | string  | Always one of: `"unit-adult"`, `"unit-child"`, `"unit-infant"`, `"unit-senior"` — these values are hardcoded by Seyaha based on the booking's pax breakdown |
| `quantity` | integer | Number of guests of this type                                                                                                                               |

### Contact object

| Field          | Type   | Description        |
| -------------- | ------ | ------------------ |
| `fullName`     | string | Customer full name |
| `emailAddress` | string | Customer email     |
| `phoneNumber`  | string | Customer phone     |

```json theme={null}
{
  "productId": "product_abc",
  "optionId": "option_standard",
  "availabilityId": "avail_2026-07-15-10",
  "unitItems": [
    { "unitId": "unit-adult", "quantity": 2 },
    { "unitId": "unit-child", "quantity": 1 }
  ],
  "contact": {
    "fullName": "Jane Smith",
    "emailAddress": "jane@example.com",
    "phoneNumber": "+966501234567"
  },
  "resellerReference": "67c896a6639e6ff76dd2f882"
}
```

***

## Response

```http theme={null}
200 OK
Content-Type: application/json
```

### Response body

| Field                         | Type   | Required | Description                                                                                                              |
| ----------------------------- | ------ | -------- | ------------------------------------------------------------------------------------------------------------------------ |
| `reservationConfirmationCode` | string | **Yes**  | A unique code Seyaha sends back to confirm or cancel this hold. Must be stable until the hold is confirmed or cancelled. |
| `expiresAt`                   | string | **Yes**  | ISO 8601 datetime when this hold expires. Seyaha will call `DELETE /bookings/{code}` if payment isn't completed by then. |
| `status`                      | string | **Yes**  | Should be `"ON_HOLD"`                                                                                                    |
| `uuid`                        | string | No       | Your internal reservation UUID                                                                                           |
| `productId`                   | string | No       | Echo of the requested product                                                                                            |
| `optionId`                    | string | No       | Echo of the requested option                                                                                             |
| `availabilityId`              | string | No       | Echo of the requested availability slot                                                                                  |
| `unitItems`                   | array  | No       | Echo of the unit items                                                                                                   |

```json theme={null}
{
  "uuid": "res_7f3a9c",
  "status": "ON_HOLD",
  "reservationConfirmationCode": "HOLD-2026-0001",
  "expiresAt": "2026-07-15T10:30:00+03:00",
  "productId": "product_abc",
  "optionId": "option_standard",
  "availabilityId": "avail_2026-07-15-10",
  "unitItems": [
    { "unitId": "unit-adult", "quantity": 2 },
    { "unitId": "unit-child", "quantity": 1 }
  ]
}
```

### Error responses

If the slot is no longer available, return `400`:

```json theme={null}
{
  "message": "The selected time slot is fully booked"
}
```

Seyaha reads the `message` field and surfaces it to the customer.

***

## Implementation notes

<Warning>
  The `reservationConfirmationCode` must be globally unique and stable. Seyaha stores
  it immediately after receiving this response and uses it as the key for all subsequent
  confirm and cancel operations. Reusing codes across different reservations will cause
  Seyaha to cancel the wrong hold.
</Warning>

* Timeout: **5 seconds** (HEALTHY) / **10 seconds** (DEGRADED)
* Decrease `vacancies` on the slot immediately when a hold is created — concurrent checkout attempts should see updated availability.
* Set `expiresAt` to a reasonable window (e.g. 15–30 minutes). Seyaha will release expired holds via `DELETE /bookings/{code}`.
* If you don't support holds, set `expiresAt` far in the future (e.g. 24 hours) — Seyaha will confirm immediately after payment and the hold will be cleaned up.
