core

Webhooks

รับ event แบบ HMAC-signed · retry อัตโนมัติ 5 ครั้ง · delivery log + auto-disable endpoint ที่ล่ม

The documentation is currently written in Thai only — an English translation is on the way. The navigation and page chrome are already in English.

ตั้ง endpoint ของคุณที่ Settings → Webhooks — SlipBolt จะ POST event ทุกครั้งที่มีผลตรวจสลิปใหม่

Event types

มี 3 event · เลือก subscribe ได้ต่อ endpoint (ไม่เลือกเลย = ได้ slip.verified อย่างเดียว)

Eventเมื่อไรdata.status ที่มากับ event
slip.verifiedสลิปผ่านการตรวจSUCCESS
slip.duplicateสลิปใบนี้เคยส่งมาแล้วDUPLICATE
slip.failedตรวจไม่ผ่านINVALID · FRAUD · AMOUNT_MISMATCH · RECEIVER_MISMATCH · PROVIDER_ERROR

ยังไม่มี event ฝั่งบัญชี/แพ็ก (เช่น subscription หรือโควตาใกล้เต็ม) — การแจ้งเตือนโควตา 80% ส่งทางอีเมล/LINE ไม่ใช่ webhook

Payload

Body เป็น JSON ตามนี้เสมอ — created เป็น unix seconds ไม่ใช่ ISO string

{
  "event": "slip.verified",
  "id": "evt_9f3c1a7b2d4e6f8a0b1c2d3e",
  "created": 1781107927,
  "data": {
    "transactionId": "8f3c…",
    "transRef": "015170106978META…",
    "amount": 250.0,
    "status": "SUCCESS",
    "bankCode": "002",
    "bankName": "ธนาคารกรุงเทพ",
    "sender": "นาย ก. …",
    "receiver": "ร้าน ข.",
    "verifiedAt": "2026-06-17T03:21:06.412Z",
    "latencyMs": 480
  }
}

sender / receiver เป็น string ชื่อ ไม่ใช่ object · ค่าที่อ่านไม่ได้จากสลิปจะเป็น null

Header ที่มากับทุก delivery:

Headerค่า
X-Slipbolt-Eventชื่อ event เช่น slip.verified
X-Slipbolt-Deliveryid ของ endpoint ที่ยิงมา
X-Slipbolt-Signaturet=<unix>,v1=<hex> — ดูหัวข้อถัดไป
User-AgentSlipbolt-Webhooks/1.0

Verify signature

X-Slipbolt-Signature: t=1781107927,v1=<hex>

v1 = HMAC-SHA256(secret, "<ts>." + raw_body)

สตริงที่เซ็นคือ <ts>.<body> — ไม่มี t= นำหน้า · ใส่ t= เข้าไปด้วยจะได้ signature คนละค่า แล้ว verify ไม่ผ่านทุกใบ · และต้องใช้ raw body ไม่ใช่ JSON ที่ parse แล้ว re-serialize

import { createHmac, timingSafeEqual } from 'node:crypto';

function verify(rawBody: string, header: string, secret: string): boolean {
  const parts = Object.fromEntries(header.split(',').map(p => p.split('=')));
  const ts = parts.t;
  const sig = parts.v1;
  if (!ts || !sig) return false;
  if (Math.abs(Date.now() / 1000 - Number(ts)) > 300) return false; // กัน replay 5 นาที

  const expected = createHmac('sha256', secret)
    .update(`${ts}.${rawBody}`)   // ← จุดที่พลาดกันบ่อย
    .digest('hex');

  const a = Buffer.from(sig, 'hex');
  const b = Buffer.from(expected, 'hex');
  return a.length === b.length && timingSafeEqual(a, b);
}

ดู secret ของแต่ละ endpoint ได้ที่ Settings → Webhooks (กดเปิดดูทีละอัน)

Retry policy

  • 2xx = สำเร็จ · อย่างอื่นทั้งหมดถือว่าล้มเหลว
  • 4xx ก็ retry — ไม่ได้ยกเว้นเหมือนบางเจ้า · ถ้าไม่อยากโดนยิงซ้ำ ตอบ 2xx แล้วค่อยไปคัดทิ้งฝั่งคุณ
  • timeout 10 วินาที ต่อครั้ง
  • ลองทั้งหมด 5 ครั้ง · backoff แบบ exponential เริ่มที่ 2 วินาที (≈ 2s → 4s → 8s → 16s)
  • ทุกครั้งที่ยิงถูกบันทึกเป็นแถวใน delivery log — ดูได้ที่ Settings → Webhooks

endpoint ที่ล้มเหลวสะสมครบ 25 ครั้งจะถูกปิดอัตโนมัติ (enabled = false) และหยุดรับ event จนกว่าจะเปิดใหม่เอง · ตัวนับรีเซ็ตทันทีที่มี delivery สำเร็จหนึ่งครั้ง

ทดสอบ endpoint

กด ส่ง event ตัวอย่าง ที่ Settings → Webhooks — ระบบยิง slip.verified ปลอมหนึ่งใบไปที่ endpoint นั้น โดยไม่สนว่า subscribe อะไรไว้และไม่แตะโควตา · ใช้ตรวจว่า signature ฝั่งคุณ verify ผ่านจริงก่อนขึ้น production

ถัดไป

  • API Reference — endpoint + error code ทั้งหมด
  • Security & PDPA — การเก็บ secret + สิทธิ์เจ้าของข้อมูล