Request a single-use manager elevation grant
PRIVILEGE ESCALATION. Presents a manager’s subject and PIN and, on success, mints a short-lived SINGLE-USE token carrying exactly ONE pos.* scope, to be spent as the x-elevation-token header on one later POST /v1/checkout/finalize. The cashier’s session is never touched: no token is re-issued and no scope is added to it.
DO NOT CALL THIS AS AN AGENT. It requires a human’s PIN, and the correct actor is the till that has a manager standing in front of it. An automated caller either does not have the PIN (and every attempt burns a failure against that manager’s account, locking them out of their own till after a few tries) or has been given one it should never hold. Issuing cannot be undone: there is no revoke endpoint, and the minted grant stays spendable for its ~5-minute window. If a sale needs manager approval, surface that to a human and stop.
Parameters, in domain terms: managerSubject is the approving manager’s identity, pin their own enrolled PIN, operation the governed act (discount.line for a single line, discount.ticket for the whole ticket), and amountCents / percentBps how big the till BELIEVES the reduction is. That magnitude is a UX input only — it decides whether approval is demanded, never what the sale may be: finalizeSale re-prices the cart server-side, so understating it yields no token and overstating it yields a token for the same single scope.
Reading the outcome: 201 returns the grant — scope is a SINGLE string (a grant that could carry a list is a grant that can accumulate), expiresAt an ISO instant. 401 INVALID_CREDENTIAL covers BOTH a wrong PIN and an unknown manager, deliberately, so the endpoint does not confirm which subjects exist — never treat it as ‘that manager does not exist’. 403 means the PIN was right but that manager cannot exercise the authority (MISSING_AUTHORITY) or their cached scopes are stale (GRANTS_STALE). 422 means the policy says no elevation is needed at this size (NO_ELEVATION_REQUIRED) or the channel is unavailable — in the first case just finalize the sale without a token. 429 is a lockout or the per-manager rate limiter; honour Retry-After and do not retry sooner. ERROR-ENVELOPE TRAP: the failure bodies keep the usual { error: { code, message, statusCode } } shape, but code here is a CHANNEL vocabulary, not the kernel ResultCode enum the shared ErrorResponse component lists. Expect values the schema does not enumerate and branch on them as opaque strings. A 429 is also reachable and is NOT in the documented response set.
Authorizations
Authorization: Bearer <token>. Accepts EITHER a Keycloak access token (scopes-in-token) OR an opaque POS session token; both resolve to the same pos.* scope vocabulary the route guards enforce.
Body
11discount.line, discount.ticket 0 <= x <= 90071992547409910 <= x <= 9007199254740991Response
The issued grant: one manager, one scope, one operation, one use.
The issued grant: one manager, one scope, one operation, one use.
discount.line, discount.ticket ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d(?:\.\d+)?)?(?:Z))$
