The six calls, in order
| # | Call | Why |
|---|---|---|
| 1 | GET /partner/v1/ping | Confirms the key works and reports the scopes you actually hold. The fastest way to diagnose a 403 later. |
| 2 | POST /partner/v1/sessions | Get-or-create the player from your external_ref, and mint a launch token. |
| 3 | POST /partner/v1/wallet/credit | Move value into the player's balance before they play. |
| 4 | Redirect the browser | https://{casino-host}/launch?token={launch_token}, ⚠ the hosted page is not deployed yet (/launch 404s); build the exchange on your side until it ships. |
| 5 | Receive match.settled | Signed callbacks to your endpoint. Return 2xx as soon as you have durably accepted. |
| 6 | GET /partner/v1/matches | Poll as the backstop. Same query as the push feed, so the two cannot disagree. |
Authenticate every /partner/v1 call with X-Api-Key, not Authorization: Bearer.
curl -s https://api.clashx.example/partner/v1/ping \
-H "X-Api-Key: $CLASHX_KEY"Four things that will bite you
A rejected transfer returns HTTP 200. Insufficient balance is a business outcome, not an error. Branch on
kind, never on the status code.applied: falsemeans replay, not failure. Retry a wallet call with the sametransfer_ref, never a new one.Errors carry no machine-readable code. Match on HTTP status; do not parse messages.
A launch token lives 60 seconds and is single-use. Mint it at the moment of the click, not when the page renders.
Your reconciliation has five terms, not four
credited − staked + won + refunded − debited == balancerefund_cents is a separate field from payout_cents, and it is non-zero on a failed start, a forfeit, a draw, or an abandoned match. Omit it and every refunded match reports a false discrepancy.