Server-side verification
The wallet identifies the player; your backend is the relying party that trusts it. Never trust a user id or wallet address claimed by the browser — verify the player’s wallet session server-to-server with your secret key, then mint your own app session.
The flow
1. The player signs into the wallet in your frontend (Telegram / browser wallet / email) → the SDK returns a session token.
2. Your frontend sends that token to your backend.
3. Your backend calls POST /v1/sessions/verify with your sk_ key and the token. The wallet confirms it, scopes it to your app + environment, and returns the canonical identity.
4. Your backend looks up / creates its own user and issues its own JWT for your UI — trusting the verified identity, not the client.
1 · Get your secret key
In the developer portal, open your app and reveal the secret key (sk_test_… for sandbox, sk_live_… after live approval). It is shown once — store it as a backend secret (never ship it to the browser). Lost it? Rotate it from the same panel.
2 · Verify the session
Backend SDK (recommended):
import { IAMGameWalletServer } from "@iamgame/wallet-sdk-server"
const wallet = new IAMGameWalletServer({
secretKey: process.env.IAMGAME_WALLET_SECRET_KEY, // sk_live_… or sk_test_…
baseUrl: "https://api-wallet.iamgame.com/v1",
})
// In your login handler — the browser sent you the player's wallet session token.
export async function login(req, res) {
const { sessionToken } = req.body
// Verify against YOUR app + environment. Throws if the token is invalid,
// expired, or not in your app's scope/environment.
const id = await wallet.verifySession(sessionToken)
// id = { userId, appId, environment, walletAddress, wallets[], identities[] }
// Look up / create YOUR own user, keyed to the canonical wallet identity.
const user = await db.users.upsert({ walletUserId: id.userId, address: id.walletAddress })
// Mint your OWN app JWT — never trust a user id the browser claims.
const appJwt = signYourJwt({ sub: user.id })
res.json({ token: appJwt })
}Or call the endpoint directly:
curl -X POST https://api-wallet.iamgame.com/v1/sessions/verify \
-H "Authorization: Bearer $IAMGAME_WALLET_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{ "sessionToken": "<player wallet session token>" }'POST /v1/sessions/verify · auth Authorization: Bearer sk_… · body { sessionToken }. The endpoint is secret-key only — it must never be called from the browser.
Response
The canonical, verified identity for the player:
{
"userId": "c8d85dc9-…",
"appId": "5a00769e-…",
"environment": "test",
"authMethod": "telegram",
"walletAddress": "J8gpeci3qKpYC34pw1Sk4XLncMawipDXGtLtVfoEq7mq",
"wallets": [
{ "address": "J8gp…", "environment": "test", "custody": "self", "status": "active" }
],
"identities": [
{
"id": "…",
"type": "telegram",
"externalId": "6931997952",
"profile": { "username": "karpi", "firstName": "Piyush" }
}
]
}userId — the wallet’s stable user id (your join key).walletAddress / wallets[] — the player’s managed address(es); lets you confirm an on-chain address belongs to this user.identities[] — each login identity with its captured profile (e.g. the Telegram username), for display and cross-app attribution.
3 · Mint your own session
With the verified identity, upsert your own user and issue your own JWT (or cookie). From here your game endpoints authenticate against your token — the wallet session is only ever used at this verify step.
Errors
401 — bad / missing secret key.403 auth/invalid_token — the session is not in your app’s scope or its environment doesn’t match your key (a test session presented with a live key is refused). Fails closed.404 user/not_found — the session’s user no longer exists.
Scope & isolation
Verification is bound to your key’s scope and environment. Apps in the shared (default) scope resolve the same portable user across the ecosystem — the same player has one wallet address everywhere. An isolated app (e.g. a regulated entity) has app-private users and wallets: only that app’s key can verify its sessions. Choose isolation at app creation when a tenant’s users must never be resolvable from anywhere else.