Errors on GA’s side, in one place
Your wallet’s codes are Appendix A.1. What GA returns to you is Appendix A.2. Every error from /v2/aggregator/* and /v2/features/* has a non-200 HTTP status and one JSON body, Content-Type: application/json:
{
"code": "ERROR_CODE_MAINTENANCE",
"message": "provider_unavailable",
"retryable": true
}
code is one of the 15 ERROR_CODE_* values of Appendix A.1. message is for your logs and GA support. It starts with a stable token (signature_invalid, game_unavailable, provider_timeout, …). GA omits retryable when false. This holds for signature and key problems (401, 403) and for a read-only key on a write call (403) too.
Retry only 429, 503, and 504 (retryable: true in the body), with backoff. Every other status, 502 included, is final for that request.
Codes your wallet returns to GA
Always HTTP 200 with {"status":"error","error":{"code":…}} (§2.5). 15 codes. The list is closed.
| Code | GA retries? | When to return it |
|---|---|---|
ERROR_CODE_INSUFFICIENT_FUNDS | no | The balance can’t cover the stake, or a credit rollback under DEBIT_MODE_REJECT |
ERROR_CODE_PLAYER_NOT_FOUND | no | No such player |
ERROR_CODE_PLAYER_BLOCKED | no | Player blocked, self-excluded, or disabled. New bets only. Still accept wins and rollbacks |
ERROR_CODE_CURRENCY_MISMATCH | no | Currency or exponent doesn’t match the player’s account |
ERROR_CODE_BUSINESS_REJECTED | no | Your own business rule refused it. Also a new bet into a closed or voided round |
ERROR_CODE_UNKNOWN_ORIGINAL | no | A credit names an original you don’t have. Never for a rollback or a reconcile |
ERROR_CODE_ALREADY_ROLLED_BACK | no | You already rolled back the op_id (Rule 4), or the round is voided |
ERROR_CODE_UNSUPPORTED_ACTION | no | You don’t implement this optional action (HTTP 200 or 404, with the envelope) |
ERROR_CODE_RATE_LIMITED | yes | You are rate-limiting GA (HTTP 200 or 429, with the envelope) |
ERROR_CODE_MAINTENANCE | yes | Your wallet is down for maintenance |
ERROR_CODE_INVALID_REQUEST | no | Malformed request: missing field, zero or negative amount, overflow, unknown enum value, missing token on a session call |
ERROR_CODE_SESSION_EXPIRED | no | Launch token or session expired. New bets only |
ERROR_CODE_LIMIT_EXCEEDED | no | Deposit or loss limit reached. New bets only |
ERROR_CODE_INTERNAL | yes | Unexpected error on your side (HTTP 200 or 500, with the envelope) |
ERROR_CODE_IDEMPOTENCY_CONFLICT | no | Same op_id, different content (Rule 1) |
Bare statuses without the envelope (401, 403, 404, 429, 5xx) are all “no answer”: GA retries, and a bet ends in a rollback.
What GA returns to you
Every /v2/aggregator/* and /v2/features/* error is the body of §2.8. message starts with the token in the table.
| HTTP | code | Retry? | message starts with | Meaning |
|---|---|---|---|---|
400 | ERROR_CODE_INVALID_REQUEST | no | invalid json body, invalid request, invalid_request, invalid_provider_ref, capability_not_supported, bonus_buy_not_cancellable | Malformed JSON, missing or invalid field, GA can’t read the body, or the game provider doesn’t offer the capability |
401 | ERROR_CODE_INVALID_REQUEST | no | unauthorized, signature_missing, signature_invalid, signature_stale | Wrong or missing key id, signature, or a timestamp outside 300 s |
403 | ERROR_CODE_BUSINESS_REJECTED | no | forbidden | The operator is suspended, or the key isn’t allowed to do this (for example a read-only key on launch_game) |
403 | ERROR_CODE_BUSINESS_REJECTED or ERROR_CODE_INVALID_REQUEST | no | operator_suspended, operator forbidden, restricted, game_unavailable, PLAYER_SELF_EXCLUDED, PLAYER_COOL_OFF | Not allowed for this operator, game, or player |
404 | ERROR_CODE_INVALID_REQUEST | no | provider not found, provider_not_found, game not found, player_not_found, bonus_buy_not_found | Provider, game, player, grant, or bonus not found |
409 | ERROR_CODE_IDEMPOTENCY_CONFLICT | no | session_token_conflict | You reused the token of launch_game with another player, game, or currency, or after its session closed or expired, or the idempotency_key of issue_grant with a different body (§4.1, §4.4) |
412 | ERROR_CODE_INVALID_REQUEST | no | DEMO_NOT_SUPPORTED | launch_demo on a game with demo_supported: false |
422 | ERROR_CODE_INVALID_REQUEST | no | unsupported action | Action not supported for this game or provider |
429 | ERROR_CODE_RATE_LIMITED | yes | Rate limit | |
500 | ERROR_CODE_INTERNAL | no | internal error | GA-side failure. GA gets an alert. Contact support if it repeats |
501 | ERROR_CODE_UNSUPPORTED_ACTION | no | Call not implemented on this binding (settlement_mode PER_ROUND) | |
502 | ERROR_CODE_INTERNAL | no (retryable not set) | provider_error | The game provider returned an error. Repeating the same call returns the same error |
503 | ERROR_CODE_MAINTENANCE | yes | provider_unavailable | The game provider is unavailable |
503 | ERROR_CODE_INTERNAL | yes | launch_in_progress | The first launch_game with this token is still running. Retry with the same token (§4.1) |
504 | ERROR_CODE_INTERNAL | yes | provider_timeout | The game provider timed out |
Retry only 429, 503, and 504, with backoff.