Authentication
Every request to /api/payments/v1/ except enrollment carries a device
credential:
Authorization: Bearer sit_pd_<hex>Enrollment: one code, one claim
Section titled “Enrollment: one code, one claim”A device is registered by the restaurant owner in Sitora Biz, then armed with a one-time enrollment code. Claiming it is the one anonymous operation on this surface — the code is the secret, so the endpoint is IP-throttled and unknown, spent, and expired codes all answer identically.
The claim returns the credential exactly once. Sitora stores only a hash; there is no endpoint that returns your key again.
Issuing a fresh enrollment code is also the reset lever: it revokes every live credential for that device first, so an old key and a claimable code are never valid at the same time.
The credential is a machine principal
Section titled “The credential is a machine principal”A device credential is not a user account. It has no membership, no role, and no staff permissions. It can never author an order, a transaction, or a session, and it never appears as the actor on anything.
Staff working at a device — a cashier on a smart POS — authenticate as themselves with their normal Sitora Pro session. One request is always exactly one principal: the human acts ride the staff session, the device plane rides the device credential. Do not attempt to use one for the other.
Scoping is derived, never claimed
Section titled “Scoping is derived, never claimed”The credential resolves to exactly one device, which belongs to exactly one station in exactly one filial. You never send a filial or station identifier — Sitora derives them from the key. A credential for one till cannot see another’s work, even inside the same restaurant.
Scopes follow capabilities
Section titled “Scopes follow capabilities”| Scope | Granted when the device declares | Grants |
|---|---|---|
device:heartbeat |
always | Heartbeat and self snapshot |
device:display |
qr_dynamic_present or customer_total_display |
The display queue |
intents:read_assigned |
payment_app_handoff |
Reading the assignment |
intents:report_handoff |
payment_app_handoff |
Reporting an outcome |
Because scopes are derived from capabilities, changing a device’s capabilities means re-enrolling it — which is why issuing a code revokes the old key.
Standing is re-derived on every request
Section titled “Standing is re-derived on every request”Authorization is not decided once at enrollment. Every request re-checks that the platform is not frozen, the device is active, its station is active, and the filial is active. A pause therefore takes effect on the very next call, mid-shift, with no cache to wait out.
A refusal names its reason:
| Reason | Meaning |
|---|---|
platform_frozen |
Provider-driven collection is frozen platform-wide (displays only) |
device_paused / device_retired |
The owner paused or retired this device |
device_not_enrolled |
The device is awaiting a fresh enrollment claim |
station_retired |
The station this device serves was retired |
filial_inactive |
The branch is not active |
Handle 401 by escalating for a new enrollment code, not by retrying: a
revoked key never becomes valid again. Handle 403 by displaying the reason
and continuing to heartbeat — standing can come back without any action from
you.