> For the complete documentation index, see [llms.txt](https://syticks.gitbook.io/merpi-by-syticks/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://syticks.gitbook.io/merpi-by-syticks/api-reference/hold-reserve-ticket-inventory/hold-reserve-hospitality-rooms.md).

# Hold/Reserve Hospitality Rooms

### Endpoint

```
POST /api/v1/merpi/validate
```

### Description

The validation endpoint creates temporary reservations (holds) on hospitality rooms, preventing other customers from booking the same accommodation while your customer completes their transaction. This is essential for maintaining room inventory accuracy and providing a seamless booking experience.

#### How It Works

1. **Reserve**: Customer selects room and dates → Your system calls `/validate` → Room is held
2. **Checkout**: Customer completes payment details (3-minute window)
3. **Complete**: Submit hold to buy endpoint → Reservation converts to confirmed booking
4. **Auto-expire**: If no purchase is made, hold automatically releases after TTL

#### Common Use Cases

* **Room Selection**: Reserve specific room types while customer enters payment and guest information
* **Extended Stays**: Reserve rooms for multi-night bookings during the checkout process
* **Vacation Packages**: Hold accommodation as part of bundled travel offerings
* **Last-Minute Bookings**: Lock in availability for high-demand dates or limited inventory properties

***

### Request Parameters

#### Headers

| Parameter       | Type   | Required | Description                   |
| --------------- | ------ | -------- | ----------------------------- |
| `Content-Type`  | string | Yes      | Must be `application/json`    |
| `Authorization` | string | Yes      | Your API authentication token |

#### Request Body

| Field                        | Type    | Required    | Description                                                                                               |
| ---------------------------- | ------- | ----------- | --------------------------------------------------------------------------------------------------------- |
| `tickets`                    | array   | Yes         | Array of room reservation requests. Minimum 1, maximum 10 items.                                          |
| `tickets[].ticket_type`      | string  | Yes         | Must be `"hospitality"` for hotel/room reservations.                                                      |
| `tickets[].resource_id`      | integer | Yes         | Room identifier. References `rooms.id` from the hospitality listing endpoint. Must be a positive integer. |
| `tickets[].quantity`         | integer | Yes         | Number of rooms to reserve. Minimum value: 1.                                                             |
| `tickets[].metadata`         | object  | **Yes**     | **Required for hospitality.** Contains check-in/check-out date information (see below).                   |
| `customer_info`              | object  | Yes         | Customer identification for hold ownership verification.                                                  |
| `customer_info.email`        | string  | Conditional | Customer email address. Required if `phone_number` is not provided.                                       |
| `customer_info.phone_number` | string  | Conditional | Customer phone number (11-13 digits). Required if `email` is not provided.                                |

#### Metadata Structure

| Field           | Type   | Required | Description                                                                             |
| --------------- | ------ | -------- | --------------------------------------------------------------------------------------- |
| `checkin_date`  | string | Yes      | Check-in date in `Y-m-d` format (e.g., `"2026-04-02"`). Must be today or a future date. |
| `checkout_date` | string | Yes      | Check-out date in `Y-m-d` format (e.g., `"2026-04-03"`). Must be after `checkin_date`.  |

**Example:**

```json
{
  "checkin_date": "2026-04-02",
  "checkout_date": "2026-04-03"
}
```

**Important Notes**

* **Customer Info**: At least one of `email` or `phone_number` must be provided. Both can be included.
* **Resource ID Format**: For hospitality, `resource_id` must be a positive integer matching a room ID.
* **Metadata Requirement**: Hospitality tickets **always require metadata** with both check-in and check-out dates.
* **Date Validation**: `checkout_date` must be at least one day after `checkin_date`. Same-day checkout is not supported.
* **Ownership Verification**: The `customer_info` values act as a session token—they must match exactly when using the hold in a buy request or when releasing the hold early.
* **Availability Window**: The system checks room availability for the entire date range (checkin\_date to checkout\_date).

***

### Response Structure

#### Success Response (201 Created)

| Field               | Type    | Description                            |
| ------------------- | ------- | -------------------------------------- |
| `success`           | boolean | Always `true` for successful requests. |
| `status`            | integer | HTTP status code (201).                |
| `message`           | string  | Human-readable success message.        |
| `data`              | object  | Contains the reservation details.      |
| `data.reservations` | array   | Array of created reservation objects.  |

**Reservation Object Fields**

| Field               | Type              | Description                                                                            |
| ------------------- | ----------------- | -------------------------------------------------------------------------------------- |
| `reservation_id`    | string (UUID)     | Unique identifier for this hold. **Use this value in buy requests.**                   |
| `ticket_type`       | string            | Type of ticket reserved (will be `"hospitality"`).                                     |
| `resource_id`       | string            | The room ID that was reserved (returned as string even though input is integer).       |
| `quantity`          | integer           | Number of rooms reserved.                                                              |
| `status`            | string            | Current hold status. Values: `"active"`, `"converted"`, `"released"`, `"expired"`.     |
| `expires_at`        | string (datetime) | ISO 8601 timestamp when this hold will automatically expire. Includes timezone offset. |
| `seconds_remaining` | integer           | Number of seconds until expiration (calculated at response time).                      |

***

### Example Requests & Responses

#### Example 1: Reserve Single Room for One Night

**Request:**

```json
POST /api/v1/merpi/validate
Content-Type: application/json

{
  "tickets": [
    {
      "ticket_type": "hospitality",
      "resource_id": 2,
      "quantity": 1,
      "metadata": {
        "checkin_date": "2026-04-02",
        "checkout_date": "2026-04-03"
      }
    }
  ],
  "customer_info": {
    "email": "user@example.com",
    "phone_number": "08085825362"
  }
}
```

**Response (201 Created):**

```json
{
  "success": true,
  "status": 201,
  "message": "Holds created",
  "data": {
    "reservations": [
      {
        "reservation_id": "a463ddd2-64df-4875-99bf-a2cbd11e1b6a",
        "ticket_type": "hospitality",
        "resource_id": "2",
        "quantity": 1,
        "status": "active",
        "expires_at": "2026-04-02T13:07:17+01:00",
        "seconds_remaining": 179
      }
    ]
  }
}
```

***

#### Example 2: Reserve Room for Extended Stay (Multiple Nights)

**Request:**

```json
POST /api/v1/merpi/validate
Content-Type: application/json

{
  "tickets": [
    {
      "ticket_type": "hospitality",
      "resource_id": 5,
      "quantity": 1,
      "metadata": {
        "checkin_date": "2026-05-15",
        "checkout_date": "2026-05-22"
      }
    }
  ],
  "customer_info": {
    "email": "vacation@example.com"
  }
}
```

**Response (201 Created):**

```json
{
  "success": true,
  "status": 201,
  "message": "Holds created",
  "data": {
    "reservations": [
      {
        "reservation_id": "b574eed3-75eg-5986-00cg-b3dce22f2c7b",
        "ticket_type": "hospitality",
        "resource_id": "5",
        "quantity": 1,
        "status": "active",
        "expires_at": "2026-05-01T10:15:45+01:00",
        "seconds_remaining": 180
      }
    ]
  }
}
```

***

#### Example 3: Reserve Multiple Rooms (Group/Family Booking)

**Request:**

```json
POST /api/v1/merpi/validate
Content-Type: application/json

{
  "tickets": [
    {
      "ticket_type": "hospitality",
      "resource_id": 2,
      "quantity": 2,
      "metadata": {
        "checkin_date": "2026-04-10",
        "checkout_date": "2026-04-12"
      }
    }
  ],
  "customer_info": {
    "email": "family@example.com",
    "phone_number": "08085825362"
  }
}
```

**Response (201 Created):**

```json
{
  "success": true,
  "status": 201,
  "message": "Holds created",
  "data": {
    "reservations": [
      {
        "reservation_id": "c685fef4-86fh-6097-11dh-c4ede33g3d8c",
        "ticket_type": "hospitality",
        "resource_id": "2",
        "quantity": 2,
        "status": "active",
        "expires_at": "2026-04-01T16:22:30+01:00",
        "seconds_remaining": 180
      }
    ]
  }
}
```

***

### Error Responses

#### 409 Conflict - Insufficient Inventory

Occurs when the requested rooms are not available for the specified date range or the property has reached capacity.

**Response:**

```json
{
  "success": false,
  "message": "Insufficient inventory. Only 7 available.",
  "status": 409,
}
```

**Common Causes:**

* Rooms fully booked for the requested date range
* Insufficient quantity available (e.g., requesting 5 rooms when only 3 are available)
* Another customer's active hold is consuming the inventory
* Room type unavailable for check-in/check-out dates due to existing bookings

**Important**: When a batch request fails at any index, **all previously created holds in that same request are automatically released** (batch rollback).

***

#### 422 Unprocessable Entity - Validation Error

Occurs when the request body contains invalid or missing required fields.

**Response:**

```json
{
  "success": false,
  "status": 422,
  "message": "The Room ID passed is not a valid one",
}
```

**Common Causes:**

* Missing `checkin_date` or `checkout_date` in metadata
* `checkout_date` not after `checkin_date` (same-day or past-date checkout)
* Invalid date format (must be `Y-m-d`, e.g., `"2026-04-02"`)
* `checkin_date` in the past
* Invalid `resource_id` format (must be positive integer)
* Missing both `email` and `phone_number` in `customer_info`
* Invalid `phone_number` format (must be 11-13 digits)
* `quantity` less than 1
* More than 10 items in `tickets` array
* Metadata object missing entirely

***

### Using Holds in Purchase Requests

Once you've successfully created a hold, use the `reservation_id` values to complete the purchase via the hospitality buy endpoint.

**Buy Endpoint:**

```
POST /api/v2/merpi/hotel/buy/bookings
```

**Example Buy Request Body:**

```json
{
  "reservation_ids": [
    "a463ddd2-64df-4875-99bf-a2cbd11e1b6a",
    "b574eed3-75eg-5986-00cg-b3dce22f2c7b"
  ],
  "customer_info": {
    "email": "user@example.com",
    "phone_number": "08085825362"
  },
  "guest_details": {
    "name": "John Doe",
    "phone": "08085825362"
  },
  "payment_method": "card",
  ...
}
```

**Critical Requirements:**

* The `customer_info.email` or `customer_info.phone_number` in the buy request **must exactly match** what was used when creating the hold
* This matching is how the system verifies hold ownership
* Mismatched customer info will result in a 404 error (hold not found)
* All `reservation_ids` in a single buy request must belong to the same customer

***

### Hold Lifecycle & Behavior

#### Status Transitions

```
POST /validate  →  status: "active"  (TTL timer starts)
                         │
          ┌──────────────┼──────────────────┐
          │              │                  │
    buy request    DELETE /validate    TTL expires
          │              │                  │
   status: converted  status: released  status: expired
```

#### Key Behaviors

**Idempotency**: If you submit the exact same hold parameters while an active hold already exists for that customer, the API returns the existing hold instead of creating a duplicate.

**Time-to-Live (TTL)**: Holds automatically expire after 3 minutes (configurable via system settings). The `expires_at` and `seconds_remaining` fields in the response help you display countdown timers to customers.

**Batch Rollback**: When creating multiple holds in a single request, if any individual hold fails (e.g., room unavailable), **all previously created holds in that same request are automatically released**. This ensures transactional consistency—either all holds succeed or none do.

**Date Range Locking**: The system checks and locks room availability for the entire date range (checkin\_date through checkout\_date). If the room is unavailable for any single night in that range, the hold fails.

***

### Early Release (Optional)

If a customer abandons their checkout or you need to release holds programmatically, use the hold release endpoint:

```
DELETE /api/v1/merpi/validate/{reservation_id}
```

**See Documentation**: [Release Hold Endpoint](https://claude.ai/chat/fc6fb558-b6df-4d86-bf40-5bbf020fd0f4#) for detailed usage instructions.

**Note**: Holds automatically release after TTL expiration, so manual release is only necessary for early cleanup or improved user experience.

***

### Best Practices

#### 1. Display Countdown Timer

Show the `seconds_remaining` or `expires_at` to customers so they know how much time they have to complete checkout. This is especially important during peak booking periods.

#### 2. Date Range Validation

Always validate date ranges on the client side before calling the hold endpoint:

* Ensure `checkout_date` is after `checkin_date`
* Prevent selection of past dates for `checkin_date`
* Show clear error messages for invalid date ranges

#### 3. Handle 409 Gracefully

If rooms are unavailable, immediately:

* Notify the customer clearly with available alternatives
* Suggest nearby check-in/check-out dates with availability
* Offer different room types that may be available for the same dates
* Refresh the room listing to show current availability
* Do NOT retry the same dates—the rooms are booked

#### 4. Retry Logic

Implement exponential backoff for transient failures, but **do not retry** on 409 errors (insufficient inventory).

#### 5. Customer Info Consistency

Store the `customer_info` values (email/phone) in your session and use them consistently across hold creation, buy requests, and release calls.

#### 6. Multi-Room Strategy

When booking multiple rooms of the same type, use a single ticket with `quantity > 1` rather than multiple separate tickets. This simplifies management and provides atomic quantity locking.

For different room types, use separate tickets in a single batch request to leverage batch rollback—if one room type isn't available, all holds are released.

#### 7. Monitor TTL

The default 3-minute TTL is suitable for most checkouts, but consider your average checkout duration, especially if you collect extensive guest information. If customers frequently lose holds, optimize your checkout flow or request a longer TTL from your account manager.

#### 8. Date Format Compliance

Always use the exact `Y-m-d` format for dates (e.g., `"2026-04-02"`). Incorrect formats will result in 422 validation errors.

#### 9. Availability Display

Before creating holds, always check room availability via the hospitality listing endpoint. Show customers which date ranges have availability to minimize 409 errors.

#### 10. Extended Stay Considerations

For long stays (7+ nights), consider informing customers about the hold TTL before they begin selecting dates. Some customers may need more time to review extended stay details.

#### 11. Group Booking UX

For group bookings requiring multiple room types, consider collecting all room preferences first, then creating all holds in a single batch request. This provides atomic locking across all rooms and better UX than sequential individual holds.

***

### Related Endpoints

* [**Get Room Listings**](/merpi-by-syticks/api-reference/hospitality-ticketing-hotels-resorts-apartments/get-hotel-apartment-resort-rooms.md): Retrieve room information and availability before creating holds
* [**Book Hotel Room**](/merpi-by-syticks/api-reference/hospitality-ticketing-hotels-resorts-apartments/book-hotel-apartment-room-tickets.md): Complete purchase using `reservation_ids` from successful holds
* [**Release Hold/Reservation**](/merpi-by-syticks/api-reference/hold-reserve-ticket-inventory/release-a-hold-reservation-early.md): Manually release holds before TTL expiration
* [**Get Hotel/Property Listings**](/merpi-by-syticks/api-reference/hospitality-ticketing-hotels-resorts-apartments/get-list-of-hotels-apartments-resorts.md): Browse available properties to present to customers
