Error Codes
รหัสข้อผิดพลาด
Error response format
รูปแบบ Error response
When a request fails, the API returns a non-200 status code with a JSON body shaped like this:
เมื่อ request ล้มเหลว API จะส่งกลับ status ที่ไม่ใช่ 200 พร้อม JSON body ในรูปแบบนี้:
{
"code": 422,
"error": "invalid-inputs",
"success": false,
"message": "amount must be at least 20"
}
code— the HTTP status code mirrored in the body (number).code— HTTP status code ของ response (number) ที่ใส่ใน body ด้วยerror— a stable machine-readable identifier (kebab-case). Use this in code branching.error— รหัสคงที่ใช้เช็คในโค้ด (kebab-case)success— alwaysfalseon error responses (boolean).success— เป็นfalseเสมอใน error response (boolean)message— a human-readable description. May change wording without notice; do not parse this.message— ข้อความสำหรับมนุษย์อ่าน — อาจเปลี่ยนได้โดยไม่แจ้งล่วงหน้า — อย่าใช้ parse
Every API endpoint (including /slip/upload) returns errors in this format. Build one error handler, use it everywhere.
ทุก endpoint (รวม /slip/upload) ใช้รูปแบบ error แบบเดียวกัน — สร้าง handler ตัวเดียวใช้ได้กับทุก endpoint
Authentication errors
Errors ของ Authentication
These can be returned by any authenticated endpoint.
ทุก endpoint ที่ต้องยืนยันตัวตนมีโอกาสส่งกลับ error เหล่านี้
| HTTP | Code | Meaning | What to do | รหัส | ความหมาย | ทำอย่างไร |
|---|---|---|---|---|---|---|
| 405 | method-not-allowed |
Used a non-POST method on a POST-only endpoint. | Switch to POST. Only /health uses GET. |
method-not-allowed |
ใช้ method ที่ไม่ใช่ POST | เปลี่ยนเป็น POST — มีเฉพาะ /health เท่านั้นที่ใช้ GET |
| 403 | authentication-failed |
Wrong merchant_id, wrong token, or merchant not found. |
Re-check credentials with your payment gateway admin. | authentication-failed |
merchant_id หรือ token ผิด หรือไม่พบ merchant |
ตรวจ credentials กับ payment gateway admin อีกครั้ง |
| 403 | signature-required |
Missing X-SIGNATURE header. |
Compute and add the header. | signature-required |
ไม่ได้ส่ง header X-SIGNATURE |
คำนวณแล้วใส่ header |
| 403 | signature-error |
HMAC doesn't match the body. | Most likely cause: re-serializing JSON before sending. Sign the exact bytes you send. See Authentication. | signature-error |
HMAC ไม่ตรงกับ body | สาเหตุที่พบบ่อย: serialize JSON ใหม่ก่อนส่ง — ต้องเซ็น bytes ตัวเดียวกับที่ส่ง — ดู Authentication |
| 403 | ip-not-whitelisted |
Source IP not in your merchant's whitelist (when configured). | Ask admin to add your egress IP, or remove the whitelist. | ip-not-whitelisted |
Source IP ไม่อยู่ใน whitelist (ถ้าเปิดใช้) | ขอ admin เพิ่ม egress IP หรือ remove whitelist |
| 400 | invalid-inputs |
Body is missing or not valid JSON. | Verify Content-Type and JSON syntax. |
invalid-inputs |
Body หาย หรือ JSON ไม่ถูกต้อง | ตรวจ Content-Type และ syntax JSON |
Endpoint-specific errors
Errors เฉพาะ Endpoint
| HTTP | Code | Endpoints | When it happens | รหัส | Endpoints | เกิดเมื่อ |
|---|---|---|---|---|---|---|
| 400 | invalid-inputs |
All | Missing or invalid required fields (e.g. time missing or out of acceptable range, amount < min, bank not recognized, account_no length, malformed URL), insufficient balance for create operations. |
invalid-inputs |
ทุก endpoint | Field ขาด, รูปแบบผิด (amount < min, bank ผิด, account_no ผิด, URL ผิด), หรือยอดไม่พอสำหรับ create operation |
| 409 | duplicate-entry |
/payment/create, /payment/create-transfer, /withdraw/create, /thb-settlement/create | Duplicate merchant_order_id within 7 days (payment, settlement) or duplicate bank+account+amount within 3 minutes (withdraw, when enabled). |
duplicate-entry |
/payment/create, /payment/create-transfer, /withdraw/create, /thb-settlement/create | merchant_order_id ซ้ำใน 7 วัน (payment, settlement) หรือ bank+account+amount ซ้ำใน 3 นาที (withdraw — ถ้าเปิดใช้) |
| 403 | permission-denied |
/payment/create, /withdraw/create, /thb-settlement/create | Operation disabled on your merchant, or settlement called outside operating hours. | permission-denied |
/payment/create, /withdraw/create, /thb-settlement/create | Operation ปิดที่ merchant ของคุณ หรือเรียก settlement นอกเวลาที่อนุญาต |
| 503 | service-unavailable |
/payment/create, /payment/create-transfer | No deposit account currently available to receive payment. Retry shortly. | service-unavailable |
/payment/create, /payment/create-transfer | ไม่มีบัญชีรับเงินที่ว่างขณะนี้ — ลองใหม่ในอีกสักครู่ |
| 429 | channel-limit-reached |
/payment/create, /payment/create-transfer | Deposit channel hit its hourly or daily limit. | channel-limit-reached |
/payment/create, /payment/create-transfer | Channel รับเงินถึงโควตารายชั่วโมงหรือรายวัน |
| 429 | too-many-requests |
/slip/upload | Rate limit hit — either >1 slip upload per order in the last 5 minutes, or order is too fresh and the configured wait time has not elapsed. | too-many-requests |
/slip/upload | Rate limit — อัปโหลดสลิปเกิน 1 ครั้งต่อ order ใน 5 นาที หรือ order ยังใหม่เกิน รอตามเวลาที่ตั้งไว้ก่อน |
| 404 | not-found |
All query endpoints, all create endpoints (partner config) | Order not found / not owned by you, or partner config missing on the merchant. Contact admin if the create endpoints return this. | not-found |
ทุก query endpoint, ทุก create endpoint (partner config) | ไม่พบ order หรือ order เป็นของ merchant อื่น หรือไม่มี partner config ของ merchant — ถ้า create endpoint ส่งกลับ error นี้ ให้ติดต่อ admin |
Recommended handling
วิธี handle ที่แนะนำ
| Error class | Strategy | กลุ่ม Error | วิธีรับมือ |
|---|---|---|---|
signature-error, signature-required |
Bug in your code — fix and redeploy. Do not retry the same request. | signature-error, signature-required |
เป็น bug ในโค้ดคุณ — แก้และ deploy ใหม่ — อย่า retry request เดิม |
authentication-failed, ip-not-whitelisted |
Configuration issue — escalate to your payment gateway admin. | authentication-failed, ip-not-whitelisted |
ปัญหา configuration — แจ้ง payment gateway admin |
invalid-inputs, permission-denied |
Caller error — log and surface to your operator. No retry. | invalid-inputs, permission-denied |
Caller error — log แล้วแจ้ง operator — ไม่ต้อง retry |
duplicate-entry |
Treat as success if you intended an idempotent retry — query the existing order to confirm. | duplicate-entry |
ถ้าตั้งใจ retry แบบ idempotent ให้ถือว่าสำเร็จ — query order เดิมยืนยันสถานะ |
service-unavailable, channel-limit-reached |
Retry with exponential backoff (e.g. 30s → 1m → 2m → 5m). Surface to operator after a few minutes of failures. | service-unavailable, channel-limit-reached |
Retry แบบ exponential backoff (เช่น 30s → 1m → 2m → 5m) — แจ้ง operator ถ้ายังพังหลายนาที |
not-found |
For queries: order doesn't exist on our side — investigate. For creates: contact admin. | not-found |
สำหรับ query: order ไม่มีฝั่งเรา — ต้องตรวจสอบ — สำหรับ create: ติดต่อ admin |
| 5xx (server error) | Retry with backoff. If persistent, escalate. | 5xx (server error) | Retry แบบ backoff — ถ้ายังเป็น escalate |
A signature or authentication error indicates a deterministic bug — retrying with the same payload will fail every time. Worse, retries against payment/withdraw create endpoints can create duplicate orders if the failure is in your code path that builds the body.
Signature หรือ auth error แปลว่ามีบั๊กที่ deterministic — retry payload เดิมจะ fail ทุกครั้ง — ยิ่งกว่านั้น การ retry create endpoint อาจสร้าง order ซ้ำถ้า bug อยู่ใน code ที่สร้าง body