Skip to navigation

Migration: Availability to Occurrences

Guide for moving from the Encore API’s GET /api/v4/availability/products/{productId}/... endpoint to GET /api/v3/events/{eventId}/occurrences in the TTG Storefront API v3, the newer API. The two APIs number their versions separately.

For the full v4 inventory reference, see Inventory API on the legacy portal.

Endpoint Comparison

Legacy (v4)New (v3)
MethodGETGET
Path/api/v4/availability/products/{productId}/quantity/{quantity}/from/{fromDate}/to/{toDate}/api/v3/events/{eventId}/occurrences
AuthNone — the optional affiliateId header only picks the retailerX-TT-API-Key, X-TT-Retailer and X-TT-Platform headers
FilteringDate range (YYYYMMDD) and quantity in URL pathOptional quantity, startDate, endDate query parameters
PaginationNot built inlimit / offset with a pagination block

What Changed

Headers

Legacy availability needed no key. v3 needs the three headers in Authentication & Headers on every call.

Pagination

The response is a page, not the whole list: { data, filters, pagination }. See Pagination.

Terminology

Legacy (v4)New (v3)Notes
ProductEventSame concept — a show or experience
productIdeventIdUsually the same value. Some older products have a different TodayTix id, which the legacy API looked up for you: check each id with GET /api/v3/events/{eventId}, or ask your TTG contact for the list
AvailabilityOccurrenceEach date/time slot is now an “occurrence”
datetimestartsAt / endsAtISO 8601 with venue timezone offset
minPrice + currencyfromPriceBoth in minor units; v3 puts them in one object

Quantity and Date Range Are Now Optional Query Parameters

In v4, quantity, from, and to were required path segments. In v3, they are optional query parameters:

v4 (path)v3 (query param)Notes
/quantity/{quantity}?quantity=2Optional. Pricing and availabilityLevel reflect that many tickets together; see Party Size.
/from/{fromDate} (YYYYMMDD)?startDate=2026-03-15Optional. Inclusive start date (ISO 8601 YYYY-MM-DD). Interpreted in the event’s local timezone.
/to/{toDate} (YYYYMMDD)?endDate=2026-03-31Optional. Inclusive end date (ISO 8601 YYYY-MM-DD). Interpreted in the event’s local timezone.

Two more optional parameters have no v4 equivalent: currency prices the dates in another currency (see Currency), and voucherCode shows the dates a presale or access code unlocks (see Vouchers).

All parameters can be combined freely or omitted entirely:

# Legacy
GET /api/v4/availability/products/123/quantity/2/from/20260315/to/20260331
# Equivalent to v4 call with all filters
GET /api/v3/events/123/occurrences?quantity=2&startDate=2026-03-15&endDate=2026-03-31
# Only filter by date range
GET /api/v3/events/123/occurrences?startDate=2026-03-15&endDate=2026-03-31
# Only filter by quantity
GET /api/v3/events/123/occurrences?quantity=2
# No filters — the first page of upcoming occurrences
GET /api/v3/events/123/occurrences

Money Format

Both use minor units. Legacy sent the price and its currency as two fields; v3 puts them in one object.

Legacy (v4):

{ "minPrice": 8500, "currency": "USD" }

New (v3):

{ "fromPrice": { "amount": 8500, "currency": "USD" } }

All money in v3 uses this shape, in minor units (cents for USD, pence for GBP). Get the scale from the currency code. See Money Format.

Availability Status

Legacy (v4)New (v3) Equivalent
Available dates returnedfromPrice is non-null
Sold-out and off-sale dates excludedIncluded, with availabilityLevel: "SOLD_OUT" and fromPrice: null — render as sold out or hide, your choice. Some events and retailers leave these dates out; see Browse Occurrences

Each occurrence also carries availabilityLevel, as legacy did: LOW (tickets are running out), SOLD_OUT, or null (no signal — display the occurrence normally). New values may be added over time; treat any unrecognized value as no signal.

Discount Information

Legacy only flagged a discount, with discount and offer set to true or false. v3 says how big it is:

  • maxDiscountPercentage — Best available % discount (e.g., 29 = “Up to 29% off”)
  • maxDiscountAmount — Best available amount discount (e.g., { amount: 5000, currency: "USD" } = “Save up to $50”)

These fields are optional — omitted when no discount exists. maxDiscountPercentage is also omitted on events that don’t show savings as a percentage.

Response Shape

Legacy (v4)

{
"request": { ... },
"response": [
{
"datetime": "2026-03-15T19:30:00-0400",
"largestLumpOfTickets": 8,
"minPrice": 8500,
"currency": "USD",
"discount": true,
"offer": true,
"availabilityLevel": null
}
],
"context": null
}

New (v3)

{
"data": [
{
"id": "456",
"admissionType": "TIMED",
"startsAt": "2026-03-15T19:30:00-04:00",
"endsAt": "2026-03-15T22:30:00-04:00",
"availabilityLevel": null,
"fromPrice": { "amount": 8500, "currency": "USD" },
"maxDiscountPercentage": 29,
"orderLimit": { "min": 1, "max": 8 },
"venue": {
"id": "UmljaGFyZCBSb2RnZXJzIFRoZWF0cmU=",
"name": "Richard Rodgers Theatre",
"address": {
"line1": "226 W 46th St", "city": "New York",
"state": "NY", "postalCode": "10036", "country": "US"
},
"timezone": "America/New_York"
}
},
{
"id": "457",
"admissionType": "TIMED",
"startsAt": "2026-03-16T19:30:00-04:00",
"endsAt": null,
"availabilityLevel": "SOLD_OUT",
"fromPrice": null,
"orderLimit": { "min": 1, "max": 8 },
"venue": {
"id": "UmljaGFyZCBSb2RnZXJzIFRoZWF0cmU=",
"name": "Richard Rodgers Theatre",
"address": {
"line1": "226 W 46th St", "city": "New York",
"state": "NY", "postalCode": "10036", "country": "US"
},
"timezone": "America/New_York"
}
}
],
"filters": [],
"pagination": { "limit": 50, "offset": 0, "total": 2 }
}

Key differences:

  • The list sits in data, not response, and comes one page at a time
  • Each occurrence has an id you’ll need for subsequent calls (inventory, cart)
  • Each occurrence names its venue
  • startsAt replaces datetime
  • endsAt is nullable (some events have no fixed end time)
  • A date with nothing on sale comes back with fromPrice: null instead of being left out
  • availabilityLevel says why nothing is buyable (SOLD_OUT) or that stock is running out (LOW)
  • orderLimit gives the min and max ticket quantity one order may contain. It is the event’s order limit, repeated on each occurrence so you can bound the quantity selector without loading the event

Migration Checklist

  1. Send X-TT-API-Key, X-TT-Retailer and X-TT-Platform on every call
  2. Replace productId with eventId. Most are the same number; for some older products ask your TTG contact for the v3 id
  3. Update the endpoint URL from v4 path to GET /api/v3/events/{eventId}/occurrences
  4. Move quantity from URL path to ?quantity= query parameter (now optional)
  5. Move the date range from the URL path to ?startDate= and ?endDate= (now optional), and change YYYYMMDD to YYYY-MM-DD
  6. Read the price from fromPrice.amount and fromPrice.currency instead of minPrice and currency
  7. Store the occurrence id — you need it for inventory browsing and cart creation
  8. Decide how to present unavailable occurrences — any date with nothing to buy comes back with availabilityLevel: "SOLD_OUT" and fromPrice: null, unless the event or your retailer leaves such dates out (see Browse Occurrences). To match the legacy behavior (which excluded every date with nothing to buy), filter out occurrences where fromPrice is null
  9. Page with limit / offset until offset >= pagination.total
  10. Optionally display discount badges using maxDiscountPercentage or maxDiscountAmount

Next Steps

After migrating the browse step, continue with the full Purchase Flow:

  1. Browse Inventory — GET /api/v3/events/{eventId}/occurrences/{occurrenceId}/inventory-items
  2. Create Cart — POST /api/v3/carts
  3. Checkout — POST /api/v3/orders