# Tickets

This guide covers what is specific to tickets: theme park tickets, multi-day passes, express passes and special events. The steps every product shares (the offer, the check, booking, reading, cancelling, the voucher and the errors) are in the [Booking flow](/developers/guides/v2-booking-flow) guide. Field-by-field detail is in the [Tickets reference](/developers/reference/v2/tickets) and the [Booking flow reference](/developers/reference/v2/bookings).

| Step | Call | What carries to the next step |
|---|---|---|
| 1 | `GET /api/v2/tickets/brands` | what to collect from travelers, per brand |
| 2 | `GET /api/v2/tickets/products` | `product_id` and `booking_options` |
| 3 | `POST /api/v2/tickets/availability` | `offer_id` |
| 4 | The [Booking flow](/developers/guides/v2-booking-flow) | |

## 1. List brands

```bash
curl "https://highstartravel.com/api/v2/tickets/brands" \
  -H "Authorization: Bearer YOUR_CREDENTIAL"
```

A brand is the resort or seller of a ticket. Everything the tickets of one brand have in common is here, once: the traveler fields and the age categories. You build your form from the brand, not from each product. A brand appears only if your credential can sell at least one of its products right now. A credential with no access to any ticket integration gets `403 FORBIDDEN`.

Each brand has:

- `code` and `name`: `UOR` (Universal Orlando Resort), `WDW` (Walt Disney World), `DLR` (Disneyland Resort), `UPR` (United Parks & Resorts) or `OTKT` (other tickets). The list can grow.
- `products`, how many products you can sell in it. Brands with more products come first.
- `age_categories`, the categories you price and book by: `adult` and `child`, each with its age range. Infants under 3 do not need a ticket and are not part of a ticket booking.
- `booking_requirements`, what to send for every traveler. `travelers.mode` is `all_travelers`: one entry per person, each with a `role`. `fields` lists the keys, each with `required`, and `age_validation` says whether the birth date is checked against the category on the visit date (`strict`) or only has to be present (`none`).

| Brand | Every traveler |
|---|---|
| Universal | `first_name`, `last_name`, `birth_date`, `nationality` |
| Disney | The same four, and an optional `phone` |

Build your form from `fields`, not from this table. A field the brand does not list is ignored: it is neither validated nor sent anywhere.

## 2. List products

```bash
curl "https://highstartravel.com/api/v2/tickets/products?brand=UOR" \
  -H "Authorization: Bearer YOUR_CREDENTIAL"
```

A ticket your credential cannot sell is not listed. Every product has a `brand` code from step 1. Filter with `?brand=UOR` or `?brand=WDW,DLR`.

Products appear only while their integration is enabled for your account and on your credential. A product whose integration is turned off is not listed and gets no offers; bookings already made can still be read, cancelled and their voucher downloaded.

Each product carries:

- `product_id`, our id. Use it in `availability`.
- `external_id` and `external_ids`, the codes the ticket has outside our platform. Use them to map and reconcile. When adult and child are sold under different codes, `external_ids` has one per category (`adult`, `child`). Both are `null` only for tickets with no code outside our platform.
- `days`, the days of admission, and `usage_window_days`, the days counted from the first visit in which all of them must be used. A 4-day ticket with a window of 7 must be used within 7 days of the first visit. `null` means no window.
- `validity`, the dates the product is sold for, and `event_date`, the one date of a special event.
- `included_venues`, `time_slots` (whether it sells by time slot) and `currency`.
- `details`, typed by `details.kind`. Read `kind` first and ignore the kinds you do not know.
- `booking_options`, the choices that belong to this product alone. It is `{}` when there are none.

Travelers and age categories are not on the product: they come from its brand.

`booking_options` holds the choices to make at booking time. Today that is `delivery_method`:

- `eticket` is an instant e-ticket.
- `kiosk_voucher` is a voucher collected at a kiosk.

When the product and your credential allow both, `values` has two entries and `required` is `true`: you must send the option. Your credential can be allowed only one of them. Then only that one is listed, and it is applied if you leave the option out.

The catalog changes rarely. Both responses have `Cache-Control: private, max-age=3600`.

## 3. Ask for availability

```bash
curl -X POST "https://highstartravel.com/api/v2/tickets/availability" \
  -H "Authorization: Bearer YOUR_CREDENTIAL" \
  -H "Content-Type: application/json" \
  -d '{
    "product_ids": [415, 331],
    "from": "2026-11-10",
    "to": "2026-11-12",
    "travelers": { "adult": 2, "child": 1 }
  }'
```

- One call covers up to 20 products and a range of 62 days, both ends counted. More answers `400 VALIDATION_ERROR`. These limits can change, and the [changelog](/developers/guides/changelog) announces it.
- `travelers` gives the quantity per category. Only `adult` and `child` are priced, with at least one traveler in total.
- The response has one entry in `results` per requested product, in request order.

```json
{
  "results": [
    {
      "product_id": 415,
      "currency": "USD",
      "days": [
        {
          "date": "2026-11-10",
          "availability": "available",
          "unit_prices": { "adult": 641.3, "child": 622.6 },
          "total": 1905.2,
          "offer_id": "OFFER_ID_FROM_THIS_RESPONSE"
        },
        { "date": "2026-11-12", "availability": "sold_out" }
      ]
    }
  ],
  "request_id": "3f8a9b7c1d2e4f5a6b7c8d9e0f1a2b3c"
}
```

- `unit_prices` is the price of one ticket for each category you asked for. `total` is the sum of each unit price, rounded to 2 decimals, times its quantity. It is the price of the whole party.
- `availability` is `available`, `limited` (few left), `sold_out` or `unknown` (no stock information for that day). Only `available` and `limited` days carry prices and an `offer_id`.
- A date with nothing to sell is left out: outside the validity, or not the date of a special event.
- The offers carry no `expires_at`. To know whether a price still holds, call the check; the booking re-quotes it live anyway. See the [Booking flow](/developers/guides/v2-booking-flow#1-the-offer).
- The response has `Cache-Control: private, max-age=300`.

### Time slots

A product with `time_slots: true` returns, for each day, one offer per slot in `time_slots[]`. The prices, `total` and `offer_id` are in each slot, not on the day.

```json
{
  "date": "2026-11-10",
  "availability": "available",
  "time_slots": [
    {
      "time": "09:30",
      "availability": "available",
      "unit_prices": { "adult": 135.0, "child": 135.0 },
      "total": 405.0,
      "offer_id": "OFFER_ID_FOR_THIS_SLOT"
    }
  ]
}
```

`time` is `HH:MM`, local to the venue.

### Partial results

If a product cannot be priced right now, its result has `days: []` and an `error` with `code: PROVIDER_ERROR`. The other products are answered as usual, and the response carries `partial: true`. If the integration behind a product is switched off, its result carries `code: PROVIDER_UNAVAILABLE` instead, also with `partial: true`. Retry the failed products.

```json
{
  "product_id": 331,
  "currency": "USD",
  "days": [],
  "error": { "code": "PROVIDER_ERROR", "message": "This product could not be priced right now. Ask again." }
}
```

If every requested product fails, the whole call answers `502 PROVIDER_ERROR`, or `503 PROVIDER_UNAVAILABLE` when all of them are switched off. A `partial` response is the only v2 answer that mixes outcomes, and it is a read: nothing was booked.

An unknown product and a product your credential cannot sell answer the same `404 PRODUCT_NOT_FOUND`, for the whole call. You never get a partial list for this case.

### Where the price comes from

- Universal prices are requested live when you call `availability`. If the live answer does not arrive in time, we answer from the last stored price for that product and day.
- Disney prices come from a store refreshed at least every 12 hours. A day that is missing or older is requested live. If that fails, the older stored price is used.
- Other tickets are priced from our own table by date. What `availability` returns is what we sell.

Whatever the source, the price is checked live again when you book. The stored price is never the price you are charged.

## 4. The ticket item of a booking

The booking is the one described in the [Booking flow](/developers/guides/v2-booking-flow#3-book). A ticket item has these specifics:

```json
{
  "offer_id": "OFFER_ID",
  "travelers": [
    { "role": "adult", "first_name": "Ana", "last_name": "Example", "birth_date": "1985-06-15", "nationality": "AR" },
    { "role": "adult", "first_name": "Luis", "last_name": "Example", "birth_date": "1983-02-03", "nationality": "AR" },
    { "role": "child", "first_name": "Sol", "last_name": "Example", "birth_date": "2018-04-10", "nationality": "AR" }
  ],
  "options": { "delivery_method": "eticket" }
}
```

- `offer_id` is the only thing that travels from availability. The date, the time slot, the quantities and the price are inside it. You do not send them again.
- `travelers` has one entry per ticket, every traveler named, each with its `role` (`adult` or `child`). The count per `role` must match the offer.
- `options.delivery_method` is required when the product lists more than one value.
- Tickets take no `logistics`.
- A price that moved answers `409 PRICE_CHANGED` with a fresh offer in `details.current_offer`, and nothing is created. Show the new price and book again with its `offer_id`.

In the booking answer, `date` of a multi-day ticket is the first day, and each item has `unit_prices` per category and the `options` you sent. The product carries `external_id` and `external_ids`. Reading a ticket booking returns the count per category, not the list of names.

Cancelling cancels the whole booking. Some tickets give you the voucher at once. Others publish it later: while `voucher.status` is `pending`, the download answers `409 VOUCHER_NOT_READY`, so retry later.

## Next

The rest is the [Booking flow](/developers/guides/v2-booking-flow) guide: the check, booking and retries, reading, cancelling, the voucher, test credentials and the errors to handle. The full list of codes is in [v2 errors](/developers/guides/v2-errors).
