No SDK, nothing runs on the device side. You hold an API key, you name a box, you pass a URL. This page is the entire integration — the machine-readable version is openapi.json in the console repo.
Create an API key in the console with the devices:trigger scope. It's shown once — store it like a password. Every request carries it as a bearer token.
One POST. The Idempotency-Key header is required — retry with the same key and you get the stored response back, never a double charge.
The URL must be http(s), at most 2048 characters. We never fetch, render, or store what's behind it — it goes straight into the QR.
The URL is the whole contract. We never fetch, inspect, or constrain what's behind it — a receipt, a warranty registration, a loyalty card, a ticket, a survey, a menu all travel through the same show_qr trigger, cost the same one credit, and fail the same honest way. If a phone browser can open it, the box can hand it over. New interaction types are pages you build, not endpoints you wait for.
202 means queued, not shown. Within a couple of seconds the box displays the code and confirms it — that confirmation spends the held credit. If the box can't confirm within 60 seconds, the request expires and the hold is released in full. A late code never appears.
There is no status endpoint or callback yet — that's deliberate minimalism at this stage, not an accident. Billing is self-reconciling (you're only ever charged for confirmed showings); the console's activity and credit ledger show every command's outcome, and GET /api/v1/usage returns your organisation's usage programmatically. If your integration needs a per-command status call, tell us — it's on the roadmap.
Beyond the transient trigger, a box (or a whole store, or the whole organisation) can hold a pinned QR — a menu, a wi-fi login, a review link that stays up until you change it. POST /api/v1/devices/{id}/pin (also /stores/{id}/pin, /org/pin). Setting a pin spends one credit immediately — a pin can't fail to display, so there's nothing to hold.
The console and API are developed in the open. Read the source, open an issue, or just write — the person answering is the person who wrote the code.