How sales work
Every kind of caller - a buyer on a website, in an app, on a partner's site, a box office operator, a promoter, an outlet, a kiosk - lists what is on sale, makes an order, authenticates a customer and reads the order back the same way. What differs is the credential.
Ticketlayer sells through many kinds of caller and manages three classes of credential. This section draws each caller through the same four moments so the pages can be read side by side:
- List what is on sale
- Make an order
- Authenticate a customer
- Read the order back
What differs from page to page is the credential: which one authenticates the request, where the sales channel comes from, and where a customer token escalates a session rather than authenticating it. The diagrams make that visible on every arrow.
Three questions every request answers#
| Question | Answered by | Never answered by |
|---|---|---|
| Who is calling, and how much do we trust them? | the credential | the request body |
| Under what commercial rules are they selling? | the sales channel | the model, or a path segment the caller picks |
| Which buyer is this for? | the customer token, carried on top | the credential alone |
A fourth thing follows and removes a false choice: the account is the business relationship, the channel is the terms it sells under, and the credential is only how a given actor arrives. An outlet has staff signing in to Backstage with a staff JWT and an EPOS calling the API with a channel secret key, on the same account, the same channel and the same access. "Is this staff or a partner" is never the question; it is two credentials reaching one business relationship.
Three credential classes#
They differ by where they may be held, not by what they reach.
| Class | Credential | Where it may be held |
|---|---|---|
| Low trust | The channel publishable key, tlpk_ | A browser, a native app binary, a site builder: anywhere a user can read it. It names one channel and reaches the low-trust surface, whose responses are built field by field so nothing a view does not declare can leak. |
| Medium trust | The channel secret key, tlsk_ | A server, never a browser. It names one channel and reaches what a storefront server needs: the channel-scoped reads, carts, checkout, payments, the channel's own orders and customer records. Nothing else. |
| High trust | The staff JWT (the identity issuer), the organisation API key tlak_, the device JWT, the embed session and the service JWT | Backstage, staff tools, paired devices and your own server. These reach the staff surface, gated by permissions. |
Two things are carried on top of a credential and never authenticate on their own:
- The customer token. Thirty minutes, with a 24 hour absolute ceiling that
a refresh carries forward rather than extends. It is obtained by a magic
link (a 15 minute code) or by a partner identity assertion.
There is no
customerprincipal: the channel key authenticates the request and the handler reads the customer from the verified token. A request that needs an identity and has none is refused withCUSTOMER_TOKEN_REQUIRED. That is why a forged body cannot widen scope: identity comes from the token, never from input. - The order access token. Emailed with an order, it grants access to that one order. A Live session holds them per order.
Where the channel comes from#
The channel is a filter on the ordinary resources, not a resource of its
own. GET /events with no channel is every event the caller may see; with a
channel it is what that channel lists as discoverable right now, with each
event's listing state and the price the channel resolves for it. A cart has no meaning without a channel, so POST /cart
requires one. There is no catalogue endpoint and no listings read for
selling. Listings are created, edited and removed at
/sales-channels/{channelId}/listings, which is
channel administration, not selling.
The channel is taken from the credential when the credential is channel-scoped, and from a header when it is not:
- A channel key (
tlpk_ortlsk_) names its channel. Nothing is supplied. - A staff JWT, an organisation API key or a device JWT names an organisation
but not a channel, so the request carries
X-Ticketlayer-Channel: <slug>. It is a slug, not an id, because ids differ between test and live configuration and slugs do not.
A caller acts only on the channels it holds. A channel key holds exactly one.
A staff credential holds the set of channels it has been granted access to, unless
its role grants the permission at organisation scope. Box office staff and
promoters sell at channel scope and may act only on channels they have
access to; organisation owners, venue admins and event managers hold the
same permissions at organisation scope and see everything. Naming a
channel outside the set is a 403. Naming none, where the permission is
granted at channel scope, is a 400, never a silent narrowing. Channel
access is the boundary; the filter is derived from it, so the filter is
never the thing withholding data.
Discoverable, visible, sellable#
An event on a channel is in three states, and every question a buyer or an app asks is one of them:
| State | The question | Where it is asked |
|---|---|---|
| Discoverable | Does it appear in a list? | GET /events with a channel, GET /sales/listings, event cards |
| Visible | Can it be opened by id? | GET /events/{id} and its occurrences, prices and layout, GET /sales/events/{id} |
| Sellable | Will a cart accept it? | POST /cart/{id}/items, checkout |
Sellable implies visible, and discoverable implies visible. A hidden event is visible and sellable but not discoverable: the link works, the list does not show it. An announced event is discoverable and visible but not yet sellable: it has a card, and the card says when. Off is none of the three.
The rules live on the event and are inherited by its listings. The event carries one rule per state, the organisation's intent for it on every channel. A listing (the event on one channel) may override any of the three for that channel, in either direction: the venue's own site opens a week earlier, the outlet a week later. Set once on the event, refine per channel only where a channel differs.
A rule is one shape, from a flag to a targeted schedule:
{ "open": true, "windows": [
{ "from": "2026-10-01T09:00:00Z", "until": null, "audienceTags": [] },
{ "from": "2026-09-24T09:00:00Z", "until": null, "audienceTags": ["member.priority-booking"] }
] }open: false is closed. open: true with no windows is always. With
windows, the rule is true when any window matches now and the buyer:
an empty audienceTags is everyone, and a list of
customer tags admits buyers who hold any of
them. The example above is on sale to members a week before everyone else.
(audience, a single tag or null, is the deprecated form of the same
field.)
Read the state; never re-derive it. The API evaluates the rules for the
caller and sends the result with the event: the listing block on a scoped
event read and every sales listing carry discoverable, visible,
sellable, opensAt (the next moment it becomes sellable for this buyer)
and closesAt. A storefront card says "on sale Friday 10:00" to the buyer
in front of it, and a member sees the member date, without a second call.
The rules bind everyone, staff included. The one exception is a permission:
a caller holding events.list_hidden on the channel (box office staff and
door scanners hold it) sees everything the channel lists whatever the rules
say right now, each flagged with its real state so the app can mark it hidden
or not yet on sale. A door has to admit the holders of an invitation-only
event too. Selling is never excepted.
For the simplest setup, a sales channel with autoList on lists every event
of its account when the event is published, inheriting the event's rules;
the website channel you are given at signup is one. Publish the event, set
its rules or leave them open, and it is on sale.
Two surfaces, and Live at the edge#
- The low-trust surface is
/sales/*on the Live API, reached only with a channel key. Every response is a declared view. - The high-trust surface is the staff endpoints of the Backstage API, with full domain shapes.
Live is the edge, and every channel-key call goes through it. It holds the publishable key on behalf of a browser session and fronts the queue and the rate limiter, so a browser client never sees a key. A server selling under a secret key calls Live too. The Backstage API serves the same operations to Live alone, as its upstream, not to a page, an app or a partner, whatever key they hold. A server with a high-trust credential talks to the Backstage API directly.
How to read the diagrams#
Each page has one sequence diagram. Solid arrows are calls, dashed arrows are replies, and the badge under an arrow is what that call carries:
- Amber - low trust: the publishable key.
- Blue - medium trust: the secret key.
- Violet - high trust: a staff JWT, an organisation API key, a device JWT.
- Teal - where the channel comes from: the key itself, the
Hostof a hosted storefront, orX-Ticketlayer-Channel. - Green - carried on top and never authenticating: a customer token, a partner assertion, an order access token.
- Grey - not a credential at all: a session id, a local token.
The channel types#
| Who | Credential that authenticates | Where the channel comes from | Customer |
|---|---|---|---|
| A buyer on your website | tlpk_, held by Live | the key | magic link; the token stays in the Live session |
| A buyer on the hosted box office | tlpk_, held by Live | the storefront's Host | magic link; the token stays in the Live session |
| A buyer in a native app | tlpk_, in the app binary | the key | magic link; the token stays in the Live session |
| A partner's own storefront | tlsk_, on the partner's server | the key | a partner identity assertion signed by the partner's IdP |
| Staff at a box office or a till | staff JWT | X-Ticketlayer-Channel | usually none; "on behalf of" is not authentication |
| A promoter | staff JWT | X-Ticketlayer-Channel | usually none |
| An outlet or reseller | staff JWT and tlsk_, one account | header and key, same channel | usually none; the sale posts a receivable |
| A kiosk | device JWT | X-Ticketlayer-Channel | magic link on screen, or none |
Keys and authentication is the reference for the headers each credential uses.