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

Security

Signature recomputed and compared before any wallet work
Compared in constant time
Verified against the raw request body, not a re-serialization
Verified against the path as registered, including any prefix
Any mismatch returns 401 and moves no money
Requests older than 5 minutes are rejected
Your outbound X-Zd-Timestamp matches the value you signed, byte for byte
Server clocks are NTP-synchronised
Callbacks accepted only from 104.248.19.126 and 46.101.149.79
Allowlist enforced at the edge, not only in application code
Valid TLS certificate on the callback host — not self-signed, not expired
Secret key absent from logs, URLs, client code and error traces
Staging and production credentials strictly separated

Wallet correctness

transactionId is the unique key of your ledger
A duplicate returns 200 OK with the original stored result
Concurrent duplicates apply once — enforced by the database, not application logic
Transaction insert and balance update share one atomic database transaction
Decimals on the wire, never minor units
A decimal type end to end — no floats anywhere in the money path
Crypto truncated to the precision in the table
JPY and other 0-decimal currencies exchanged with 2 decimal places
balance returned is the balance after the movement
A losing round’s credit with payout: 0 returns 200 OK
/credit and /rollback work with no player session
An unsettled bet is never expired locally — the window is 3 days
rollback for an unknown referenceTransactionId returns 404, never a credit
gameRoundId stored on every row for reconciliation
409 for insufficient balance — not 400, not 500
422 returned only when nothing was written
500 returned when the transaction may exist
Errors carry { "message": "…" } with a specific cause
accountId is unique, permanent and free of personal data
One currency per account ID, forever
displayName safe to show to other players
subOperatorId returned if several brands share the integration

Launch and lobby

Random and non-deterministic — never the player ID
Valid for at least 2 hours, sliding where supported
Reusable across reloads and multiple requests
Revocable
Launch URL requested at click time, never pre-generated
ipAddress is the player’s real IP, not your server’s
New tab or window — or an iframe meeting the sizing requirements with allow="fullscreen"
Popup opened inside the click handler so the blocker allows it
Games list cached and polled, not fetched per page render
If-None-Match sent with the stored ETag
available, desktop, mobile respected when rendering tiles
restrictedCountries filtered client side as well as enforced at launch
Artwork picked by ratio, with width/height set to prevent reflow
Only games with freeRound: true included in campaigns
Campaign, bonus code and account currency all match
maxRounds set on the campaign or the code
userId on the bonus code equals your accountId
Zero-stake debit creates a transaction and returns 200 OK

Operability

transactionId, referenceTransactionId, gameRoundId and playerId on every row
Raw request bodies retained long enough to debug a signature failure
Secrets and tokens redacted
Alert on repeated 4xx from your callbacks — retries will not fix a 400
Alert on callback latency and error rate
Get transaction implemented and tested
Callbacks answer well inside your timeout under expected peak
Wallet writes do not serialize on a single lock across all players
Retry storms after an outage do not take the wallet down again

Test scenarios

Run each of these against staging before certification.

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.
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.