# Casino Sandbox Integration Guide This guide is the partner-facing path from a clean checkout to a verified sandbox round. It assumes the casino owns player accounts, balances, KYC, AML, responsible gaming, payments, and jurisdiction controls. The game provider only launches games, requests the casino balance, debits bets, credits wins, rolls back failed rounds, and stores an auditable game trail. ## Sandbox Credentials Use these local demo values only for sandbox testing: ```txt Provider base URL: http://localhost:3000 Operator id: demo Shared secret: demo_casino_shared_secret_change_me Default player: player-demo-1 VIP test player: player-demo-2 Supported games: dice, limbo, plinko ``` Never use the demo shared secret in production. Production operator secrets belong in deployment environment variables or a managed secrets system. ## Local Provider Sandbox Start the game provider: ```powershell npm.cmd install npm.cmd start ``` The local provider listens on: ```txt http://localhost:3000 ``` Open these URLs while testing: ```txt Game client: http://localhost:3000/game.html Operator dashboard: http://localhost:3000/admin.html Fairness verifier: http://localhost:3000/verifier.html Documentation page: http://localhost:3000/docs.html OpenAPI JSON: http://localhost:3000/docs/openapi.json Postman collection: http://localhost:3000/docs/postman_collection.json ``` The default `demo` operator uses an in-process sandbox casino wallet through `sandbox://demo-casino`. This lets a partner test the full provider flow without standing up a separate callback service. The Postman collection at `docs/postman_collection.json` follows the same order as this guide and stores the launch token, session id, round ids, proof fields, and revealed seed as collection variables. ## First Successful Round ### 1. Create a Launch Token Request: ```http POST /sandbox/launch Content-Type: application/json ``` ```json { "operatorId": "demo", "playerRef": "player-demo-1", "gameType": "dice", "launchMode": "single" } ``` Expected response: ```json { "launchPayload": { "operatorId": "demo", "launchToken": "demo_launch_player-demo-1", "gameType": "dice", "launchMode": "single" }, "signature": "provider-launch-signature", "launchUrl": "/game.html?operatorId=demo&game=dice&token=demo_launch_player-demo-1" } ``` `launchMode` can be omitted for a normal single-game launch. In that mode the embedded client hides the game switcher and the backend locks the provider session to the launched game. Use `launchMode: "lobby"` only when the casino wants a provider mini-lobby; the returned URL then includes `mode=lobby` and the client shows the operator's enabled games. For the clean casino-facing iframe, append `embed=1` to the launch URL. This removes demo-only header information, including the visible seed hash line, balance badge, and operator/admin link. Seed and verifier data remain available through the shield icon. The default embed uses natural content height; add `fill=1` only when the casino wants the game to fill the iframe height. When using `fill=1`, size the iframe with `height: 100dvh` on mobile so the game receives the actual visible browser height. ```html ``` ### 2. Create a Game Session Request: ```http POST /api/sessions Content-Type: application/json ``` ```json { "operatorId": "demo", "launchToken": "demo_launch_player-demo-1", "gameType": "dice", "launchMode": "single" } ``` Expected response includes: - provider session id - casino player reference - casino-provided balance - operator public configuration - current server seed hash and next nonce - launch mode and locked game, when the session is a single-game launch Copy `session.sessionId` for the next steps. ### 3. Check Casino Balance Request: ```http GET /api/balance?sessionId=replace-session-id ``` Expected response: ```json { "balance": 1000, "currency": "USD" } ``` The balance is read from the casino wallet. The game provider does not maintain an external player wallet. ### 4. Place a Dice Bet Request: ```http POST /api/bets Content-Type: application/json ``` ```json { "sessionId": "replace-session-id", "gameType": "dice", "amount": 10, "idempotencyKey": "partner-demo-bet-001", "clientSeed": "partner-demo-client-seed", "params": { "target": 50, "direction": "over" } } ``` Expected result: - casino debit is created before the result is generated - win credit is created only when payout is greater than zero - response includes the settled bet and latest casino balance - round can be found later by `roundId` ### 5. Replay the Same Bet Request Send the exact same request body again with the same `idempotencyKey`. Expected result: - provider returns the original bet response - casino debit is not duplicated - casino credit is not duplicated ### 6. Try an Idempotency Conflict Send the same `idempotencyKey` with a different amount or params. Expected result: ```json { "code": "IDEMPOTENCY_CONFLICT", "error": "Duplicate idempotency key has a conflicting request payload." } ``` ## Failed Round and Rollback Test Use an invalid dice target after session creation: ```json { "sessionId": "replace-session-id", "gameType": "dice", "amount": 9, "idempotencyKey": "partner-demo-failed-round-001", "clientSeed": "partner-demo-failed-seed", "params": { "target": 99, "direction": "over" } } ``` Expected result: - casino debit succeeds first - game validation fails - provider sends casino rollback - API error includes `roundId` and `roundStatus` - stored round status is `rolled_back` Use the returned `roundId` to fetch the dispute packet: ```http GET /api/bets/{roundId} ``` The response contains: - original bet amount and status - fairness proof - game result or failure reason - casino debit transaction reference - casino rollback transaction reference - callback request and response audit for debit and rollback ## Reconciliation Request: ```http GET /api/reconciliation ``` Use this endpoint to compare provider-side wallet movements against casino-side wallet records. The important fields are: - `roundId` - `type` - `amount` - `casinoTransactionId` - `status` - `reason` - timestamp ## Operator Dashboard Review Open: ```txt http://localhost:3000/admin.html ``` Select a round to review the dispute packet. The dashboard should show: - round id, player reference, game, bet, payout, and status - casino debit, credit, and rollback references - fairness proof - game result - wallet callback request and response bodies ## External Casino Callback Harness The repository includes a small sample casino backend: ```powershell node docs\sample-casino-backend.js 4100 ``` It implements: - `POST /wallet/validate-session` - `POST /wallet/balance` - `POST /wallet/debit` - `POST /wallet/credit` - `POST /wallet/rollback` It verifies provider signatures, requires idempotency keys on money-changing requests, and stores idempotent responses in memory. To use it as a real callback target, create or configure an operator whose `callbackBaseUrl` points to: ```txt http://localhost:4100 ``` The current default `demo` operator uses the built-in sandbox wallet. External callback testing is intended for staging operator configuration. ## Production Readiness Checklist Before a real casino integration, confirm: - launch tokens are generated by the casino and expire quickly - provider validates launch/session state before showing balance - wallet callbacks are HTTPS only - request signatures use the production operator secret - timestamp skew and nonce replay checks are enforced - debit, credit, and rollback are idempotent - retries return the original transaction result - failed rounds can be found by `roundId` - support can inspect callback request/response audit - reconciliation exports match casino wallet records - game limits, max payout, and emergency disable are configured - legal, certification, and jurisdiction review are completed where required