Partner Credentials & Key Handling
Everything your integration needs comes down to three credentials and two rules. This page is the canonical reference for what each key is, where it lives, and how to handle it safely.
Your tenant gets three things
| Credential | Lives | What it's for |
|---|---|---|
| game_id | Anywhere | Your tenant id. Not secret. |
| SDK secret_key ivsdk_… | Server-side ONLY | Sent as the X-Game-Secret-Key header to mint player tokens and for server-to-server calls. |
| Webhook signing secret | Server-side ONLY | Used to verify the webhooks we send you. It is NOT sent in requests to us. |
Where to find them
- • game_id and the SDK secret_key: on the dashboard's Platform & Keys page (user menu, top-right → Platform & Keys → pick your game). The key has a reveal/copy affordance and a self-serve rotate.
- • Webhook signing secret: shown once when you create the webhook on the dashboard's Webhooks page (and again on each rotation). Store it then; it isn't retrievable later.
Never put a secret in a frontend bundle
Anything in a browser build (Vite/React, etc.) is world-readable. The ivsdk_… secret and the webhook signing secret are server-side credentials. They must never ship to the client.
Two rules that matter
1. The browser never holds the SDK key
Your server mints a short-lived player token; the browser uses that for every /api/sdk/* call.
POST /api/sdk/player-token
Header: X-Game-Secret-Key: <SDK secret_key> // server-to-server ONLY
Body: { "player_email": "user@example.com" } // player must exist in your tenant
→ { "token": "<player token>", // Authorization: Bearer <token>
"expires_at": "...Z", // ~15-min lifetime, NO refresh
"identity_id": "id_…" }
// On a 401 from any /api/sdk/* call → mint a fresh token and retry.2. Verify every webhook
X-Invo-Signature: t=<ts>,v1=<hmac> is HMAC-SHA256 over the literal string "<timestamp>.<raw_body>", keyed with your signing secret. Verify constant-time, reject if the timestamp is outside a 5-minute window, and de-duplicate on X-Invo-Idempotency-Key.
Full reference + verify snippet: Receiving Webhooks.
Web platforms: passkey step-up
WebAuthn runs on your origin
Web platforms enroll a passkey on login and approve high-value transfers/sends with an assertion. The ceremony runs in the browser on your web origin, which must match the relying-party ID configured for your tenant. You configure the domain yourself on the dashboard's Platform & Keys page: submit the RP ID and origins, prove domain ownership with a DNS TXT record, and step-up turns on when verification passes. Un-enrolled users fall back to SMS automatically. See Platform Step-Up (WebAuthn).
Sandbox only: the clock key
A fourth credential, if you test subscriptions
The three above are everything a production integration needs. Sandbox adds one more, and only if you use the subscription time-travel endpoints (the ones that let you make a renewal due, bill it, fail it, or force a step-up challenge without waiting a month). Those calls require X-Sandbox-Clock-Key in addition to X-Game-Secret-Key.
- • Why two. One of those endpoints genuinely charges a test card on demand. A leaked SDK key should not also be a charge-on-demand button, so the second factor is a separate credential. It is deliberately not retrievable using the SDK key, or it would not be a second factor at all.
- • Where to get it. Per game, from the sandbox developer API:
GET /sandbox/api/dev/games/{game_id}/sandbox-clock-key(the first call mints it). A console screen is on the way; until it ships, that endpoint is how you get one. It authenticates with your dashboard session token (Authorization: Bearer …, signed in as the developer who owns the title) and not withX-Game-Secret-Key, which is the point: if the SDK key could fetch this one, the SDK key would again be sufficient on its own. Full walkthrough on Sandbox Testing. - • Rotation. Self-serve at
POST …/sandbox-clock-key/rotate, same session auth. By default the previous key keeps working for a 7-day grace window so a test run already in flight does not break, the same dual-key handling as the SDK key below. A leaked clock key is the exception: send{"immediate": true}to revoke the old value on the spot, or the grace window keeps a charge-on-demand credential live for a week. - • There is no production version of this key, because the endpoints it opens do not exist in production. Server-side only, like every other secret on this page.
Key rotation
Every key rotates self-serve, each with a 7-day grace window
- • The SDK secret_key rotates from the dashboard's Platform & Keys page (user menu → Platform & Keys → your game → Rotate key). The old key keeps working for 7 days so your integration can cut over without downtime. The new key is shown once in a copy dialog, and the page banners the grace deadline.
- • The webhook signing secret rotates from the dashboard's Webhooks page, also with a 7-day grace window. Deliveries are dual-signed (two
v1=values) so you can deploy the new value without downtime.X-Invo-Secret-Versiontells you which is current. - • The sandbox clock key (above) rotates at
POST /sandbox/api/dev/games/{game_id}/sandbox-clock-key/rotate, also with a 7-day grace window by default. - • If a key is ever exposed, rotate it immediately, and check that "immediately" is what you actually got. For the SDK key and the signing secret, rotate from the console and treat the grace window as the window in which the exposed value still works, so cut over and let it lapse. For the sandbox clock key, the default rotation is not a revocation: pass
{"immediate": true}or the leaked key stays live for 7 more days. Don't wait on us, and never share keys in chat or commit them to a repo.