Player sessions
Your server tells the platform who the player is. There is no sportsbook login for your players: the call below is the login, authenticated by your API key. The platform finds the player by your id (or creates them), opens a session and returns a single-use launch token for the iframe.
- Endpoint, server to server
- POST /api/v1/integration/sessions
- Launch token
- single use, 120 s
- Session
- 12 h absolute, idle timeout
Create a session
Section titled “Create a session”POST /api/v1/integration/sessionsContent-Type: application/jsonX-Tenant-ID: demo-embedX-API-Key: <your integration API key>
{"externalPlayerId": "player-42", "displayName": "Maria", "path": "/live", "locale": "pt-BR"}| Field | Type | ||
|---|---|---|---|
externalPlayerId |
string | required | Your stable player id, at most 128 characters. The same id is always the same player; it is the playerId of every wallet call. |
displayName |
string | optional | Shown in the sportsbook, at most 64 characters. Updated when it changes. Default Player. |
currency |
string | optional | Must equal the tenant currency when sent. |
cpf |
string | BR tenants | The player’s CPF, digits or formatted (529.982.247-25). See Brazil. |
path |
string | optional | Deep link put in launchUrl: /, /live, /live/{sportId}, /sport/{sportId}, /competition/{id}, /event/{eventId}, /my-bets. |
locale |
string | optional | en or pt-BR, put in launchUrl. Default: the tenant locale. |
Unknown fields are refused (400 validation), so typos do not pass silently.
Response
Section titled “Response”200 OK:
{ "launchToken": "lt_NIpjVSCtwQlG0iLUbF9T7WeY84YSVs3pVQeLxbbH1O0", "launchExpiresAt": "2026-10-16T03:01:22.081091Z", "launchUrl": "https://sportsbook.example.com/?tenant=demo-embed&launch=lt_NIpjVSCtwQlG0iLUbF9T7WeY84YSVs3pVQeLxbbH1O0&path=%2Flive&locale=pt-BR", "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9…", "player": { "id": "pl_bd387263c326f44e90808bde", "tenantId": "demo-embed", "externalId": "player-42", "status": "active", "displayName": "Maria", "currency": "USD", "kycStatus": "verified", "createdAt": "2026-10-16T02:43:38.465403Z" }}| Field | |
|---|---|
launchToken |
Give this to the page: pass it to the embed SDK (launchToken option or setLaunchToken()). Single use, expires at launchExpiresAt. |
launchUrl |
The same token as a ready-made iframe URL, for integrations without the SDK. |
token |
The session token itself. Keep it on your server (or ignore it): never put it in a URL or a page. It stays in the response for backward compatibility. |
player |
The platform’s player record (abridged above). kycStatus is verified because identity checks are delegated to you, which is recorded as evidence. |
The origin of launchUrl is the platform’s configured sportsbook URL
(SPORTSBOOK_URL); when unset, the origin your request was sent to.
Errors
Section titled “Errors”| Status | code |
When |
|---|---|---|
| 401 | unauthorized |
Missing or wrong X-API-Key, or the tenant has no key. Every failure is audited with the caller’s IP. |
| 400 | validation |
Bad field; details.field names it (externalPlayerId, displayName, currency, cpf, path, locale), or an unknown field. |
| 403 | account_blocked |
The player is blocked or closed on the platform. |
| 403 | prohibited_bettor, self_excluded |
BR: the CPF is on the prohibited-bettor list or in the national self-exclusion system. |
| 404 | not_found |
Unknown tenant (X-Tenant-ID). |
| 503 | unavailable |
The tenant is suspended, or a compliance provider is down. Retry later. |
Launch tokens
Section titled “Launch tokens”A launch token is how the session reaches the iframe without ever being put in
a URL. The sportsbook exchanges it once, at start-up or when it receives
set_launch_token:
POST /api/v1/integration/launchContent-Type: application/jsonX-Tenant-ID: demo-embed
{"launchToken": "lt_NIpjVSCtwQlG0iLUbF9T7WeY84YSVs3pVQeLxbbH1O0"}{ "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9…", "player": { "id": "pl_bd387263c326f44e90808bde", "…": "…" } }You never call this endpoint yourself; the iframe does. It keeps the session
token in memory and in sessionStorage for that iframe, and removes launch
from its own address before anything else loads.
| Rule | |
|---|---|
| Single use | The exchange marks the token used in the same database statement: a second exchange (a replayed or shared URL, the browser history) gets 401 with details.reason: "launch_token_used", and the replay is audited. |
| Expiry | 120 seconds after it was issued (launchExpiresAt): 401, launch_token_expired. Create the session right before you render the sportsbook. |
| Tenant | A token only works for its own tenant: elsewhere it is launch_token_invalid, like an unknown token. |
| Session | The session must still be alive: a logged-out or expired session gives 401 (unauthorized or session_expired). |
| Storage | Only a SHA-256 hash of the token is stored. Used and expired tokens are deleted after a day. |
When the exchange fails at start-up, the sportsbook stays anonymous and sends
your page an error event (code = the reason) followed by
session_expired, so the SDK’s onSessionExpired can fetch a fresh token.
Session lifetime and refresh
Section titled “Session lifetime and refresh”- A session lasts at most 12 hours and ends after the jurisdiction’s idle
timeout (60 minutes for
.comtenants, 30 minutes for Brazil). Every authenticated call from the iframe (balance, bets, My Bets) counts as activity; browsing odds does not. - Each call to
integration/sessionsopens a new session; earlier sessions of the player keep working until they expire. When the player logs out of your site, calllogout()on the SDK to end the sportsbook session too. - To refresh, call
integration/sessionsagain and send the new launch token to the iframe. With the SDK, return it fromonSessionExpired:
BookmakerSportsbook.mount('#sportsbook', { url: 'https://sportsbook.example.com', tenant: 'your-tenant', launchToken, // called when the sportsbook session ends (idle, expiry, refused token) onSessionExpired: async () => { const res = await fetch('/my-site/sportsbook-launch', { method: 'POST' }); // your endpoint return res.ok ? (await res.json()).launchToken : null; // null: stay logged out },});The same mechanism logs a player in without reloading the iframe: after
your login dialog, call sb.setLaunchToken(newLaunchToken).
Brazil: CPF
Section titled “Brazil: CPF”Brazilian tenants must send cpf for every session. The platform validates it
and checks it against the operator’s prohibited-bettor list and the national
self-exclusion system before the session opens. If the player already exists
with another CPF, the call is refused (400 validation, field cpf). For
other tenants cpf is optional and, when sent, checked the same way.