savrsoft

เอกสาร API

REST API แบบง่ายสำหรับอ่านและเขียนข้อมูลการจัดเลี้ยงของคุณ พร้อม webhook ที่มีการเซ็นรับรองสำหรับอีเวนต์แบบเรียลไทม์ สร้างคีย์ได้ที่ Developer ในแอป

การยืนยันตัวตน

คำขอ API ทั้งหมดใช้ API key เป็น bearer token สร้างคีย์ได้ในแอปที่ Developer → API keysคีย์มีสองแบบคือ read-only หรือ read/write.

curl https://savrsoft.com/api/v1/events \
  -H "Authorization: Bearer savr_live_your_key_here"

Base URL: https://savrsoft.com/api/v1 · คำตอบทั้งหมดเป็นรูปแบบ JSON ข้อผิดพลาดจะส่งคืนเป็น { "error": "…" } พร้อมสถานะ 4xx/5xx

รหัสสถานะ

รหัสเมื่อไหร่ที่คุณจะได้รับ
200อ่านข้อมูลสำเร็จ
201สร้างข้อมูลสำเร็จ เนื้อหาคือ { "id": 42 } — ดึงข้อมูลระเบียนหากคุณต้องการรายละเอียดที่เหลือ
400ขาดฟิลด์ที่จำเป็น เช่น { "error": "name is required" }หรือไม่สามารถอ่านเคอร์เซอร์สำหรับการแบ่งหน้าได้
401ไม่มี API key, key ผิดรูปแบบ หรือ key ที่ถูกเพิกถอนไปแล้ว
403มีการใช้ read-only key สำหรับการเขียนข้อมูล สร้าง read/write key ได้ที่ Developer → API keys.
404ไม่มีเรคคอร์ดนี้อยู่จริง หรือเป็นของอีกองค์กรหนึ่ง — ทั้งสองกรณีนี้ตั้งใจให้แยกไม่ออกจากกัน และยังใช้ตอบกลับกรณี path หรือ method ที่ไม่รู้จักด้วย

ขอบเขตของ API นี้

API นี้รองรับการ อ่านและสร้างข้อมูลเท่านั้น, ไม่มี endpoint สำหรับ DELETE, PUT หรือ PATCH — คำขอที่ใช้ method เหล่านี้จะได้รับ 404 Unknown endpointเช่นเดียวกับ path ที่ไม่รู้จักใดๆ การลบและ แก้ไขข้อมูลทำผ่านแอปเท่านั้น ดังนั้นการเชื่อมต่อระบบภายนอกจึงไม่สามารถทำลายข้อมูลของผู้จัดเลี้ยงได้ หากต้องการสิทธิ์เขียนข้อมูลมากกว่าการสร้าง บอกเราว่าคุณกำลังสร้างอะไร.

การแบ่งหน้า (Pagination)

ทุก endpoint ที่แสดงรายการจะถูกแบ่งหน้า ส่งค่า limit (ค่าเริ่มต้น 100, สูงสุด 500) และ ใช้ next_cursor ต่อไปเรื่อยๆ จนกว่า has_more จะเป็น false:

{
  "data": [ ... ],
  "has_more": true,
  "next_cursor": "eyJuYW1lIjoiQWNtZSIsImlkIjo0Mn0"
}

ส่ง cursor กลับไปตรงๆ เพื่อดึงหน้าถัดไป ให้ถือว่าเป็นค่าที่ไม่ต้องตีความ — รูปแบบการเข้ารหัสอาจเปลี่ยนแปลงได้ในอนาคต:

curl "https://savrsoft.com/api/v1/clients?limit=100&cursor=eyJuYW1lIjoiQWNtZSIsImlkIjo0Mn0" \
  -H "Authorization: Bearer savr_live_your_key_here"

การแบ่งหน้าจะยึดตามแถวสุดท้ายที่คุณได้รับ ไม่ใช่ยึดตามค่า offset ดังนั้นแม้จะมีแถวถูกสร้างหรือลบระหว่างที่คุณแบ่งหน้า ก็จะไม่ทำให้คุณข้ามหรือได้รับข้อมูลซ้ำ cursor จะยังคงใช้งานได้ตลอดไป

พารามิเตอร์พฤติกรรม
limit1–500 หากไม่ระบุ เป็นศูนย์ ติดลบ หรือไม่ใช่ตัวเลข จะกลับไปใช้ค่าเริ่มต้น 100 โดยอัตโนมัติ ส่วนค่าที่เกิน 500 จะถูกจำกัดไว้ที่ 500
cursornext_cursor จากหน้าก่อนหน้า ไม่ต้องระบุสำหรับหน้าแรก หาก cursor ไม่สามารถอ่านได้ — เสียหาย หรือมาจาก endpoint อื่น — ระบบจะส่งค่า 400 Invalid cursor แทนที่จะเริ่มต้นใหม่โดยไม่แจ้งเตือน

การเรียงลำดับ: /events และ /invoices ใหม่สุดก่อน; /recipes และ /clients เรียงตามชื่อ โดยหากชื่อซ้ำกันจะใช้ id ตัดสิน เพื่อให้การแบ่งหน้ายังคงเสถียรแม้ชื่อจะซ้ำกัน

Endpoints

GET/v1/me

องค์กรของคุณ (id, ชื่อ, สกุลเงิน)

GET/v1/events

แสดงรายการอีเวนต์ ใหม่สุดก่อน รองรับการแบ่งหน้า — ดู การแบ่งหน้า ด้านบน

GET/v1/events/{id}

หนึ่งอีเวนต์พร้อมเมนูอาหาร

POST/v1/events · ต้องมีสิทธิ์ read/write

สร้างอีเวนต์ Body:

{ "name": "Acme holiday party", "event_date": "2026-12-18",
  "guests": 120, "price_per_head": 55, "event_type": "corporate" }
GET/v1/recipes · GET/v1/recipes/{id}

แสดงรายการสูตรอาหาร (พร้อมสารก่อภูมิแพ้และป้ายกำกับข้อจำกัดด้านอาหาร) หรือดูสูตรอาหารรายการเดียวพร้อมส่วนผสม รายการนี้แบ่งหน้าและเรียงตามชื่อ

GET/v1/clients · POST/v1/clients

แสดงรายการลูกค้า (แบ่งหน้า เรียงตามชื่อ) หรือสร้างลูกค้าใหม่ Body สำหรับสร้าง: { "name": "...", "email": "...", "phone": "...", "company": "..." }

GET/v1/invoices · GET/v1/invoices/{id}

แสดงรายการใบแจ้งหนี้พร้อมยอดรวมที่คำนวณแล้ว เรียงจากล่าสุด หรือดูใบแจ้งหนี้รายการเดียวพร้อมรายการย่อย รายการนี้แบ่งหน้า

Webhooks

ลงทะเบียน endpoint ได้ที่ Developer → Webhooksเราจะ POST ข้อมูล JSON เมื่อเกิดอีเวนต์ต่างๆ:

{
  "id": "evt_abc123",
  "type": "event.inquiry",
  "created_at": "2026-07-17T18:20:00.000Z",
  "data": { "id": 42, "name": "Corporate lunch — Dana Ruiz", ... }
}

ประเภทอีเวนต์

ประเภทเกิดขึ้นเมื่อ
event.createdมีการสร้างอีเวนต์
event.inquiryมีคำขอจัดเลี้ยงออนไลน์เข้ามาใหม่
invoice.sentใบแจ้งหนี้ถูกทำเครื่องหมายว่าส่งแล้ว
invoice.paidใบแจ้งหนี้ถูกทำเครื่องหมายว่าชำระแล้ว
proposal.approvedลูกค้าอนุมัติข้อเสนอ
client.createdมีการสร้างลูกค้าใหม่

การตรวจสอบลายเซ็น

การส่งข้อมูลแต่ละครั้งจะมีส่วนหัว x-savrsoft-signature : ค่า HMAC-SHA256 ของเนื้อหาคำขอดิบ โดยใช้ signing secret ของ webhook ของคุณเป็นคีย์ คำนวณค่าเดียวกันแล้วเปรียบเทียบ:

// Node.js
const crypto = require('crypto');
const sig = crypto.createHmac('sha256', SIGNING_SECRET)
  .update(rawBody).digest('hex');
if (sig !== req.headers['x-savrsoft-signature']) reject();
นโยบายความเป็นส่วนตัว · ความปลอดภัย · ข้อกำหนด · มีคำถาม? savrsoft.com · สร้างการเชื่อมต่อระบบจัดเลี้ยงได้ภายในไม่กี่นาที