Panel — QR & Terminals
- Base path
/api/panel/v1/wallet- Identity
- Panel session (JWT) —
Authorization: Bearer <panel access token>. The token comes from panel login; an s2s signing key does NOT open these endpoints. - Authorization
- RBAC permission:
wallet:qr:read·wallet:qr:manage·wallet:terminal:read·wallet:terminal:manage·wallet:sponsor-policy:manage·wallet:sponsor-policy:approveFour-eyes: the requester and the approver cannot be the same person — this is enforced by identity comparison, not by a role gate. - Cross-surface
- Only four QR endpoints are shared (
POST qr,GET qr,GET qr/:id,POST qr/:id/revoke); s2s additionally carriesGET qr/:id/imageandPOST qr/parse. The whole terminal-management and QR producer-code surface (18 endpoints) is panel-only — device provisioning, credential issue/rotate/revoke, suspend, bulk actions and producer-code approval cannot be called with a signing key.
Where you manage your physical acceptance points and QR codes.
QR management
GET qr # codes (filter by programId, qrType, status, targetEndUserId)
POST qr # generate
GET qr/:id
POST qr/:id/revoke # revokeGeneration and payment flow: QR.
Track active codes here rather than keeping your own code ledger. A suspicious code can be invalidated instantly with revoke.
Producer codes
GET qr/producer-codes
POST qr/producer-codes
POST qr/producer-codes/:id/approve
POST qr/producer-codes/:id/retireA producer code identifies the institution inside a standard QR scheme. It is managed with approval and retirement steps.
Producer codes become meaningful with a standard QR scheme. Today's format is closed loop and carries no institution identity. This section activates when a standard scheme is supported. Status: Roadmap · QR — Interoperability.
Terminals
GET terminals # filter by q, storeCode, status; cursor pagination
POST terminals # create
GET terminals/:id
PATCH terminals/:id
GET terminals/:id/events # terminal event historyTerminal fields: bound business account, label, form factor, store and lane code, per-transaction cap (perTxnCap + perTxnCapCurrency), credential id.
The currency of the per-transaction cap
perTxnCap is not a bare number: perTxnCapCurrency always travels with it. That field is not accepted from the caller — it is derived from the currency of the business account the terminal is bound to.
The reason is directly a security one: if the request body could set the cap's currency, writing "cap = 10000 USD" would be a way to widen a TRY cap, and the cap would lose its meaning.
The two exist together or not at all: you cannot store a cap without a denomination, or a denomination without a cap. Removing the cap clears the currency too.
In a multi-currency program the same "10,000" means a very different real ceiling on a TRY terminal and on a USD one. Choosing the terminal's business account is also choosing the currency the cap is enforced in.
If the cap's currency differs from the operation currency, the operation is rejected — no FX conversion is performed.
Fill in storeCode and laneCode from the start. As the estate grows, reporting and bulk actions rely on them; backfilling later becomes manual cleanup.
Activation and credentials
POST terminals/:id/activation # issue an activation code ({ ttlMinutes })
POST terminals/:id/credential # bind a credential
POST terminals/:id/rotate-credential # rotate
POST terminals/:id/revoke-credential # revokeA terminal is commissioned in the field with a short-lived activation code.
When a terminal is lost or stolen, revoke its credential (revoke-credential) — suspending is not enough. Requests carrying a revoked credential are rejected.
Lifecycle
POST terminals/:id/suspend # { reason }
POST terminals/:id/resume
POST terminals/:id/retire| Action | Effect |
|---|---|
| Suspend | The terminal cannot transact; reversible |
| Resume | Lifts the suspension |
| Retire | Permanently decommissions it |
Bulk actions
POST terminals/bulk # bulk creation (row list + activation TTL)
POST terminals/bulk-suspend # bulk suspensionBulk suspension works by terminal id list, store code, or the whole tenant.
allInTenant: true suspends every terminal — acceptance stops completely. Use it only for deliberate situations such as a security incident, and record the reason.
Reporting
GET reports/terminalsPer-terminal transaction reporting, filterable by store code, status and date range.
Checklist
- Terminal labels, store and lane codes filled in consistently
- Per-transaction cap (
perTxnCap) configured andperTxnCapCurrencyis the currency you expect - Activation codes delivered to the field over a secure channel
- Credentials revoked for lost/stolen terminals
- Retired terminals cleaned out of the list