API Reference
Public REST API สำหรับ integrator — ตรวจสลิป, อ่านโควตา, รูปแบบ error + status ครบทุก endpoint
Public REST API สำหรับเชื่อมต่อระบบของคุณ (POS / ERP / บอท) เข้ากับ SlipBolt
ยืนยันตัวตนด้วย API key (sk_live_… / sk_test_…) — ดู Authentication
Base URL
https://api.slip-bolt.com/api/v1
ทุก request ต้องมี header:
Authorization: Bearer sk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
เช็คก่อนยิงงานชุดใหญ่ — GET /api/v1/me (ร้าน · แพ็ก · โควตา live+test · บัญชีรับเงิน)
และ GET /api/v1/quota (โควตาอย่างเดียว) ไม่หักสลิป · ต้องมี scope read
ช่วง Trial ไม่มี API key — ดูกระเบื้องโควตาบน Dashboard
Test mode — ใช้ key sk_test_… เพื่อรันทั้ง pipeline จริงโดย ไม่กินโควตาของร้าน เหมาะกับตอน
dev/CI · แต่มีเพดานแยกของตัวเอง 200 ครั้ง/ร้าน/เดือน (ตรวจกับธนาคารจริงทุกครั้ง ไม่ใช่ของจำลอง)
เกินแล้วได้ 402 TEST_QUOTA_EXCEEDED เหมือนกัน — ดูรายละเอียดที่ Authentication
POST /api/v1/verify
ตรวจสลิปโอนเงิน 1 ใบ ส่งรูปสลิปเป็น raw bytes (ไม่ใช่ JSON / ไม่ใช่ base64)
Request
| Method | POST |
| Content-Type | application/octet-stream |
| Body | ไฟล์รูปสลิป (JPEG/PNG) เป็น binary ดิบ |
| Scope ที่ต้องมี | verify |
curl -X POST https://api.slip-bolt.com/api/v1/verify \
-H "Authorization: Bearer sk_live_..." \
-H "Content-Type: application/octet-stream" \
--data-binary "@slip.jpg"
Node.js
import { readFile } from 'node:fs/promises';
const image = await readFile('slip.jpg');
const res = await fetch('https://api.slip-bolt.com/api/v1/verify', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.SLIPBOLT_API_KEY}`,
'Content-Type': 'application/octet-stream',
},
body: image,
});
if (res.status === 402) throw new Error('โควตาหมด — อัปเกรดแพ็ก');
const data = await res.json();
console.log(data.verified, data.amount, res.headers.get('X-Slipbolt-Quota-Remaining'));
Python
import requests
with open("slip.jpg", "rb") as f:
res = requests.post(
"https://api.slip-bolt.com/api/v1/verify",
headers={
"Authorization": f"Bearer {API_KEY}",
"Content-Type": "application/octet-stream",
},
data=f.read(),
)
if res.status_code == 402:
raise RuntimeError("quota exhausted")
print(res.json()["verified"], res.headers["X-Slipbolt-Quota-Remaining"])
Response 200 OK
{
"success": true,
"data": {
"id": "8f3c…",
"status": "SUCCESS",
"verified": true,
"transRef": "015170106978META…",
"amount": 250.0,
"bankCode": "002",
"bankName": "ธนาคารกรุงเทพ",
"senderName": "นาย ก. …",
"senderAccount": "xxx-x-x1234-x",
"receiverName": "ร้าน ข.",
"receiverAccount": "xxx-x-x5678-x",
"transDate": "2026-06-17T03:21:05.000Z",
"errorCode": null,
"errorMessage": null,
"createdAt": "2026-06-17T03:21:06.412Z",
"duplicate": false,
"cached": false,
"latencyMs": 480,
"environment": "live",
"quota": { "used": 132, "limit": 500, "remaining": 368 }
},
"meta": { "requestId": "req_…", "timestamp": "2026-06-17T10:21:06+07:00" }
}
verified เป็น true เฉพาะเมื่อ status === "SUCCESS" — ดูตาราง status ด้านล่าง
Quota — pool เดียวกับสลิป LINE
การเรียก API ใช้โควตารายเดือนเดียวกับสลิปจาก LINE ของร้าน (pool เดียว นับรวมกัน) ไม่ใช่โควตาแยก — ใช้ผ่านช่องไหนก็หักจากก้อนเดียวกัน
ทุก response (รวม GET /api/v1/quota) แนบ header บอกยอดคงเหลือ:
| Header | ความหมาย |
|---|---|
X-Slipbolt-Quota-Limit | เพดานสลิป/เดือนของแพ็กปัจจุบัน |
X-Slipbolt-Quota-Used | ใช้ไปแล้วในรอบเดือนนี้ |
X-Slipbolt-Quota-Remaining | คงเหลือ |
X-Slipbolt-Quota-Reset-Days | กี่วันก่อนรีเซ็ตรอบใหม่ |
โควตาหมด → 402 Payment Required (เฉพาะ key live) — ไม่ใช่ 200 เงียบ ๆ ให้ integrator เช็คจาก HTTP status ได้เลย
{ "success": false, "statusCode": 402, "error": "Payment Required",
"message": "โควตาสลิปรายเดือนของร้านถูกใช้หมดแล้ว — อัปเกรดแพ็กหรือรอรอบบิลถัดไป",
"code": "QUOTA_EXCEEDED", "quota": { "used": 500, "limit": 500, "remaining": 0 } }
key sk_test_ ไม่กินโควตาก้อนนี้ (ของร้าน) จึงไม่ได้ 402 ตัวนี้ — แต่มีเพดานแยกของตัวเอง
200 ครั้ง/เดือน เกินแล้วได้ 402 TEST_QUOTA_EXCEEDED เหมือนกัน (ดูหัวข้อ Idempotency/Test mode ด้านบน)
GET /api/v1/quota
อ่านโควตาคงเหลือ โดยไม่เปลือง verify — เหมาะให้ระบบ poll ก่อนยิงงานชุดใหญ่
| Method | GET |
| Scope ที่ต้องมี | read |
curl https://api.slip-bolt.com/api/v1/quota \
-H "Authorization: Bearer sk_live_..."
{
"success": true,
"data": {
"used": 132,
"limit": 500,
"remaining": 368,
"percentUsed": 26,
"allowOverage": false,
"planCode": "STARTER",
"periodMonth": "2026-06",
"daysUntilReset": 13
}
}
GET /api/v1/me
ข้อมูลร้าน · คีย์ · แพ็ก · โควตาคงเหลือ — ไม่เปลืองโควตา เหมาะเรียกตอนบูตระบบของคุณ
เพื่อเช็คว่าคีย์ถูกร้าน scope ครบ เหลือสลิปเท่าไหร่ และบัญชีรับเงินที่ระบบใช้เทียบผู้รับคือบัญชีไหน
(สาเหตุอันดับหนึ่งของ RECEIVER_MISMATCH คือร้านยังไม่ได้เพิ่มบัญชีที่ลูกค้าโอนเข้า)
ช่วงทดลอง 7 วัน plan.code จะเป็น "TRIAL" และ quota.limit = 50 เสมอ
แม้ร้านจะเคยเลือกการ์ด Pro/Business ตอนสมัคร — สิทธิ์แพ็กจ่ายเริ่มหลังชำระแล้วเท่านั้น
| Method | GET |
| Scope ที่ต้องมี | read |
curl https://api.slip-bolt.com/api/v1/me \
-H "Authorization: Bearer sk_live_..."
{
"success": true,
"data": {
"shop": { "id": "8f3c…", "name": "ร้าน ข." },
"apiKey": {
"name": "POS หน้าร้าน",
"prefix": "sk_live_a1b2c3",
"environment": "live",
"scopes": ["verify", "read"],
"lastUsedAt": "2026-06-17T03:21:06.000Z",
"createdAt": "2026-05-01T00:00:00.000Z"
},
"plan": { "code": "STARTER", "name": "Starter" },
"quota": { "used": 132, "limit": 500, "remaining": 368, "percentUsed": 26,
"overage": 0, "allowOverage": false, "planCode": "STARTER",
"periodMonth": "2026-06", "daysUntilReset": 13 },
"testQuota": { "used": 12, "limit": 200, "remaining": 188 },
"rateLimit": { "perKeyPerMinute": 120, "verifyPerMinute": 240 },
"payeeAccounts": [
{ "bankCode": "kbank", "kind": "BANK", "holder": "ร้าน ข.", "accountLast4": "5678", "isPrimary": true, "status": "ACTIVE" }
]
}
}
payeeAccounts ส่งแค่ 4 ตัวท้าย ของเลขบัญชี — คีย์ API รั่วได้ง่ายกว่ารหัสผ่านหน้าเว็บ
ไม่จำเป็นต้องให้เลขเต็มเพื่อรู้ว่า "บัญชีไหน" · testQuota.used: null = วัดไม่ได้ชั่วคราว
(คีย์ sk_test_ จะตกไปกินโควตาปกติของร้านแทน ไม่ใช่ error)
GET /api/v1/transactions
ลิสต์ผลตรวจสลิปของร้านย้อนหลัง — ใหม่สุดก่อน แบ่งหน้าแบบ cursor รวมทุกช่องทาง (API / LINE / Dashboard)
เหมาะกับตอน POST /verify หลุดกลางทาง (timeout/เน็ตตัด) แล้วอยากรู้ผลจริงโดยไม่ต้องส่งสลิปซ้ำ
| Method | GET |
| Scope ที่ต้องมี | read |
| Query | status · source · transRef · from/to (ISO-8601) · cursor · limit (1-100, default 50) |
curl "https://api.slip-bolt.com/api/v1/transactions?status=SUCCESS&limit=20" \
-H "Authorization: Bearer sk_live_..."
{
"success": true,
"data": {
"items": [ { "id": "8f3c…", "status": "SUCCESS", "verified": true, "…": "…" } ],
"nextCursor": "7ab1…"
}
}
ส่ง nextCursor กลับมาเป็น cursor เพื่อดึงหน้าถัดไป · null = หมดแล้ว
GET /api/v1/transactions/:id
ดึงผลตรวจสลิป 1 รายการ — ใช้คู่กับ webhook (รับ data.id จาก event แล้วมาดึงรายละเอียดเต็ม)
รายการของร้านอื่น หรือ id ที่ไม่มีอยู่ → 404 เหมือนกัน (ไม่ยืนยันว่า id นั้นมีอยู่จริงในระบบ)
curl https://api.slip-bolt.com/api/v1/transactions/8f3c2a1e-… \
-H "Authorization: Bearer sk_live_..."
Scopes
แต่ละ key ถือ scope ได้หลายตัว — endpoint ต้องการ scope ครบทุกตัวที่ระบุ (ตั้งค่าได้ที่ Settings → API Keys)
| Scope | ใช้กับ |
|---|---|
verify | POST /api/v1/verify (default ของทุก key) |
read | GET /api/v1/quota · GET /api/v1/me · GET /api/v1/transactions[/:id] |
webhook | สำรองไว้สำหรับอนาคต — ตอนนี้ยังไม่มี public endpoint ใช้งาน scope นี้ (ตั้งค่า outgoing webhook ทำผ่าน Dashboard → Settings → Webhooks เท่านั้น ไม่ใช่ API key) |
scope ไม่พอ → 403 Forbidden (API key missing scope(s): …)
Rate limit
120 req/min ต่อ key (เท่ากันทุกแพ็ก) + เพดานรวมของ POST /api/v1/verify ที่ 240 req/min
เกินแล้ว → 429 Too Many Requests + header Retry-After · ดู Authentication
Transaction status
status | verified | ความหมาย |
|---|---|---|
SUCCESS | ✅ | สลิปถูกต้อง โอนเข้าบัญชีร้าน |
DUPLICATE | ❌ | เลขอ้างอิง (transRef) นี้เคยตรวจแล้ว |
AMOUNT_MISMATCH | ❌ | ยอดบนสลิปไม่ตรงเงื่อนไข |
RECEIVER_MISMATCH | ❌ | โอนเข้าบัญชีที่ไม่ใช่ของร้าน |
INVALID | ❌ | อ่านสลิปไม่ได้ / ไม่ใช่สลิป / สลิปไม่ใช่รายการล่าสุด (errorCode: STALE_SLIP) |
FRAUD | ❌ | สลิปปลอม/แก้ไข — ไม่ตรงข้อมูลธนาคาร |
QUOTA_EXCEEDED | ❌ | โควตาหมด (ดู 402 ด้านบน) |
PROVIDER_ERROR | ❌ | ผู้ให้บริการตรวจสลิปขัดข้องชั่วคราว — ลองใหม่ |
Idempotency
ระบบ dedupe ให้อัตโนมัติ — สองเคสที่ต่างกัน:
- ส่ง "รูปเดิม" ซ้ำภายใน 24 ชม. →
cached: true·status/verifiedเป็นผลจริงของ รายการเดิม (retry ตอนเน็ตตัด/timeout ได้อย่างปลอดภัย — ไม่ตรวจซ้ำ ไม่หักโควตา) transRefเดียวกัน เคยตรวจผ่านไปแล้ว (คนละไฟล์รูป/ถ่ายซ้ำ) →duplicate: trueและstatusจะเป็น"DUPLICATE"เสมอในการตอบครั้งนี้ (verified: false) — ไม่ว่าผลตรวจ ครั้งแรกจะเป็นอะไรก็ตาม
ห้าม credit ออเดอร์จากแค่ verified === true — ต้องเช็ค duplicate ก่อนเสมอถ้าระบบคุณ
เคยประมวลผล transRef นั้นไปแล้ว ไม่งั้นการ retry/ส่งซ้ำโดยไม่ตั้งใจจะ credit ซ้ำ
Error envelope
ทุก error รูปแบบเดียวกัน:
{
"success": false,
"error": "Forbidden",
"message": "API key missing scope(s): read",
"statusCode": 403,
"path": "/api/v1/quota",
"requestId": "req_abc123",
"timestamp": "2026-06-17T10:30:45+07:00"
}
| Status | เมื่อไร |
|---|---|
400 | body ไม่ใช่ raw bytes / ไม่มีรูป |
401 | API key ผิด/ถูก revoke |
402 | โควตาหมด — QUOTA_EXCEEDED (key live) หรือ TEST_QUOTA_EXCEEDED (key test เกิน 200/เดือน) |
403 | scope ไม่พอ หรือแพ็กปัจจุบันไม่รวม REST API (PLAN_API_ACCESS_REQUIRED) |
404 | ไม่พบรายการ (GET /transactions/:id) — หรือเป็นของร้านอื่น |
429 | เกิน rate limit |
ถัดไป
- Webhooks — รับ event
slip.verified/slip.duplicate/slip.failedแบบ HMAC-signed แทนการ poll - Authentication — รายละเอียด key · โควตาต่อแพ็ก · rate limit

