Game Launch
Issues a launch URL that sends a player to the game screen. For how to open the URL in the browser, iframe vs. new window, and postMessage events, see Game Launch Flow.
POST /launch
POST {API_BASE}/operator/v1/launchRegisters (or updates) the player and returns a launch URL that can be used only once within 60 seconds.
- If the
external_idhas not been seen before, a new platform player is created; if it already exists,nicknameandcountryare updated. - If both
game_codeandtable_idare omitted, the player enters the game lobby. With onlygame_code, the player enters that game's lobby; withtable_id, the player goes straight to that table. - Issue a new launch URL every time the player clicks. A URL that has been opened once cannot be reused, and a URL created in advance expires after 60 seconds.
Request fields
| Field | Type | Required | Description |
|---|---|---|---|
player.external_id | string | Required | The player ID on the operator side. 1–64 bytes. The (operator, external_id) pair identifies the player. This value is also included in wallet callbacks. |
player.nickname | string | Required | The name shown on the game screen. 2–16 characters (Unicode character count). Updated to this value on every launch. |
player.currency | string | Required | Player currency code (e.g. PHP). Must be one of the operator's enabled currencies. Fixed to the currency used at the first launch and cannot be changed afterwards. |
player.country | string | null | Country code (e.g. PH). If omitted, the existing value is kept. | |
player.vip_level | integer | null | Accepted but currently not used. | |
game_code | string | Code of the game to enter (Game codes). Must be a game enabled for this operator. If omitted, the game lobby. | |
table_id | string | null | ID of the table to enter (tbl_…), as returned by GET /tables. If game_code is also given, the table must belong to the same game; if game_code is omitted, it is filled in with the table's game. | |
table_password | string | Private table password. Send it together with table_id. Ignored if the table has no private reservation. See Private tables. | |
lang | string | Game screen language. Matched to one of ko en zh ja th vi (region suffixes and different casing such as zh-CN, ja_JP, EN are accepted). If omitted or unknown, ko. | |
device | string | desktop (default) or mobile. Used for screen layout and live video quality selection. Any other value is an error. | |
return_url | string | The address the game screen uses to send the player back to the operator site (session expired, connected from another window, etc.). If omitted, the default return URL registered during onboarding. The game screen's postMessage is sent to this address's origin (Game Launch Flow). | |
operator_session_id | string | A session identifier on the operator side. It is passed through as-is in the operator_session_id of wallet callback bodies coming from games started by this launch. |
The player currency cannot be changed
Sending a different player.currency with the same external_id returns 409 CURRENCY_MISMATCH. If one member uses several currencies, use a different external_id for each currency.
Validation order
If there are several errors, only the first one hit in the order below is returned (step 1 collects and returns all invalid fields).
- Field format:
player.external_id,player.nickname,player.currency,device→400 INVALID_REQUEST - Whether the currency is one of the operator's currencies →
400 CURRENCY_NOT_SUPPORTED - Whether
game_codeis an enabled game →404 GAME_NOT_FOUND; under maintenance →503 GAME_MAINTENANCE - Whether
table_idis an existing table →404 TABLE_NOT_FOUND - Currency and status of the existing player →
409 CURRENCY_MISMATCH,403 PLAYER_BLOCKED - Player registration / update
- Private table password (when
table_passwordis sent) →403 PRIVATE_PASSWORD,429 RATE_LIMITED - Launch token issuance
table_id returns 404 TABLE_NOT_FOUND in all of the following cases: a nonexistent or closed table, a table whose game differs from game_code, or another operator's dedicated table.
Request example
POST /operator/v1/launch HTTP/1.1
Host: {API_HOST}
Content-Type: application/json; charset=utf-8
X-Operator: acme
X-Api-Key: ak_5d2c9e0f7a1b3c4d5e6f708192a3b4c5d6e7f809
X-Timestamp: 1792368067512
X-Nonce: 9f2c4e7a1b3d5f60718293a4
X-Signature: 4be1c0d7f3a29e8b6c5d4e3f2a1b0c9d8e7f6a5b4c3d2e1f0a9b8c7d6e5f4a3b
{
"player": {
"external_id": "user-10293",
"nickname": "LuckyAce",
"currency": "PHP",
"country": "PH"
},
"game_code": "live_holdem",
"table_id": "tbl_019a0f3c8e1f7a2b9c4d5e6f7a8b9c0d",
"lang": "en",
"device": "mobile",
"return_url": "https://www.acme.example/",
"operator_session_id": "s-7f3a9c21"
}To send the player to the lobby, leave out game_code and table_id.
{
"player": { "external_id": "user-10293", "nickname": "LuckyAce", "currency": "PHP" },
"lang": "ko",
"return_url": "https://www.acme.example/"
}Response
200 OK
{
"launch_url": "https://{GAME_ORIGIN}/launch#token=lt_8fJ2kQ9wLmN3pR5tV7xZ1aC4eG6iK8mO0qS2uW4yA6c",
"expires_at": "2026-10-19T00:02:07.512Z",
"player_id": "pl_019a0f3c7b2e7d41a8c35e9f0b1d2c3a"
}| Field | Type | Description |
|---|---|---|
launch_url | string | Game screen address. It has the form {GAME_ORIGIN}/launch#token=lt_… and must be opened as-is. The token is carried in the URL fragment (#), so it does not end up in server logs or the Referer. |
expires_at | string | Token expiry time (60 seconds after issuance). Fixed UTC millisecond format YYYY-MM-DDTHH:mm:ss.sssZ. |
player_id | string | Platform player ID (pl_ + 32 hex digits). Always the same value for the same external_id. |
Handling the launch URL
- Receive
launch_urlin the operator backend, hand it to the browser, and open it immediately. Do not log or store the URL. - The token is single-use. After using the token once, the game screen continues the session within that tab. When the player closes the window and comes back, issue a new one.
Errors
| HTTP | error.code | Cause |
|---|---|---|
| 400 | INVALID_REQUEST | Not JSON, or a field format error. Invalid fields are listed in details.fields (player.external_id, player.nickname, player.currency, device). |
| 400 | CURRENCY_NOT_SUPPORTED | player.currency is not one of the operator's currencies |
| 404 | GAME_NOT_FOUND | game_code is not a game enabled for this operator |
| 503 | GAME_MAINTENANCE | The game is under maintenance |
| 404 | TABLE_NOT_FOUND | The table does not exist, belongs to a different game, or is another operator's dedicated table |
| 409 | CURRENCY_MISMATCH | player.currency differs from the existing player's currency |
| 403 | PLAYER_BLOCKED | A player blocked via POST /players/{external_id}/logout |
| 403 | PRIVATE_PASSWORD | Wrong private table password |
| 429 | RATE_LIMITED | More than 5 password attempts per minute per player and table, or the operator-wide rate limit (200 requests per second) |
| 500 | INTERNAL_ERROR | Internal platform error. Retry after a short while. |
Authentication and signature errors (INVALID_SIGNATURE, TIMESTAMP_OUT_OF_RANGE, NONCE_REUSED, IP_NOT_ALLOWED, OPERATOR_DISABLED) are common to all endpoints. See Error codes.
Example error response:
{
"error": {
"code": "INVALID_REQUEST",
"message": "invalid fields",
"details": { "fields": ["player.nickname"] }
}
}When showing errors to players
Replace PLAYER_BLOCKED, GAME_MAINTENANCE, and PRIVATE_PASSWORD with an appropriate message for the player. Other errors are integration errors, so it is better to check them in the operator-side logs.