Skip to content

Error codes ​

A failed response always looks like this:

json
{ "ok": false, "error": { "code": "INSUFFICIENT_BALANCE", "message": "insufficient available balance" } }
  • Branch on code, never on message: message is a developer-facing explanation (mostly English) and may change.
  • HTTP status codes are meaningful: 400 bad input, 401 authentication failed, 403 not allowed (IP, tenant, player), 404 not found, 409 conflict, 413 body too large, 429 rate limited, 5xx server error.
  • A 5xx body may not be JSON (for example when it fails at the Cloudflare layer); always treat it as temporary.

Retry rules ​

SituationWhat to do
429, 5xx, timeout, connection errorBack off and retry (for example 1, 2, 4, 8 seconds with jitter), with a new nonce and timestamp each time
Deposit or withdrawal with an unknown outcomeRetry with the same txnId and content until you get a 2xx or 4xx; see Wallet: timeouts and retries
Any other 4xxDo not retry as is: fix the request according to the code
401 (nonce already used)The request was not processed; send it again with a new nonce

The tables below are generated from the OpenAPI spec and list every error code the implementation can return.

Common errors (any endpoint) ​

CodeHTTPMeaningWhat to doRetry
UNAUTHORIZED401Authentication failed. invalid credentials: the key ID is malformed, unknown or revoked (a rotated key more than 24 hours old counts), the nonce is malformed, or the signature does not match. timestamp outside the ±300 s window: X-Timestamp is malformed or more than 300 seconds away from server time. nonce already used: the nonce was used again within 10 minutes (this request was not processed).
message: invalid credentials, timestamp outside the ±300 s window, nonce already used
Compare your string to sign with the Signature debugger. Check that the path starts with /api/tenant/v1 and includes the query string, and that you hash the exact body bytes you send. Sync your server clock (NTP). Use a new nonce and timestamp for every request, including retries.fix first
IP_NOT_ALLOWED403You have an IP allowlist and the request came from an IP that is not on it.
message: source IP is not in the allowlist
Add your server's outbound IP (IPv4/IPv6 or CIDR) in the Console under "Go-live & integration → IP allowlist and Webhook".fix first
TENANT_SUSPENDED403The tenant is disabled, suspended or closed; the whole API is unavailable.
message: tenant is suspended
Check the account state in the Console or contact support.fix first
RATE_LIMITED429Too many requests per second (100/s on the paid plan, 20/s in the sandbox, 5/s on the free plan; short bursts up to 2×).
message: too many requests
Back off and retry (for example 200 ms, 400 ms, 800 ms… with jitter) with a new nonce and timestamp. Reduce calls by paging with cursors.yes (new nonce and timestamp)
PAYLOAD_TOO_LARGE413The request body is larger than 64 KB.
message: request body too large
Send a smaller body; normal requests to this API are far below the limit.fix first
INVALID_JSON400The body is not valid JSON, or not a JSON object.
message: request body is not valid JSON, request body must be an object
Send Content-Type: application/json and a JSON object ({…}).fix first
NOT_FOUND404unknown endpoint: no such method and path (for example GET on a POST endpoint, or a round ID that is not a 26-character upper-case ULID). table not found: the table to enable or disable does not exist.
message: unknown endpoint, table not found
Check the method and path in the API reference; take table IDs from GET /tables.fix first
INTERNAL_ERROR500A temporary server error. Treat any 5xx (including ones whose body is not JSON) the same way.
message: internal error, please retry
Back off and retry. Retry transfers with the same txnId, or look them up with GET /wallet/transfer first. If it persists, check the status page or contact support.yes (new nonce and timestamp)

Endpoint errors ​

CodeHTTPMeaningWhat to doRetry
INVALID_PARAMETER400A required field is missing, or a field has the wrong format or value; message names the field.
message: <field> is required, <field> must be a string, unsupported lang, lobbyUrl must be an http(s) URL, status must be active, locked or no_bet, password must be 6–64 characters, limitProfileId must be a positive integer or null, limitProfileId not found, limitProfileId currency is <CUR>, player currency is <CUR>, txnId must be 1–64 characters of A-Z a-z 0-9 _ . : -, txnId is required, from must be an ISO time, date must be a valid YYYY-MM-DD, from and to must be YYYY-MM-DD
Fix the field according to the API reference and send again.fix first
INVALID_USERNAME400The username breaks the rules (1–32 characters of letters, digits and _ . @ -), or username is missing from a query.
message: username must be 1–32 characters of A-Z a-z 0-9 _ . @ -, invalid username
Map your players to usernames that follow the rules (for example derived from your member ID).fix first
INVALID_CURRENCY400The currency code given for a new player is invalid (3–5 letters required).
message: invalid currency
Use a valid currency code, or leave currency out to use the tenant default.fix first
CURRENCY_NOT_ENABLED400The currency given for a new player is not enabled for the operator (Console → Bet limits → Currencies). Existing players are not affected.
message: currency <CUR> is not enabled for this operator (enabled: <CUR>, <CUR>)
Enable the currency in Console and set up its bet-limit profiles first, or leave currency out to use the primary currency.fix first
INVALID_AMOUNT400The amount is not a positive decimal string with at most 4 decimals.
message: amount must be a positive decimal string with at most 4 decimals, invalid amount
Send the amount as a string (for example "100.5"), never as a float or in scientific notation.fix first
INVALID_CURSOR400cursor is malformed.
message: cursor must come from a previous response
Send back the previous page's nextCursor unchanged. If you lost it, resync from a time with from and de-duplicate on (slipId, rev).fix first
CURRENCY_MISMATCH400The transfer currency differs from the player's currency, which is fixed when the player is created.
message: player currency is <CUR>
Transfer in the player's currency (see GET /player). Use separate usernames for different currencies.fix first
PLAYER_NOT_FOUND404No player with this username.
message: player not found
Players are created on their first launch or first deposit; do one of those first.fix first
PLAYER_LOCKED403The player is locked and cannot be launched.
message: player is locked
If appropriate, set status back to active with POST /player/update.fix first
PLAYER_LIMIT403The plan's player limit is reached (50 by default on the free demo plan, 500 in the sandbox).
message: demo plan allows at most <N> players
Reuse existing test players, or upgrade to the paid plan.fix first
TXN_CONFLICT409This txnId was already used for a transfer with a different amount or direction, or for another player within the last two months.
message: txnId was already used with different content, txnId was already used for another player
This is an ID bug on your side. Every new transfer needs a new txnId, unique across your tenant, and a retry must be identical to the first attempt.fix first
INSUFFICIENT_BALANCE409The withdrawal is larger than the available balance (stakes of unsettled bets cannot be withdrawn).
message: insufficient available balance
Read the available balance with GET /wallet/balance and withdraw at most that.fix first
TXN_NOT_FOUND404No transfer with this txnId was found. With username in the query this means the transfer was not executed (or is still being processed); without it only the tenant ledger (current and previous 3 months) is searched.
message: transfer not found
Resend the transfer with the same txnId and content until you get a definite success or 4xx. Do not treat it as failed and switch to a new ID.fix first
ROUND_NOT_FOUND404The round does not exist or is not settled yet.
message: round not found
Rounds become available once settled; any roundId from a bet record can be looked up.fix first
QUOTA_EXCEEDED409You have reached the free plan's table quota (2 tables by default).
message: 超過方案配額(<N> 桌)
Disable another table first, or upgrade in the Console under "Plan & billing → Plan".fix first
ACCOUNT_LOCKED409The account is suspended or closed, so tables cannot be enabled.
message: account is suspended
Contact support.fix first

Errors by endpoint ​

PathCode
POST /player/launchINVALID_PARAMETER INVALID_USERNAME INVALID_CURRENCY CURRENCY_NOT_ENABLED PLAYER_LOCKED PLAYER_LIMIT
POST /player/logoutINVALID_PARAMETER INVALID_USERNAME PLAYER_NOT_FOUND
GET /playerINVALID_USERNAME PLAYER_NOT_FOUND
POST /player/updateINVALID_PARAMETER INVALID_USERNAME PLAYER_NOT_FOUND
POST /wallet/depositINVALID_PARAMETER INVALID_AMOUNT INVALID_USERNAME INVALID_CURRENCY CURRENCY_NOT_ENABLED CURRENCY_MISMATCH PLAYER_LIMIT TXN_CONFLICT
POST /wallet/withdrawINVALID_PARAMETER INVALID_AMOUNT INVALID_USERNAME CURRENCY_MISMATCH PLAYER_NOT_FOUND TXN_CONFLICT INSUFFICIENT_BALANCE
GET /wallet/transferINVALID_PARAMETER TXN_NOT_FOUND
GET /wallet/balanceINVALID_USERNAME PLAYER_NOT_FOUND
GET /betsINVALID_CURSOR INVALID_PARAMETER
GET /bets/summaryINVALID_PARAMETER
GET /rounds/{roundId}ROUND_NOT_FOUND NOT_FOUND
GET /tables—
POST /tables/enableINVALID_PARAMETER NOT_FOUND QUOTA_EXCEEDED ACCOUNT_LOCKED
POST /tables/disableINVALID_PARAMETER NOT_FOUND
GET /account—
GET /account/usageINVALID_PARAMETER
GET /account/statements—

elite Tenant Integration API v1