> 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/experience-ticketing-events-parties-conference-comedy-and-more/get-ticket-categories-and-pricing.md).

# Get Ticket Categories & Pricing

## Get Ticket Categories and Pricing

This endpoint returns all available ticket types and their pricing for a specific experience. Use this endpoint to:

* Display ticket prices to customers before booking
* Show available ticket categories (Regular, VIP, Premium, etc.)
* Check seat availability via `slots_remaining`
* Understand pricing breakdown including ticket price, convenience fees, and merchant commissions
* Validate ticket availability before initiating checkout

This is the primary endpoint for retrieving ticket pricing information. Always call this endpoint before displaying ticket purchase options to customers.

### Endpoint

```
GET /api/v1/merpi/experience/tickets/{experience_id}
```

***

### Path Parameters

| Parameter       | Type          | Required | Description                          |
| --------------- | ------------- | -------- | ------------------------------------ |
| `experience_id` | string (UUID) | Yes      | Unique identifier of the experience. |

***

### Query Parameters

| Parameter            | Type    | Required | Description                                                                                                                                                                                                                                               |
| -------------------- | ------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `cinema_location_id` | integer | No       | **For cinema experiences with multiple locations only.** Specifies which cinema location's ticket pricing to retrieve. If not provided, defaults to headquarters location. Get this from `cinema_info.locations[].id` in the experience details response. |

**Cinema-Specific Note**: When fetching tickets for a multi-location cinema, always include `cinema_location_id` to get the correct pricing and availability for the customer's selected location. Ticket prices and availability may vary by location.

***

### Response Format

#### Root Response Object

| Field     | Type    | Description                                     |
| --------- | ------- | ----------------------------------------------- |
| `success` | boolean | Indicates whether the request was successful.   |
| `status`  | integer | HTTP status code (200 for successful requests). |
| `message` | string  | Human-readable description of the response.     |
| `data`    | object  | Container object holding ticket information.    |

#### Data Object

| Field        | Type   | Description                                 |
| ------------ | ------ | ------------------------------------------- |
| `tickets`    | array  | Array of available ticket type objects.     |
| `experience` | object | Reference information about the experience. |

#### Ticket Object

| Field             | Type          | Description                                                                               |
| ----------------- | ------------- | ----------------------------------------------------------------------------------------- |
| `id`              | string (UUID) | Unique identifier for this ticket type. **Use this when creating bookings.**              |
| `title`           | string        | Display name of the ticket category (e.g., "Regular", "VIP", "Premium").                  |
| `price`           | number        | Total price customers pay (in Naira or applicable currency). Includes all fees.           |
| `slots_remaining` | integer       | Number of tickets available for this category. **Always check before allowing purchase.** |
| `free`            | boolean       | Indicates if the ticket is free (`true`) or paid (`false`).                               |
| `price_breakdown` | object        | Detailed breakdown of how the price is calculated.                                        |

#### Price Breakdown Object

**New Field**: The `price_breakdown` object provides transparency in pricing by showing how the total price is calculated.

| Field                 | Type   | Description                                    |
| --------------------- | ------ | ---------------------------------------------- |
| `ticket_price`        | number | Base ticket price set by the organizer/cinema. |
| `convenience_fee`     | number | Platform convenience fee.                      |
| `merchant_commission` | number | Merchant/platform commission.                  |

**Important**: `price = ticket_price + convenience_fee + merchant_commission`

The total `price` is what customers pay. The `price_breakdown` shows how this total is calculated.

#### Experience Reference Object

| Field   | Type          | Description            |
| ------- | ------------- | ---------------------- |
| `id`    | string (UUID) | Experience identifier. |
| `title` | string        | Experience title.      |

***

### Example Requests

#### Regular Experience

```http
GET /api/v1/merpi/experience/tickets/223f279b-28b2-4b72-8020-cfc2c02b95cb HTTP/1.1
Accept: application/json
```

#### Cinema Experience (Single Location or Default to HQ)

```http
GET /api/v1/merpi/experience/tickets/9b0c2340-8274-4e9b-b7b8-a652dbb652eb HTTP/1.1
Accept: application/json
```

#### Cinema Experience (Specific Location)

```http
GET /api/v1/merpi/experience/tickets/9b0c2340-8274-4e9b-b7b8-a652dbb652eb?cinema_location_id=4 HTTP/1.1
Accept: application/json
```

***

### Example Response

```json
{
  "success": true,
  "status": 200,
  "message": "Success",
  "data": {
    "tickets": [
      {
        "id": "3161487b-f3f7-4b7d-a92c-a09bfaf11347",
        "title": "Regular",
        "price": 2100,
        "slots_remaining": 3454,
        "free": false,
        "price_breakdown": {
          "ticket_price": 2000,
          "convenience_fee": 40,
          "merchant_commission": 60
        }
      },
      {
        "id": "ee1cbdd5-b581-4363-aab0-050dca412b17",
        "title": "VIP",
        "price": 5250,
        "slots_remaining": 3455,
        "free": false,
        "price_breakdown": {
          "ticket_price": 5000,
          "convenience_fee": 100,
          "merchant_commission": 150
        }
      },
      {
        "id": "a7c2bed6-c692-5474-b1b1-161edb523c28",
        "title": "Student (Free)",
        "price": 0,
        "slots_remaining": 50,
        "free": true,
        "price_breakdown": {
          "ticket_price": 0,
          "convenience_fee": 0,
          "merchant_commission": 0
        }
      }
    ],
    "experience": {
      "id": "9b0c2340-8274-4e9b-b7b8-a652dbb652eb",
      "title": "Batman: The Yahoo Junction Menace"
    }
  }
}
```

***

### Validating Ticket Availability

#### CRITICAL - Always Validate Before Checkout

Check `slots_remaining` before allowing ticket purchases:

* If `slots_remaining` is `0`, the ticket category is sold out
* If `slots_remaining` is less than requested quantity, show error
* Refresh ticket data before finalizing purchases (availability can change)

### Working with Free Tickets

When `free: true`:

```javascript
function displayTicketPrice(ticket) {
  if (ticket.free) {
    return 'FREE';
  }
  return `₦${ticket.price.toLocaleString()}`;
}

function handleFreeTickets(ticket, quantity) {
  if (ticket.free && ticket.slots_remaining >= quantity) {
    // Free tickets still need booking
    return {
      total: 0,
      message: `${quantity} free tickets reserved`
    };
  }
}
```

***

### Multi-Location Cinema Handling

#### Detecting Multi-Location Cinemas

Before fetching tickets for a cinema experience, check if it has multiple locations:

```javascript
async function fetchCinemaTickets(experienceId) {
  // 1. Get cinema details first
  const detailsResponse = await fetch(`/api/v1/merpi/experience/v/${experienceId}`);
  const details = await detailsResponse.json();
  
  if (!details.data.cinema) {
    // Not a cinema - fetch tickets normally
    return fetchTickets(experienceId);
  }
  
  const locations = details.data.cinema_info.locations;
  
  if (locations.length === 1) {
    // Single location - cinema_location_id not needed
    return fetchTickets(experienceId);
  }
  
  // Multi-location - need cinema_location_id
  return {
    isMultiLocation: true,
    locations: locations,
    message: 'Please select a location first'
  };
}
```

#### Fetching Tickets for Specific Location

```javascript
async function fetchTicketsForLocation(experienceId, locationId) {
  const url = `/api/v1/merpi/experience/tickets/${experienceId}?cinema_location_id=${locationId}`;
  const response = await fetch(url);
  const data = await response.json();
  
  return data.data.tickets;
}

// Usage
const selectedLocationId = 4; // Customer selected location
const tickets = await fetchTicketsForLocation(experienceId, selectedLocationId);
displayTickets(tickets);
```

#### Complete Multi-Location Flow

```javascript
async function loadCinemaTickets(experienceId) {
  // 1. Get cinema details
  const details = await getCinemaDetails(experienceId);
  const locations = details.cinema_info.locations;
  
  if (locations.length > 1) {
    // 2. Show location selector to customer
    const selectedLocation = await showLocationSelector(locations);
    
    // 3. Fetch tickets for selected location
    const tickets = await fetchTicketsForLocation(
      experienceId, 
      selectedLocation.id
    );
    
    return {
      tickets: tickets,
      selectedLocation: selectedLocation
    };
  } else {
    // Single location - fetch directly
    const tickets = await fetchTickets(experienceId);
    
    return {
      tickets: tickets,
      selectedLocation: locations[0]
    };
  }
}
```

***

### Response Caching Considerations

**Important**: Ticket availability (`slots_remaining`) can change rapidly, especially for popular events.

#### Recommendations:

* Cache ticket data for maximum 1-2 minutes
* Always fetch fresh data before checkout
* Implement optimistic UI with server validation
* Handle "sold out" errors gracefully during booking

#### Example Cache Implementation

```javascript
class TicketCache {
  constructor(ttlSeconds = 60) {
    this.cache = new Map();
    this.ttl = ttlSeconds * 1000;
  }
  
  async get(experienceId, cinemaLocationId = null) {
    const cacheKey = cinemaLocationId 
      ? `${experienceId}_${cinemaLocationId}` 
      : experienceId;
    
    const cached = this.cache.get(cacheKey);
    const now = Date.now();
    
    if (cached && (now - cached.timestamp) < this.ttl) {
      return cached.data;
    }
    
    // Fetch fresh data
    const url = cinemaLocationId
      ? `/api/v1/merpi/experience/tickets/${experienceId}?cinema_location_id=${cinemaLocationId}`
      : `/api/v1/merpi/experience/tickets/${experienceId}`;
    const response = await fetch(url);
    const data = await response.json();
    
    this.cache.set(cacheKey, {
      data: data.data.tickets,
      timestamp: now
    });
    
    return data.data.tickets;
  }
}

const ticketCache = new TicketCache(60); // 60 second cache
```

***

### Next Steps

After fetching ticket information:

1. **Display ticket options** - Show all categories with prices and availability
2. **Validate selection** - Check `slots_remaining` before allowing checkout
3. **Create holds** - Reserve tickets via POST /api/v1/merpi/validate before purchase
4. **Complete purchase** - Use the ticket `id` and `reservation_ids` when calling the buy endpoint
5. **Handle sold out** - Gracefully handle cases where `slots_remaining` is 0

***

### Related Endpoints

* [**Get Experience Details**](/merpi-by-syticks/api-reference/experience-ticketing-events-parties-conference-comedy-and-more/get-experience-details.md)- Fetch complete experience information before showing tickets
* [**Get Cinema Experience Details**](/merpi-by-syticks/api-reference/cinema-ticketing-cinema-movies-available-days-purchase-etc/get-cinema-experience-details.md)- For cinema-specific movie details with locations
* [**Hold/Reserve Tickets**](/merpi-by-syticks/api-reference/hold-reserve-ticket-inventory/hold-reserve-experience-inventory.md) - Create holds before purchasing
* [**Buy Experience Tickets**](/merpi-by-syticks/api-reference/experience-ticketing-events-parties-conference-comedy-and-more/buy-experience-tickets.md) - Complete purchase using ticket IDs and reservation IDs
* [**Get List of Experiences**](/merpi-by-syticks/api-reference/experience-ticketing-events-parties-conference-comedy-and-more/get-list-of-experiences.md) - Browse available events and movies
