Authentication
The INVO Network API authenticates server-to-server requests with a single header:X-Game-Secret-Key. Every title has its own SDK key issued at registration. Send the key on every API request. This works the same for a game or a platform: the API calls the tenant a game and names the header accordingly, but a platform tenant sends the same header, with the same key, on the same calls.
Server-to-Server Authentication
Set the SDK key on every request. No login flow, no token refresh, no cookies.
X-Game-Secret-Key: ivsdk_{your_sdk_key}Server-side only. Never embed your SDK key in client builds, mobile apps, or browser code.
Your Server → Invo API
Your backend calls Invo with X-Game-Secret-Key. This is the only auth pattern an integration should use.
Developer Console (Browser)
The developer dashboard at console.invo.network uses session-based login for the human accessing the UI, separate from API auth.
One Key Per Title
Each registered title has a unique secret_key. New keys name their environment: ivsdk_live_<random> for production, ivsdk_test_<random> for test mode. Older ivsdk_<random> keys keep working. Different titles on the same account get different keys. A title that ships on more than one storefront also gets one key per storefront. See Payment Methods.
Sandbox + Production
Two fully isolated environments with independent SDK keys. Use /sandbox/api/... for testing, /api/... for production. A test key (ivsdk_test_) works only in test mode and a live key (ivsdk_live_) only in production.
Quick Example
A complete authenticated call. Replace ivsdk_YOUR_SDK_KEY with the key from your title registration.
// Production
const BASE_URL = 'https://invo.network';
// Sandbox: const BASE_URL = 'https://sandbox.invo.network/sandbox';
const SDK_KEY = process.env.INVO_SDK_KEY; // ivsdk_<random>
const response = await fetch(
`${BASE_URL}/api/player-balances/player/by-email/player@example.com`,
{
headers: { 'X-Game-Secret-Key': SDK_KEY }
}
);
const data = await response.json();
console.log(data);Server-Side Only
Your SDK key authorises every API call as your title. Anyone holding it can move your players' balances. Treat it like a database password.
- ✅ Store in your server's environment variables / secrets manager
- ✅ Make API calls from your backend, never directly from client builds
- ❌ Never commit it to source control
- ❌ Never bundle it into a Unity/Unreal/mobile build
- ❌ Never include it in HTML/JavaScript served to a browser
Getting Your SDK Key
SDK keys are issued automatically when you register a title. Choose the environment that matches your stage:
🧪 Sandbox (Testing)
Register at:
console.invo.network/testTest with virtual cards. No real money. Independent database.
Create your developer account
Email verification, password, profile, ToS acceptance.
Register your title
Registration wizard: art, name, genre, distribution, transfer policy.
Copy your SDK key
Format: ivsdk_live_<random> in production, ivsdk_test_<random> in test mode. Keys issued before the prefix was added start ivsdk_<random> and keep working; nothing to change. Shown in the title settings page, labelled test or live; rotate any time it leaks (the new key always carries the prefix). A live key works only once the title is live.
Start making API calls
Send X-Game-Secret-Key on every request from your server.
Core Endpoints
A handful of endpoints cover most integrations. Auth header is the same on all of them.
const SDK_KEY = process.env.INVO_SDK_KEY;
const BASE = 'https://invo.network';
// Get player's currency balance (auto-creates if writing flow runs first)
async function getPlayerBalance(playerEmail) {
const r = await fetch(
`${BASE}/api/player-balances/player/by-email/${encodeURIComponent(playerEmail)}`,
{ headers: { 'X-Game-Secret-Key': SDK_KEY } }
);
return r.json();
}
// Player buys an in-game item with their currency balance
async function purchaseItem(payload) {
const r = await fetch(`${BASE}/api/item-purchases/purchase-item`, {
method: 'POST',
headers: {
'X-Game-Secret-Key': SDK_KEY,
'Content-Type': 'application/json'
},
body: JSON.stringify(payload)
});
return r.json();
}
// Player sends currency to another player by phone
async function initiateSend(payload) {
const r = await fetch(`${BASE}/api/currency-sends/initiate-send`, {
method: 'POST',
headers: {
'X-Game-Secret-Key': SDK_KEY,
'Content-Type': 'application/json'
},
body: JSON.stringify(payload)
});
return r.json();
}Authentication Errors
401: missing or invalid SDK key
// balance and most REST routes: a message only
{ "message": "Invalid game secret key" }
// /api/sdk/* routes: the code is in "code"
{ "error": "Invalid game secret key", "code": "INVALID_GAME_SECRET" }Verify the header name is exactly X-Game-Secret-Key and the value is your full ivsdk_... string, prefix included.
401: key for the other environment
A test key (ivsdk_test_) sent to production, or a live key (ivsdk_live_) sent to test mode, returns 401 with error_code KEY_FOR_OTHER_ENVIRONMENT and a message naming the right server. Send test keys to https://sandbox.invo.network/sandbox and live keys to https://invo.network. Retrying the same call does not help.
403: title inactive
Your title's status isn't live or testing. Check the developer console.
403: account suspended
Any write call made with a suspended account's keys returns 403 with error_code ACCOUNT_SUSPENDED. Reads keep working. A closed account answers the same way. While an account is suspended, payments and payouts stop, and renewals of existing subscriptions are held without charging the member. If INVO closes the account for risk, the closure becomes final once the appeal window ends, and the live subscriptions in your games are canceled. Players keep their balances. See account standing. Contact INVO support.
403: payments paused
When INVO has paused payments on an account, calls that start a new payment (a coin purchase, a hosted checkout session, a Platform Commerce card purchase, a new subscription, a Steam purchase or subscription) return 403 with error_code PAYMENTS_PAUSED (the hosted checkout and wallet routes name the field code). Refunds, reads, balances, transfers and renewals of existing subscriptions keep working. Payouts are held while payments are paused: a new payout request (POST /api/partner-payouts/request) returns 403 PAYMENTS_PAUSED, and payouts already requested are paid once payments resume. Contact INVO support.
429: rate-limited
You've exceeded the per-IP or per-key request budget for that endpoint. Body includes a retry_after seconds value; back off accordingly.
Rotating Your SDK Key
Rotate a key from the developer console (Platform & Keys) at any time. A normal rotation keeps the old key working for a grace period so you can cut over; a rotation with {"immediate": true} revokes the old key on the spot, for a key you believe is exposed. The current key stays readable on Platform & Keys, and the key a title starts with is also emailed to you when you register it.