Errors and fixes
API errors are JSON in the form {"error":"CODE"}.
Error codes
| HTTP | Code | Meaning |
|---|---|---|
400 | INVALID_REQUEST | A field is malformed, or a field was sent that is not allowed |
400 | IDEMPOTENCY_KEY_REQUIRED | The Idempotency-Key header is missing or malformed |
401 | LIVE_KEY_REQUIRED | The Authorization header is missing or is not a valid ez2_live_... key |
401 | INVALID_API_KEY | The key is unknown or revoked |
401 | INVALID_MCP_TOKEN | The MCP token is malformed, expired or revoked |
403 | MCP_FORBIDDEN | An MCP token tried a route or scope it is not allowed to use |
403 | MCP_DRAFT_ONLY | MCP tried to create a SKU in a game that is not draft, or to set the webhook URL of a game that is not draft or that has orders |
404 | SKU_NOT_FOUND | No active SKU has this code in this game. pending and suspended SKUs cannot be sold |
404 | ORDER_NOT_FOUND | The order does not exist or belongs to another game |
404 | GAME_NOT_FOUND | The game does not exist or is not yours |
409 | IDEMPOTENCY_CONFLICT | This Idempotency-Key was used with different input |
409 | GAME_APPROVAL_REQUIRED | The game is not approved yet |
409 | ORDER_NOT_NOTIFIED | Delivery was acknowledged while the order was not NOTIFYING, NOTIFIED or DELIVERED |
409 | GAME_SLUG_UNAVAILABLE | Another game already uses this slug |
409 | SKU_CODE_EXISTS | This game already has a SKU with this code |
413 | PAYLOAD_TOO_LARGE | The request body is over 16 KiB |
415 | JSON_REQUIRED | The request needs Content-Type: application/json |
422 | UNSAFE_WEBHOOK_URL | The webhook URL is not public HTTPS |
500 | INTERNAL_ERROR | An unexpected error. Try again |
Common mistakes
Signature check fails
Your framework parsed the JSON before you read it, so the bytes changed. Read the raw body first. See other frameworks.
If only some webhooks fail, check for player names with non-ASCII characters. Sign the raw bytes, not a re-encoded string.
If every webhook started failing after someone pressed สร้าง secret ใหม่, your server still has the old secret. See Changing the webhook secret.
Clock skew
Your server clock is more than 5 minutes off. Sync it with NTP.
The webhook keeps repeating
Your server answered something other than 200. 201 and 204 count as failed. Answer exactly 200.
Goods delivered twice
You tracked "already granted" in memory, or outside the transaction. Store the order_id in the same database transaction as the grant. See Grant exactly once.
The order is not confirmed paid
The order is not in a paid status, or its sku or buyer differ from the webhook. Do not grant. If the player says they paid, search the order in the Dashboard.
400 when creating an order
You sent a field that is not allowed, such as amount or price. Send only sku, buyer, customer_email and return_url.
409 IDEMPOTENCY_CONFLICT
You reused a key with different input. Each purchase needs a new key. A retry of the same purchase must send the same input.
SKU_NOT_FOUND for a SKU you can see
The SKU is pending or suspended, or it belongs to another game. Only active SKUs can be sold.
The order stays at NOTIFIED
Your acknowledgement failed, for example your server crashed after granting. Check that the goods were granted, then call POST /v1/orders/{id}/delivered. It is safe to call again.
Webhook URL refused
The URL must be HTTPS on port 443, and must resolve to a public address. localhost and private addresses are refused, and redirects are not followed.
Rounding errors in money
0.1 + 0.2 is not 0.3 in floating point. Keep integer satang. amount is a string such as "100.00". Compare it as a string, or convert it to integer satang.
A player paid but the goods did not arrive
- The player opens the receipt and contacts your game team.
- Search the order in the Dashboard by Order ID or Player ID.
- If it is
NOTIFY_FAILED, resend the notification. - If you cannot fix it, escalate it to EZ2Pay from the same screen.
Still stuck
Escalate from the order search screen in the Dashboard, and include the Order ID.