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 ในรูปแบบนี้:

JSON
{
  "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 — always false on error responses (boolean).
  • success — เป็น false เสมอใน error response (boolean)
  • message — a human-readable description. May change wording without notice; do not parse this.
  • message — ข้อความสำหรับมนุษย์อ่าน — อาจเปลี่ยนได้โดยไม่แจ้งล่วงหน้า — อย่าใช้ parse
All endpoints use the same shape
ทุก endpoint ใช้ shape เดียวกัน

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 เหล่านี้

HTTPCodeMeaningWhat to do รหัสความหมายทำอย่างไร
405method-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
403authentication-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 อีกครั้ง
403signature-required Missing X-SIGNATURE header. Compute and add the header. signature-required ไม่ได้ส่ง header X-SIGNATURE คำนวณแล้วใส่ header
403signature-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
403ip-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
400invalid-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

HTTPCodeEndpointsWhen it happens รหัสEndpointsเกิดเมื่อ
400invalid-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
409duplicate-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 — ถ้าเปิดใช้)
403permission-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 นอกเวลาที่อนุญาต
503service-unavailable /payment/create, /payment/create-transfer No deposit account currently available to receive payment. Retry shortly. service-unavailable /payment/create, /payment/create-transfer ไม่มีบัญชีรับเงินที่ว่างขณะนี้ — ลองใหม่ในอีกสักครู่
429channel-limit-reached /payment/create, /payment/create-transfer Deposit channel hit its hourly or daily limit. channel-limit-reached /payment/create, /payment/create-transfer Channel รับเงินถึงโควตารายชั่วโมงหรือรายวัน
429too-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 ยังใหม่เกิน รอตามเวลาที่ตั้งไว้ก่อน
404not-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
Never retry signature/auth errors
ห้าม retry signature/auth error

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