4.1 Modes
A click on a game in a widget is handled the way agreed for your installation (form,
widgets.game_launch; manifest launch.mode):
| Mode | What happens |
|---|---|
sdk-modal | the SDK launches the game itself and shows it in a modal iframe over your page (§2.3, §4.3) |
redirect | the page goes to your URL template with the game’s values in place, e.g. /game/{gameId}; with target _blank the URL opens in a new tab |
popup | the same URL opens in a new window |
host-handled | the widget does nothing itself and tells your page (§4.2); your page launches the game, on GA as in §4.3 |
The URL template takes three placeholders, each filled URL-encoded, in every place it appears:
| Placeholder | Value |
|---|---|
{gameId} | the game’s id in the catalogue — unique across all providers |
{gameSlug} | the game’s code at its provider; when the game has none, {gameId} |
{providerId} | the provider’s id in GA’s catalogue; for the catalogue you send us (§8.1), its provider |
A game code is unique only within its provider: two providers can offer a game under the same code. Route on {gameId}, or on {providerId} and {gameSlug} together — never on {gameSlug} alone.
4.2 The ig:game-launch event
{
"gameId": "019edf56-a69e-75ed-bf7f-06706720a9d6",
"gameSlug": "10869",
"providerId": "00000000-0000-0000-0000-000000000de3",
"providerName": "Yggdrasil",
"gameTitle": "Hercules Fortune Quest",
"mode": "redirect",
"url": "/game/019edf56-a69e-75ed-bf7f-06706720a9d6"
}
gameSlug is absent when the game has no code; url is present for redirect and popup only. With sdk-modal the event comes after the modal has opened, carries "mode": "sdk-modal" and no url: the SDK has launched the game itself (§2.3).
With host-handled your page launches the game. A minimal handler:
document.addEventListener('ig:game-launch', (e) => {
const { gameId, gameSlug, providerId, system, page } = e.detail;
// launch the game on GA as in §4.3; with `system` and `page` — by that pair
});
gameId is the game’s UUID in GA’s catalogue; gameSlug is the game’s code at its provider (absent when the game has none); providerId is the provider’s id in GA’s catalogue. gameSlug is unique only within one provider, so route on gameId, or on providerId with gameSlug — never on gameSlug alone.
system, page are optional strings: the System/Page pair from Game/List for operators on the SoftGaming protocol; launch the game by it if it is present. A game without the pair has no such keys.
4.3 Launching on GA
If your games run through GA’s aggregation, the chosen game is launched through GA. With sdk-modal
the SDK sends this request; with host-handled your page does. The player is proven by an operator token (§3.2): on the click, a fresh one is taken (the SDK takes it from tokenProvider, §3.2.1) and sent in the body. The GA player token of §3.1 stays inside the widgets; your page does not need it.
A real launch plays with the player’s money: the game’s provider asks GA for the balance and every bet and win, and GA forwards each of them to your wallet (Operator API v1 or v2). Until your wallet endpoint is connected, GA refuses real launches with 403 wallet_not_configured; demo
launches need no wallet.
One token for the whole launch
The operator token your page already holds is the only token of a real-money launch. Pass it as
operatorToken when launching. GA verifies its signature, takes the player from it, and calls your wallet once before the game provider is called, with this exact string as launch_token
(Authenticate if your wallet declares it, otherwise GetBalance).
- If your wallet refuses (invalid token, blocked or unknown player), the launch is refused with
401login_required(insdk-modalmode:ig:login-required) and no session stays open. - If your wallet cannot be reached, the launch is refused with a retryable
503; retry with a fresh token. - The same string is then the
launch_tokenon every wallet call of that session.
Your side:
- Mint a fresh token for every launch (for example a unique
jti): the token is also the launch’s idempotency key. - Resolve the player from the token on every wallet call.
- Do not apply the JWT
expto a session that is already running;explimits the time to start the game.
Only some games have a demo. A game’s has_demo says it: true — mode: "demo" launches it;
false — the answer is 400 demo_not_supported, offer the game signed-in only. has_demo is in every game of the catalogue the widgets read,
GET https://<api host>/public/v1/catalog/lobby?operator_id=<your GA operator id> (no key needed;
data[].games[], the game’s id is the event’s gameId; a game may carry the optional strings system and page — the System/Page pair from Game/List for SoftGaming operators, absent when the game has none), and of GA’s catalogue for your side (§8.2).
POST https://<api host>/public/v1/embed/launch
Content-Type: application/json
{"gameId": "019edf56-a69e-75ed-bf7f-06706720a9d6", "providerId": "00000000-0000-0000-0000-000000000de3", "operatorToken": "<JWT of §3.2>", "mode": "real", "returnUrl": "https://casino.example/lobby", "lang": "en"}
| Field | Rule |
|---|---|
gameId | the gameId of the event (§4.2) — unique on its own; a game code works too, but it is unique only together with providerId |
providerId | optional; the providerId of the event. With a game code it picks that provider’s game; with a gameId of another provider the answer is 404 |
operatorToken | the operator token of §3.2 for the signed-in player, checked the same way: signed with your key, HS256, with exp. Currency and locale come from its claims |
mode | real (default) needs operatorToken and your connected wallet; demo works without a token, then operatorId — your GA operator id — is required; only for a game with has_demo: true |
returnUrl | where the game sends the player back |
lang | the game’s language; by default the player’s, then en |
200 {"launchUrl":"…","mode":"popup","expiresAt":"…"} — with sdk-modal the SDK opens launchUrl
in its modal (a 200 without launchUrl is ig:game-launch-error); with host-handled open it in an iframe or a new window.
| Status | error / message | Meaning |
|---|---|---|
400 | bad_request / what is wrong | no gameId, a providerId or operatorId that is not a UUID, a demo launch without operatorId |
400 | bad_request / demo_not_supported | a demo launch of a game with has_demo: false |
401 | unauthorized / login_required | a real launch without operatorToken, or with one that is not signed with your key, has no exp or has expired; take a fresh token. With sdk-modal the SDK raises ig:login-required with {reason: 'launch'} (§2.3); show your sign-in |
403 | forbidden / wallet_not_configured | a real launch before your wallet (Operator API v1 or v2) is connected; ask your manager to connect it |
401 | unauthorized / login_required | your wallet refused the operator token (invalid token, blocked or unknown player); no session stays open |
503 | retryable | your wallet could not be reached; retry with a fresh token |
403, 404 | forbidden, not_found / the reason, e.g. game_not_found | the game is unavailable to you or does not exist |
502 | bad_gateway | our side failed; try again |
With sdk-modal the SDK sends gameId, providerId, mode, operatorToken (real) and operatorId (your GA operator id, when known). Every answer except 200 and 401 raises ig:game-launch-error with {status, reason} and the game’s fields of §4.2: status is the HTTP status, reason is the message of the answer or launch_failed. A network failure gives status 0, reason network_error.
If your games are not on GA, you launch them yourself: gameId is the id you sent in your catalogue (§8.1).