API /v1/x402
Three endpoints. No authentication on plan discovery. Payment is the auth on order creation. Below: full request/response schema for each.
https://api.esimahora.com/api/v1/x402/plans
List all available eSIM plans, optionally filtered by country. No authentication. Cached for 5 minutes server-side.
| Param | Type | Description |
|---|---|---|
| country | string (ISO 2) | Optional. Filter to plans for one country, e.g. JP, US, TR. |
| type | enum | Optional. single | regional | global. |
{
"plans": [
{
"id": "JP_5GB_30D",
"country": "JP",
"country_name": "Japan",
"data_gb": 5,
"validity_days": 30,
"price_usd": 6.21,
"carrier": "NTT Docomo / SoftBank",
"type": "single",
"topup_supported": true
},
...
],
"count": 18
}/order
Create a pending order. Server reserves the order, replies 402 Payment Required with payment details in the response headers. Order expires in 30 minutes if unpaid (no cost to you).
{
"plan_id": "JP_5GB_30D",
"callback_url": "https://your-server.example.com/x402-webhook" // optional
}Critical headers (the x402 protocol payload):
| Header | Description |
|---|---|
| x-payto | Recipient address (0x... for Polygon, EQ... for TON) |
| x-amount | Amount in USD as decimal string, e.g. "6.21" |
| x-asset | USDC or USDT (uppercase) |
| x-chain | polygon or ton (lowercase) |
| x-token-address | On-chain token contract address (USDC/USDT on the chosen chain) |
| x-expires | ISO 8601 — pay before this or the order expires |
| x-order-id | Same as the body order_id, for clients that read headers only |
{
"order_id": "ord_a8f3b2c1d5e4f6a9",
"status": "awaiting_payment",
"plan_id": "JP_5GB_30D",
"payment": {
"to": "0x742d35cc6634c053...",
"amount_usd": "6.21",
"asset": "USDC",
"chain": "polygon",
"token_address": "0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174",
"expires_at": "2026-05-15T14:30:00Z"
}
}/order/{order_id}
Poll an order's status. Returns 402 while awaiting payment, 200 once eSIM is delivered, 410 if the order expired, 404 if the id doesn't exist.
{
"order_id": "ord_a8f3b2c1d5e4f6a9",
"status": "delivered",
"plan_id": "JP_5GB_30D",
"esim": {
"iccid": "8901260123456789012",
"qr_code_data": "LPA:1$smdp.example.com$matching_id",
"qr_image_url": "https://api.esimahora.com/esim/qr/8901260...png",
"activation_link": "https://esimsetup.apple.com/esim_qrcode_provisioning?carddata=LPA:1$..."
},
"payment": {
"tx_hash": "0xabc123...",
"confirmed_at": "2026-05-15T14:05:23Z",
"asset": "USDC",
"amount_usd": "6.21"
}
}Error catalog
| Status | Code | Cause |
|---|---|---|
| 400 | invalid_plan | plan_id not in catalog or disabled |
| 400 | malformed_request | JSON parse error or missing required field |
| 402 | awaiting_payment | Normal — keep polling. Not actually an error. |
| 404 | order_not_found | order_id never existed or was purged |
| 410 | order_expired | Payment window passed. Create a new order. |
| 422 | underpaid | Tx confirmed but amount < required. Refund issued. |
| 422 | wrong_chain | Tx confirmed on different chain than order specified. |
| 429 | rate_limited | Slow down. 60 req/min per IP on /order, 600/min on /plans. |
| 500 | internal_error | Server bug. Logged. Retry with exponential backoff. |
| 503 | esim_provider_unavailable | Wholesale provider (eSIM Access) is down. Order auto-retries; if still 503 after 60s, refund. |
Refunds
Failed orders refund automatically to the address that paid (within ~5 minutes after the failure is detected). No support ticket needed.
User-requested refund (e.g. "I activated the wrong country"): not available — once the eSIM ICCID is issued by the wholesaler, we owe them. This is a hard rule of the protocol and is documented at order time.
Webhooks (optional)
If you pass callback_url when creating an order, we POST status updates to that URL instead of you having to poll. Signed with HMAC-SHA256 using a secret you generate at first call.
{
"order_id": "ord_a8f3b2c1d5e4f6a9",
"event": "delivered",
"timestamp": "2026-05-15T14:05:23Z",
"esim": { ... } // same shape as GET /order/{id}
}
# Headers:
# x-x402-signature: sha256=abc123... (verify with your secret)
# x-x402-timestamp: 1715785523Rate limits
- ·
GET /plans: 600 requests / minute / IP - ·
POST /order: 60 requests / minute / IP - ·
GET /order/{id}: 600 requests / minute / IP
Higher limits for verified high-volume customers — see /contact.
Need help?
Email dev@esimx402.com with: order_id (if relevant), tx_hash (if you paid), expected vs actual behavior. Same-business-day response on most enquiries.
Contact details