DEVELOPER DOCUMENTATION

เชื่อมต่อการตรวจสลิป
เข้ากับระบบของคุณ

ส่งสลิป ติดตามผล และรับ Webhook อย่างปลอดภัย
คู่มือและตัวอย่างสำหรับพัฒนาระบบชำระเงินด้วย SlipMatrix

REST + JSONSigned Webhook10 endpointsอัปเดต 11 ต.ค. 2026

01 / QUICKSTART

จากสลิป สู่ผลตรวจที่นำไปใช้งานได้

สมัครบัญชีและยืนยันข้อมูล จากนั้นสร้าง API Key ใน Merchant Portal ทุกตัวอย่างใช้ Production API และคำขอตรวจสลิปอาจใช้เครดิตจริง ค่าตัวอย่างในเอกสารเป็นข้อมูลสมมติ ให้แทนด้วยสลิปที่คุณมีสิทธิ์ใช้งาน

  1. เตรียม CredentialsApp ID · API Key · Webhook Secret
  2. ส่งสลิปรับ transactionId แล้วบันทึกไว้
  3. ติดตามผลPolling หรือ Signed Webhook
  4. เทียบคำสั่งซื้อยอดเงิน · สกุลเงิน · ผู้รับ · เวลาโอน
Production base URL
https://api.slipmatrix.com/api

Base URL มี /api แล้ว ต่อ path ในเอกสารได้เลย

ส่งรูปสลิปด้วย cURL
# ตั้ง APP_ID และ API_KEY ใน environment ของเซิร์ฟเวอร์ก่อน
curl --fail-with-body --max-time 30 \
  'https://api.slipmatrix.com/api/verify/image/upload' \
  -H "x-app-id: $APP_ID" \
  -H "x-api-key: $API_KEY" \
  -F 'file=@./slip.png'
ตัวอย่างตอบกลับ · HTTP 201
{
  "success": true,
  "data": {
    "transactionId": "0199d720-0000-7000-8000-000000000001",
    "status": "PENDING",
    "message": "Verification request submitted"
  },
  "timestamp": "2026-10-10T12:00:00+07:00"
}
HTTP 201 = รับคำขอแล้ว

ยังไม่ใช่หลักฐานว่าชำระเงินสำเร็จ เก็บ data.transactionId แล้วรอผลสุดท้ายก่อนยืนยันคำสั่งซื้อ

ติดตาม transactionId เดิม
curl --fail-with-body --max-time 30 \
  "https://api.slipmatrix.com/api/verify/$TRANSACTION_ID" \
  -H "x-app-id: $APP_ID" \
  -H "x-api-key: $API_KEY"
สร้างบัญชีและเริ่มใช้งาน →

02 / AUTHENTICATION

ยืนยันตัวตนจากเซิร์ฟเวอร์ของคุณ

ส่ง headers ทั้งสองรายการในทุก Merchant API ยกเว้น GET /verify/banks ไม่ใช้ JWT ของหน้า Portal มาแทน API Key

Credentials สำหรับเชื่อมต่อ
ค่าใช้ทำอะไร
x-app-idระบุ App ID ของร้านค้า
x-api-keyAPI Key ที่ยังเปิดใช้งาน หากตั้ง IP whitelist ต้องส่งจาก IP ที่อนุญาต
Webhook Secretตรวจลายเซ็น callback ใช้ค่าที่ได้รับเมื่อสมัครหรือจากผู้ดูแลระบบ

เก็บค่าลับใน environment หรือระบบจัดการ secrets ฝั่งเซิร์ฟเวอร์ ห้ามใส่ใน JavaScript ของหน้าเว็บ, URL, Git หรือ log หากหมุนเวียนกุญแจให้ปรับค่าในระบบที่เชื่อมต่อด้วย

03 / API REFERENCE

เลือกวิธีส่งสลิปที่เหมาะกับระบบ

ทุก path ต่อจาก Base URL ด้านบน ผลตอบกลับที่สำเร็จอยู่ใน data และมี success, timestamp ครอบไว้

แสดง 10 จาก 10 endpoints

POST/verify

ส่งเลขอ้างอิงสลิป

ส่ง transRef และรหัสธนาคารผู้โอนจากสลิปจริง

x-app-id + x-api-keyapplication/jsonHTTP 201
พารามิเตอร์สำหรับ POST /verify
ชื่อ / ชนิดการใช้งาน
transRefstring · จำเป็นเลขอ้างอิงจากสลิปจริง อย่างน้อย 10 ตัวอักษร
sendingBankstring · จำเป็นรหัสธนาคารผู้โอน เก็บเป็นข้อความ 3 หลัก เช่น 014
qrDatastring · ไม่บังคับข้อความ QR จากสลิป (ถ้ามี)
ตัวอย่าง POST /verify
curl --fail-with-body --max-time 30 "https://api.slipmatrix.com/api/verify" \
  -H "x-app-id: $APP_ID" \
  -H "x-api-key: $API_KEY" \
  -H 'Content-Type: application/json' \
  --data '{
  "transRef": "EXAMPLE_TRANS_REF_001",
  "sendingBank": "014"
}'

รูปแบบผลตอบกลับ: Accepted ในไฟล์ OpenAPI · ต้องติดตามผลหลังรับคำขอ

GET/verify

ดูประวัติรายการ

อ่านรายการที่ body.data.data; กรองวันที่สร้างรายการ createdAt ไม่ใช่เวลาโอน; วันที่ YYYY-MM-DD ใช้เขตเวลา Bangkok

x-app-id + x-api-keyQuery / Path parametersHTTP 200
พารามิเตอร์สำหรับ GET /verify
ชื่อ / ชนิดการใช้งาน
pageinteger · query · ไม่บังคับเลขหน้า เริ่มที่ 1
limitinteger · query · ไม่บังคับจำนวนต่อหน้า ใช้จำนวนเต็มบวก
statusstring · query · ไม่บังคับสถานะที่ต้องการ
startDatestring · query · ไม่บังคับYYYY-MM-DD หรือ ISO 8601 พร้อมเขตเวลา
endDatestring · query · ไม่บังคับYYYY-MM-DD หรือ ISO 8601 พร้อมเขตเวลา
ตัวอย่าง GET /verify
curl --fail-with-body --max-time 30 "https://api.slipmatrix.com/api/verify?page=1&limit=20&status=VERIFIED" \
  -H "x-app-id: $APP_ID" \
  -H "x-api-key: $API_KEY"

รูปแบบผลตอบกลับ: HistoryResponse ในไฟล์ OpenAPI

POST/verify/qr

ส่งข้อความ QR

ใช้ QR ของสลิปเต็มอย่างน้อย 50 ตัวอักษร ไม่ใช่ QR รับเงิน

x-app-id + x-api-keyapplication/jsonHTTP 201
พารามิเตอร์สำหรับ POST /verify/qr
ชื่อ / ชนิดการใช้งาน
qrDatastring · จำเป็นข้อความ QR เต็มจากสลิปจริง ไม่ใช่ QR สำหรับรับเงิน
ตัวอย่าง POST /verify/qr
curl --fail-with-body --max-time 30 "https://api.slipmatrix.com/api/verify/qr" \
  -H "x-app-id: $APP_ID" \
  -H "x-api-key: $API_KEY" \
  -H 'Content-Type: application/json' \
  --data '{
  "qrData": "REPLACE_WITH_THE_FULL_QR_TEXT_FROM_YOUR_REAL_PAYMENT_SLIP"
}'

รูปแบบผลตอบกลับ: Accepted ในไฟล์ OpenAPI · ต้องติดตามผลหลังรับคำขอ

POST/verify/image

ส่งภาพ Base64

JSON body รวมไม่เกิน 10 MiB ภาพ JPEG/PNG/WEBP แนะนำ multipart เพื่อลดขนาดคำขอ

x-app-id + x-api-keyapplication/jsonHTTP 201
พารามิเตอร์สำหรับ POST /verify/image
ชื่อ / ชนิดการใช้งาน
imageBase64string · จำเป็นภาพ JPEG, PNG หรือ WEBP แบบ Base64 หรือ Data URI; JSON body ทั้งคำขอไม่เกิน 10 MiB
ตัวอย่าง POST /verify/image
curl --fail-with-body --max-time 30 "https://api.slipmatrix.com/api/verify/image" \
  -H "x-app-id: $APP_ID" \
  -H "x-api-key: $API_KEY" \
  -H 'Content-Type: application/json' \
  --data '{
  "imageBase64": "REPLACE_WITH_BASE64_OR_DATA_URI_OF_YOUR_SLIP"
}'

รูปแบบผลตอบกลับ: Accepted ในไฟล์ OpenAPI · ต้องติดตามผลหลังรับคำขอ

POST/verify/image/upload

อัปโหลดภาพสลิป

ส่งไฟล์ใน field file; JPEG/PNG/WEBP ไม่เกิน 5 MiB

x-app-id + x-api-keymultipart/form-dataHTTP 201
พารามิเตอร์สำหรับ POST /verify/image/upload
ชื่อ / ชนิดการใช้งาน
filefile · จำเป็นไฟล์ JPEG, PNG หรือ WEBP ไม่เกิน 5 MiB (5,242,880 bytes)
ตัวอย่าง POST /verify/image/upload
# ตั้ง APP_ID และ API_KEY ใน environment ของเซิร์ฟเวอร์ก่อน
curl --fail-with-body --max-time 30 \
  'https://api.slipmatrix.com/api/verify/image/upload' \
  -H "x-app-id: $APP_ID" \
  -H "x-api-key: $API_KEY" \
  -F 'file=@./slip.png'

รูปแบบผลตอบกลับ: Accepted ในไฟล์ OpenAPI · ต้องติดตามผลหลังรับคำขอ

POST/verify/batch

ส่งหลายเลขอ้างอิง

1–50 รายการ; รับได้บางส่วน; referenceId ใช้จับคู่ผล ไม่ใช่ idempotency key

x-app-id + x-api-keyapplication/jsonHTTP 201
พารามิเตอร์สำหรับ POST /verify/batch
ชื่อ / ชนิดการใช้งาน
itemsarray (1–50) · จำเป็นสลิป 1–50 รายการ
items[].transRefstring · จำเป็นเลขอ้างอิงจากสลิปจริง อย่างน้อย 10 ตัวอักษร
items[].sendingBankstring · จำเป็นรหัสธนาคารผู้โอน เก็บเป็นข้อความ 3 หลัก เช่น 014
items[].qrDatastring · ไม่บังคับข้อความ QR จากสลิป (ถ้ามี)
items[].referenceIdstring · ไม่บังคับเลขอ้างอิงของคุณ ส่งกลับในผลลัพธ์; ไม่ใช่ idempotency key
ตัวอย่าง POST /verify/batch
curl --fail-with-body --max-time 30 "https://api.slipmatrix.com/api/verify/batch" \
  -H "x-app-id: $APP_ID" \
  -H "x-api-key: $API_KEY" \
  -H 'Content-Type: application/json' \
  --data '{
  "items": [
    {
      "transRef": "EXAMPLE_TRANS_REF_001",
      "sendingBank": "014",
      "referenceId": "order-001"
    }
  ]
}'

รูปแบบผลตอบกลับ: BatchResult ในไฟล์ OpenAPI · ต้องติดตามผลหลังรับคำขอ

POST/verify/batch/images

ส่งหลายภาพ Base64

1–20 ภาพ; JSON body รวมไม่เกิน 10 MiB; ตรวจผลแต่ละรายการ

x-app-id + x-api-keyapplication/jsonHTTP 201
พารามิเตอร์สำหรับ POST /verify/batch/images
ชื่อ / ชนิดการใช้งาน
imagesarray (1–20) · จำเป็นภาพแบบ Base64 1–20 ภาพ; รวม JSON ไม่เกิน 10 MiB
images[].imageBase64string · จำเป็นภาพ JPEG, PNG หรือ WEBP แบบ Base64 หรือ Data URI; JSON body ทั้งคำขอไม่เกิน 10 MiB
images[].referenceIdstring · ไม่บังคับเลขอ้างอิงของคุณ (ไม่บังคับ)
ตัวอย่าง POST /verify/batch/images
curl --fail-with-body --max-time 30 "https://api.slipmatrix.com/api/verify/batch/images" \
  -H "x-app-id: $APP_ID" \
  -H "x-api-key: $API_KEY" \
  -H 'Content-Type: application/json' \
  --data '{
  "images": [
    {
      "imageBase64": "REPLACE_WITH_BASE64_OR_DATA_URI_OF_YOUR_SLIP",
      "referenceId": "order-001"
    }
  ]
}'

รูปแบบผลตอบกลับ: BatchResult ในไฟล์ OpenAPI · ต้องติดตามผลหลังรับคำขอ

POST/verify/batch/images/upload

อัปโหลดหลายภาพ

ส่ง field files ซ้ำ 1–20 ไฟล์ แต่ละไฟล์ไม่เกิน 5 MiB; referenceIds คั่น comma เรียงตามไฟล์

x-app-id + x-api-keymultipart/form-dataHTTP 201
พารามิเตอร์สำหรับ POST /verify/batch/images/upload
ชื่อ / ชนิดการใช้งาน
filesarray (1–20) · จำเป็นส่ง field files ซ้ำ 1–20 ไฟล์; แต่ละไฟล์ JPEG/PNG/WEBP ไม่เกิน 5 MiB
referenceIdsstring · ไม่บังคับรายการอ้างอิงคั่นด้วย comma เรียงตามไฟล์ เช่น order-001,order-002
ตัวอย่าง POST /verify/batch/images/upload
curl --fail-with-body --max-time 30 "https://api.slipmatrix.com/api/verify/batch/images/upload" \
  -H "x-app-id: $APP_ID" \
  -H "x-api-key: $API_KEY" \
  -F 'files=@./slip-001.png' \
  -F 'files=@./slip-002.png' \
  -F 'referenceIds=order-001,order-002'

รูปแบบผลตอบกลับ: BatchResult ในไฟล์ OpenAPI · ต้องติดตามผลหลังรับคำขอ

GET/verify/{transactionId}

ติดตามผลตรวจ

อ่าน body.data; HTTP 200 พร้อม data: null หากไม่พบหรือไม่มีสิทธิ์อ่านรายการ

x-app-id + x-api-keyQuery / Path parametersHTTP 200
พารามิเตอร์สำหรับ GET /verify/{transactionId}
ชื่อ / ชนิดการใช้งาน
transactionIdstring · path · จำเป็นเลขรายการจากคำขอแรก
ตัวอย่าง GET /verify/{transactionId}
curl --fail-with-body --max-time 30 "https://api.slipmatrix.com/api/verify/$TRANSACTION_ID" \
  -H "x-app-id: $APP_ID" \
  -H "x-api-key: $API_KEY"

รูปแบบผลตอบกลับ: StatusResponse ในไฟล์ OpenAPI

GET/verify/banks

ดูรหัสธนาคาร

ไม่ต้องส่ง Credentials; อ่านรายการที่ body.data.data เป็นข้อมูลรหัสธนาคาร ไม่ใช่คำรับประกันการตรวจทุกสลิป

Public · ไม่ต้องมี API KeyQuery / Path parametersHTTP 200
ตัวอย่าง GET /verify/banks
curl --fail-with-body --max-time 30 "https://api.slipmatrix.com/api/verify/banks"

รูปแบบผลตอบกลับ: BanksResponse ในไฟล์ OpenAPI

QR และ Base64 ในตัวอย่างเป็น placeholder ต้องแทนด้วยข้อมูลจริง ภาพต้องอ่าน QR ได้ชัดเจน ไม่เกิน 12 ล้านพิกเซล JSON ทั้งคำขอไม่เกิน 10 MiB; multipart แต่ละไฟล์ไม่เกิน 5 MiB

04 / RESULTS

อ่านสถานะและข้อมูลชำระเงิน

ใช้ GET /verify/{transactionId} พร้อม Credentials เดิม กำหนดระยะห่างในการ polling เช่นเริ่มที่ 3–5 วินาที เพิ่มระยะห่างเมื่อรอนาน และตั้งเวลารอสูงสุดในระบบของคุณ ผล data: null พร้อม HTTP 200 หมายถึงไม่พบรายการในบัญชีของคุณ

สถานะรายการตรวจสลิป
statusความหมาย / การจัดการ
PENDINGรับเข้าคิวแล้ว รอผลตรวจ
PROCESSINGกำลังตรวจสอบ ให้ติดตามรายการเดิม
VERIFIEDตรวจผ่าน ต้องเทียบข้อมูลกับคำสั่งซื้อก่อนยืนยันชำระเงิน
FAILEDตรวจไม่ผ่าน อ่าน errorMessage และตรวจสอบรายการ
DUPLICATEสลิปซ้ำ ห้ามใช้ยืนยันคำสั่งซื้ออีกครั้ง
INVALIDข้อมูลสลิปไม่ถูกต้อง
INSUFFICIENT_CREDITเครดิตไม่เพียงพอ
ตัวอย่างผลตรวจ · HTTP 200
{
  "success": true,
  "data": {
    "transactionId": "0199d720-0000-7000-8000-000000000001",
    "transRef": "EXAMPLE_TRANS_REF_001",
    "status": "VERIFIED",
    "statusText": "Passed",
    "amount": "100.00",
    "paidLocalCurrency": "764",
    "currencyName": "THB",
    "receiverAccount": "xxx-x-x0000-x",
    "sendingBank": "004",
    "receivingBank": "014",
    "transferDate": "2026-10-10T11:59:00+07:00"
  },
  "timestamp": "2026-10-10T12:00:03+07:00"
}
ข้อมูลสำคัญในผลตรวจ
ฟิลด์รายละเอียด
amountยอดเงินทศนิยมแบบ string เช่น 100.00 ใช้ decimal หรือหน่วยย่อยในการเทียบยอด
paidLocalCurrency / currencyNameเช่น 764 / THB ตรวจให้ตรงกับสกุลเงินของคำสั่งซื้อ
receiverAccount / receiverProxyข้อมูลผู้รับ อาจถูกปิดบังหรือมีรูปแบบต่างกัน หากพิสูจน์ผู้รับไม่ได้ ให้ตรวจสอบเพิ่มเติมก่อนอนุมัติ
sender* / receivingBank / sendingBankข้อมูลผู้โอนและธนาคาร อาจไม่ส่งกลับเมื่อไม่มีข้อมูลจากธนาคาร
transferDateเวลาโอน ISO 8601 พร้อม timezone แยกจาก timestamp ของคำตอบและเวลาสร้างรายการ
ref1 / ref2 / ref3 / errorMessageข้อมูลอ้างอิงหรือรายละเอียดข้อผิดพลาด ถ้ามี

ประวัติ GET /verify ใช้ data.data เป็นรายการ, data.total เป็นจำนวนรวม แต่ละแถวใช้ id และ verifiedAmount ส่วนตัวกรอง startDate/endDate กรองวันที่สร้างรายการ ไม่ใช่เวลาโอน

05 / BATCH

ตรวจผลรับคำขอทีละรายการ

เลขอ้างอิงส่งได้ 1–50 รายการ ภาพส่งได้ 1–20 ภาพ ระบบอาจรับเพียงบางรายการ จึงต้องอ่าน data.results ทุกแถว ใช้ index หรือ referenceId จับคู่กับคำขอเดิม และติดตาม transactionId ของแต่ละรายการที่รับเข้าคิว

ตัวอย่าง batch ที่รับได้บางส่วน
{
  "success": true,
  "data": {
    "results": [
      {
        "index": 0,
        "referenceId": "order-001",
        "transactionId": "0199d720-0000-7000-8000-000000000001",
        "status": "PENDING",
        "message": "Submitted"
      },
      {
        "index": 1,
        "referenceId": "order-002",
        "status": "DUPLICATE",
        "message": "Slip already exists"
      }
    ],
    "submitted": 1,
    "errors": 1
  },
  "timestamp": "2026-10-10T12:00:00+07:00"
}

สถานะผล batch: PENDING, DUPLICATE, INSUFFICIENT_CREDIT, INVALID_QR หรือ ERROR เป็นผลรับคำขอ ไม่ใช่ผลตรวจสุดท้าย หาก ERROR มี transactionId ให้ตรวจรายการเดิมก่อนลองใหม่

ระบบสำรอง 1 เครดิตต่อรายการที่รับเข้าคิว ตรวจผ่านจึงหักเครดิต และคืนเครดิตที่สำรองเมื่อไม่ผ่าน referenceId เป็นค่าอ้างอิงที่ส่งกลับ ไม่ได้ป้องกันคำขอซ้ำ

06 / ERRORS & LIMITS

จัดการข้อผิดพลาดโดยไม่สร้างรายการซ้ำ

ตัวอย่างข้อผิดพลาด
{
  "success": false,
  "statusCode": 400,
  "code": "DUPLICATE_SLIP",
  "message": "This slip has already been verified",
  "timestamp": "2026-10-10T12:00:00+07:00"
}

message อาจเป็นข้อความ, array หรือ object และบางข้อผิดพลาดไม่มี code ให้ตรวจ HTTP status ร่วมด้วย หาก proxy หรือ firewall ตอบกลับเป็น HTML ให้ตรวจ Content-Type ก่อนอ่าน JSON

ข้อผิดพลาดที่ควรจัดการ
HTTP / codeแนวทาง
400DUPLICATE_SLIPตรวจประวัติและคำสั่งซื้อเดิม ไม่ส่งสลิปซ้ำเพื่อยืนยันอีกรายการ
400VERIFICATION_RETRY_REQUIRES_REVIEWติดตาม transactionId ที่ส่งกลับ และตรวจสอบก่อนลองใหม่
400NO_QR_FOUND / INVALID_QRใช้รูปที่อ่าน QR ได้ชัดเจน หรือส่ง QR / เลขอ้างอิงที่ถูกต้อง
400INSUFFICIENT_CREDITตรวจเครดิตใน Merchant Portal ก่อนส่งใหม่
400Validation errorตรวจชนิดข้อมูลและฟิลด์จำเป็น ไม่ส่งฟิลด์ที่ไม่ได้ระบุในสัญญา API
401Credentials errorตรวจ App ID และ API Key ที่ใช้งานอยู่ (อาจไม่มี code)
413Request too largeลดขนาด JSON / รูป หรือแบ่ง batch
429RATE_LIMIT_EXCEEDED / Throttledรอตาม Retry-After ถ้ามี แล้วลดความถี่ด้วย backoff
503VERIFICATION_QUEUE_UNAVAILABLEถ้ามี transactionId ให้ติดตามรายการเดิมก่อนส่งใหม่

Rate limits

การส่งตรวจมีค่าเริ่มต้น 10 คำขอต่อนาที และ 100 คำขอต่อชั่วโมงต่อร้านค้า รวม API Keys ของร้านค้านั้น ตรวจ X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset (epoch วินาที) และ Retry-After (วินาที) เมื่อส่งกลับ ระบบยังมีขีดจำกัดรวม จึงอาจได้รับ 429 จากการ polling หรือเรียกถี่เกินไปด้วย

เมื่อคำขอ timeout ผลอาจรับเข้าคิวแล้ว

ถ้ามี transactionId ให้ติดตามรายการเดิม หากยังไม่ได้เลขรายการให้ค้นประวัติหรือ Merchant Portal ด้วย transRef ก่อนลองใหม่ ระบบป้องกัน transRef ซ้ำ และยังไม่มีสัญญา Idempotency-Key สำหรับการส่งตรวจ

07 / SIGNED WEBHOOK

รับผลตรวจโดยไม่ต้อง polling ตลอดเวลา

ตั้ง Callback URL ในเมนูตั้งค่าของ Merchant Portal และใช้ Webhook Secret ที่ได้รับเมื่อสมัคร (แสดงในหน้าสมัครสำเร็จและอีเมลต้อนรับ) หากไม่มีค่าดังกล่าวให้ติดต่อทีมงาน ใช้ HTTPS ที่เข้าถึงได้จากอินเทอร์เน็ต ปลายทาง localhost, private network และ URL ที่ฝัง username/password ใช้งานไม่ได้ ระบบไม่ติดตาม redirect

Headers ของ callback
Headerรูปแบบ
X-Gateway-SignatureHMAC-SHA256 ของ raw body ด้วย Webhook Secret เป็น hex 64 ตัว ไม่มี sha256= นำหน้า
X-Gateway-Eventslip.verified, slip.failed หรือ slip.duplicate ใช้ event ใน body ที่ตรวจลายเซ็นแล้วเป็นหลัก
X-Gateway-Timestampepoch มิลลิวินาทีของแต่ละความพยายามส่ง ไม่ได้รวมในลายเซ็น จึงใช้เป็นหลักฐานป้องกัน replay ไม่ได้
ตัวอย่าง Webhook body · ไม่มี success/data ครอบ
{
  "event": "slip.verified",
  "transactionId": "0199d720-0000-7000-8000-000000000001",
  "transRef": "EXAMPLE_TRANS_REF_001",
  "status": "VERIFIED",
  "statusText": "Passed",
  "amount": "100.00",
  "currencyName": "THB",
  "paidLocalCurrency": "764",
  "receiverAccount": "xxx-x-x0000-x",
  "transferDate": "2026-10-10T11:59:00+07:00",
  "verifiedAt": "2026-10-10T12:00:03+07:00"
}

ตรวจ HMAC จาก bytes ของ body ก่อน JSON parsing ห้าม stringify JSON ที่ parse แล้วมาคำนวณใหม่ เพราะ whitespace และลำดับ field อาจเปลี่ยน หากใช้ middleware ให้เก็บ raw body ก่อน JSON parser

ตรวจลายเซ็น · Node.js 22+
// © 2026 ByteMatrix Co., Ltd. — Node.js 22+, no external dependencies.
import { createHmac, timingSafeEqual } from 'node:crypto';

// rawBody must be the exact UTF-8 bytes received, before JSON parsing.
// signature is X-Gateway-Signature (64 hex characters, no "sha256=" prefix).
export function verifyWebhook(rawBody, signature, secret) {
  if (!Buffer.isBuffer(rawBody) || typeof secret !== 'string' || !secret) return false;
  if (typeof signature !== 'string' || !/^[a-f0-9]{64}$/i.test(signature)) return false;
  const expected = createHmac('sha256', secret).update(rawBody).digest();
  const supplied = Buffer.from(signature, 'hex');
  return supplied.length === expected.length && timingSafeEqual(expected, supplied);
}

// After verification:
// 1. Parse and validate the signed JSON body (use its event, not the event header).
// 2. Persist to a durable inbox / database with duplicate detection.
// 3. Respond 2xx only after persistence succeeds; otherwise respond 5xx for retry.
// 4. Process orders idempotently; reconcile amount, currency, receiver and transferDate.
// X-Gateway-Timestamp is not covered by the signature. It is not replay protection.

อ้างอิง Node.js crypto: timingSafeEqual ↗

  1. ตรวจลายเซ็น แล้วตรวจ event/status ใน body
  2. บันทึกลงฐานข้อมูลหรือ durable inbox พร้อมป้องกันรายการซ้ำ เช่น unique transactionId + event
  3. ตอบ 2xx หลังบันทึกสำเร็จ หากยังบันทึกไม่ได้ให้ตอบ 5xx เพื่อให้ลองส่งใหม่
  4. ประมวลผลคำสั่งซื้อแบบ idempotent และเทียบยอด ผู้รับ สกุลเงิน เวลาโอนก่อนให้สิทธิ์

ปลายทางต้องตอบภายใน 10 วินาที ระบบพยายามส่งรวมสูงสุด 5 ครั้งด้วย exponential backoff Webhook อาจมาซ้ำหรือมาหลังจาก polling ได้ผลแล้ว จึงต้องป้องกันการอนุมัติคำสั่งซื้อซ้ำ อย่าคาดว่าทุก HTTP 400 จะมี callback ให้

verifiedAt คือเวลาที่เตรียมผลส่ง Webhook ไม่ใช่เวลาโอน ใช้ transferDate สำหรับเทียบเวลาชำระเงิน

08 / CODE EXAMPLES

เริ่มจากภาษาที่คุณใช้

ตัวอย่างอัปโหลดรูปสำหรับฝั่งเซิร์ฟเวอร์ ตั้ง APP_ID และ API_KEY ใน environment ก่อนรัน เมื่อได้รับ transactionId ให้เก็บไว้และติดตามผลตามขั้นตอนด้านบน

เลือกภาษา
อัปโหลดสลิป · cURL
# ตั้ง APP_ID และ API_KEY ใน environment ของเซิร์ฟเวอร์ก่อน
curl --fail-with-body --max-time 30 \
  'https://api.slipmatrix.com/api/verify/image/upload' \
  -H "x-app-id: $APP_ID" \
  -H "x-api-key: $API_KEY" \
  -F 'file=@./slip.png'

สัญญาไฟล์ดาวน์โหลดใช้ OpenAPI 3.0.3 ระบุเฉพาะ Merchant API และ schema ของ Webhook

อ่านวิธีตรวจสลิปและเทียบผลตรวจกับออเดอร์ →

09 / GO LIVE

ตรวจให้ครบก่อนยืนยันชำระเงินอัตโนมัติ

  • ทดสอบผลผ่าน, ยอดไม่ตรง, ผู้รับไม่ตรง และข้อมูลผู้รับที่ถูกปิดบัง
  • ทดสอบสลิปซ้ำ, QR อ่านไม่ได้, เครดิตไม่พอ และ batch ที่รับได้บางส่วน
  • ทดสอบ timeout / 429 และค้นประวัติก่อนส่งซ้ำ
  • ทดสอบลายเซ็นไม่ถูกต้อง, Webhook ส่งซ้ำ และกรณีฐานข้อมูลปลายทางไม่พร้อม
  • เก็บ Credentials ฝั่งเซิร์ฟเวอร์ และป้องกันข้อมูลสลิปหรือกุญแจหลุดผ่าน log

ต้องการความช่วยเหลือในการเชื่อมต่อ?

ส่ง endpoint, HTTP status และ transactionId ที่เกี่ยวข้อง โดยไม่ส่ง API Key หรือ Webhook Secret

ติดต่อทีมงาน ↗