core

API Reference

Public REST API สำหรับ integrator — ตรวจสลิป, อ่านโควตา, รูปแบบ error + status ครบทุก endpoint

⏱ REST

Public REST API สำหรับเชื่อมต่อระบบของคุณ (POS / ERP / บอท) เข้ากับ SlipBolt ยืนยันตัวตนด้วย API key (sk_live_… / sk_test_…) — ดู Authentication

Base URL

URL
https://api.slip-bolt.com/api/v1

ทุก request ต้องมี header:

HTTP
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

มีสเปก OpenAPI ให้ใช้

https://api.slip-bolt.com/api/v1/openapi.json — import เข้า Postman / Insomnia / Bruno เพื่อลองยิงได้ทันที หรือใช้ generate client ภาษาที่คุณถนัด (เช่น openapi-generator) ครอบคลุมทุก endpoint ในหน้านี้

Postman collection พร้อมใช้: https://api.slip-bolt.com/api/v1/postman.json — Import แล้วใส่ตัวแปร apiKey ก็กดส่งได้เลย · POST /verify แยกให้ครบ 5 แบบ (ไฟล์ดิบ · multipart · base64 · url · qr)

โค้ดก๊อปไปวางของ POST /verify ใน Node.js · Python · PHP · Go · Java · C# อยู่ที่ ตัวอย่างพร้อมใช้

ผลของ request ที่สำเร็จอยู่ใน data เสมอ — { "success": true, "data": { … }, "meta": { … } } ส่วน error เป็นก้อนแบน (ดู Error envelope) · อ่าน verified ที่ data.verified ไม่ใช่ที่ราก


POST /api/v1/verify

ตรวจสลิปโอนเงิน 1 ใบ — ส่งได้ 5 แบบ: raw bytes (แนะนำ) · multipart/form-data · JSON image (base64) · JSON url · JSON qr

Request

MethodPOST
Bodyไฟล์รูปสลิป (JPEG/PNG) · ทั้งคำขอไม่เกิน 5 MB
Scope ที่ต้องมีverify
ส่งแบบContent-TypeBody
raw bytes (แนะนำ)application/octet-stream (หรือ image/jpeg · image/png)ไฟล์รูปเป็น binary ดิบ
multipartmultipart/form-dataไฟล์ในฟิลด์ชื่อ file (ไม่มีฟิลด์ชื่อนี้ → ใช้ไฟล์แรกที่เจอ)
JSON base64application/json{ "image": "<base64>" } — มี prefix data:image/…;base64, ก็ได้
JSON URLapplication/json{ "url": "https://…" } — เราดาวน์โหลดรูปให้ · https สาธารณะเท่านั้น · ไม่ตาม redirect · ไม่เกิน 5 MB
JSON QRapplication/json{ "qr": "<ข้อความใน QR ของสลิป>" } — ไม่ต้องมีรูป

qr เป็นข้อมูลขาเข้าเท่านั้น — คือข้อความที่สแกนได้จาก QR บนสลิป (QR ตรวจสอบรายการ) · API นี้ ไม่มี endpoint สร้าง QR / PromptPay สำหรับรับเงิน

  • ส่ง QR รับเงิน (PromptPay / QR ร้านค้า — ข้อความขึ้นต้น 000201) มาแทน → 400 ไม่หักโควตา
  • ข้อความอื่นที่ไม่ใช่ QR ของสลิป → ธนาคารเป็นผู้ตัดสิน ผลออกมาเป็น INVALID หรือ FRAUD (รายการไม่มีอยู่จริงที่ธนาคาร) — ไม่หักโควตา

JSON ใส่ได้ อย่างเดียว ใน image / url / qr · ตัวอย่างด้านล่างใช้ raw bytes · ตัวอย่างแบบอื่นครบทุกภาษาอยู่ที่ ตัวอย่างพร้อมใช้

curl -X POST https://api.slip-bolt.com/api/v1/verify \
  -H "Authorization: Bearer $SLIPBOLT_API_KEY" \
  -H "Content-Type: application/octet-stream" \
  --data-binary "@slip.jpg"

Response 200 OK

JSON
{
  "success": true,
  "data": {
    "id": "8f3c…",
    "status": "SUCCESS",
    "verified": true,
    "source": "API",
    "transRef": "015170106978META…",
    "amount": 250.0,
    "bankCode": "002",
    "bankName": "ธนาคารกรุงเทพ",
    "senderName": "นาย ก. …",
    "senderAccount": "xxx-x-x1234-x",
    "receiverName": "ร้าน ข.",
    "receiverAccount": "xxx-x-x5678-x",
    "receiverBankCode": "014",
    "receiverBankName": "ธนาคารไทยพาณิชย์",
    "transDate": "2026-06-17T03:21:05.000Z",
    "errorCode": null,
    "errorMessage": null,
    "createdAt": "2026-06-17T03:21:06.412Z",
    "receipt": { "code": "SB-7K2F-9QX4", "checkUrl": "https://slip-bolt.com/c/PyuMHlp9Tp-wwdLj9KW2xzQ1dGhVb2xr" },
    "duplicate": false,
    "cached": false,
    "latencyMs": 480,
    "environment": "live",
    "quota": { "used": 132, "limit": 500, "remaining": 368 }
  },
  "meta": { "requestId": "3b1f0c9e-6a2d-4f5e-8b7c-1d2e3f4a5b6c", "timestamp": "2026-06-17T03:21:06.412Z" }
}

verified เป็น true เฉพาะเมื่อ status === "SUCCESS" — ดูตาราง status ด้านล่าง meta.requestId ตรงกับ header X-Request-Id ของคำตอบ — เก็บลง log ไว้ใช้ตอนติดต่อทีมงาน

ตัวอย่างผลที่ไม่ผ่าน

ทุกกรณีด้านล่างเป็น HTTP 200 — คำขอสำเร็จ แต่คำตัดสินของสลิปคือไม่ผ่าน (ตัดเฉพาะฟิลด์ที่ต่างจากตัวอย่างข้างบน)

{
  "id": "8f3c2a1e-…",
  "status": "DUPLICATE",
  "verified": false,
  "transRef": "015170106978META…",
  "amount": 250.0,
  "errorCode": null,
  "errorMessage": null,
  "duplicate": true,
  "cached": false
}
  • DUPLICATE คืนข้อมูลของ รายการเดิม (id · transRef · amount เป็นของครั้งแรกที่ตรวจ) — ใช้ transRef หาว่าออเดอร์ไหนใช้สลิปนี้ไปแล้ว
  • RECEIVER_MISMATCH · AMOUNT_MISMATCH อ่านสลิปได้ครบ จึงมี transRef / amount / ผู้รับ ให้ดูว่าโอนไปที่ไหน · errorCode เป็น null — แตกกิ่งด้วย status
  • INVALID · FRAUD ไม่มีข้อมูลบนสลิปให้เชื่อ — transRef เป็น null และ amount เป็น 0

ฟิลด์ใน data

ฟิลด์ชุดแรก (ถึง createdAt) เป็นรูปร่างเดียวกับที่ GET /transactions คืน — parse ด้วยโค้ดชุดเดียวได้

ฟิลด์ชนิดความหมาย
idstring (uuid)id ของรายการ — ใช้กับ GET /transactions/:id
statusstringผลตรวจ — ดู Transaction status
verifiedbooleantrue เฉพาะเมื่อ status เป็น SUCCESS
sourcestringช่องทางที่สลิปเข้ามา: API · LINE · LIFF · DASHBOARD
transRefstring | nullเลขอ้างอิงธนาคาร — ใช้เป็น unique key ฝั่งคุณ · null เมื่ออ่านจากสลิปไม่ได้
amountnumberยอดโอน (บาท) — 0 เมื่ออ่านไม่ได้
bankCode · bankNamestring | nullธนาคารผู้โอน — bankCode เป็นรหัส 3 หลัก ดู รหัสธนาคาร
senderName · senderAccountstring | nullผู้โอน — เลขบัญชีถูกปิดบางหลักตามที่ธนาคารให้มา
receiverName · receiverAccountstring | nullผู้รับ — receiverAccount คือบัญชีธนาคารที่เงินเข้า
receiverProxyAccountstring | nullเลขพร้อมเพย์ของผู้รับ (เบอร์/เลขบัตร/e-Wallet) — เลขที่เห็นบนรูปสลิปเมื่อโอนผ่านพร้อมเพย์ · ต่างจาก receiverAccount เป็นปกติ · null เมื่อโอนเข้าบัญชีตรง
receiverBankCode · receiverBankNamestring | nullธนาคารผู้รับ (รหัส 3 หลักเช่นกัน)
transDatestring (ISO-8601 UTC) | nullเวลาที่โอนตามธนาคาร
errorCode · errorMessagestring | nullเหตุผลเมื่อไม่ผ่าน — หรือคำเตือนเมื่อผ่าน (STALE_SLIP) · ดู errorCode
warningsarrayคำเตือนของสลิปที่ผ่าน [{ code, message }] — ว่าง [] เมื่อไม่มีหรือเมื่อไม่ผ่าน · ตอนนี้มีแค่ STALE_SLIP (ค่าเดียวกับ errorCode คงไว้ทั้งคู่)
createdAtstring (ISO-8601 UTC)เวลาที่เราตรวจ
receiptobject | nullใบยืนยันการตรวจสลิป — code (เลขยืนยันบนใบ) · checkUrl (ลิงก์ใน QR) · มีเฉพาะ SUCCESS · รูป/PDF ดู receipt.png
duplicatebooleantransRef นี้เคยตรวจแล้ว (status = DUPLICATE)
cachedbooleanส่งรูปเดิมซ้ำใน 24 ชม. — คืนผลของรายการเดิม ไม่หักโควตา
quotaChargedbooleanคำขอนี้หักโควตา/เครดิตของร้านไหม — true เฉพาะ SUCCESS ที่ตรวจใหม่ด้วยคีย์ live · ไม่ผ่าน · DUPLICATE · cached · คีย์ sk_test_ = false
latencyMsinteger | nullเวลาที่ใช้ตรวจกับธนาคาร
environmentstringlive หรือ test ตามชนิดคีย์
quotaobjectused · limit · remaining หลังคำขอนี้

ชื่อผู้โอน/ผู้รับไม่ใช่ชื่อ-นามสกุลเต็ม — senderName / receiverName คือชื่อตามที่ธนาคารส่งมา (เราไม่ได้อ่านจากรูปสลิป) ซึ่งธนาคารปิดนามสกุลไว้เหลืออักษรตัวแรก เช่น นาย สมชาย ใ · บางธนาคารส่งเป็นภาษาอังกฤษ (MR. SOMCHAI J) · ชื่อร้าน/ชื่อบัญชีที่ยาวอาจถูกตัดท้าย ขอชื่อเต็มไม่ได้ทุกช่องทาง (API · webhook · LINE) · อย่าใช้ชื่อเทียบตัวตนผู้รับ — เราเทียบเลขบัญชีกับบัญชีรับเงินของร้านให้แล้ว ผลอยู่ที่ status (RECEIVER_MISMATCH)

ส่งรูปเดิมซ้ำคนละรูปแบบ = รูปเดียวกัน — raw bytes / multipart / base64 / url ถูกแปลงเป็น bytes ชุดเดียวกันก่อนตรวจ จึงได้ cached: true เหมือนส่งซ้ำแบบเดิม · qr นับแยกจากรูป (ข้อความเดิมซ้ำ = cached · รูปของสลิปใบเดียวกัน = DUPLICATE) — ดู ตัวอย่างพร้อมใช้


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 · มีเครดิตเหลือ = ตัดเครดิตต่อ ไม่ได้ 402) — ไม่ใช่ 200 เงียบ ๆ ให้ integrator เช็คจาก HTTP status ได้เลย

JSON
{ "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 ก่อนยิงงานชุดใหญ่

MethodGET
Scope ที่ต้องมีread
curl "https://api.slip-bolt.com/api/v1/quota" \
  -H "Authorization: Bearer $SLIPBOLT_API_KEY"
JSON
{
  "success": true,
  "data": {
    "used": 132,
    "limit": 500,
    "remaining": 368,
    "percentUsed": 26,
    "allowOverage": false,
    "planCode": "STARTER",
    "periodMonth": "2026-06",
    "daysUntilReset": 13,
    "creditsAvailable": 0
  }
}

creditsAvailable = เครดิตสลิปคงเหลือ (แบบจ่ายตามใช้) — ใช้ต่อเมื่อโควตาแพ็กหมด ก่อนคิดค่าส่วนเกิน ร้านที่ไม่มีแพ็กรายเดือนแต่มีเครดิตก็ตรวจสลิปได้ · remaining ยังเป็นโควตาของแพ็กอย่างเดียว ⇒ ตรวจได้อีกทั้งหมด ≈ remaining + creditsAvailable


GET /api/v1/me

ข้อมูลร้าน · คีย์ · แพ็ก · โควตาคงเหลือ — ไม่เปลืองโควตา เหมาะเรียกตอนบูตระบบของคุณ เพื่อเช็คว่าคีย์ถูกร้าน scope ครบ เหลือสลิปเท่าไหร่ และบัญชีรับเงินที่ระบบใช้เทียบผู้รับคือบัญชีไหน (สาเหตุอันดับหนึ่งของ RECEIVER_MISMATCH คือร้านยังไม่ได้เพิ่มบัญชีที่ลูกค้าโอนเข้า)

ช่วงทดลอง 7 วัน plan.code จะเป็น "TRIAL" และ quota.limit = 50 เสมอ แม้ร้านจะเคยเลือกการ์ด Pro/Business ตอนสมัคร — สิทธิ์แพ็กจ่ายเริ่มหลังชำระแล้วเท่านั้น

MethodGET
Scope ที่ต้องมีread
curl "https://api.slip-bolt.com/api/v1/me" \
  -H "Authorization: Bearer $SLIPBOLT_API_KEY"
JSON
{
  "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 },
    "credits": { "available": 0, "usedThisMonth": 0, "nextExpiry": null },
    "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[].bankCode เป็น slug (kbank) ไม่ใช่รหัส 3 หลักแบบในผลตรวจ (004) — เทียบด้วยตาราง รหัสธนาคาร

payeeAccounts ส่งแค่ 4 ตัวท้าย ของเลขบัญชี — คีย์ API รั่วได้ง่ายกว่ารหัสผ่านหน้าเว็บ ไม่จำเป็นต้องให้เลขเต็มเพื่อรู้ว่า "บัญชีไหน" · testQuota.used: null = วัดไม่ได้ชั่วคราว (คีย์ sk_test_ จะตกไปกินโควตาปกติของร้านแทน ไม่ใช่ error)


GET /api/v1/transactions

ลิสต์ผลตรวจสลิปของร้านย้อนหลัง — ใหม่สุดก่อน แบ่งหน้าแบบ cursor รวมทุกช่องทาง (API / LINE / Dashboard) เหมาะกับตอน POST /verify หลุดกลางทาง (timeout/เน็ตตัด) แล้วอยากรู้ผลจริงโดยไม่ต้องส่งสลิปซ้ำ

MethodGET
Scope ที่ต้องมีread
Querystatus · source · transRef · from/to (ISO-8601 — ใส่ +07:00 ถ้าคิดเป็นเวลาไทย) · cursor · limit (1-100, default 50)
curl "https://api.slip-bolt.com/api/v1/transactions?status=SUCCESS&limit=20" \
  -H "Authorization: Bearer $SLIPBOLT_API_KEY"
JSON
{
  "success": true,
  "data": {
    "items": [ { "id": "8f3c…", "status": "SUCCESS", "verified": true, "…": "…" } ],
    "nextCursor": "7ab1…"
  }
}

ส่ง nextCursor กลับมาเป็น cursor เพื่อดึงหน้าถัดไป · null = หมดแล้ว

GET /api/v1/transactions/:id

ดึงผลตรวจสลิป 1 รายการ — ใช้คู่กับ webhook (รับ data.transactionId จาก event แล้วมาดึงรายละเอียดเต็ม) รายการของร้านอื่น หรือ id ที่ไม่มีอยู่ → 404 เหมือนกัน (ไม่ยืนยันว่า id นั้นมีอยู่จริงในระบบ)

Terminal
curl https://api.slip-bolt.com/api/v1/transactions/8f3c2a1e-… \
  -H "Authorization: Bearer $SLIPBOLT_API_KEY"

GET /api/v1/transactions/:id/receipt.png · receipt.pdf

ใบยืนยันการตรวจสลิป ของรายการที่ผ่าน — รูปเดียวกับที่ลูกค้าได้จากบอท LINE / LIFF (หัว "ตรวจแล้ว · สลิปจริง" · ยอด · ผู้โอน → ผู้รับ · เลขอ้างอิง · QR + เลขยืนยัน) ใช้ส่งต่อให้ลูกค้าในระบบของคุณเอง (แชต · อีเมล · หน้าออเดอร์) ได้เลย

  • QR บนใบเปิดหน้าเช็คบน slip-bolt.com/c/… — ใครถือรูปก็สแกนเช็คได้ว่าใบออกจาก SlipBolt จริง (หน้านั้นโชว์ข้อมูลแบบปิดบางส่วน) · ลิงก์และเลขเดียวกันอยู่ใน data.receipt ของผลตรวจ
  • ใบนี้ใช้แทนสลิปโอนเงินไม่ได้ และพิมพ์ไว้บนใบแล้ว — เป็นหลักฐานว่า "สลิปนี้ผ่านการตรวจ" ไม่ใช่หลักฐานการโอน
  • ?maskSender=true — ปิดชื่อผู้โอนบางส่วน ("สมชาย ใจ***") และไม่พิมพ์เลขบัญชีผู้โอน · ใช้เมื่อจะโพสต์ในที่ที่หลายคนเห็น
  • สร้างใหม่ทุกครั้งที่ขอ เราไม่เก็บไฟล์ — เก็บรูปไว้เองถ้าต้องใช้ซ้ำ · PNG กว้าง 784px · PDF เป็นหน้าเดียวขนาดเท่าใบ
  • รายการที่ไม่ผ่าน (status ≠ SUCCESS) หรือข้อมูลถูกลบตามระยะเก็บของร้านแล้ว → 409 · ร้านอื่น/ไม่มีอยู่ → 404 · เพดาน 30 คำขอ/นาที ต่อ IP
Required scoperead
Terminal
curl https://api.slip-bolt.com/api/v1/transactions/8f3c2a1e-…/receipt.png \
  -H "Authorization: Bearer $SLIPBOLT_API_KEY" \
  -o receipt.png

POST /api/v1/verify/async

ตรวจสลิปแบบ ไม่รอผล — ตอบ 202 ภายในไม่กี่มิลลิวินาที แล้วตรวจต่อเบื้องหลัง เหมาะกับร้านที่ส่งสลิปเป็นชุด หรือไม่อยากให้ request ค้างรอระบบธนาคาร · body/header/scope เหมือน POST /verify ทุกอย่าง (รวม Idempotency-Key)

Terminal
curl -i -X POST https://api.slip-bolt.com/api/v1/verify/async \
  -H "Authorization: Bearer $SLIPBOLT_API_KEY" \
  -H "Idempotency-Key: order-1001" \
  -H "Content-Type: application/octet-stream" \
  --data-binary @slip.jpg
HTTP
HTTP/1.1 202 Accepted
Location: /api/v1/verifications/vrf_3f9a1c0b7e2d4a6f8b1c2d3e
JSON
{
  "success": true,
  "data": {
    "id": "vrf_3f9a1c0b7e2d4a6f8b1c2d3e",
    "status": "PENDING",
    "createdAt": "2026-10-22T03:21:06.412Z",
    "completedAt": null,
    "statusUrl": "/api/v1/verifications/vrf_3f9a1c0b7e2d4a6f8b1c2d3e",
    "result": null,
    "error": null
  },
  "meta": { "requestId": "…", "timestamp": "…" }
}

รับผลได้ 2 ทาง (ใช้คู่กันได้):

  1. Webhook verification.completed — ติ๊ก event นี้ที่ endpoint ใน Settings → Webhooks (รูปแบบ payload)
  2. Poll GET /api/v1/verifications/{id} ทุก 1–2 วินาที (ไม่เปลือง verify)

GET /api/v1/verifications/:id

statusความหมาย
PENDING · PROCESSINGยังไม่จบ
COMPLETEDตรวจจบแล้ว — result คือ data ชุดเดียวกับที่ POST /verify ตอบ ทุกฟิลด์ (status ของสลิปดูที่ result.status — สลิปไม่ผ่านก็ยังเป็น COMPLETED)
FAILEDไม่ได้ตรวจ — ดู error · ไม่หักโควตา · ส่งใหม่ได้

error.code ของ FAILED (error.httpStatus = status ที่ POST /verify จะตอบในกรณีเดียวกัน):

error.codeเมื่อไร
QUOTA_EXCEEDED · TEST_QUOTA_EXCEEDEDโควตา/เครดิตหมด (sync = 402)
SPEND_CAP_EXCEEDEDถึงเพดานต่อคีย์ที่ร้านตั้ง (sync = 429)
VERIFY_TIMEOUTค้างคิวเกิน 5 นาที — ระบบไม่ได้ตรวจ
API_KEY_REVOKEDคีย์ถูกยกเลิกก่อนตรวจเสร็จ
INTERNAL_ERRORระบบเราขัดข้องหลังลองซ้ำแล้ว
  • เก็บผล 24 ชม. หลังจากนั้น 404 — ผลถาวรอยู่ที่ GET /transactions/{result.id}
  • id ของร้านอื่น / คีย์คนละ environment (sk_live_ vs sk_test_) → 404
  • Idempotency-Key เดิม + สลิปเดิม = ได้ 202 ชุดเดิม (id เดิม · Idempotent-Replayed: true) ไม่สร้างงานซ้ำ · key ของ async แยกจาก POST /verify (ใช้ค่าเดียวกันสองเส้นได้ไม่ชนกัน)
  • งานรอตรวจต่อร้านมีเพดาน (ค่าเริ่มต้น 50 ใบ) — เต็มได้ 429 code: "ASYNC_QUEUE_FULL" + Retry-After
  • ระบบเราไม่มีคิวชั่วคราว → 503 code: "ASYNC_UNAVAILABLE" — ส่งที่ POST /verify แทน

ผลตรวจ, DUPLICATE, STALE_SLIP, quotaCharged ของโหมด async เหมือนโหมดปกติทุกกรณี — ใช้เส้นตรวจตัวเดียวกัน event slip.* เดิมก็ยังส่งตามปกติ (ได้ทั้ง slip.verified และ verification.completed ถ้าติ๊กไว้ทั้งคู่)


Scopes

แต่ละ key ถือ scope ได้หลายตัว — endpoint ต้องการ scope ครบทุกตัวที่ระบุ (ตั้งค่าได้ที่ Settings → API Keys)

Scopeใช้กับ
verifyPOST /api/v1/verify (default ของทุก key)
readGET /api/v1/quota · GET /api/v1/me · GET /api/v1/transactions[/:id] · GET /api/v1/transactions/:id/receipt.{png,pdf}
webhookสำรองไว้สำหรับอนาคต — ตอนนี้ยังไม่มี public endpoint ใช้งาน scope นี้ (ตั้งค่า outgoing webhook ทำผ่าน Dashboard → Settings → Webhooks เท่านั้น ไม่ใช่ API key)

scope ไม่พอ → 403 Forbidden · message: "API key missing scope(s): verify" (ไม่มี code — รูปร่างเต็มอยู่ที่ Error envelope) คีย์ที่ถูก revoke ได้ 401 ตั้งแต่คำขอถัดไปทันที — ไม่มีช่วง cache


Health check

ไม่ต้องใช้คีย์ · ไม่กินโควตาหรือ rate limit ของคีย์ · Cache-Control: no-store · จำกัด 120 คำขอ/นาที ต่อ IP

Endpointใช้ทำอะไรตอบ
GET /api/v1/healthprocess ยังรับคำขอไหม (ไม่แตะ dependency)200 { "status": "ok" }
GET /api/v1/readyพร้อมตรวจสลิปจริงไหม — เช็คฐานข้อมูล · คิว · ระบบตรวจสลิป (ผลแคช 15 วินาที)200 ok / degraded · 503 down
JSON
{ "status": "degraded", "checks": { "database": "ok", "queue": "ok", "verification": "degraded" }, "timestamp": "2026-10-21T08:00:00.000Z" }
  • degraded = ยังตรวจได้ แต่วิ่งเส้นสำรองอยู่ (อาจช้ากว่าปกติ) · down = ตรวจไม่ได้ตอนนี้ — ระบบคุณควรพักการส่งแล้วลองใหม่
  • ตั้ง uptime monitor ที่ /api/v1/ready ได้เลย · สถานะรวมและประวัติเหตุขัดข้องดูที่ หน้าสถานะระบบ

Rate limit

120 req/min ต่อ key (เท่ากันทุกแพ็ก) + เพดานรวมของ POST /api/v1/verify ที่ 240 req/min เกินแล้ว → 429 Too Many Requests + header Retry-After + code: "RATE_LIMITED" (แยกจาก SPEND_CAP_EXCEEDED / ASYNC_QUEUE_FULL ด้วย code) · ดู Authentication

Header ที่มากับทุกคำตอบ:

Headerความหมายหน่วย
X-RateLimit-Limitเพดานของ endpoint นี้ ต่อ IP ต้นทาง — 120 ทุก endpoint · 240 บน POST /verifyคำขอ/นาที
X-RateLimit-Remainingเหลือในหน้าต่างปัจจุบัน (ต่อ IP)คำขอ
X-RateLimit-Resetเวลาจนกว่าหน้าต่างจะรีเซ็ตวินาที (ไม่ใช่ epoch)
Retry-Afterมาเฉพาะกับ 429 — ต้องรอเท่าไรก่อนยิงใหม่วินาที
X-Request-Idid ของคำขอ — ค่าเดียวกับ meta.requestId / requestId ใน errorUUID

มีตัวนับสองชั้น — X-RateLimit-* คือชั้น ต่อ IP (จึงเห็น 240 บน /verify และ 120 ที่อื่น) ส่วนเพดาน 120 req/min ต่อ key เป็นอีกตัวนับหนึ่งที่ ไม่มี header บอกยอดคงเหลือ — คีย์เดียวยิง /verify ได้จริง 120 ครั้ง/นาที แม้ X-RateLimit-Limit จะเขียน 240 · ชนชั้นไหนก่อนก็ได้ 429 + Retry-After เหมือนกัน ⇒ ให้ throttle จาก 429 ไม่ใช่จาก Remaining


Transaction status

statusverifiedหักโควตา/เครดิตWebhookความหมาย · ทำอย่างไรต่อ
SUCCESS✅หัก 1 (key live)slip.verifiedสลิปถูกต้อง โอนเข้าบัญชีร้าน → เทียบ amount กับยอดออเดอร์ แล้วปล่อยของ · เช็ค errorCode ด้วย — STALE_SLIP = สลิปเก่า
DUPLICATE❌ไม่หักslip.duplicateเลขอ้างอิง (transRef) นี้เคยตรวจแล้ว → ห้ามปล่อยของซ้ำ
AMOUNT_MISMATCH❌ไม่หักslip.failedยอดบนสลิปไม่ตรงเงื่อนไขที่ธนาคารถูกขอให้เช็ค — POST /verify ไม่รับยอดที่คาดไว้ ⇒ ให้เทียบ amount กับยอดออเดอร์ฝั่งคุณเอง
RECEIVER_MISMATCH❌ไม่หักslip.failedโอนเข้าบัญชีที่ไม่ใช่ของร้าน → เช็ค payeeAccounts ใน GET /me ว่าเพิ่มบัญชีที่ลูกค้าโอนเข้าแล้วหรือยัง
INVALID❌ไม่หักslip.failed (ยกเว้น NO_PAYEE_CONFIGURED — ไม่มี event)อ่านสลิปไม่ได้ / ไม่ใช่สลิป → ให้ลูกค้าส่งรูปสลิปจากแอปธนาคารใหม่ · ดู errorCode
FRAUD❌ไม่หักslip.fraudสลิปปลอม/แก้ไข — ไม่ตรงข้อมูลธนาคาร → ไม่ปล่อยของ
QUOTA_EXCEEDED❌ไม่หักไม่มีโควตาหมด — POST /verify ตอบ 402 ไม่ใช่ 200 (ดูด้านบน) · สถานะนี้เห็นได้ใน GET /transactions เท่านั้น
PROVIDER_ERROR❌ไม่หักไม่มีระบบตรวจกับธนาคารขัดข้องชั่วคราว (200 + สถานะนี้) — ยังไม่ใช่คำตัดสิน → ส่งสลิปเดิมใหม่ได้เลย (ตรวจใหม่จริง ไม่ถูกแคช)
  • โควตานับเฉพาะ SUCCESS — สลิปที่ไม่ผ่านทุกแบบ · ของซ้ำ · cached: true · และคีย์ sk_test_ ไม่หักโควตาหรือเครดิตของร้าน · ดูผลของคำขอนั้น ๆ ได้จาก quotaCharged
  • GET /transactions?status= รับได้ครบทั้ง 8 ค่าในตารางนี้ (ค่าอื่น → 400)
  • คำขอที่ได้ cached: true ไม่ยิง webhook ซ้ำ — event ออกครั้งเดียวตอนตรวจครั้งแรก

errorCode ของผลตรวจ

มีโค้ดสองที่ซึ่ง คนละชุดกัน — data.errorCode (คำขอสำเร็จ 200 · บอกเหตุผลของผลตรวจ) กับ code ในซอง error (4xx)

data.errorCode — อยู่ในผลตรวจ (POST /verify · GET /transactions)

errorCodeมากับ statusเกิดเมื่อไรฝั่งคุณควรทำอะไร
nullSUCCESS · DUPLICATE · RECEIVER_MISMATCH · AMOUNT_MISMATCHไม่มีเหตุผลเพิ่มเติมแตกกิ่งด้วย status
STALE_SLIPSUCCESS (หรือ INVALID — ดู Stale slip)สลิปจริง แต่เวลาโอนเก่าเกิน 24 ชม. หรือลงเวลาล่วงหน้าตัดสินใจเองว่าจะรับสลิปเก่าไหม — เป็น คำเตือน ไม่ใช่การปฏิเสธ
NO_PAYEE_CONFIGUREDINVALIDร้านยังไม่ได้เพิ่มบัญชีรับเงินสักบัญชี — ยังไม่ได้ส่งไปตรวจกับธนาคารเพิ่มบัญชีที่ Settings → Shop → บัญชีรับเงิน แล้วส่งสลิปเดิมใหม่
INVALIDINVALIDอ่านสลิปไม่ได้ / ไม่ใช่สลิป / ธนาคารไม่พบรายการให้ลูกค้าส่งรูปสลิปใหม่
FRAUDFRAUDสลิปปลอมหรือถูกแก้ไขไม่ปล่อยของ
PROVIDER_ERRORPROVIDER_ERRORระบบตรวจขัดข้องชั่วคราวส่งสลิปเดิมใหม่แบบเว้นช่วง
QUOTA_EXCEEDEDQUOTA_EXCEEDEDโควตา + เครดิตหมด (เห็นใน GET /transactions)เติมเครดิต / อัปเกรดแพ็ก

errorCode ไม่ใช่ null เสมอไปเมื่อ status เป็น SUCCESS — อย่าเขียน if (errorCode) reject() · ตัดสินผ่าน/ไม่ผ่านจาก verified (หรือ status) เท่านั้น และถือ errorCode ที่ไม่รู้จักเป็น "ไม่ผ่านด้วยเหตุอื่น" — เราอาจเพิ่มค่าใหม่โดยไม่ถือเป็น breaking change · errorMessage เป็นข้อความสำหรับคนอ่าน ห้ามใช้แตกกิ่ง

code — อยู่ในซอง error (Error envelope) · มีเฉพาะสามกรณีนี้ error อื่นไม่มีฟิลด์ code

codeHTTPเกิดเมื่อไรหักโควตาไหมฝั่งคุณควรทำอะไร
QUOTA_EXCEEDED402key live — โควตารายเดือนและเครดิตของร้านหมดไม่เติมเครดิต / อัปเกรดแพ็ก / รอรอบใหม่ — retry ไม่ช่วย
TEST_QUOTA_EXCEEDED402key test — ใช้ครบ 200 ครั้ง/เดือนไม่ย้ายไปคีย์ sk_live_ หรือรอเดือนถัดไป
PLAN_API_ACCESS_REQUIRED403แพ็กปัจจุบันไม่รวม REST API (Trial · แพ็กหมดอายุ · ร้านถูกพัก)ไม่อัปเกรดเป็น Starter ขึ้นไป

Stale slip

สลิป จริง ที่ถูกนำกลับมาใช้กับออเดอร์ใหม่ผ่านการตรวจกับธนาคารได้ (ธนาคารยืนยันว่ารายการมีจริง ไม่ได้ยืนยันว่า "เพิ่งโอน") เราจึงเทียบเวลาโอน (transDate) กับเวลาที่ส่งมาตรวจ — เก่ากว่า 24 ชั่วโมง หรือลงเวลาล่วงหน้า = ติดธง STALE_SLIP · เช็คเฉพาะสลิปที่ผ่าน — สลิปที่ไม่ผ่านด้วยเหตุอื่น (เช่น RECEIVER_MISMATCH) จะไม่มี STALE_SLIP แม้จะเก่า เพราะไม่ผ่านอยู่แล้ว

โหมดผลที่ได้ใช้อยู่ไหม
alertstatus: "SUCCESS" · verified: true · errorCode: "STALE_SLIP" — เจ้าของร้านได้รับแจ้งเตือน · หักโควตาตามปกติค่าที่ใช้อยู่ตอนนี้
rejectstatus: "INVALID" · verified: false · errorCode: "STALE_SLIP" — ไม่หักโควตายังไม่เปิด (ตั้งที่ระดับแพลตฟอร์ม ไม่ใช่ต่อร้าน)
JSON
{
  "status": "SUCCESS",
  "verified": true,
  "transDate": "2026-06-15T03:21:05.000Z",
  "errorCode": "STALE_SLIP",
  "errorMessage": "สลิปลงวันที่ย้อนหลังเกิน 24 ชม. (เก่า 48 ชม.)",
  "warnings": [{ "code": "STALE_SLIP", "message": "สลิปลงวันที่ย้อนหลังเกิน 24 ชม. (เก่า 48 ชม.)" }]
}

ถ้าธุรกิจของคุณไม่รับสลิปเก่า ต้องเช็คเอง — verified === true อย่างเดียวไม่พอ: if (slip.verified && slip.warnings.some((w) => w.code === 'STALE_SLIP')) { /* ถือเป็นไม่ผ่าน หรือส่งให้คนตรวจ */ } (โค้ดเดิมที่เช็ค slip.errorCode === 'STALE_SLIP' ยังใช้ได้) หรือเทียบ transDate กับเวลาสร้างออเดอร์ตามกติกาของคุณเอง (เช่น ต้องโอนหลังเปิดออเดอร์)


Idempotency

ระบบ dedupe ให้อัตโนมัติ — สามเคสที่ต่างกัน:

  • ส่ง "รูปเดิม" ซ้ำภายใน 24 ชม. → cached: true · status/verified เป็นผลจริงของ รายการเดิม (retry ตอนเน็ตตัด/timeout ได้อย่างปลอดภัย — ไม่ตรวจซ้ำ ไม่หักโควตา)
  • transRef เดียวกัน เคยตรวจผ่านไปแล้ว (คนละไฟล์รูป/ถ่ายซ้ำ) → duplicate: true และ status จะเป็น "DUPLICATE" เสมอในการตอบครั้งนี้ (verified: false) — ไม่ว่าผลตรวจ ครั้งแรกจะเป็นอะไรก็ตาม
  • ส่งรูปของสลิปที่ตอบ DUPLICATE ไปแล้วซ้ำอีก → ยังได้ DUPLICATE (duplicate: true พร้อม cached: true) — ผลเดิมแบบ cached มีให้เฉพาะรูปที่ API เป็นคนตรวจครั้งแรกเอง · สลิปที่เคยเข้าทาง LINE หรือ Dashboard มาก่อน ส่งเข้า API กี่ครั้งก็เป็น DUPLICATE

Idempotency-Key — retry คำขอเดิมแบบไม่มีผลข้างเคียง

cached ครอบเฉพาะ "รูปเดิมไบต์ต่อไบต์ที่ตรวจเสร็จแล้ว" · ถ้าระบบคุณ retry ตอน timeout ระหว่างที่คำขอแรกยังไม่จบ หรืออยากได้คำตอบชุดเดิมเป๊ะ (รวม quotaCharged ของครั้งแรก) ให้ส่ง header Idempotency-Key — ค่าเฉพาะต่อคำขอ เช่น UUID หรือเลขออเดอร์

Terminal
curl -X POST https://api.slip-bolt.com/api/v1/verify \
  -H "Authorization: Bearer sk_live_xxx" \
  -H "Idempotency-Key: order-1001" \
  -H "Content-Type: application/octet-stream" \
  --data-binary @slip.jpg
เหตุการณ์ผล
ส่ง key เดิม + สลิปเดิม หลังครั้งแรกตอบ 200 แล้ว200 พร้อม data ชุดเดิมทุกฟิลด์ + header Idempotent-Replayed: true · ไม่ตรวจซ้ำ ไม่หักโควตาซ้ำ ไม่กลายเป็น DUPLICATE
ส่ง key เดิม ระหว่างที่ครั้งแรกยังประมวลผลอยู่409 code: "IDEMPOTENCY_IN_PROGRESS" + Retry-After — รอแล้วส่งซ้ำด้วย key เดิม
ส่ง key เดิม แต่เป็นสลิปคนละใบ422 code: "IDEMPOTENCY_KEY_REUSED" — ใช้ key ใหม่ต่อหนึ่งคำขอ
key ผิดรูป (ว่าง · เกิน 255 ตัว · ไม่ใช่ ASCII ที่พิมพ์ได้)400 code: "IDEMPOTENCY_KEY_INVALID"
ครั้งแรกจบด้วย error (4xx/5xx เช่น 402 โควตาหมด)ไม่ถูกจำ — ส่งซ้ำด้วย key เดิมได้ ประมวลผลจริงอีกรอบ
  • เก็บ 24 ชม. ต่อร้าน (คีย์ sk_live_ กับ sk_test_ แยกกัน · ร้านอื่นใช้ค่าเดียวกันได้ไม่ชนกัน)
  • "สลิปเดิม" เทียบจากรูปหลังถอดรูปแบบแล้ว — ส่ง multipart ใหม่ (boundary เปลี่ยน) ก็ยังนับเป็นคำขอเดิม
  • meta.requestId/timestamp ของ envelope เป็นของคำขอปัจจุบัน · header X-Slipbolt-Quota-* เป็นยอดปัจจุบัน
  • ไม่ส่ง header = พฤติกรรมเดิมทุกอย่าง (ไม่บังคับ)

ห้าม credit ออเดอร์จากแค่ verified === true — ต้องเช็ค duplicate ก่อนเสมอถ้าระบบคุณ เคยประมวลผล transRef นั้นไปแล้ว ไม่งั้นการ retry/ส่งซ้ำโดยไม่ตั้งใจจะ credit ซ้ำ


Error envelope

ทุก error รูปแบบเดียวกัน:

JSON
{
  "success": false,
  "error": "Forbidden",
  "message": "API key missing scope(s): read",
  "statusCode": 403,
  "path": "/api/v1/quota",
  "requestId": "3b1f0c9e-6a2d-4f5e-8b7c-1d2e3f4a5b6c",
  "timestamp": "2026-06-17T03:30:45.120Z"
}

code มีเฉพาะบาง error (402 ทั้งสองแบบ · 403 กรณีแพ็ก · IDEMPOTENCY_* ของ 400/409/422 · METHOD_NOT_ALLOWED ของ 405 — ดู ตาราง code) · error อื่นไม่มีฟิลด์นี้ ให้แยกด้วย statusCode · message เป็น string เสมอ ยกเว้น 400 จาก validation ที่ผิดหลายข้อจะเป็น array ของ string · requestId ตรงกับ header X-Request-Id ของคำตอบนั้น — แนบมาด้วยเมื่อติดต่อทีมงาน

Statusเมื่อไรลองใหม่ได้ไหม
400ไม่มีรูปในคำขอ / multipart ไม่มีไฟล์ / image ไม่ใช่ base64 / ดาวน์โหลด url ไม่ได้ / qr ผิดรูปแบบหรือเป็น QR รับเงิน · query ที่ไม่รู้จัก (เช่น ?page=2 → property page should not exist) หรือค่าผิดชนิด (limit=500 · status=PASSED)ไม่ — แก้ request
401ไม่มี header Authorization: Bearer … (Missing API key — …) · คีย์ผิดหรือถูก revoke (Invalid or revoked API key) — X-API-Key และ Basic auth ใช้ไม่ได้ไม่ — เช็คคีย์
402โควตา + เครดิตหมด — QUOTA_EXCEEDED (key live) หรือ TEST_QUOTA_EXCEEDED (key test เกิน 200/เดือน)ไม่ — เติมเครดิต/อัปเกรด หรือใช้คีย์ live
403scope ไม่พอ (error: "Forbidden" · ไม่มี code — ตัวอย่างด้านบน) หรือแพ็กปัจจุบันไม่รวม REST API (code: "PLAN_API_ACCESS_REQUIRED")ไม่ — เพิ่ม scope / อัปเกรดแพ็ก
403IP ไม่อยู่ใน allowlist ของคีย์ — code: "IP_NOT_ALLOWED" (ตั้งค่า)ไม่ — เพิ่ม IP หรือเรียกจากเครื่องที่อนุญาต
404ไม่พบรายการ (GET /transactions/:id) — เป็นของร้านอื่น หรือ id ไม่ใช่ UUID ก็ได้ 404 เหมือนกัน (ไม่ใช่ 400) · path ที่ไม่มี ก็ 404ไม่
405path ถูก แต่ method ผิด (เช่น GET /api/v1/verify) — code: "METHOD_NOT_ALLOWED" · header Allow บอก method ที่ใช้ได้ไม่ — แก้ method
409IDEMPOTENCY_IN_PROGRESS — คำขอที่ใช้ Idempotency-Key เดียวกันยังประมวลผลอยู่ได้ — รอตาม Retry-After แล้วส่งซ้ำด้วย key เดิม
422IDEMPOTENCY_KEY_REUSED — Idempotency-Key นี้เคยใช้กับสลิปใบอื่นไม่ — ใช้ key ใหม่
429เกิน rate limit — รอตาม header Retry-After (วินาที) ก่อนยิงใหม่ได้ — หลังรอตาม Retry-After
429 SPEND_CAP_EXCEEDEDถึงเพดานต่อคีย์ที่ร้านตั้งเอง (spendCap.window = hour/day)อย่า retry วน — รอรอบใหม่ตาม Retry-After
5xxระบบเราขัดข้องชั่วคราวได้ — เว้นช่วงแบบ exponential (ส่งรูปเดิมซ้ำปลอดภัย ไม่หักโควตาซ้ำ)

แยกกรณีด้วย statusCode และ code — อย่าเทียบจากข้อความใน message (ข้อความปรับได้โดยไม่ถือเป็น breaking change) ไคลเอนต์ที่ทำ retry ตามตารางนี้ให้แล้วอยู่ที่ ตัวอย่างพร้อมใช้


รหัสธนาคาร

bankCode / receiverBankCode ในผลตรวจ (และใน webhook) เป็น รหัสธนาคาร 3 หลัก ตามที่เครือข่ายธนาคารส่งมา ส่วน payeeAccounts[].bankCode ใน GET /me เป็น ชื่อย่อ (slug) ที่ร้านเลือกตอนเพิ่มบัญชีรับเงิน — สองรูปแบบนี้ไม่เท่ากันตรง ๆ ใช้ตารางนี้เทียบ

รหัส 3 หลักslug ใน /meธนาคารBank
002bblกรุงเทพBangkok Bank
004kbankกสิกรไทยKasikornbank
006ktbกรุงไทยKrungthai Bank
011ttbทีเอ็มบีธนชาตTMBThanachart (ttb)
014scbไทยพาณิชย์Siam Commercial Bank
017citiซิตี้แบงก์Citibank
020scสแตนดาร์ดชาร์เตอร์ด (ไทย)Standard Chartered (Thai)
022cimbซีไอเอ็มบี ไทยCIMB Thai
024uobยูโอบีUOB
025bayกรุงศรีอยุธยาKrungsri (Bank of Ayudhya)
030gsbออมสินGovernment Savings Bank
033ghbอาคารสงเคราะห์ (ธอส.)Government Housing Bank
034baacธ.ก.ส.BAAC
067tiscoทิสโก้TISCO
069kkpเกียรตินาคินภัทรKiatnakin Phatra
070icbcไอซีบีซี (ไทย)ICBC (Thai)
071tcrbไทยเครดิตThai Credit
073lhbankแลนด์ แอนด์ เฮ้าส์LH Bank
088clicxคลิกซ์CLICX

slug ที่ ไม่มีรหัส 3 หลัก (ไม่ใช่ธนาคาร): promptpay (kind: "PROMPTPAY") · truemoney (kind: "WALLET") · other (ธนาคารที่ร้านพิมพ์เอง)

  • ถือรหัสเป็น string ทึบ — เก็บเลข 0 นำหน้าไว้ ("002" ไม่ใช่ 2) และรองรับรหัสที่ไม่อยู่ในตาราง: เราส่งต่อค่าที่ธนาคารให้มา ธนาคารใหม่จึงโผล่ได้โดยไม่มีประกาศ · แสดงผลให้คนอ่านใช้ bankName / receiverBankName ได้เลย
  • สลิปโอนเข้า PromptPay — receiverBankCode คือธนาคารที่บัญชีปลายทางผูกอยู่ (หรือ null ถ้าสลิปไม่บอก) ไม่ใช่ promptpay
  • แอปรับเงินร้านค้า (K SHOP · แม่มณี · ถุงเงิน · มั่งมี) ใช้ slug ของธนาคารเจ้าของ (kbank · scb · ktb · bay)
  • อย่าเทียบผู้รับเองจากรหัสธนาคาร — เราเทียบกับบัญชีรับเงินของร้านให้แล้ว ผลอยู่ที่ status (RECEIVER_MISMATCH)

ถัดไป

  • Webhooks — รับ event slip.verified / slip.duplicate / slip.fraud / slip.failed แบบ HMAC-signed แทนการ poll
  • Authentication — รายละเอียด key · โควตาต่อแพ็ก · rate limit