> ## Documentation Index
> Fetch the complete documentation index at: https://docs.zerodash.studio/llms.txt
> Use this file to discover all available pages before exploring further.

# Go-live checklist

> Everything certification verifies, in one list you can work through before you ask for it.

Work through this before requesting certification. Every item here corresponds to something that has broken a real integration.

## Security

<AccordionGroup>
  <Accordion title="Signature verification on every callback" icon="key">
    <Check>Signature recomputed and compared **before** any wallet work</Check>
    <Check>Compared in constant time</Check>
    <Check>Verified against the **raw** request body, not a re-serialization</Check>
    <Check>Verified against the path **as registered**, including any prefix</Check>
    <Check>Any mismatch returns `401` and moves no money</Check>
  </Accordion>

  <Accordion title="Timestamp freshness" icon="clock">
    <Check>Requests older than 5 minutes are rejected</Check>
    <Check>Your outbound `X-Zd-Timestamp` matches the value you signed, byte for byte</Check>
    <Check>Server clocks are NTP-synchronised</Check>
  </Accordion>

  <Accordion title="Network and secrets" icon="shield-halved">
    <Check>Callbacks accepted only from `104.248.19.126` and `46.101.149.79`</Check>
    <Check>Allowlist enforced at the edge, not only in application code</Check>
    <Check>Valid TLS certificate on the callback host — not self-signed, not expired</Check>
    <Check>Secret key absent from logs, URLs, client code and error traces</Check>
    <Check>Staging and production credentials strictly separated</Check>
  </Accordion>
</AccordionGroup>

## Wallet correctness

<AccordionGroup>
  <Accordion title="Idempotency" icon="fingerprint">
    <Check>`transactionId` is the unique key of your ledger</Check>
    <Check>A duplicate returns `200 OK` with the **original** stored result</Check>
    <Check>Concurrent duplicates apply once — enforced by the database, not application logic</Check>
    <Check>Transaction insert and balance update share one atomic database transaction</Check>
  </Accordion>

  <Accordion title="Amounts" icon="coins">
    <Check>Decimals on the wire, never minor units</Check>
    <Check>A decimal type end to end — no floats anywhere in the money path</Check>
    <Check>Crypto truncated to the precision in the [table](/wallet/amounts#crypto)</Check>
    <Check>JPY and other 0-decimal currencies exchanged with 2 decimal places</Check>
    <Check>`balance` returned is the balance **after** the movement</Check>
  </Accordion>

  <Accordion title="Round lifecycle" icon="rotate">
    <Check>A losing round's `credit` with `payout: 0` returns `200 OK`</Check>
    <Check>`/credit` and `/rollback` work with **no** player session</Check>
    <Check>An unsettled bet is never expired locally — the window is 3 days</Check>
    <Check>`rollback` for an unknown `referenceTransactionId` returns `404`, never a credit</Check>
    <Check>`gameRoundId` stored on every row for reconciliation</Check>
  </Accordion>

  <Accordion title="Status codes" icon="triangle-exclamation">
    <Check>`409` for insufficient balance — not `400`, not `500`</Check>
    <Check>`422` returned **only** when nothing was written</Check>
    <Check>`500` returned when the transaction may exist</Check>
    <Check>Errors carry `{ "message": "…" }` with a specific cause</Check>
  </Accordion>

  <Accordion title="Player identity" icon="id-card">
    <Check>`accountId` is unique, permanent and free of personal data</Check>
    <Check>One currency per account ID, forever</Check>
    <Check>`displayName` safe to show to other players</Check>
    <Check>`subOperatorId` returned if several brands share the integration</Check>
  </Accordion>
</AccordionGroup>

## Launch and lobby

<AccordionGroup>
  <Accordion title="Session tokens" icon="key">
    <Check>Random and non-deterministic — never the player ID</Check>
    <Check>Valid for at least 2 hours, sliding where supported</Check>
    <Check>Reusable across reloads and multiple requests</Check>
    <Check>Revocable</Check>
  </Accordion>

  <Accordion title="Launching" icon="gamepad">
    <Check>Launch URL requested at click time, never pre-generated</Check>
    <Check>`ipAddress` is the player's real IP, not your server's</Check>
    <Check>New tab or window — or an iframe meeting the [sizing requirements](/launch/iframe) with `allow="fullscreen"`</Check>
    <Check>Popup opened inside the click handler so the blocker allows it</Check>
  </Accordion>

  <Accordion title="Catalogue" icon="grid-2">
    <Check>Games list cached and polled, not fetched per page render</Check>
    <Check>`If-None-Match` sent with the stored `ETag`</Check>
    <Check>`available`, `desktop`, `mobile` respected when rendering tiles</Check>
    <Check>`restrictedCountries` filtered client side as well as enforced at launch</Check>
    <Check>Artwork picked by `ratio`, with `width`/`height` set to prevent reflow</Check>
  </Accordion>

  <Accordion title="Free rounds" icon="gift">
    <Check>Only games with `freeRound: true` included in campaigns</Check>
    <Check>Campaign, bonus code and account currency all match</Check>
    <Check>`maxRounds` set on the campaign or the code</Check>
    <Check>`userId` on the bonus code equals your `accountId`</Check>
    <Check>Zero-stake debit creates a transaction and returns `200 OK`</Check>
  </Accordion>
</AccordionGroup>

## Operability

<AccordionGroup>
  <Accordion title="Logging" icon="file-lines">
    <Check>`transactionId`, `referenceTransactionId`, `gameRoundId` and `playerId` on every row</Check>
    <Check>Raw request bodies retained long enough to debug a signature failure</Check>
    <Check>Secrets and tokens redacted</Check>
  </Accordion>

  <Accordion title="Monitoring" icon="bell">
    <Check>Alert on repeated `4xx` from your callbacks — retries will not fix a `400`</Check>
    <Check>Alert on callback latency and error rate</Check>
    <Check>[Get transaction](/api-reference/callbacks/get-transaction) implemented and tested</Check>
  </Accordion>

  <Accordion title="Load" icon="gauge-high">
    <Check>Callbacks answer well inside your timeout under expected peak</Check>
    <Check>Wallet writes do not serialize on a single lock across all players</Check>
    <Check>Retry storms after an outage do not take the wallet down again</Check>
  </Accordion>
</AccordionGroup>

## Test scenarios

Run each of these against staging before certification.

| #  | Scenario                            | Expected                                   |
| -- | ----------------------------------- | ------------------------------------------ |
| 1  | Bet and win                         | Debit, then credit with `payout > 0`       |
| 2  | Bet and lose                        | Debit, then credit with `payout = 0`       |
| 3  | Bet with insufficient funds         | Debit returns `409`                        |
| 4  | Duplicate debit, sequential         | Balance moves once, identical responses    |
| 5  | Duplicate debit, concurrent         | Balance moves once                         |
| 6  | Rollback of a real bet              | Stake returned, `200 OK`                   |
| 7  | Rollback of an unknown bet          | `404`, no money moved                      |
| 8  | Credit with the player logged out   | `200 OK`                                   |
| 9  | Credit replayed after a later round | Original `balanceAfter` returned           |
| 10 | Free round: zero-stake debit        | Transaction created, balance unchanged     |
| 11 | Free round win                      | Credit applied as sent                     |
| 12 | Tampered signature                  | `401`, no money moved                      |
| 13 | Timestamp 10 minutes old            | `401`                                      |
| 14 | Request from a non-allowlisted IP   | Rejected at the edge                       |
| 15 | Reload mid-round                    | Session resumes, no duplicate transactions |

## Certification

You run the scenarios above yourself, against staging. The automated validation against our test system is ours to run — it drives your wallet callbacks end to end, and only we can execute it.

<Accordion title="Request validation on the integration chat" icon="comments">
  Contact us on the integration chat once staging is ready. We run the automated suite against your callbacks and report the results. Certification does not begin until we have exercised every endpoint end to end — a self-test on your side is not sufficient.
</Accordion>
