An outlet or reseller
A third-party business selling on your behalf is an account with a channel. Its staff arrive with a staff JWT and its EPOS with a secret key, and the money moves through the ledger: the sale posts a receivable, and a settlement clears it later.
An outlet is a third-party business that sells on the organiser's behalf: a record shop, a tourist office, a ticket agency with its own EPOS. It is an account, not a credential kind. The account is the business relationship; the channel is the terms it sells under - its own listings, its own fee profile, its pinned payment method; and the credential is only how a given actor arrives.
The credentials. Two of them, reaching one account and one channel. The
outlet's staff sign in to Backstage and carry a staff JWT (high trust),
naming the channel in X-Ticketlayer-Channel. The outlet's EPOS calls
the API with a secret key (tlsk_, medium trust) issued for the same
channel, which names the channel itself. Same permissions, same
access; "is this staff or a partner" is never the question.
The four moments#
| Moment | What happens | Credential |
|---|---|---|
| List what is on sale | GET /events with the outlet's channel. The channel's event filter decides what is visible. | staff JWT plus the header, or tlsk_ |
| Make an order | POST /cart, items, POST /cart/{id}/checkout. The channel's pinned payment method applies, so an outlet cannot accidentally take a card through the organiser's provider. | staff JWT plus the header, or tlsk_ |
| Authenticate a customer | Usually not at all: the outlet is the customer of record. Otherwise a partner identity assertion, as on a partner storefront. | either credential; a customer token only if a buyer signs in |
| Read the order back | GET /orders/{id}, scoped to the channel under either credential. | staff JWT plus the header, or tlsk_ |
The money#
An outlet that takes cash at its counter owes the organiser for what it sold. That is not a new subsystem; it is a payment method plus a journal cause:
- The channel's pinned payment method is on account. Checkout on the outlet channel does not take a card through the organiser's provider; it records that the outlet will settle.
- The sale posts a receivable. When the order is confirmed the ledger
posts a journal from the outlet's account to the organiser's, keyed on
the cause (
causeType,causeId), and that uniqueness is the idempotency: one order posts once. - The balance is read from the ledger.
GET /ledger/balancesfor the organiser's account shows what the outlet owes, per counterparty and per currency;GET /ledger/statementshows the postings behind the figure. Currencies are never summed. - A settlement clears it. When the outlet pays, the organiser records it
with
POST /ledger/settlementsand the balance moves towards zero. An over-payment leaves the direction reversed, not clamped: the ledger says "you owe" or "owed to you" in words, never a bare sign.
Two zeros read differently. A balance of zero with postings behind it is an outlet that is paid up; a balance of zero with none is an outlet that never traded. Backstage's Finance section shows which is which, and so does the statement.
Why the credential is not the model#
user_account_roles(user, account, role) and the channel's accountId
carry the whole thing. The outlet's staff hold a role on the outlet's
account; the outlet's channel belongs to that account; access resolves
only when the user holds the role on the account the channel names. Without
that last condition, granting a role the phone channel on one account would
grant it on every account's phone channel. The EPOS is granted nothing:
its secret key is bound to the one channel, structurally.