ข้อผิดพลาด
ทุกความล้มเหลวกลับมาเป็น JSON รูปแบบเดียวกันเสมอ ไม่ว่าจะผิดพลาดเรื่องอะไร
รหัสสถานะ HTTP บอกประเภทของปัญหา ส่วนช่อง error บอกว่าเป็นตัวไหนแน่ชัด
รูปแบบข้อผิดพลาด
หัวข้อที่มีชื่อว่า “รูปแบบข้อผิดพลาด”{ "ok": false, "error": "shop_not_in_scope", "message": "this API key cannot access that shopId"}| ช่อง | มีเสมอไหม | หมายเหตุ |
|---|---|---|
ok |
มี | เป็น false เสมอเมื่อผิดพลาด คำตอบที่สำเร็จจะเป็น "ok": true |
error |
มี | รหัสที่เครื่องอ่านได้และเสถียร ให้แตกสาขาที่ช่องนี้ |
message |
ในทางปฏิบัติมี | ข้อความสำหรับคนอ่าน เป็นภาษาอังกฤษ แก้ถ้อยคำได้ตลอด |
retryAfterSec |
เฉพาะ rate_limited |
จำนวนวินาทีที่ควรรอ คำตอบนั้นยังมี limit และ windowSec ด้วย |
รหัสสถานะ
หัวข้อที่มีชื่อว่า “รหัสสถานะ”| สถานะ | หมายความว่า | ควรลองใหม่ไหม |
|---|---|---|
200 |
สำเร็จ ผลลัพธ์ที่ data เป็นอาเรย์ว่างก็ยังนับว่าสำเร็จ |
— |
400 |
คำขอผิดรูป ขาดพารามิเตอร์ ส่งพารามิเตอร์ที่ขัดกันเอง หรือ cursor ตายแล้ว | ไม่ ให้แก้คำขอ |
401 |
ไม่มีกุญแจ กุญแจผิด หรือกุญแจถูกยกเลิก | ไม่ ให้แก้กุญแจ |
403 |
กุญแจถูกต้อง แต่ร้านหรือแบรนด์สมาชิกที่ขออยู่นอกขอบเขต หรือเส้นนั้นต้องใช้สิทธิ์รายกุญแจที่กุญแจใบนี้ยังไม่ได้รับ | ไม่ ให้ขอรหัสที่กุญแจอ่านได้ หรือขอเปิดสิทธิ์ |
404 |
ไม่มีบิลหรือสมาชิกนั้น หรือ อยู่นอกขอบเขตของคุณ | ไม่ |
429 |
ยิงถี่เกินไปในนาทีนี้ หรือโควตารายวันหมด | ควร แต่ต้องรอก่อน |
500 |
มีบางอย่างล้มเหลวฝั่งเรา | ควร แบบถอยเวลาเพิ่มขึ้น |
503 |
ระบบตรวจกุญแจไม่พร้อมชั่วคราวฝั่งเรา | ควร แบบถอยเวลาเพิ่มขึ้น |
สังเกตความต่างระหว่าง 403 กับ 404 ซึ่งตั้งใจให้ต่างกัน เส้นแบบลิสต์ตอบ 403
เพราะ shopId หรือ providerId ที่ส่งมาเป็นค่าที่คุณรู้อยู่แล้ว ส่วนเส้นที่ขอรายการเดียว
ตอบ 404 ทั้งกรณี “ไม่มีบิลนี้” และ “บิลนี้อยู่ในร้านที่คุณอ่านไม่ได้”
เพื่อไม่ให้คำตอบยืนยันว่ารหัสนั้นมีอยู่ที่อื่นใน ScanFood หรือไม่
รหัสข้อผิดพลาด
หัวข้อที่มีชื่อว่า “รหัสข้อผิดพลาด”| สถานะ | error |
เกิดเมื่อ |
|---|---|---|
400 |
bad_query |
shopId is required เส้นลิสต์บิลต้องมีร้าน |
400 |
bad_query |
providerId is required เส้นลิสต์สมาชิกต้องมีแบรนด์ |
400 |
bad_query |
choose exactly one mode: from+to (calendar days) or updatedSince (ISO-8601) ส่งมาทั้งสองโหมด หรือไม่ส่งเลย |
400 |
bad_query |
updatedSince must be an ISO-8601 datetime วันนี้ตัวตรวจยังหลวม รูปแบบนอกมาตรฐานอย่าง 2026/09/01 จึงอาจผ่านไปได้ แต่ให้ส่งเป็น ISO-8601 จริงเสมอ เพราะนั่นคือรูปแบบที่เรารองรับ |
400 |
bad_query |
from/to must be YYYYMMDD ฝั่งคำขอไม่มีขีด |
400 |
bad_query |
from must be <= to |
400 |
bad_query |
range too wide: N days (max 31) |
400 |
bad_query |
id is required ไม่มีรหัสบิลในเส้นทาง |
400 |
bad_query |
เรียกเส้นค้นสมาชิกโดยไม่ส่ง providerId หรือส่ง lineUserId ที่ไม่ได้อยู่ในรูป U ตามด้วยเลขฐานสิบหก 32 ตัว |
400 |
bad_cursor |
cursor no longer exists แถวที่ cursor ชี้อยู่หายไปแล้ว |
400 |
bad_cursor |
cursor is not a valid member token ส่งค่าที่ไม่ใช่ token รูป m1_… |
400 |
not_supported |
ส่ง updatedSince ที่เส้นลิสต์สมาชิก การซิงก์เฉพาะส่วนที่เปลี่ยนของสมาชิกยังไม่เปิด ให้ไล่หน้าด้วย cursor แทน |
401 |
invalid_key |
Invalid API key ไม่มีกุญแจ ผิดรูป ไม่มีอยู่จริง หรือรหัสลับผิด ทั้งสี่แบบตอบเหมือนกัน |
401 |
key_revoked |
API key has been revoked |
403 |
shop_not_in_scope |
this API key cannot access that shopId |
403 |
provider_not_in_scope |
this API key cannot access that providerId |
403 |
lookup_not_enabled |
กุญแจใบนี้ยังไม่ได้เปิดสิทธิ์ค้นสมาชิก สิทธิ์นี้ให้เป็นรายกุญแจเหมือน tel และ email ดูที่ สมาชิก |
404 |
not_found |
transaction not found รหัสไม่มีอยู่ หรือเป็นบิลของร้านนอกขอบเขต |
404 |
not_found |
member not found token ไม่ถูกต้อง ไม่มีสมาชิกนั้น หรือแบรนด์อยู่นอกขอบเขต |
404 |
not_found |
ค้นด้วย LINE user id แล้วไม่พบสมาชิกที่ตรงกัน คำตอบเดียวสำหรับสามกรณี ไม่ได้เป็นสมาชิกของแบรนด์นี้ เป็นสมาชิกของแบรนด์อื่น หรือไม่มีตัวตนเลย |
429 |
rate_limited |
Too many requests, retry in about N seconds ยิงเกินขีดจำกัดต่อนาที ใน body มี retryAfterSec limit windowSec และส่วนหัว Retry-After บอกค่าเดียวกัน |
429 |
quota_exceeded |
daily quota exceeded (N requests/day, Thailand time). Resets at 00:00 ICT. |
500 |
internal |
temporary failure, please retry เป็นฝั่งเรา |
503 |
auth_unavailable |
Authentication service temporarily unavailable, retry later ระบบตรวจกุญแจไม่พร้อมชั่วคราว เราตอบ 503 แทน 401 เพื่อไม่ให้คุณเสียเวลาไปไล่ตรวจกุญแจที่ไม่ได้มีปัญหาอะไรเลย |
การลองใหม่อย่างปลอดภัย
หัวข้อที่มีชื่อว่า “การลองใหม่อย่างปลอดภัย”ทุกเส้นเป็น GET ที่ไม่เปลี่ยนข้อมูลของร้าน การลองใหม่จึงไม่มีทางทำให้บิลซ้ำ
หรือทำอะไรซ้ำซ้อนได้ ร่องรอยที่การยิงซ้ำทิ้งไว้คือตัวนับโควตาเพิ่มขึ้นหนึ่ง
และอีกหนึ่งแถวในสมุดคำขอของเรา ซึ่งเก็บไว้ 90 วัน
นโยบายลองใหม่ที่ใช้ได้จริง
| สถานการณ์ | นโยบาย |
|---|---|
429 rate_limited |
รอตาม Retry-After วินาที แล้วลองใหม่ อย่าลดเวลารอ |
429 quota_exceeded |
หยุดจนถึง 00:00 น. เวลาไทย หรือขอเพิ่มโควตา ลองใหม่เร็วกว่านั้นคือเผาคำขอทิ้งเปล่า ๆ |
500 503 การเชื่อมต่อหลุด หมดเวลา |
ถอยเวลาเพิ่มขึ้นแบบมีการสุ่ม เช่น 1 วิ 2 วิ 4 วิ 8 วิ ไม่เกินห้าครั้ง |
400 401 403 404 |
อย่าลองใหม่ คำขอเดิมยิงอีกกี่ครั้งก็ไม่สำเร็จ |
อีกสองนิสัยที่ควรมี
- เขียน log รหัส
errorสถานะ และพารามิเตอร์ของคำขอ แต่อย่าเขียนกุญแจลงไป รหัสกุญแจ 12 ตัวเขียนได้ ส่วนรหัสลับเขียนไม่ได้ - ถือว่า cursor ตายคือการเริ่มหน้านั้นใหม่ ไม่ใช่ความล้มเหลว
bad_cursorแปลว่าแถวที่ cursor ชี้อยู่หายไปแล้ว ให้ทิ้ง cursor แล้วขอหน้านั้นใหม่ตั้งแต่ต้นช่วง ดู การแบ่งหน้าและการซิงก์