โหมดมืด
ภาพรวม API
API ของ KlevIQ เป็น HTTP/JSON ทั้งหมด ทุก endpoint ใช้รูปแบบเดียวกันและรับส่งข้อมูลเป็น UTF-8 เท่านั้น หน้านี้อธิบายกฎที่ใช้ร่วมกันทุก endpoint เพื่อไม่ต้องเขียนซ้ำในหน้าอ้างอิงของแต่ละโมดูล
รูปแบบที่อยู่
ทุกอย่างอยู่ใต้โดเมนของไซต์คุณเอง ไม่มี API gateway กลาง — หนึ่งลูกค้าคือหนึ่งโฮสต์ ไซต์ของแต่ละบริษัทมี base URL ของตัวเอง และ token ของไซต์หนึ่งใช้กับอีกไซต์ไม่ได้
มีสองตระกูลที่ต้องแยกให้ออก
| ตระกูล | รูปแบบ | ใช้เมื่อ |
|---|---|---|
| Resource | /api/resource/<DocType> และ /api/resource/<DocType>/<name> | อ่าน–เขียนเอกสารตรง ๆ GET อ่าน · POST สร้าง · PUT แก้ · DELETE ลบ |
| Method | /api/method/<เส้นทางฟังก์ชัน> | เรียกฟังก์ชันที่เปิดไว้ให้เรียก เช่นการคำนวณหรือการทำงานหลายขั้นในครั้งเดียว |
ชื่อ DocType ใส่ตามชื่อจริงรวมช่องว่าง เช่น /api/resource/Sales Invoice (เข้ารหัส URL ตามปกติ)
เลขรุ่นอยู่ใน path — /api/v1/... และ /api/v2/... โดย /api/resource/... ที่ไม่ระบุรุ่นเทียบเท่ากับ v1 รุ่น 2 เปลี่ยนคำว่า resource เป็น document และเพิ่ม /api/v2/doctype/<DocType>/meta กับ /count เข้ามา สำหรับงานเชื่อมระบบให้ยึด v1 ไว้ก่อน เพราะเป็นรุ่นที่ทุกไซต์ในฟลีตรองรับแน่นอน
หลายบริษัทในไซต์เดียวไม่ได้แยกด้วย URL แต่แยกด้วยฟิลด์ company บนเอกสาร เวลาอ่านต้องใส่เงื่อนไขกรองเอง และเวลาเขียนต้องส่ง company มาด้วยเสมอ — อย่าพึ่งค่าเริ่มต้นของผู้ใช้ เพราะค่านั้นเปลี่ยนได้โดยที่โค้ดของคุณไม่รู้
การยืนยันตัวตน
ดู การยืนยันตัวตน ทุกคำขอต้องมี token ที่ยังไม่หมดอายุ ไม่มี endpoint ใดที่เรียกได้โดยไม่ยืนยันตัวตน
การแบ่งหน้า
การแบ่งหน้าเป็นแบบ offset ไม่ใช่ cursor
| พารามิเตอร์ | ความหมาย |
|---|---|
limit_start | เริ่มจากลำดับที่เท่าไร (นับจาก 0) |
limit_page_length | ขอกี่รายการ — ถ้าไม่ระบุจะได้ 20 รายการ ไม่ใช่ทั้งหมด |
fields | รายการฟิลด์ที่ต้องการ เป็น JSON array เช่น ["name","status"] |
filters | เงื่อนไขกรอง เป็น JSON เช่น [["status","=","Draft"]] |
order_by | ลำดับการเรียง |
offset ไม่ปลอดภัยกับข้อมูลที่ยังเคลื่อนไหว
ถ้ามีเอกสารใหม่ถูกสร้างระหว่างที่คุณไล่ดึงทีละหน้า รายการจะเลื่อน — บางใบถูกดึงซ้ำ บางใบหลุดหายไปเงียบ ๆ งานซิงก์ที่ต้องครบจริงควรกรองด้วยช่วง modified ที่คุณคุมเอง แล้วไล่ทีละช่วง ไม่ใช่ไล่ทีละหน้า
อย่าขอฟิลด์ทั้งหมด การไม่ระบุ fields จะได้ข้อมูลน้อยกว่าที่คิด (ได้แค่ name) ส่วนการใส่ ["*"] จะดึงทุกฟิลด์รวมตารางย่อยและช้ามาก ระบุเฉพาะที่ใช้จริงเสมอ
รหัสสถานะและรูปแบบข้อผิดพลาด
| สถานะ | ความหมาย | สิ่งที่ควรทำ |
|---|---|---|
417 | ข้อมูลไม่ผ่านการตรวจสอบทางธุรกิจ — นี่คือรหัสหลักของ "ข้อมูลผิด" ไม่ใช่ 400 | อ่านข้อความแล้วแก้ที่ต้นทาง อย่าลองซ้ำ |
400 | คำขอผิดรูปแบบ หรือ CSRF token ไม่ถูกต้อง | ตรวจโครงคำขอ ไม่ใช่ตรวจข้อมูล |
401 | ไม่ได้ยืนยันตัวตน token ผิด หรือ session หมดอายุ | ขอ token ใหม่แล้วลองอีกครั้งหนึ่งรอบ |
403 | ยืนยันตัวตนผ่านแต่ไม่มีสิทธิ์ | ตรวจบทบาทและ User Permission ของบัญชีที่ใช้เรียก |
404 | ไม่พบเอกสารหรือ endpoint | ตรวจชื่อ DocType และชื่อเอกสาร |
409 | ชื่อเอกสารชนกัน | เปลี่ยนชื่อหรือปล่อยให้ระบบตั้งชื่อเอง |
429 | เรียกถี่เกินกำหนด | รอตามค่าใน Retry-After แล้วค่อยลองใหม่ |
503 | ระบบปิดรับชั่วคราว เช่นระหว่างอัปเกรด | ถอยแล้วลองใหม่แบบเพิ่มระยะห่างทีละรอบ |
ตัวข้อความอยู่ในเนื้อคำตอบ ไม่ใช่ในสถานะ — ฟิลด์ที่ควรอ่านคือ exc_type (ชนิดข้อผิดพลาด เช่น ValidationError, PermissionError) และ _server_messages ซึ่งเป็น JSON ที่ซ้อนอยู่ในสตริง ต้องแกะสองชั้นถึงจะได้ข้อความที่ผู้ใช้ควรเห็น อย่าจับคู่ข้อความด้วยการเทียบสตริง เพราะมันแปลตามภาษาของผู้ใช้ที่เรียก
ข้อจำกัดอัตราการเรียก
การจำกัดอัตราเป็นตัวเลือกที่ตั้งรายไซต์ ไม่ได้เปิดเป็นค่าเริ่มต้น ถ้าไซต์เปิดไว้ คำตอบจะมีส่วนหัว X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset และเมื่อเกินโควตาจะได้ 429 พร้อม Retry-After
อย่าเขียนโค้ดโดยสมมติว่าไม่มีลิมิต
ไซต์ที่วันนี้ไม่จำกัด อาจถูกเปิดจำกัดพรุ่งนี้เพราะมีคนอื่นยิงถี่เกิน โค้ดที่ดีควรอ่าน Retry-After และถอยเป็นขั้นอยู่แล้วตั้งแต่แรก
กฎข้อเดียวที่ขอให้ยึด
ขยายระบบผ่านจุดต่อที่เอกสารระบุไว้เท่านั้น อย่าเขียนลงตารางฐานข้อมูลตรง ระบบไม่รับประกันโครงสร้างตารางระหว่างรุ่น และการอัปเกรดจะพาข้อมูลที่เขียนเข้าไปเองหายไปโดยไม่มีข้อความเตือน
Data Assurance รายงวด
GET /assurance?period=&company= — ผลของงวดที่ ตรึงไว้แล้ว · ไม่มี POST /assurance/run คู่กัน เพราะการตรึงงวดผูกพันกับการปิดงบ จึงไม่ควรเกิดจากการเปิดหน้าเว็บ · ตัวรันเป็นเครื่องมือฝั่งหลังบ้านที่ทีม KlevIQ เป็นผู้เรียก
ยังไม่เคยตรึงงวด → {"status": "none"} ไม่ใช่ 404 และไม่ใช่ศูนย์ — ศูนย์ที่มาจากการไม่ได้ตรวจ หน้าตาเหมือนศูนย์ที่มาจากบัญชีสะอาด
ทุกช่องที่คำนวณไม่ได้คืน null พร้อมธง เช่น materiality.known = false · ชั้นที่เรียกต้องแยก ยังคำนวณไม่ได้ ออกจาก ไม่กระทบ ให้ได้