# Local Sandbox Integration Guide This guide is optional local/demo testing only. It is not the casino staging handoff. For the casino staging path, start with `docs/staging-integration-start-here.md` and operator `bspin-staging`. 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. ## Local 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, keno, mines, blackjack ``` 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 and operator/admin link, while keeping a compact casino-provided balance well inside the betting panel by default. 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. The balance can be hidden with a launch URL value of `showBalance=0`, `false`, `no`, or `off`, or with `operator.theme.showBalanceInEmbed: false`. A launch URL value of `showBalance=1`, `true`, `yes`, or `on` forces it visible even when the operator default is disabled. This does not change wallet ownership: Rouge Reels only displays the casino balance returned by the wallet callbacks and does not poll it in v1. ```html ``` Explicit embedded-balance launch: ```text /game.html?operatorId=demo&game=dice&token=demo_launch_player-demo-1&embed=1&showBalance=1 ``` ### 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 - a credit close callback is created for every successfully settled result - losing results send the credit callback with `amount: 0` - 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." } ``` ### 7. Start And Settle A Mines Round Mines is an active-round game. It debits once at round start, reveals tiles without wallet movement, and credits once at final close. Cashout sends the payout amount; bust sends `amount: 0`. Start: ```http POST /api/mines/rounds Content-Type: application/json ``` ```json { "sessionId": "replace-session-id", "amount": 10, "idempotencyKey": "partner-demo-mines-start-001", "clientSeed": "partner-demo-client-seed", "params": { "mineCount": 3 } } ``` Reveal: ```http POST /api/mines/rounds/{roundId}/reveal Content-Type: application/json ``` ```json { "sessionId": "replace-session-id", "tile": 0, "idempotencyKey": "partner-demo-mines-reveal-001" } ``` Cash out if the round is still active: ```http POST /api/mines/rounds/{roundId}/cashout Content-Type: application/json ``` ```json { "sessionId": "replace-session-id", "idempotencyKey": "partner-demo-mines-cashout-001" } ``` Restore or inspect: ```http GET /api/mines/rounds/{roundId}?sessionId=replace-session-id ``` Duplicate start, reveal, and cashout calls must return the original idempotent response without a second debit, reveal, or credit. ## 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