게임 실행
플레이어를 게임 화면으로 보내는 실행 URL 을 발급합니다. 브라우저에서 URL 을 여는 방법, iframe · 새 창, postMessage 이벤트는 게임 실행 흐름을 보세요.
POST /launch
POST {API_BASE}/operator/v1/launch플레이어 정보를 등록(또는 갱신)하고, 60초 동안 한 번만 쓸 수 있는 실행 URL 을 돌려줍니다.
- 처음 보는
external_id면 플랫폼 플레이어를 새로 만들고, 이미 있으면nickname·country를 갱신합니다. game_code·table_id를 모두 비우면 게임 로비로 들어갑니다.game_code만 주면 그 게임의 로비,table_id를 주면 그 테이블로 바로 들어갑니다.- 실행 URL 은 플레이어가 누를 때마다 새로 발급하세요. 한 번 연 URL 은 다시 쓸 수 없고, 미리 만들어 두면 60초 뒤 만료됩니다.
요청 필드
| 필드 | 타입 | 필수 | 설명 |
|---|---|---|---|
player.external_id | string | 필수 | 오퍼레이터 쪽 플레이어 ID. 1~64바이트. (오퍼레이터, external_id) 쌍이 플레이어를 식별합니다. 지갑 콜백에도 이 값이 실립니다. |
player.nickname | string | 필수 | 게임 화면에 보이는 이름. 2~16자(유니코드 문자 수). 실행할 때마다 이 값으로 갱신됩니다. |
player.currency | string | 필수 | 플레이어 통화 코드(예: PHP). 오퍼레이터 사용 통화 중 하나여야 합니다. 처음 실행한 통화로 고정되며 이후 바꿀 수 없습니다. |
player.country | string | null | 국가 코드(예: PH). 비우면 기존 값을 유지합니다. | |
player.vip_level | integer | null | 받기는 하지만 현재 쓰이지 않습니다. | |
game_code | string | 들어갈 게임 코드(게임 코드). 이 오퍼레이터에 켜진 게임이어야 합니다. 비우면 게임 로비. | |
table_id | string | null | 들어갈 테이블 ID(tbl_…). GET /tables 의 값. game_code 를 함께 주면 같은 게임의 테이블이어야 하고, 비우면 테이블의 게임으로 채워집니다. | |
table_password | string | 프라이빗 테이블 비밀번호. table_id 와 함께 보냅니다. 그 테이블에 프라이빗 예약이 걸려 있지 않으면 무시됩니다. 프라이빗 테이블 참고. | |
lang | string | 게임 화면 언어. ko en zh ja th vi 중 하나로 맞춥니다(zh-CN, ja_JP, EN 처럼 지역 · 대소문자가 붙어도 됩니다). 비우거나 모르는 언어면 ko. | |
device | string | desktop(기본) 또는 mobile. 화면 배치와 라이브 영상 화질 선택에 쓰입니다. 그 밖의 값은 오류입니다. | |
return_url | string | 게임 화면이 플레이어를 오퍼레이터 사이트로 돌려보낼 때(세션 만료, 다른 창에서 접속 등) 쓰는 주소. 비우면 온보딩 때 등록한 기본 return URL. 게임 화면의 postMessage 는 이 주소의 오리진으로 보내집니다(게임 실행 흐름). | |
operator_session_id | string | 오퍼레이터 쪽 세션 식별값. 이 실행으로 생긴 게임에서 오는 지갑 콜백 본문의 operator_session_id 에 그대로 실려 옵니다. |
플레이어 통화는 바꿀 수 없습니다
같은 external_id 로 다른 player.currency 를 보내면 409 CURRENCY_MISMATCH 입니다. 한 회원이 여러 통화를 쓴다면 통화마다 다른 external_id 를 쓰세요.
검사 순서
오류가 여러 개면 아래 순서에서 먼저 걸린 것 하나만 돌아옵니다(1번은 잘못된 필드를 모두 모아 돌려줍니다).
- 필드 형식:
player.external_id·player.nickname·player.currency·device→400 INVALID_REQUEST - 통화가 오퍼레이터 사용 통화인지 →
400 CURRENCY_NOT_SUPPORTED game_code가 켜진 게임인지 →404 GAME_NOT_FOUND, 점검 중이면503 GAME_MAINTENANCEtable_id가 있는 테이블인지 →404 TABLE_NOT_FOUND- 기존 플레이어의 통화 · 상태 →
409 CURRENCY_MISMATCH,403 PLAYER_BLOCKED - 플레이어 등록 · 갱신
- 프라이빗 테이블 비밀번호(
table_password를 보냈을 때) →403 PRIVATE_PASSWORD,429 RATE_LIMITED - 실행 토큰 발급
table_id 는 다음 경우 모두 404 TABLE_NOT_FOUND 입니다: 없거나 닫힌 테이블, game_code 와 게임이 다른 테이블, 다른 오퍼레이터의 전용 테이블.
요청 예시
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"
}로비로 보내려면 game_code · table_id 를 빼면 됩니다.
{
"player": { "external_id": "user-10293", "nickname": "LuckyAce", "currency": "PHP" },
"lang": "ko",
"return_url": "https://www.acme.example/"
}응답
200 OK
{
"launch_url": "https://{GAME_ORIGIN}/launch#token=lt_8fJ2kQ9wLmN3pR5tV7xZ1aC4eG6iK8mO0qS2uW4yA6c",
"expires_at": "2026-10-19T00:02:07.512Z",
"player_id": "pl_019a0f3c7b2e7d41a8c35e9f0b1d2c3a"
}| 필드 | 타입 | 설명 |
|---|---|---|
launch_url | string | 게임 화면 주소. {GAME_ORIGIN}/launch#token=lt_… 모양이며 그대로 열어야 합니다. 토큰은 URL fragment(#) 에 실려 서버 로그 · Referer 에 남지 않습니다. |
expires_at | string | 토큰 만료 시각(발급 60초 뒤). UTC 밀리초 고정 형식 YYYY-MM-DDTHH:mm:ss.sssZ. |
player_id | string | 플랫폼 플레이어 ID(pl_ + 32자리 16진수). 같은 external_id 면 항상 같은 값입니다. |
실행 URL 다루기
launch_url은 오퍼레이터 백엔드에서 받아 브라우저로 넘기고, 받는 즉시 엽니다. URL 을 로그에 남기거나 저장하지 마세요.- 토큰은 1회용입니다. 게임 화면은 토큰을 한 번 쓴 뒤 그 탭 안에서 세션을 이어 갑니다. 창을 닫고 다시 들어올 때는 새로 발급하세요.
오류
| HTTP | error.code | 원인 |
|---|---|---|
| 400 | INVALID_REQUEST | JSON 이 아니거나 필드 형식 오류. 잘못된 필드는 details.fields 에 있습니다(player.external_id, player.nickname, player.currency, device). |
| 400 | CURRENCY_NOT_SUPPORTED | player.currency 가 오퍼레이터 사용 통화가 아님 |
| 404 | GAME_NOT_FOUND | game_code 가 이 오퍼레이터에 켜진 게임이 아님 |
| 503 | GAME_MAINTENANCE | 그 게임이 점검 중 |
| 404 | TABLE_NOT_FOUND | 테이블이 없거나, 게임이 다르거나, 다른 오퍼레이터 전용 테이블 |
| 409 | CURRENCY_MISMATCH | 기존 플레이어의 통화와 player.currency 가 다름 |
| 403 | PLAYER_BLOCKED | POST /players/{external_id}/logout 으로 차단된 플레이어 |
| 403 | PRIVATE_PASSWORD | 프라이빗 테이블 비밀번호가 틀림 |
| 429 | RATE_LIMITED | 비밀번호 시도가 플레이어 · 테이블당 분당 5회를 넘음, 또는 오퍼레이터 전체 속도 제한(초당 200건) |
| 500 | INTERNAL_ERROR | 플랫폼 내부 오류. 잠시 뒤 다시 시도하세요. |
인증 · 서명 오류(INVALID_SIGNATURE, TIMESTAMP_OUT_OF_RANGE, NONCE_REUSED, IP_NOT_ALLOWED, OPERATOR_DISABLED)는 모든 엔드포인트 공통입니다. 오류 코드를 보세요.
오류 응답 예:
{
"error": {
"code": "INVALID_REQUEST",
"message": "invalid fields",
"details": { "fields": ["player.nickname"] }
}
}플레이어에게 보여 줄 때
PLAYER_BLOCKED · GAME_MAINTENANCE · PRIVATE_PASSWORD 는 플레이어에게 알맞은 안내 문구로 바꿔 보여 주세요. 그 밖의 오류는 연동 오류이므로 오퍼레이터 쪽 로그로 확인하는 것이 좋습니다.