Ticket purchase flow
From discovery to a confirmed order, step by step.
A ticket purchase moves through discovery, event detail with its seating map, ticket selection at checkout, an optional lock, the order, and delivery tracking.
search/events → search/event → search/ticket → orders/lock → orders/create → orders/status
(discover) (+ map, seats) (cart / price) (if supported) (confirm) (track)
Alongside
search/eventyou loadsearch/map(interactive map script) andsearch/ticketsMap(map-ready tickets).orders/lockis optional and not supported by every ticket.
1. Find an event
Search by destination, performer or venue. Each result carries an event_id.
curl https://production.ticketero.co/api/v4/search/events \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "searchType": "performer", "performerId": "160" }'
Need IDs? Use /search/fastAutocomplete to suggest performers,
venues and destinations in one call.
2. Get the event and its map
Fetch the event detail with search/event. In parallel, load the seating map and the
map-ready tickets so the customer can browse availability:
search/eventreturns the event detail.search/mapreturns the interactive map script (see Interactive maps).search/ticketsMapreturns the tickets shaped for the map, each with atgID(used asticketSkuwhen ordering), the allowed quantities insplits, and atgSplitsBitmap.
curl https://production.ticketero.co/api/v4/search/event \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "eventId": "5614" }'
curl https://production.ticketero.co/api/v4/search/ticketsMap \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "eventId": "5614" }'
Tickets sell only in specific quantities. Each result already includes them in splits, so pick a quantity from that array. tgSplitsBitmap is also returned because the interactive maps need it; decode it with GET /splits/{tgSplitsBitmap} only when you have a bitmap on its own.
3. Select the ticket (cart / checkout)
When the customer adds a ticket to the cart or reaches checkout, call search/ticket for
the chosen ticket to get its full detail and current price.
curl https://production.ticketero.co/api/v4/search/ticket \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "eventId": "5614", "ticketSku": "5113" }'
It returns the ticket detail, including the current ticket_price, the
purchasableQuantities, and required_purchase_fields (which attendee fields the order
will require).
To revalidate the price right before ordering, call search/ticket again. Prices and availability change in real time, so check just before orders/create.
4. Lock the ticket (if supported)
Some tickets can be held for 5 minutes with orders/lock, which returns a requestId
you pass to orders/create. Not every ticket supports locking; if the lock is not
available, go straight to step 5.
curl https://production.ticketero.co/api/v4/orders/lock \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "ticketSku": 5113, "quantity": 2, "eventId": "5614" }'
{
"success": true,
"data": { "requestId": "9b184bb4-b926-4232-b230-c9a4fb3fed73", "ticket": { "section": "..." } },
"message": "Lock successfully created."
}
5. Create the order
Pass the requestId from the lock to convert the hold into an order. Some tickets require
attendee details (paxes), check required_purchase_fields on the ticket, and a
delivery block tells us where to send the tickets.
curl https://production.ticketero.co/api/v4/orders/create \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"orderType": "ticket",
"ticketSku": 5113,
"quantity": 2,
"eventId": "5614",
"requestId": "9b184bb4-b926-4232-b230-c9a4fb3fed73",
"delivery": { "first_name": "John", "last_name": "Doe", "email": "[email protected]", "phone": "+5215555555555" }
}'
If the ticket does not support locking, omit requestId and orders/create books directly. When a lock is available, locking first lets you show the customer a confirmed hold before charging.
If the ticket needs attendees, include paxes (one per ticket). Use
/orders/countries for nationality_country_id:
{
"paxes": [
{ "full_name": "John Doe", "birth_date": "1990-05-24", "nationality_country_id": 1055 },
{ "full_name": "Jane Doe", "birth_date": "1993-02-14", "nationality_country_id": 1055 }
]
}
Attendee fields
required_purchase_fields tells you what each ticket needs. Values are strings: "1" means
required, "0" means not requested. Send every flagged field on each paxes entry.
required_purchase_fields key |
Field in paxes[] |
Format |
|---|---|---|
full_name_required |
full_name |
Text, first and last name |
birth_date_required |
birth_date |
YYYY-MM-DD |
passport_info_required |
passport_number |
Text |
nationality_id_required |
nationality_country_id |
Integer, id from /orders/countries |
city_of_birth_required |
city_of_birth |
Text |
email_required |
email |
|
address_required |
address |
Text, single line |
phone_required |
phone |
Text, with country code |
address is one text field, not an object. Send the full address on a single line: street and
number, area, postal code, city and country.
{
"paxes": [
{
"full_name": "John Doe",
"email": "[email protected]",
"address": "221B Baker Street, Marylebone, NW1 6XE, London, United Kingdom",
"phone": "+44 20 7946 0958"
}
]
}
paxes[].phone is the attendee’s phone; delivery.phone is the buyer’s delivery contact. When phone_required is “1”, send both. Read the whole object instead of assuming a fixed set of keys: new ones are added over time and must not break your parser. The venue enforces these details, so missing or wrong data can block delivery or entry.
Retry safely with an idempotency key
A timeout leaves you not knowing whether the order was created. Send an Idempotency-Key
header with a unique value per order (a UUID works well) and reuse the same value on every
retry of that order. A retry then never buys twice.
curl https://production.ticketero.co/api/v4/orders/create \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Idempotency-Key: 4f0c2b7e-6a2d-4c5e-9d5a-3f8e1b2c7a10" \
-H "Content-Type: application/json" \
-d '{ "orderType": "ticket", "ticketSku": 5113, "quantity": 2, "eventId": "5614" }'
| What you send | What you get |
|---|---|
| Same key, same body, first order created | The original response again, with the Idempotent-Replayed: true header |
| Same key while the first request is still running | 409 with data.code IDEMPOTENCY_IN_PROGRESS. Wait a few seconds and retry with the same key |
| Same key, different ticket, event or quantity | 409 with IDEMPOTENCY_KEY_REUSED. Use a new key for a new order |
| The first request ended without a confirmed result | 409 with IDEMPOTENCY_OUTCOME_UNKNOWN. Do not retry: contact support with the key |
Keys are scoped to your account and kept for 24 hours. A retry that only changes paxes or
delivery is the same order and returns the original response: the corrections are not
applied and the order keeps the attendee data of the first request. The header in the replayed
response only echoes the request of the retry. If the order is rejected (validation, credit or
the venue refusing it), the key is released and you can retry with it after fixing the cause.
The header is optional. If you lock
first and send no header, the requestId of the lock is used as the key. The requestId
must be a real lock: do not invent one to use as a key, because it can be rejected. Send the header instead.
Without any key, an identical request that arrives while the first is still running is answered with 409 IDEMPOTENCY_IN_PROGRESS. Idempotency covers ticket orders.
6. Track the order
Poll orders/status with the requestId from the orders/create response (sent as
confirmation) to follow delivery. This is not the requestId of the lock.
curl https://production.ticketero.co/api/v4/orders/status \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "confirmation": "ebd5a322-283c-487d-a4fe-169b72bd7ff6" }'
{
"success": true,
"data": { "orderStatus": "PE", "orderStatusText": "Pending Delivery", "bookingId": "539323" },
"message": "Order status successfully obtained."
}
Tips
- Revalidate the price with
search/ticketright beforeorders/create. - Read
required_purchase_fieldsper ticket: it varies by ticket, and the key set grows over time. - Validate quantity against
tgSplitsBitmap; mismatched quantities are rejected. - Locking is optional and not supported by every ticket. When unavailable,
orders/createbooks directly. - Send an
Idempotency-Keyonorders/createand reuse it on every retry of the same order. - Two different
requestIds: the one fromorders/lockgoes intoorders/create; the one in theorders/createresponse goes intoorders/statusasconfirmation. - Locks expire in 5 minutes. Create the order before then, or lock again.

API