Skip to content
Docs
Concept

Staff at a box office or a till

An operator is a named human and carries a staff JWT from the identity issuer. The channel travels as X-Ticketlayer-Channel, and whether the operator has to pick one depends on the scope their role grants.

An operator is a named human, so they carry a staff credential, not a device one. The till's hardware - the printer, the cash drawer, the payment terminal - is a separate concern, handled by Stagehand's device pairing and its Local Control Token; the sale itself is the operator's.

The credential. A staff JWT (high trust) from the identity issuer, carrying the organisation. It names no channel, so the request carries X-Ticketlayer-Channel: <slug>. A customer, where there is one, is selected or signed in by magic link; the operator is never the customer.

Staff at a box office or a till: a staff JWT, with the channel in a headerSign in: Operator (box office app) to Identity issuer: OAuth: authorization code + PKCE; Identity issuer to Operator (box office app): a staff JWT carrying the organisation (staff JWT); Operator (box office app) to Backstage API: GET /my/sales-channels (staff JWT); Backstage API to Operator (box office app): the channels this operator has access to; Box office roles sell at channel scope, so the app offers a picker and sends the chosen slug as X-Ticketlayer-Channel on everything after. An organisation-scoped role (owner, venue admin, event manager) sees everything and need not pick.. 1 List what is on sale: Operator (box office app) to Backstage API: GET /events (staff JWT, X-Ticketlayer-Channel: box-office); Backstage API to Operator (box office app): full shapes: the operator may see cost and allocation. 2 Make an order: Operator (box office app) to Backstage API: POST /cart, items, POST /cart/{id}/checkout (staff JWT, X-Ticketlayer-Channel: box-office); Comps, manual discounts and seat holds live here, each behind its own permission.; Operator (box office app) to Backstage API: POST /orders/{id}/payments (staff JWT); Cash, or a card on the terminal, driven through Stagehand.. 3 Authenticate a customer: Usually not at all. A walk-up is anonymous, or the operator selects an existing customer, which is "on behalf of" rather than authentication. A customer who signs in at the counter uses the magic link unchanged; the operator is never the customer.. 4 Read the order back: Operator (box office app) to Backstage API: GET /orders/{id} (staff JWT, X-Ticketlayer-Channel: box-office); Amendments, cancellations and refunds are /orders/*: the post-checkout surface for every path.Sign in1 List what is on sale2 Make an order3 Authenticate a customer4 Read the order backOperator (box office app)Identity issuerBackstage APIBox office roles sell at channel scope, so the app offers a picker and sends thechosen slug as X-Ticketlayer-Channel on everything after. An organisation-scopedrole (owner, venue admin, event manager) sees everything and need not pick.Comps, manual discounts and seat holds live here, each behind its own permission.Cash, or a card on the terminal, driven through Stagehand.Usually not at all. A walk-up is anonymous, or the operator selects an existing customer,which is "on behalf of" rather than authentication. A customer who signs in at the counteruses the magic link unchanged; the operator is never the customer.Amendments, cancellations and refunds are /orders/*: the post-checkout surface for every path.OAuth: authorization code + PKCEa staff JWT carrying the organisationstaff JWTGET /my/sales-channelsstaff JWTthe channels this operator has access toGET /eventsstaff JWTX-Ticketlayer-Channel: box-officefull shapes: the operator may see cost and allocationPOST /cart, items, POST /cart/{id}/checkoutstaff JWTX-Ticketlayer-Channel: box-officePOST /orders/{id}/paymentsstaff JWTGET /orders/{id}staff JWTX-Ticketlayer-Channel: box-officeHigh trust: staff, organisation key, deviceWhere the channel comes from

The four moments#

MomentWhat happensCredential
List what is on saleGET /events with the box office channel in the header. Full shapes: the operator may see cost and allocation. Box office staff hold events.list_hidden, so the list also carries the channel's hidden and not-yet-on-sale events, each flagged with its state; the cart still accepts only what is on sale.staff JWT plus X-Ticketlayer-Channel
Make an orderPOST /cart with the channel header, items, POST /cart/{id}/checkout, then POST /orders/{id}/payments for cash or the terminal. Comps, manual discounts and seat holds are here, each behind its own permission.staff JWT plus X-Ticketlayer-Channel
Authenticate a customerUsually not at all. A walk-up is anonymous, or the operator selects an existing customer, which is "on behalf of" rather than authentication. A customer who signs in at the counter uses the magic link unchanged.staff JWT; a customer token only if the customer signs in
Read the order backGET /orders/{id} under the staff JWT. Amendments, cancellations and refunds are the /orders/* surface, which is the post-checkout surface for every path.staff JWT plus X-Ticketlayer-Channel

Who has to pick a channel#

Not every staff role is channel-bound, and the header follows the role.

  • Box office staff sell at channel scope. The box office role holds the selling permissions - list and read events, create and read orders, take payments, manage customers - within the channels the operator has access to. The app calls GET /my/sales-channels at sign-in, offers a picker, and sends the chosen slug as X-Ticketlayer-Channel on every request after. Naming a channel the operator has no access to is a 403; naming none is a 400, never a silent narrowing.
  • Organisation owners, venue admins and event managers hold the same permissions at organisation scope. They see everything and do not have to pick. In Backstage an event manager reads GET /events with no header and gets every event they may see; with a header they get the channel's view, as a convenience filter and nothing more.

Channel access is data, granted and revoked on the channel ("who can sell here", which is GET/POST /sales-channels/{channelId}/access and DELETE /sales-channels/{channelId}/access/{accessId}, behind saleschannels.access.read and .write), not part of the permission grant. Opening a phone channel to a whole box office is one grant of access to the role, and a rota change never touches what the role may do.

A filter is not a boundary#

On the high-trust surface X-Ticketlayer-Channel is a filter and nothing relies on it to withhold data: a request that reached the filter has already passed the access check. Withholding is the low-trust surface's job, structurally. That is why an operator sees full shapes and a buyer on the same channel sees a declared view of the same listing, and why the two agree about what is on sale and what it costs, because both resolve through one listings service.

Set up a box office covers the storefront, the counter calls and scanning at the door.