Orders and checkout links
An order is one purchase. Your game server creates it when the player taps buy.
Base URL: https://api.ez2pay.gg
Every request uses your game's API key:
Authorization: Bearer ez2_live_...
Call the API from your server only. Errors are JSON in the form {"error":"CODE"}. See Errors and fixes. Request bodies are limited to 16 KiB.
Create an order
curl -X POST https://api.ez2pay.gg/v1/orders \
-H "Authorization: Bearer $EZ2PAY_API_KEY" \
-H "Idempotency-Key: purchase-7f3a9c" \
-H "Content-Type: application/json" \
-d '{"sku":"gem_pack_100","buyer":"p_123","customer_email":"[email protected]","return_url":"https://game.example/topup/result"}'
| Field | Meaning | Rules |
|---|---|---|
sku | The SKU code | 1-100 characters. Must be an active SKU in this game |
buyer | Your player's ID | 1-200 characters. This is who you deliver to |
customer_email | The player's email, for the receipt | Valid email, up to 254 characters. Never returned to AI through MCP |
return_url | Your result page | HTTPS, up to 2048 characters, no username or password |
There is no price field. EZ2Pay always takes the price from the SKU. Any field not listed here is rejected with 400.
The game must be approved. Otherwise the API answers 409 GAME_APPROVAL_REQUIRED.
Idempotency-Key
This header is required. It stops your server from creating two orders when it retries.
- Same key and same input: returns the existing order with
200. - Same key and changed input:
409 IDEMPOTENCY_CONFLICT. - A new purchase always needs a new key.
- Format: 1-200 printable ASCII characters with no spaces.
The response
A new order answers 201. A replay of the same key answers 200.
{
"order_id": "ord_00000000-0000-4000-8000-000000000001",
"sku": "gem_pack_100",
"buyer": "p_123",
"status": "CREATED",
"amount": "100.00",
"currency": "THB",
"checkout_url": "https://pay.ez2pay.gg/my-fantasy-town?t=Xk29fQ...",
"expires_at": "2026-11-09T05:10:00.000Z",
"paid_at": null,
"delivered_at": null,
"paid_channel": null,
"unlock_at": null,
"void_reason": null
}
| Field | Meaning |
|---|---|
order_id | ord_ followed by a UUID |
amount | Full retail price the player pays EZ2Pay, as a string with 2 decimals. Not the amount you receive |
currency | Always THB |
checkout_url | Send the player here |
expires_at | When the order stops accepting new payments, in UTC |
paid_at | When payment was first confirmed, in UTC. Never changes once set |
delivered_at | When you acknowledged delivery, in UTC |
paid_channel | promptpay or card, once paid |
unlock_at | The date you can receive payment for this sale, in UTC |
void_reason | Why the order was cancelled, if it was |
Use the checkout link
- Send the player to
checkout_url. - The checkout page shows your game, the item, the price and Seller: EZ2Pay.
- The player pays. PromptPay QR is open now. Card shows "coming soon" until it opens.
An order accepts new payments for 10 minutes. A QR lasts 10 minutes from when it is issued, so a player who starts just before expires_at can still finish. The order shows EXPIRED and then moves to PAID. Treat that webhook as a normal sale.
After expires_at, create a new order with a new Idempotency-Key. Reusing the old key returns the expired order.
return_url is where the player lands afterwards. It is for display only. Arriving there proves nothing, so never deliver goods from it.
Read an order
curl https://api.ez2pay.gg/v1/orders/ord_00000000-0000-4000-8000-000000000001 \
-H "Authorization: Bearer $EZ2PAY_API_KEY"
Answers the same fields as above. An order that belongs to another game answers 404 ORDER_NOT_FOUND.
Order statuses
| Status | Meaning |
|---|---|
CREATED | Created. The player has not started paying |
PENDING_PAYMENT | Payment issued. Waiting for the player |
PAID | Payment confirmed |
NOTIFYING | The webhook is being sent to your server |
NOTIFIED | Your server answered 200 |
DELIVERED | Your server answered 200 and acknowledged delivery |
EXPIRED | The payment window ended |
NOTIFY_FAILED | Every webhook attempt failed. The order is still paid. Resend it from the Dashboard |
MISMATCH | Payment details did not match. The EZ2Pay team reviews it. Never deliver |
VOIDED | Cancelled by EZ2Pay |
FAILED | The payment could not be created |
Only these statuses mean the order is paid: PAID, NOTIFYING, NOTIFIED, NOTIFY_FAILED, DELIVERED.
Cancellations and resending
The API has no endpoint to cancel an order or to resend a webhook. Use the Dashboard: search the order by Order ID or Player ID, resend the notification, or escalate it to EZ2Pay.
Next: Webhooks and delivery