Sirasupa Payment Relay API
SMS-to-Webhook + PromptPay QR — Shortcuts ส่ง SMS เข้า Sirasupa จับคู่กฎแล้ว POST ไป webhook ปลายทางพร้อม HMAC-SHA256
01ภาพรวมระบบ
สายงาน: SMS เข้า iPhone → Shortcuts ยิง POST /api/sms/relay (x-api-key) → Sirasupa
จับคู่กฎ → POST Webhook URL พร้อม x-sirasupa-signature → ปลายทางตรวจด้วย
Secret key
- SMS จากธนาคารเข้าเครื่อง
- Shortcuts ส่งเข้า relay
- Sirasupa จับคู่และ forward webhook
- ปลายทางยืนยัน HMAC แล้วประมวลผล
023 ความลับที่ต้องเข้าใจ
srs_… กับ Secret key หรือวาง Bearer ผิดที่
x-api-key — เข้า Sirasupa
คีย์ srs_… จาก /portal/ — ใช้ใน header ตอน
POST /api/sms/relay เท่านั้น · หมุนคีย์ได้ในพอร์ทัล
Secret key — ลายเซ็น Webhook
Sirasupa แนบ x-sirasupa-signature: sha256=… (HMAC ของ body) · คัดลอก Secret จากพอร์ทัล
ไปวางที่ปลายทาง (แดชบอร์ด / ตั้งค่ารับชำระของเว็บคุณ) — ไม่ใส่ใน Shortcut
x-api-key — ใส่ srs_… แทน Secret = ลายเซ็นไม่ผ่าน
Authorization: Bearer … (ถ้าปลายทางบังคับ)
Sirasupa ไม่ออก Bearer ให้ — ถ้าจำเป็น เอาโทเค็นจากแดชบอร์ดปลายทาง ใส่ใน «หัว HTTP เพิ่มเติม» ของกฎเป็น JSON
{
"Authorization": "Bearer …"
}
ถ้าไม่มีข้อกำหนด Bearer จากปลายทาง — ส่วนใหญ่เว้นว่างหรือ {}
03เริ่มใช้งานใน 5 นาที
- /portal/ — สร้าง API Key (
srs_…) และแสดง Secret key - วางทั้งคู่ที่เว็บรับชำระของคุณ (ช่องตั้งค่าที่เอกสารของระบบนั้นระบุ)
- สร้างกฎ: Webhook URL ตามที่ปลายทางให้มา เช่น
https://your-domain.example/api/sirasupa/webhook - ตั้ง Shortcuts ตาม หัวข้อ 9 — ยิง
POST /api/sms/relay+x-api-key - ทดสอบโอน → เช็กบันทึกในพอร์ทัล
04POST/api/sms/relay
ส่งข้อความ SMS เข้าระบบเพื่อจับคู่กฎและส่งต่อ webhook
Request Headers
| Header | ค่า |
|---|---|
Content-Type |
application/json |
x-api-key |
API Key ของลูกค้า (srs_…) จากพอร์ทัล |
Request Body
{
"message": "บช X-1234 เงินเข้า 100.00 บาท คงเหลือ 1,234.56 บาท"
}
รองรับคีย์ text แทน message ได้ หากสะดวกในคำสั่งลัด
cURL
curl -sS -X POST "https://payment.sirasupa.com/api/sms/relay" \
-H "Content-Type: application/json" \
-H "x-api-key: srs_YOUR_KEY" \
-d '{"message":"บช X-1234 เงินเข้า 100.00 บาท"}'
ตัวเลขใน SMS และ JSON
หัวข้อนี้เกี่ยวกับการอ่านเลขจากข้อความ SMSและ body JSON — ไม่ใช่หลักการคำนวณยอดบน QR พร้อมเพย์ (ดูหัวข้อ PromptPay QR)
-
JSON / API — ใช้จุด (
.) เป็นทศนิยมแบบมาตรฐาน JSON เช่น123.45ไม่ใส่ comma คั่นหลักพันใน JSON -
ข้อความใน
message— ตัว parse ลบ,ออกจากทั้งข้อความก่อน จึงรองรับยอดแบบ1,234.56 บาท(comma = หลักพัน + จุด = ทศนิยม) -
ยอดที่ดึงได้ (
parsed_amount_baht) — มักเป็น ทศนิยม 2 ตำแหน่ง หรือnullถ้าอ่านไม่ได้ -
ข้อควรระวัง — รูปแบบทศนิยมด้วยจุลภาค เช่น
100,50 บาทไม่รองรับ (comma ถูกลบแล้วค่าผิด)
05รูปแบบการตอบกลับ
{
"ok": true,
"id": "ad8c1e3b-…", // log id (ตรงกับ x-sirasupa-delivery)
"parsed_amount_baht": 100, // null = parse ยอดไม่ได้
"matched_count": 1, // กฎที่ match ทั้งหมด
"forwarded_count": 1, // กฎที่ส่งต่อจริง (พ้นยอดขั้นต่ำ ฯลฯ)
"results": [
{
"translationId": "rule_doc_id",
"status": 200, // HTTP จากปลายทาง
"webhook": "https://your-domain.example/api/sirasupa/webhook"
}
]
}
matched_count = 0 แปลว่า SMS ไม่ตรงกฎใด · ถ้า forwarded_count = 0
แต่ matched_count > 0 แปลว่ายอดต่ำกว่าขั้นต่ำหรือ parse ไม่ได้
06Webhook callback
เมื่อจับคู่กฎสำเร็จ Sirasupa จะ POST ไปยัง Webhook URL ที่คุณตั้งในกฎ
Headers ที่ Sirasupa ส่ง
| Header | ค่า |
|---|---|
Content-Type |
application/json |
x-sirasupa-signature |
sha256=<hex> — HMAC-SHA256 ของ body กับ webhookSignSecret |
x-sirasupa-delivery |
ตรงกับ id ใน response ของ relay — ใช้กัน replay/dedupe |
Body ที่ Sirasupa ส่ง
{
"event": "sms.bank_inbound",
"raw_message": "บช X-1234 เงินเข้า 100.00 บาท …",
"parsed_amount_baht": 100,
"translation": { "id": "rule_doc_id", "name": "ชื่อกฎ" },
"received_at": "2026-05-04T12:00:00.000Z",
"relay": { "auth": "api_key", "profile_id": "firebase_uid" }
}
ระบบปลายทางควรตอบ HTTP 2xx เมื่อประมวลผลเสร็จ — Sirasupa ไม่ retry อัตโนมัติ
07วิธีตรวจ HMAC ฝั่งคุณ
ใช้ raw body bytes ที่รับมาเทียบ HMAC-SHA256 กับ Secret — ตัด prefix sha256=
ใน header แบบ timing-safe · ห้าม stringify JSON ใหม่ก่อนคำนวณ
Node.js (Express + raw body)
import express from "express";
import crypto from "crypto";
const app = express();
const SECRET = process.env.SIRASUPA_WEBHOOK_SECRET; // คัดลอกจาก /portal/
app.post(
"/api/sirasupa/webhook",
express.raw({ type: "application/json", limit: "256kb" }),
(req, res) => {
const raw = req.body; // Buffer
const headerSig = String(req.header("x-sirasupa-signature") || "");
const m = /^sha256=([a-f0-9]+)$/i.exec(headerSig.trim());
if (!m) return res.status(400).json({ error: "missing_signature" });
const expected = crypto.createHmac("sha256", SECRET).update(raw).digest("hex");
const a = Buffer.from(m[1].toLowerCase(), "hex");
const b = Buffer.from(expected, "hex");
if (a.length !== b.length || !crypto.timingSafeEqual(a, b)) {
return res.status(400).json({ error: "invalid_signature" });
}
const payload = JSON.parse(raw.toString("utf8"));
// … processing payload …
return res.status(200).json({ ok: true });
}
);
Python (FastAPI / Flask)
import hmac, hashlib, os
SECRET = os.environ["SIRASUPA_WEBHOOK_SECRET"].encode()
def verify(raw_body: bytes, header_value: str) -> bool:
if not header_value or not header_value.lower().startswith("sha256="):
return False
received = bytes.fromhex(header_value.split("=", 1)[1])
expected = hmac.new(SECRET, raw_body, hashlib.sha256).digest()
return hmac.compare_digest(received, expected)
express.raw() ตามตัวอย่าง
08PromptPay QR
สร้าง QR ใน Portal/Admin — ระบบคำนวณยอดโอนจริงบน QR เพื่อลดโอกาสจับคู่ SMS ชนกันเมื่อหลายคนสร้าง QR ยอดฐานเดียวกันในช่วง timeout 5 / 10 นาที → SMS เข้า relay → จับคู่ตามยอด + เวลา → webhook
ยอดเต็ม (100.00) เมื่อไหร่
ใช้โหมด whole เมื่อก่อนสร้างรายการใหม่:
-
ไม่มีรายการ
pendingอื่นที่ใช้ เลขพร้อมเพย์เดียวกันและยอดฐาน (baseBaht) เดียวกัน -
ใน session (
sessionSlug) เดียวกัน มี QR ค้างไม่เกิน 2 รายการ
ผลคือ QR ขอให้โอน จำนวนเต็มบาท เช่น base 100 → 100.00 บาท
เศษสตางค์ (กันชน) — ไม่เกินยอดฐาน
ถ้ามีอย่างน้อยหนึ่งข้อ: มี pending เดิมที่เลขพร้อมเพย์ + ยอดฐานซ้ำ (เช่น คนที่สองสร้าง 100 บาทขณะคนแรกยังค้าง)
หรือ ใน session มี pending มากกว่า 2 แล้ว — ระบบจะเพิ่มเศษเฉพาะแบบหักจากยอดจำนวนเต็ม
สุ่ม 0.01–0.20 บาท — เช่น base 100 → โอนได้เฉพาะช่วง 99.80 … 99.99 (20 ช่อง) จะไม่ใช้ยอดเกิน 100
API ตอบ HTTP 409 คีย์ ppay_queue_full เมื่อมี pending ยอดฐานเดียวกันครบ
20 รายการแล้ว หรือช่องเศษถูกใช้หมด — ต้องรอให้มีรายการสำเร็จหรือหมดเวลา แล้วสร้าง QR ใหม่
-
decimalMode: whole— โอนตรงยอดจำนวนเต็ม เช่น 100.00 -
decimalMode: under_minus_01_20— โอนใต้ยอดเต็ม 99.80 … 99.99 (กรณี base 100)
ยอดสุดท้ายอยู่ใน exactAmountBaht และถูกเก็บใน Firestore (ppay_test_transactions) เมื่อ SMS มียอดตรงทุกสตางค์
ระบบจับคู่กับรายการค้างภายในหน้าต่างเวลาที่ตั้งใน Cloud Functions
ขอบเขต
-
สูงสุด 20 รายการ
pendingต่อชุดเลขพร้อมเพย์ + ยอดฐานเดียวกัน — เกินจะได้ 409ppay_queue_full - สูงสุด 20 รายการ
pendingต่อ session — เกินจะได้ข้อผิดพลาดtoo_many_session_pending - Timeout ต่อ QR: 5 หรือ 10 นาที (เลือกตอนสร้าง)
09ตั้งค่า iOS Shortcuts
สร้างคำสั่งลัดที่มี Action «รับเนื้อหาของ URL» (POST + x-api-key) ก่อน
จากนั้นค่อยตั้ง Automation ให้รันลัดนั้นเมื่อมี SMS ตรงคีย์เวิร์ด
กดปุ่ม + เพิ่มคำสั่งลัดใหม่ → ค้นหา รับเนื้อหาของ URL → ตั้ง
https://payment.sirasupa.com/api/sms/relay · POST ·
Content-Type + x-api-key · body message
ทริกเกอร์ข้อความ + «สั่งทำงานทันที» → รันคำสั่งลัดข้างบน
ตัวอย่างที่ถูกต้อง — คัดลอกได้
// ใน Shortcut → "รับเนื้อหาของ URL"
URL: https://payment.sirasupa.com/api/sms/relay
Method: POST
Headers:
Content-Type: application/json
x-api-key: srs_XXXXXXXXXXXXXXXXXXXXXXXX
Request Body (JSON):
{
"message": "[ข้อความ SMS จาก Get Contents of input ของ Shortcut]",
"received_at": "[ISO timestamp ถ้ามี]"
}
10แอป Android (APK)
แอป SRSP SMS Gateway ทำหน้าที่เดียวกับ iOS Shortcut — ฟัง SMS เข้า แล้ว
POST ไปยัง /api/sms/relay พร้อม x-api-key ใช้
API Key เดียวกัน และกฎเดียวกันที่ตั้งใน /portal/
SRSP SMS Gateway v2.0.3 — Android 8.0+
srs_… → ทดสอบ relay ด้วยปุ่ม
«ทดสอบส่ง» (ไม่รับ SMS จริงบนหูฟัง VR) · มือถือที่มีซิมยังใช้ Google Sign-In + รับ SMS ตามเดิม
RECEIVE_SMS / READ_SMS
อย่างเข้มงวด แอป relay ส่วนตัวมักไม่ผ่านการรีวิว ฉะนั้นเราเผยแพร่เป็น
APK ติดตั้งตรง ที่เซ็นแล้วสำหรับใช้ภายในเท่านั้น
ภาพตัวอย่างหน้าจอ
เปิดแอปครั้งแรกจะเห็นโล่ payment.sirasupa.com เต้นเบา ๆ แตะโลโก้ เพื่อไปหน้า เข้าสู่ระบบด้วย Google (บัญชีเดียวกับเว็บพอร์ทัล)
หลังล็อกอิน Google แอปจะ ออก API key ให้อัตโนมัติ (หรือ «วางคีย์
srs_… ที่มีอยู่» ก็ได้) → ใส่คำที่ต้องมีใน SMS เช่น บช X-1234
→ เปิดสวิตช์ → กด บันทึก → ทดสอบด้วย ทดสอบส่ง
ขั้นตอนติดตั้ง (5 นาที)
-
บนมือถือ Android เปิด URL
https://payment.sirasupa.com/downloads/sirasupa-sms-relay.apkเพื่อโหลด APK โดยตรง (หรือกดปุ่ม «ดาวน์โหลด APK» ด้านบนจากเครื่องที่จะติดตั้ง) - เปิดไฟล์ APK → อนุญาต «ติดตั้งแอปจากแหล่งที่ไม่รู้จัก» สำหรับแอปที่ใช้เปิดไฟล์ (เช่น Chrome / ตัวจัดการไฟล์)
- เปิดแอป SRSP SMS Gateway → แตะโลโก้บนหน้า splash → กด «เข้าสู่ระบบด้วย Google» ใช้บัญชีเดียวกับเว็บ
- เข้าครั้งแรก: ระบบจะออก API Key ให้อัตโนมัติ · มีคีย์อยู่แล้ว: กด «วางคีย์ srs_… ที่มีอยู่» และวางคีย์เดิม · ต้องการคีย์ใหม่: กด «หมุน API key ใหม่» (ยืนยัน warning จะทำลายคีย์เดิม)
- ในการ์ด «สถานะ» — กด «ขอสิทธิ์ SMS / การแจ้งเตือน» และอนุญาตทุกข้อ
-
(เลือก) ใส่ คำที่ต้องมีใน SMS เช่น
บช X-1234เพื่อกรองฝั่งเครื่อง (กฎจริงตั้งในพอร์ทัลเว็บ) บรรทัดละ 1 คำ — เว้นว่างจะส่งทุกข้อความเข้า relay - เปิดสวิตช์ «เปิด relay เมื่อมี SMS เข้า» → กด «บันทึก» → กด «ทดสอบส่ง» เพื่อดูว่ากฎใน Sirasupa Portal จับคู่ได้
Meta Quest / Horizon OS (โหมด companion)
Quest ไม่มี SMS และไม่มี Google Play Services — ใช้แอปเป็นเครื่องมือ ทดสอบ relay และจัดการคีย์เท่านั้น (SMS จริงยังต้องใช้มือถือที่มีซิม)
- Sideload APK บน Quest (หรือ
hzdb app install …จากเครื่อง dev) - หน้า login → «ใช้ API key จากพอร์ทัล»
- วาง
srs_…จาก /portal/ - กด «ทดสอบส่ง» แล้วดู log ในแอปและใน Portal
srs_… ฝังในโค้ดและห้าม sideload ลงเครื่องลูกค้าโดยไม่ได้รับ
ความยินยอมเป็นลายลักษณ์อักษร
11ตัวอย่างเว็บรับ webhook
สมมติเว็บรับชำระของคุณมีหน้าตั้งค่าให้ใส่ API Key / Secret สำหรับลายเซ็น webhook และกำหนด Webhook URL ที่ Sirasupa จะยิงเข้ามา — ขั้นตอนโดยรวมอาจเป็นแบบนี้ (แทนที่ URL ด้วยของจริงตามเอกสารของระบบคุณ):
-
เข้าแดชบอร์ด / หน้าตั้งค่ารับชำระของเว็บคุณ (ตัวอย่าง URL:
https://your-domain.example/admin/payments) -
ในช่องที่ให้ใส่คีย์จากผู้ให้บริการ relay → วาง
srs_…จาก Sirasupa Portal -
เปิดส่วนขยายถ้ามี → ในช่อง «Secret key / Webhook signing secret» (หรือชื่อเทียบเท่า)
วางค่าจากพาเนล «Secret key» ใน Portal — ไม่ใช่ค่า
srs_… -
กดบันทึก → ใน Sirasupa Portal สร้างกฎ โดย Webhook URL =
https://your-domain.example/api/sirasupa/webhook· หัวเพิ่มเติม{}ถ้าไม่ต้องการส่ง Bearer เพิ่ม
srs_… ในช่อง Secret โดยเข้าใจผิด · ต้องใช้ Secret key (signing) จากพอร์ทัล
12แก้ปัญหา (HTTP 400 / 401)
| อาการ | สาเหตุที่พบบ่อย | วิธีแก้ |
|---|---|---|
relay ตอบ 401 unauthorized |
x-api-key ไม่ถูกต้อง / หมดอายุเพราะหมุนใหม่ / ใช้ x-relay-secret ที่ไม่ใช่ค่าภายใน |
หมุนคีย์ใหม่ในพอร์ทัล แล้วอัปเดต Shortcuts ทุกเครื่อง |
results[].status: 400 เมื่อยิง relay
|
ปลายทางตรวจ HMAC ไม่ผ่าน — มักเพราะวาง srs_… แทน webhookSignSecret |
คัดลอก webhookSignSecret จาก /portal/ ไปวางใหม่ที่ปลายทาง |
| ปลายทางตรวจ HMAC ผ่าน แต่ body parse ไม่ได้ | middleware แปลง JSON ก่อนคำนวณ HMAC ทำให้ raw bytes เปลี่ยน | ใช้ express.raw() หรือ Buffer ตามตัวอย่างในหัวข้อ 7 |
matched_count: 0 แม้ส่ง SMS ที่คาดว่าจะ match |
ข้อความใน «ข้อความต้องมี» ไม่ตรงกับ SMS จริง (เช่นช่องว่าง / ขีด) | ใช้ปุ่ม «คัดลอกข้อความจับคู่» หลังเลือกเลขบัญชีอัตโนมัติ |
| กสิกรไทย SMS ไม่เข้าช่วง 23:00–02:00 | ผู้ให้บริการกำลังปรับปรุงระบบ (ตามคำเตือนใน UI) | รอช่วงเวลาปกติ หรือใช้บัญชีธนาคารสำรอง |