In-App Verification
The modern way to verify cross-game transfers and player-to-player sends — the player approves right inside your app with a hardware-backed signature, instead of typing an SMS PIN. It is faster, dramatically reduces SMS costs, and resists SIM-swap attacks that a texted code cannot.
Why in-app verification
SIM-swap resistant
Approval is a signature from a key sealed in the device's secure hardware — it can't be intercepted or forwarded like an SMS code.
Fewer SMS, lower cost
The in-app prompt replaces the per-step verification text. SMS stays only as a fallback for players who don't have the app.
Seamless UX
The player taps approve in your game — no leaving the app to read a text and type a code back.
Additive and opt-in — nothing you have today breaks
In-app verification is a new, parallel set of endpoints under /api/sdk/*. Your existing initiate → verify-sms → claim integration is unchanged and keeps working.
It is enabled per game. Your game stays entirely on the SMS flow until Invo enables in-app verification for it (coordinated with you, after your plugin is live and tested). Players without the app continue to receive the SMS PIN as before.
How the flow works
ENROLL (once, on login)
Your server ──(X-Game-Secret-Key)──▶ POST /api/sdk/player-token ──▶ player token ──▶ device
Device generates a hardware keypair ─▶ POST /api/sdk/device/register (sends the PUBLIC key only)
PER TRANSFER / SEND
Your server starts it as normal (initiate-transfer / initiate-send).
The device polls GET /api/sdk/transfers/pending (the authoritative to-do list)
The player taps approve; the device SIGNS the action and calls
POST /api/sdk/transfers/{id}/approve (self-transfer)
POST /api/sdk/send/{id}/approve (player-to-player send)
For a SEND, the receiver confirms in their app:
POST /api/sdk/send/{id}/confirm-receipt
FALLBACK
A player without the app uses the existing SMS PIN flow (verify-sms) exactly as today.A push is not required — the device polls GET /api/sdk/transfers/pending on open and while in the foreground to discover what needs approval. That endpoint is always the source of truth.
The auth model (read this first)
Never put your game secret on the device
The X-Game-Secret-Key is server-side only. The device authenticates as the player, using a short-lived player token your server mints for it. A secret on the client is a leaked secret.
| Credential | Lives where | Authenticates | Used for |
|---|---|---|---|
| X-Game-Secret-Key | Your server only | The game | Minting player tokens; your existing server APIs |
| player token | The player's device | The player | Every /api/sdk/* call from the device (as Authorization: Bearer) |
The player token is short-lived (15 minutes) and there is no refresh call. On a 401, mint a fresh one via your server's /api/sdk/player-token call and retry — never re-prompt the player just to refresh.
The endpoints
/api/sdk/player-tokenServer mints a short-lived player token (X-Game-Secret-Key)
/api/sdk/device/registerRegister the device + its hardware public key
/api/sdk/transfers/pendingThe authoritative list of actions awaiting this player
/api/sdk/transfers/{id}/approveApprove a self-transfer with a device signature
/api/sdk/send/{id}/approveApprove a player-to-player send (sender side)
/api/sdk/send/{id}/confirm-receiptReceiver confirms an incoming send
/api/transfers/{id}/statusServer-side: detect one transfer’s verification completion (X-Game-Secret-Key)
/api/currency-sends/{id}/statusServer-side: detect one send’s verification completion (X-Game-Secret-Key)
Getting started
- Integrate the Invo plugin / SDK in your client (Unity / Unreal / native).
- On login, have your server mint a player token and the device register itself (Device Enrollment).
- Poll
/api/sdk/transfers/pendingand render the approve / confirm prompts (Approve in App, Confirm Receipt). - Test in sandbox. When you're ready, Invo enables in-app verification for your game — players migrate as they update; SMS stays as the fallback.