Error codes and HTTP statuses
Every failure returns a stable machine-readable code alongside the HTTP status. Branch on the code, never on the message text: messages are written for humans and may be reworded, while codes are part of the contract.
All 42 codes the reseller API can return, grouped by what went wrong. Every entry names the HTTP status it arrives with and the change that resolves it.
Authentication (401)
| Code | HTTP | What it means | How to fix it |
|---|---|---|---|
| MISSING_API_KEY | 401 | API key is requiredNo Authorization header was provided, or the header format is incorrect. | Include the header: Authorization: Bearer <keyId>.<secret>action: FIX_INPUT · retryable: false · retry_after: null |
| INVALID_API_KEY | 401 | Invalid API keyThe provided API key does not match any active key in the system. | Verify your key ID and secret are correct. Regenerate the key from the API Access panel if needed.action: FIX_INPUT · retryable: false · retry_after: null |
Authorization (403)
| Code | HTTP | What it means | How to fix it |
|---|---|---|---|
| ACCOUNT_DISABLED | 403 | Account is disabledNo longer returned. An account that cannot place orders answers ACCOUNT_FROZEN (HTTP 403). | Handle ACCOUNT_FROZEN instead.No longer returned — replaced by ACCOUNT_FROZEN |
| ACCOUNT_FROZEN | 403 | Account is frozenYour account has been temporarily frozen, usually due to suspicious activity. | Contact support to unfreeze your account.action: CONTACT_SUPPORT · retryable: false · retry_after: null |
| IP_NOT_ALLOWED | 403 | IP address not in allowlistThe request originated from an IP address not in your API key allowlist. | Add your server IP to the allowlist in the API Access panel, or remove IP restrictions.action: FIX_INPUT · retryable: false · retry_after: null |
Request validation (400)
| Code | HTTP | What it means | How to fix it |
|---|---|---|---|
| MISSING_REQUIRED_FIELD | 400 | Missing required fieldA required field is missing from the request body. For player requirements, details.field names the missing field. | Check the endpoint documentation — and GET /catalog/category/:categoryId/requirements for player fields — then send every required field.action: FIX_INPUT · retryable: false · retry_after: null |
| INVALID_PARAMETER_FORMAT | 400 | A parameter has an invalid formatA requirement field has the wrong format (for example text in a numeric field). details.field names the field. | Re-read the category requirements and send the field in the format its data_type and validation rules expect.action: FIX_INPUT · retryable: false · retry_after: null |
| INVALID_PARAMETER_VALUE | 400 | A parameter has an invalid valueA requirement field is outside its allowed values (below the minimum, above the maximum, or not one of its select_options). details.field names the field. | Send a value the category requirements allow for that field.action: FIX_INPUT · retryable: false · retry_after: null |
| INVALID_PARAMETER_LENGTH | 400 | A parameter has an invalid lengthA requirement field is shorter or longer than allowed. details.field names the field. | Check min_length / max_length in the category requirements.action: FIX_INPUT · retryable: false · retry_after: null |
| INVALID_UUID_FORMAT | 400 | Invalid UUID formatThe order_id is not a valid UUID format. | Use any valid UUID format (v1, v4, v7, etc). Format: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.action: FIX_INPUT · retryable: false · retry_after: null |
| INVALID_QUANTITY | 400 | Invalid quantityQuantity must be a positive integer. | Provide a quantity >= 1 as an integer.action: FIX_INPUT · retryable: false · retry_after: null |
| INVALID_CATEGORY_ID | 400 | Invalid category IDThe provided categoryId is not a valid number. | Use the Catalog Explorer or GET /catalog/categories to find valid category IDs.action: FIX_INPUT · retryable: false · retry_after: null |
| INVALID_BIG_CATEGORY_ID | 400 | Invalid big category IDThe provided bigCategoryId is not a valid number. | Use the Catalog Explorer or GET /catalog/big-categories to find valid big category IDs.action: FIX_INPUT · retryable: false · retry_after: null |
| INVALID_ITEM_ID | 400 | Invalid item IDThe provided item ID is not valid. | Use the Catalog Explorer or GET /catalog/subcategories to find valid item IDs.action: FIX_INPUT · retryable: false · retry_after: null |
| INVALID_SUBCATEGORY | 400 | Invalid subcategoryThe subcategory ID does not exist. | Verify the sub_category_id using the catalog endpoints.action: FIX_INPUT · retryable: false · retry_after: null |
| INVALID_PRODUCT_CONFIG | 400 | Invalid product configurationNo longer returned. A missing requirement field now answers MISSING_REQUIRED_FIELD; a product that cannot be sold right now answers PRODUCT_UNAVAILABLE. | Handle MISSING_REQUIRED_FIELD and PRODUCT_UNAVAILABLE instead.No longer returned — replaced by MISSING_REQUIRED_FIELD |
| INVALID_PAGINATION | 400 | Invalid pagination parametersPage or limit values are out of range. | Use page >= 1 and limit between 1 and 100.action: FIX_INPUT · retryable: false · retry_after: null |
| INVALID_DATE_FORMAT | 400 | Invalid date formatThe created_after or created_before parameter is not a valid ISO 8601 date. | Use ISO 8601 format: 2024-01-01T00:00:00Z.action: FIX_INPUT · retryable: false · retry_after: null |
Player validation (400 / 429 / 503)
| Code | HTTP | What it means | How to fix it |
|---|---|---|---|
| PLAYER_NOT_FOUND | 400 | Player not foundThe game confirmed that this player ID does not exist. Only a confirmed answer returns this code — when the ID cannot be checked you get PLAYER_CHECK_UNAVAILABLE instead. | Verify the player ID is correct. Check if a zone_id is required for the game.action: FIX_INPUT · retryable: false · retry_after: null |
| PLAYER_CHECK_UNAVAILABLE | 503 | Player IDs for this game can't be verified right nowPlayer IDs for this game cannot be checked at the moment. The player ID was NOT rejected. | Try the same request again after retry_after seconds. Do not tell your customer the ID is wrong.action: RETRY_LATER · retryable: true · retry_after: 60 |
| PLAYER_BUSY | 429 | This player ID is already being checkedAnother request for the same player ID is still being checked. | Send the request again after retry_after seconds.action: RETRY_SOON · retryable: true · retry_after: 5 |
| PLAYER_VALIDATION_FAILED | 400 | Player validation failedNo longer returned. A player ID that cannot be checked right now answers PLAYER_CHECK_UNAVAILABLE (HTTP 503). | Handle PLAYER_CHECK_UNAVAILABLE instead.No longer returned — replaced by PLAYER_CHECK_UNAVAILABLE |
| REGION_MISMATCH | 400 | This player's region can't receive this productThe player belongs to a region this product cannot be delivered to. The error carries player_region and player_name. | Choose the product for the player's region.action: CHOOSE_OTHER · retryable: false · retry_after: null |
Business rules (400 / 409)
| Code | HTTP | What it means | How to fix it |
|---|---|---|---|
| INSUFFICIENT_BALANCE | 400 | Insufficient wallet balanceYour wallet does not have enough funds to complete this order. | Top up your wallet from the Reload page before placing the order.action: TOP_UP · retryable: false · retry_after: null |
| OUT_OF_STOCK | 400 | Product is out of stockThe requested product is out of stock right now. | Try again later or choose a different product.action: RETRY_LATER · retryable: true · retry_after: null |
| INSUFFICIENT_STOCK | 400 | Fewer units are available than requestedFewer units are available than your order asked for. Unlike OUT_OF_STOCK this one you can act on: error.max_quantity is how many units can be ordered right now. Nothing was charged. | Send the order again with a quantity of error.max_quantity or less.action: FIX_INPUT · retryable: false · retry_after: null |
| PRODUCT_UNAVAILABLE | 409 | This product is temporarily unavailableThe product exists but cannot be sold right now. | Try again later, or choose a different product.action: RETRY_LATER · retryable: true · retry_after: null |
| PRICING_UPDATING | 409 | Product pricing is being updatedThis product's price is being refreshed. | Send the same request again after retry_after seconds, then re-check the price.action: RETRY_SOON · retryable: true · retry_after: 30 |
| OFFER_NOT_FOUND | 400 | This offer is not available for this player accountA one-time offer (for example a first-top-up bonus) is not available for this player account — it may already have been used. | Choose a different product for this player.action: CHOOSE_OTHER · retryable: false · retry_after: null |
| DUPLICATE_ORDER | 409 | Duplicate order IDAn order with this UUID already exists. This is an idempotency protection. | Generate a new UUID for a new order. Getting this on a retry means the first attempt went through: read that order with GET /orders/{orderId} instead of creating another.action: CHECK_ORDER · retryable: false · retry_after: null |
| PRICE_INCREASED | 400 | Price has increased beyond expectedThe current unit price is higher than the expected_unit_price you provided. | Fetch the latest price with GET /catalog/subcategory/:id/price and update expected_unit_price.action: FIX_INPUT · retryable: false · retry_after: null |
| SUBCATEGORY_DISABLED | 400 | Subcategory is disabledNo longer returned. A product that cannot be sold right now answers PRODUCT_UNAVAILABLE (HTTP 409). | Handle PRODUCT_UNAVAILABLE instead.No longer returned — replaced by PRODUCT_UNAVAILABLE |
Not found (404)
| Code | HTTP | What it means | How to fix it |
|---|---|---|---|
| ORDER_NOT_FOUND | 404 | Order not foundNo order exists with the given order ID. | Verify the order ID is correct.action: FIX_INPUT · retryable: false · retry_after: null |
| ITEM_NOT_FOUND | 404 | Item not foundThe requested catalog item does not exist. | Use the catalog endpoints to find valid item IDs.action: FIX_INPUT · retryable: false · retry_after: null |
| NO_REQUIREMENTS_FOUND | 404 | No requirements found for this categoryThe category has no player requirements to return right now. | Try again later, or pick another category.action: RETRY_LATER · retryable: true · retry_after: null |
| ITEM_NOT_AVAILABLE | 404 | Item not availableNo longer returned. An item that exists but cannot be sold right now answers PRODUCT_UNAVAILABLE (HTTP 409). | Handle PRODUCT_UNAVAILABLE instead.No longer returned — replaced by PRODUCT_UNAVAILABLE |
Batch request validation (400)
| Code | HTTP | What it means | How to fix it |
|---|---|---|---|
| INVALID_ORDER_IDS_FORMAT | 400 | Invalid order_ids formatThe order_ids field must be an array of strings. | Provide order_ids as: { "order_ids": ["uuid1", "uuid2"] }.action: FIX_INPUT · retryable: false · retry_after: null |
| EMPTY_ORDER_IDS | 400 | Empty order_ids arrayThe order_ids array cannot be empty. | Provide at least one order ID in the array.action: FIX_INPUT · retryable: false · retry_after: null |
| TOO_MANY_ORDER_IDS | 400 | Too many order IDsMaximum 50 order IDs can be queried at once. | Split your request into batches of 50 or fewer.action: FIX_INPUT · retryable: false · retry_after: null |
Rate limiting (429)
| Code | HTTP | What it means | How to fix it |
|---|---|---|---|
| RATE_LIMIT_EXCEEDED | 429 | Rate limit exceededYou have exceeded the limit for this endpoint. The per-minute buckets (catalog, orders, account) send X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset on every response, and details repeats limit, remaining (0), retry_after and window_seconds. POST /player/validate is metered by your daily player-check quota instead: it sends no X-RateLimit headers, and its 429 carries limit, current, remaining, reset_at and reset_in_seconds inside error. Either way error.retry_after and the Retry-After header carry the seconds to wait. | Wait for the number of seconds in retry_after or the Retry-After header before retrying. On the per-minute endpoints, watch X-RateLimit-Remaining to avoid hitting the limit at all.action: RETRY_LATER · retryable: true · retry_after: seconds to reset |
Server side (5xx)
| Code | HTTP | What it means | How to fix it |
|---|---|---|---|
| INTERNAL_ERROR | 500 | Internal server errorAn unexpected error occurred on the server. | Send the request again after retry_after seconds. For POST /orders/create reuse the same order_id, so the order can never be created twice. If it persists, contact support.action: RETRY_LATER · retryable: true · retry_after: 30 |
| SERVICE_UNAVAILABLE | 503 | Service temporarily unavailableNo longer returned. A server-side fault answers INTERNAL_ERROR (HTTP 500); the only 503 is PLAYER_CHECK_UNAVAILABLE, when a player ID cannot be checked right now. | Handle INTERNAL_ERROR and PLAYER_CHECK_UNAVAILABLE instead.No longer returned — replaced by INTERNAL_ERROR |
New to the platform? Start with the game top-up API overview for resellers, or read the SHOP2TOPUP reseller programme overview for how the partner account works.