Device Approval (Consoles & TVs)

A console has no browser, so it cannot run a passkey ceremony at all. Device Approval moves the ceremony to a device that can: your game shows a short code, the player approves on their phone, and your game polls until it hears back. It is the OAuth 2.0 Device Authorization Grant (RFC 8628) — the same “enter this code on your phone” flow every console and TV app uses — so you can reach for an existing client library rather than write one.

When you need it

Use this anywhere the device running your game cannot perform WebAuthn: consoles, TV apps, and native desktop builds without a real browser origin. You do not need it on web, iOS or Android — those run the ceremony in-process.

It is available to every title, with nothing to configure

The constraint is a property of the device, not of your game. A title that ships a website and a console build uses the normal ceremony in the browser and this one on the console. There is no flag to set and no domain to verify — the ceremony happens on INVO’s own domain, which is the whole point.

The flow

1. Your server starts an approval

After you initiate a transfer, ask INVO to start an approval for that transaction. You get back a short code, two URLs, a device code, a poll interval and an expiry.

2. Your game shows the code and a QR

Render verification_uri_complete as a QR code and print the user_code underneath. The QR already contains the code, so most players scan and never type anything.

3. The player approves on their phone

They land on an INVO page, see what they are approving, and confirm with their passkey — fingerprint, face or screen lock. Nothing about this step touches your servers.

4. Your game polls until it hears back

Poll with the device code at the interval INVO gave you. You can also subscribe to the device_approval.approved webhook and learn the moment it lands, instead of waiting for the next poll.

Starting an approval

Server-to-server, with the player’s SDK session token. flow is the action being approved: transfer, send, send_receipt or transfer_receipt.

POST /api/sdk/approvals/device/begin
Authorization: Bearer <sdk_session_token>
Content-Type: application/json

{
  "transaction_id": "TXN_...",
  "flow": "transfer"
}
200 OK
{
  "device_code": "b1s4...",                 // secret; keep it on your server
  "user_code": "K7QP-3MRD",                 // show this
  "verification_uri": "https://invo.network/device",
  "verification_uri_complete": "https://invo.network/device?user_code=K7QP-3MRD",
  "expires_in": 600,
  "interval": 5
}

Polling

Poll no faster than interval seconds. The error codes are the RFC 8628 ones, so a standard client understands them without translation.

POST /api/sdk/approvals/device/poll
Authorization: Bearer <sdk_session_token>

{ "device_code": "b1s4..." }
ResponseMeaningWhat to do
status: approvedThe player approvedContinue — complete the transfer
authorization_pendingNot yetKeep polling at interval
slow_downYou are polling too fastBack off, then resume
expired_tokenThe code timed outStart a new approval
access_deniedThe player declinedStop; do not retry silently
invalid_grantUnknown or not yoursStart a new approval

The completion webhook

Subscribe to device_approval.approved and your server hears the moment an approval lands. Polling still works on its own — the webhook is a latency improvement, not a replacement, and you should not rely on it as your only signal.

{
  "event": "device_approval.approved",
  "schema_version": "1.0",
  "data": {
    "transaction_id": "TXN_...",
    "flow": "transfer",
    "identity_id": "9f2c...",
    "method": "device_grant_webauthn"
  }
}

Rules worth knowing

One approval authorises one transaction

Unlike the plain RFC 8628 grant, which authorises a client, an INVO device code is bound to the single transaction you named and is consumed when it is used. It cannot approve anything else, and it cannot be reused.

Codes are short-lived, and only one is live per transaction

A code expires in minutes. Starting a second approval for a transaction that already has a live one returns 409 DEVICE_APPROVAL_ALREADY_PENDING — reuse the code you have, or wait for it to expire.

Keep the device code on your server

The user_code is meant to be seen; the device_code is not. Poll from your backend, not from the game client.

The player needs an INVO passkey

The approval page uses a passkey registered with INVO. A passkey a player set up on your domain is a different credential and cannot be used here — that is how passkeys work, not a limitation of this flow. The page tells them plainly when they need to set one up.

What this is not for

Currency purchases on a console go through that console’s own store, as required by the platform holder. This flow is for approving transfers and sends — moving currency a player already has.