Purchase Flow

Four-step flow to browse, reserve, and purchase tickets via the TTG API.

Browse Occurrences → Browse Inventory → Create Cart → Checkout

1. Browse Occurrences

GET /api/v3/events/{eventId}/occurrences

Returns dates with pricing summaries. fromPrice: null means sold out or off-sale — filter these out.

The discount fields (maxDiscountPercentage or maxDiscountAmount) represent the best available discount across all price points. They may come from a different price point than fromPrice.

2. Browse Inventory

GET /api/v3/events/{eventId}/occurrences/{occurrenceId}/inventory-items

Returns purchasable items. Use inventoryVariant._type to determine the type:

TypeDescriptionQuantity Rule
AssignedSeatSpecific seat (section, row, seat)Must be 1
GeneralAdmissionGA area1 to quantityAvailable
ExtraAdd-on (drinks, merch, parking)1 to quantityAvailable

Pricing: sellPrice is the all-in price customers pay (fees included). listPrice appears only when a discount exists — display as strikethrough.

Example response (trimmed):

1{
2 "data": [
3 {
4 "id": "eyJzIjoiT1JDSC1BLTEwMSJ9",
5 "inventoryVariant": {
6 "_type": "AssignedSeat",
7 "id": "Orchestra-A-101",
8 "name": "Orchestra A 101",
9 "section": "Orchestra",
10 "row": "A",
11 "seat": "101"
12 },
13 "quantityAvailable": 1,
14 "priceOptions": [
15 {
16 "id": "eyJjIjoiRlVMTCJ9",
17 "category": { "name": "Adult" },
18 "listPrice": { "amount": 15000, "currency": "USD" },
19 "sellPrice": { "amount": 12500, "currency": "USD" }
20 }
21 ]
22 }
23 ]
24}

3. Create Cart

POST /api/v3/carts

Reserves inventory and starts a hold timer. All items must be from the same occurrence.

1{
2 "items": [
3 {
4 "occurrenceId": "123",
5 "inventoryItemId": "eyJzIjoiT1JDSC1BLTEwMSJ9",
6 "priceOptionId": "eyJjIjoiRlVMTCJ9",
7 "quantity": 1
8 }
9 ]
10}

The response includes expiresAt (UTC) — display a countdown. When the cart expires, inventory is released and GET /api/v3/carts/{cartId} returns 404. Create a new cart to continue.

To release held inventory early: DELETE /api/v3/carts/{cartId} (idempotent, returns 204).

4. Checkout

POST /api/v3/orders
1{
2 "cartId": "cart_001",
3 "expectedTotal": { "amount": 18500, "currency": "USD" },
4 "contact": {
5 "name": "John Smith",
6 "email": "john.smith@example.com",
7 "phone": "+12125550123"
8 }
9}

expectedTotal must match the cart total exactly. If prices changed, the server returns 409 — re-fetch the cart and confirm the new price with the customer.

On success, tickets are in items[].tickets[] — each with a barcode (value, format, optional imageUrl).

Receipt Rendering

Both cart and order responses include receiptLines[]. Render them in order — do not compute totals client-side.

Each line has sign: positive = charge, negative = credit/discount. All total.amount values are positive integers.

Common Errors

HTTPError CodeCauseRecovery
409TOTAL_PRICE_MISMATCHexpectedTotal doesn’t match cartRe-fetch cart, confirm new price
410CART_EXPIREDHold timed outCreate a new cart
409INVENTORY_EXHAUSTEDItems no longer availableBrowse inventory again

For the full error format and retry strategy, see Error Handling.