> 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/cinema-ticketing-cinema-movies-available-days-purchase-etc/buy-cinema-experience-tickets.md).

# Buy Cinema Experience Tickets

**Endpoint**

```
POST /api/v1/merpi/experience/buy/tickets
```

#### **Before you buy: your own transaction reference**

You can pass your own reference for a transaction using the optional `merchant_reference` field in the request body. This lets you tie a MERPI purchase directly to an order or record in your own system.

Once a purchase is complete, you can use that reference to look up the transaction at:

```
GET /api/v1/merpi/transaction?merchant_reference=YOUR_REFERENCE
```

Keep in mind that the purchase response gives you a summary only and does not include full ticket details. You should always call the requery endpoint after every successful purchase to get the complete record.

Also worth knowing: only successful purchases create a transaction on the platform. If you query by `merchant_reference` and get a 404, it means nothing was recorded under that reference and the purchase did not go through.

#### **Important: Hold First, Then Buy**

**You must create holds before purchasing cinema tickets.** This prevents situations where a customer completes payment but the seats are no longer available.

**Required Flow:**

1. Create holds via `POST /api/v1/merpi/validate` (holds inventory for 3 minutes)
2. Customer completes payment details
3. Call this buy endpoint with `reservation_ids` (converts holds to confirmed bookings)

**Why this matters:** Without holds, seats could be sold to another customer between when your customer starts checkout and when payment completes. Holds guarantee seat availability during the checkout process.

#### Buy Cinema Experience Tickets

> This endpoint allows users to purchase cinema experience tickets using reserved inventory. You must create holds first via POST /api/v1/merpi/validate, then use the reservation\_ids to complete the purchase. This prevents situations where customers complete payment but seats are no longer available. This endpoint is similar to the normal experience purchase endpoint, with the exception of the `attendance_date`, `time_id`, `reservation_ids`, and `cinema_location_id` attributes.

## Buy Cinema Experience Tickets

> This endpoint allows users to purchase cinema experience tickets using reserved inventory.  You must create holds first via POST /api/v1/merpi/validate, then use the reservation\_ids  to complete the purchase. This prevents situations where customers complete payment but  seats are no longer available. This endpoint is similar to the normal experience purchase  endpoint, with the exception of the \`attendance\_date\`, \`time\_id\`, \`reservation\_ids\`, and  \`cinema\_location\_id\` attributes.<br>

```json
{"openapi":"3.0.3","info":{"title":"Syticks API","version":"1.0.0"},"paths":{"/api/v1/merpi/experience/buy/tickets":{"post":{"summary":"Buy Cinema Experience Tickets","description":"This endpoint allows users to purchase cinema experience tickets using reserved inventory.  You must create holds first via POST /api/v1/merpi/validate, then use the reservation_ids  to complete the purchase. This prevents situations where customers complete payment but  seats are no longer available. This endpoint is similar to the normal experience purchase  endpoint, with the exception of the `attendance_date`, `time_id`, `reservation_ids`, and  `cinema_location_id` attributes.\n","operationId":"buyCinemaTickets","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["reservation_ids","tickets","experience_id","attendance_date","time_id","customer_info"],"properties":{"reservation_ids":{"type":"array","description":"Array of reservation IDs from the hold creation response. Must contain at least  one valid UUID. These are obtained by calling POST /api/v1/merpi/validate to  create holds before purchasing.\n","items":{"type":"string","format":"uuid"}},"tickets":{"type":"array","description":"Array of objects containing ticket details.","items":{"type":"object","required":["id","count"],"properties":{"id":{"type":"string","format":"uuid","description":"Unique identifier of the ticket category."},"count":{"type":"integer","description":"Number of tickets to purchase for this category.","minimum":1}}}},"experience_id":{"type":"string","format":"uuid","description":"Unique identifier of the cinema experience (movie)."},"cinema_location_id":{"type":"integer","description":"ID of the cinema location where the customer will watch the movie. If the cinema  has multiple locations, this specifies which one. Defaults to headquarters location  if not provided. Get this from the cinema_info.locations[].id field in the experience  details response.\n"},"attendance_date":{"type":"string","description":"The date the user plans to watch the movie at the cinema.  Format: DD-MM-YYYY (e.g., 23-09-2024). The user should select a date from those returned by the cinema schedule endpoint.\n","pattern":"^\\d{2}-\\d{2}-\\d{4}$"},"time_id":{"type":"integer","description":"The ID of the time period that the user will be watching the movie.  The cinema business sets the time during the day that the movie shows. Example: 11:30AM - 2:30PM, 6:05 PM - 8:45 PM.  Each of these time ranges has an ID.\n"},"customer_info":{"type":"object","description":"Information about the customer. The email or phone_number must exactly match  what was used when creating the holds via POST /api/v1/merpi/validate.\n","required":["name","email","phone_number"],"properties":{"name":{"type":"string","description":"Full name of the customer."},"email":{"type":"string","format":"email","description":"Customer's email address. Must match the email used when creating the holds.\n"},"phone_number":{"type":"string","description":"Customer's phone number. Must match the phone number used when creating the holds.\n","pattern":"^\\d{11,13}$"},"dob":{"type":"string","format":"date","description":"Customer's date of birth (in YYYY-MM-DD format)."},"username":{"type":"string","description":"Customer's username."}}},"merchant_reference":{"type":"string","description":"Your own reference for this transaction. Max 255 characters. Must be unique  across all your purchases. If you pass a reference that was already used in a  previous successful purchase, the request will be rejected and the response will  include a pointer to the existing transaction so you can requery it.\n","maxLength":255}}}}}},"responses":{"201":{"description":"Ticket purchased successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"status":{"type":"integer"},"message":{"type":"string"},"data":{"type":"object","properties":{"reference":{"type":"string"},"invoice_id":{"type":"integer"},"name":{"type":"string"},"email":{"type":"string"},"phone_number":{"type":"string"},"merchant_reference":{"type":"string","nullable":true,"description":"Your reference for this transaction if provided, null otherwise."},"tickets":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"price":{"type":"number"}}}}}}}}}}},"400":{"description":"Bad request due to invalid input or validation error","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"string"}}}}}},"404":{"description":"Hold not found - reservation IDs are invalid or don't belong to the customer","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"status":{"type":"integer"},"message":{"type":"string"}}}}}},"409":{"description":"Conflict - reserved inventory no longer available (holds expired)","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"status":{"type":"integer"},"message":{"type":"string"}}}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"string"}}}}}}}}}}}
```

### **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                                                                                                                                                                                                                                                                                                     |
| ---------------------------- | ---------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `reservation_ids`            | array of strings | Yes      | Array of reservation IDs from the hold creation response. Must contain at least one valid UUID.                                                                                                                                                                                                                 |
| `tickets`                    | array            | Yes      | Array of ticket objects specifying which tickets to purchase.                                                                                                                                                                                                                                                   |
| `tickets[].id`               | string (UUID)    | Yes      | Unique identifier of the ticket category.                                                                                                                                                                                                                                                                       |
| `tickets[].count`            | integer          | Yes      | Number of tickets to purchase for this category. Must be positive.                                                                                                                                                                                                                                              |
| `experience_id`              | string (UUID)    | Yes      | Unique identifier of the cinema experience (movie).                                                                                                                                                                                                                                                             |
| `cinema_location_id`         | integer          | No       | ID of the cinema location where the customer will watch the movie. If the cinema has multiple locations, this specifies which one. **Defaults to headquarters location if not provided.** Get this from the `cinema_info.locations[].id` field in the experience details response.                              |
| `attendance_date`            | string           | Yes      | The date the customer plans to watch the movie. Format: `DD-MM-YYYY` (e.g., `"23-09-2024"`). Must be a date returned by the cinema schedule endpoint.                                                                                                                                                           |
| `time_id`                    | integer          | Yes      | ID of the showtime period (e.g., morning, afternoon, evening slot). Each cinema sets specific time ranges with unique IDs.                                                                                                                                                                                      |
| `customer_info`              | object           | Yes      | Customer information for the booking.                                                                                                                                                                                                                                                                           |
| `customer_info.name`         | string           | Yes      | Full name of the customer.                                                                                                                                                                                                                                                                                      |
| `customer_info.email`        | string           | Yes      | Customer's email address. **Must match the email used when creating the holds.**                                                                                                                                                                                                                                |
| `customer_info.phone_number` | string           | Yes      | Customer's phone number. **Must match the phone number used when creating the holds.**                                                                                                                                                                                                                          |
| `customer_info.dob`          | string           | No       | Customer's date of birth in `YYYY-MM-DD` format.                                                                                                                                                                                                                                                                |
| `customer_info.username`     | string           | No       | Customer's username.                                                                                                                                                                                                                                                                                            |
| `merchant_reference`         | string           | No       | Your own reference for this transaction. Max 255 characters. Must be unique across all your purchases. If you pass a reference that was already used in a previous successful purchase, the request will be rejected and the response will include a pointer to the existing transaction so you can requery it. |

#### **Critical Requirements:**

* The `customer_info.email` or `customer_info.phone_number` must **exactly match** what was used when creating the holds
* This matching verifies hold ownership and prevents unauthorized use of someone else's reservations
* All `reservation_ids` must belong to the same customer and be in `"active"` status
* `attendance_date` and `time_id` specify the exact showtime — customers must select these from available cinema schedules
* **Multi-location cinemas**: If the cinema has multiple locations (chains), include `cinema_location_id` to specify which location the customer is booking for. Without it, the system defaults to the headquarters location, which may not be what the customer wants.
* Holds convert to bookings upon successful purchase and cannot be reused

**Response Fields:**

| Field                     | Type    | Description                                                                                                       |
| ------------------------- | ------- | ----------------------------------------------------------------------------------------------------------------- |
| `success`                 | boolean | Always `true` for successful purchases.                                                                           |
| `status`                  | integer | HTTP status code (201).                                                                                           |
| `message`                 | string  | Human-readable success message.                                                                                   |
| `data.reference`          | string  | Unique booking reference for this purchase.                                                                       |
| `data.invoice_id`         | integer | Invoice ID for this transaction.                                                                                  |
| `data.name`               | string  | Customer name from the request.                                                                                   |
| `data.email`              | string  | Customer email from the request.                                                                                  |
| `data.phone_number`       | string  | Customer phone number from the request.                                                                           |
| `data.merchant_reference` | string  | Your reference for this transaction, if you provided one. `null` if not provided.                                 |
| `data.tickets`            | array   | Array of purchased ticket objects with details. Call the requery endpoint after purchase to get the full details. |

### **Error Responses**

#### **400 Bad Request - Validation Error**

Occurs when required fields are missing or invalid.

```json
{
  "success": false,
  "message": "Invalid request payload. Please check the input fields.",
  "status": 400
}
```

**Common Causes:**

* Invalid `experience_id` or `tickets[].id` (UUID not found)
* Missing required fields (`attendance_date`, `time_id`)
* Invalid date format for `attendance_date` (must be `DD-MM-YYYY`)
* Invalid `time_id` (doesn't exist for this cinema/movie)
* Missing `customer_info` required fields

#### **404 Not Found - Hold Not Found**

Occurs when reservation IDs are invalid or don't belong to the customer.

```json
{
  "success": false,
  "status": 404,
  "message": "One or more reservations not found or already used"
}
```

**Common Causes:**

* `reservation_ids` don't exist
* Customer info doesn't match the hold owner (email/phone mismatch)
* Holds already expired (TTL passed)
* Holds already used in a previous purchase (status: "converted")
* Holds manually released (status: "released")

#### **409 Conflict - Inventory No Longer Available**

Occurs when holds have expired and seats were taken by another customer.

```json
{
  "success": false,
  "status": 409,
  "message": "Reserved seats no longer available"
}
```

**Common Causes:**

* Hold TTL expired before purchase completed
* Seats sold to another customer after expiration

#### **500 Internal Server Error**

Occurs when an unexpected server error happens.

```json
{
  "success": false,
  "message": "An unexpected error occurred. Please try again later.",
  "status": 500
}
```

**Action**: Retry the request. If the error persists, contact API support.

### **Integration Checklist**

#### **Before calling this endpoint:**

1. Retrieved available cinema schedules (dates and showtimes)
2. Customer selected `attendance_date` and `time_id` from available options
3. **For multi-location cinemas**: Customer selected their preferred cinema location and you have the `cinema_location_id` from `cinema_info.locations[].id`
4. Created holds via `POST /api/v1/merpi/validate`
5. Stored `reservation_ids` from hold response
6. Stored `customer_info` (email/phone) used during hold creation
7. Verified holds are still active (not expired)
8. Customer completed payment/checkout details

#### **In your request:**

1. Include all `reservation_ids` from the hold
2. Use the **exact same** `customer_info.email` and `customer_info.phone_number` as during hold creation
3. Include complete ticket details (`tickets` array with `id` and `count`)
4. Include `experience_id`, `attendance_date`, and `time_id`
5. **For multi-location cinemas**: Include `cinema_location_id` to specify which location the customer chose
6. Ensure `attendance_date` format is `DD-MM-YYYY`
7. Pass `merchant_reference` if you want to tie this transaction to your own internal reference

#### **After successful purchase:**

1. Store `reference` and `invoice_id` for customer records
2. Call the requery endpoint to retrieve the full ticket details
3. Display booking confirmation with movie details, showtime, and seat info
4. Send confirmation email/SMS with `reference`, movie title, date, and time

### **Quick Tips**

**Multi-Location Cinemas**: If the cinema has multiple locations (check `cinema_info.locations` array length), always let customers select their preferred location and include `cinema_location_id` in the request. Without it, the booking defaults to headquarters, which might be in a different city from where the customer wants to watch.

**Showtime Selection**: Always present customers with available `attendance_date` and `time_id` options from the cinema schedule endpoint. Don't allow manual date/time entry — this will cause validation errors.

**Customer Info Must Match**: The most common error is mismatched customer info between hold and buy. Store the email/phone from hold creation and reuse them exactly.

**Don't Release Before Buying**: Never call `DELETE /api/v1/merpi/validate/{id}` before purchasing. Just submit the buy request — successful purchases automatically convert holds.

**Handle Expired Holds**: If holds expire before payment completes, redirect customers to start over with new holds. Don't retry the buy request — the seats are gone.

**Date Format**: `attendance_date` must be `DD-MM-YYYY` (e.g., `"23-09-2024"`), not `YYYY-MM-DD`. This is different from other date fields in the API.

### **Related Endpoints**

* [**Hold/Reserve Experience Tickets**:](/merpi-by-syticks/api-reference/hold-reserve-ticket-inventory/hold-reserve-experience-inventory.md) Create holds before purchasing
* [**Get Cinema Experience Details**:](/merpi-by-syticks/api-reference/cinema-ticketing-cinema-movies-available-days-purchase-etc/get-cinema-experience-details.md) Retrieve movie and ticket information
* [**Release Hold/Reservation**:](/merpi-by-syticks/api-reference/hold-reserve-ticket-inventory/release-a-hold-reservation-early.md) Cancel holds if customer abandons checkout


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://syticks.gitbook.io/merpi-by-syticks/api-reference/cinema-ticketing-cinema-movies-available-days-purchase-etc/buy-cinema-experience-tickets.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
