API Conventions

Patterns and standards that apply across all TTG API v3 endpoints. Read this first — individual endpoint docs assume familiarity with these conventions.

Response Envelope

All responses use a consistent envelope:

Success:

1{
2 "data": { ... }
3}

Success (list):

1{
2 "data": [ ... ],
3 "pagination": { "limit": 50, "offset": 0, "total": 142 }
4}

Error:

1{
2 "error": {
3 "type": "NOT_FOUND_ERROR",
4 "code": "RESOURCE_NOT_FOUND",
5 "message": "The requested resource was not found."
6 }
7}

The top-level key is always data or error, never both. Parse the HTTP status code first (2xx vs 4xx/5xx), then read the body.

Money Format

All monetary values use integer minor units with an ISO 4217 currency code. No floating-point, no strings.

1{
2 "amount": 18500,
3 "currency": "USD"
4}

The number of decimal places depends on the currency:

CurrencyScaleamount: 18500 means
USD, GBP, EUR2$185.00
JPY, KRW0¥18,500
KWD3KD 18.500

Use your platform’s i18n library to determine the scale from the currency code — don’t hardcode / 100.

Client examples:

  • JavaScript: new Intl.NumberFormat(locale, { style: "currency", currency }).format(amount / 10 ** scale)
  • iOS: NumberFormatter with currencyCode set
  • Android: Currency.getInstance(currency).defaultFractionDigits for scale

Currency

Every price can be shown and charged in a local currency. The default is the event’s base currency.

The rule: reads take a currency query parameter (display); writes take a currency body field (state).

Browsing. On occurrences and inventory-items, send ?currency= (ISO 4217) to see prices in that currency; omit it for the base currency. This affects display only. Events carry no prices, so GET /api/v3/events takes no currency.

A cart owns its currency. A cart is created in a currency — base by default, or the body’s currency when supported. The cart’s current currency is total.currency on the response; options.currencies lists the currencies it can be priced in.

  • Quote: GET /api/v3/carts/{cartId}?currency=EUR returns the cart priced in euros, without changing the cart. Read it again without the parameter and you get the cart’s own currency back.
  • Switch: PATCH /api/v3/carts/{cartId} with { "currency": "EUR" } changes the currency the cart is priced and settled in. Later reads come back in euros with no parameter. Send the event’s base currency to go back to base prices.

Prices are always current. Every amount is worked out from the exchange rate at the time you read the cart, so a total can move while the cart is open. Read the cart again just before checkout and send that amount as expectedTotal.

Orders confirm the cart. POST /api/v3/orders settles in the cart’s currency — the order call takes no currency input, so switch currency on the cart (PATCH) beforehand. expectedTotal must equal the cart total exactly, both amount and currency.

Asking for a currency the retailer doesn’t sell the event in — or a three-letter code that isn’t a real ISO 4217 currency — returns 400 CURRENCY_NOT_SUPPORTED; a value that isn’t a three-letter code at all returns 400 INVALID_FIELD_VALUE. A currency the retailer does sell but that can’t be priced right now (no current exchange rate) returns 503 CURRENCY_TEMPORARILY_UNAVAILABLE — retry shortly. This applies wherever a currency is accepted: browsing, cart create (POST), cart quote (GET), and cart switch (PATCH). Asking for nothing prices in the cart’s own currency — the base currency unless the cart was created in or switched to another one. A requested currency is never silently swapped for base.

Example — a London show (base GBP), customer paying in euros: create the cart, PATCH it with { "currency": "EUR" }, read the cart to get the current euro total, then place the order with expectedTotal set to it — e.g. { "amount": 4899, "currency": "EUR" }.

IDs

All IDs are opaque strings. Never parse, construct, or derive meaning from an ID — treat them as tokens you receive from one endpoint and pass to another. The format may change without notice.

Stable IDs — persist across sessions and are safe to store:

  • Events, Occurrences, Carts, Orders, Tickets

Ephemeral IDs — valid only for the current session; re-fetch inventory to get fresh ones:

  • Inventory Items, Price Options

Pagination

All v3 list endpoints — events, occurrences, inventory-items, locations — use limit/offset pagination and return a pagination block. Page until you’ve read pagination.total results.

ParameterTypeDefaultDescription
limitinteger50Max results per page (1–1000)
offsetinteger0Number of results to skip

The response includes a pagination object:

1{
2 "pagination": {
3 "limit": 50,
4 "offset": 0,
5 "total": 142
6 }
7}

To iterate all pages: increment offset by limit until offset >= total.

Timezones

Occurrence times (startsAt, endsAt) use the venue’s local timezone with UTC offset:

2026-03-15T19:30:00-05:00

Use the venue.timezone field (IANA identifier, e.g., America/New_York) if you need an IANA timezone for calendar integration (Apple Calendar, Google Calendar). For display, the offset embedded in the timestamp is sufficient — no timezone manipulation required.

System timestamps (createdAt, expiresAt) use UTC:

2026-03-15T19:40:00Z

Nullability

Fields are nullable only when absence carries meaning:

  • availabilityLevel: null — no availability signal; display the occurrence normally
  • fromPrice: null — occurrence is sold out or not yet on sale
  • endsAt: null — event has no known end time
  • listPrice: null — no discount exists (or display is contractually prohibited)
  • barcode: null — barcode not yet available (delayed delivery venues)
  • totalTaxes: null — taxes not disclosed in this market

When a nullable field is null, handle it explicitly in your UI — don’t display “null” or “$0.00”.

Optional fields that carry no information are omitted entirely rather than sent as null. For example, maxDiscountPercentage is absent (not null) when no discount exists.

Forward Compatibility

The API may add new fields, enum values, or error codes at any time without a version bump. To avoid breaking:

  • Ignore unknown fields — don’t fail on unexpected keys in response objects
  • Handle unknown enum values — use a default/fallback case for enums like status, _type, and error code
  • Don’t switch on error messages — use type and code for programmatic handling; message is for display only and may change