Sirasupa Sirasupa Payment · API Docs
HMAC-SHA256 verified asia-southeast1 v2026.05

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

  1. SMS จากธนาคารเข้าเครื่อง
  2. Shortcuts ส่งเข้า relay
  3. Sirasupa จับคู่และ forward webhook
  4. ปลายทางยืนยัน HMAC แล้วประมวลผล

023 ความลับที่ต้องเข้าใจ

400 / 401 ส่วนใหญ่ — สลับ srs_… กับ Secret key หรือวาง Bearer ผิดที่
A

x-api-key — เข้า Sirasupa

คีย์ srs_… จาก /portal/ — ใช้ใน header ตอน POST /api/sms/relay เท่านั้น · หมุนคีย์ได้ในพอร์ทัล

B

Secret key — ลายเซ็น Webhook

Sirasupa แนบ x-sirasupa-signature: sha256=… (HMAC ของ body) · คัดลอก Secret จากพอร์ทัล ไปวางที่ปลายทาง (แดชบอร์ด / ตั้งค่ารับชำระของเว็บคุณ) — ไม่ใส่ใน Shortcut

คนละค่ากับ x-api-key — ใส่ srs_… แทน Secret = ลายเซ็นไม่ผ่าน
C

Authorization: Bearer … (ถ้าปลายทางบังคับ)

Sirasupa ไม่ออก Bearer ให้ — ถ้าจำเป็น เอาโทเค็นจากแดชบอร์ดปลายทาง ใส่ใน «หัว HTTP เพิ่มเติม» ของกฎเป็น JSON

{
  "Authorization": "Bearer …"
}

ถ้าไม่มีข้อกำหนด Bearer จากปลายทาง — ส่วนใหญ่เว้นว่างหรือ {}

03เริ่มใช้งานใน 5 นาที

  1. /portal/ — สร้าง API Key (srs_…) และแสดง Secret key
  2. วางทั้งคู่ที่เว็บรับชำระของคุณ (ช่องตั้งค่าที่เอกสารของระบบนั้นระบุ)
  3. สร้างกฎ: Webhook URL ตามที่ปลายทางให้มา เช่น https://your-domain.example/api/sirasupa/webhook
  4. ตั้ง Shortcuts ตาม หัวข้อ 9 — ยิง POST /api/sms/relay + x-api-key
  5. ทดสอบโอน → เช็กบันทึกในพอร์ทัล

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)
ข้อผิดพลาดยอดฮิต: middleware กิน raw body ก่อนคำนวณ HMAC — ใช้ express.raw() ตามตัวอย่าง

08PromptPay QR

สร้าง QR ใน Portal/Admin — ระบบคำนวณยอดโอนจริงบน QR เพื่อลดโอกาสจับคู่ SMS ชนกันเมื่อหลายคนสร้าง QR ยอดฐานเดียวกันในช่วง timeout 5 / 10 นาที → SMS เข้า relay → จับคู่ตามยอด + เวลา → webhook

ระบบที่รับเงินของคุณสร้าง EMV QR เองแล้วรับ webhook ตามกฎเดิมได้ — หัวข้อนี้อธิบายพฤติกรรมฝั่ง Sirasupaเมื่อใช้ฟอร์มสร้าง QR ของเรา

ยอดเต็ม (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 ต่อชุดเลขพร้อมเพย์ + ยอดฐานเดียวกัน — เกินจะได้ 409 ppay_queue_full
  • สูงสุด 20 รายการ pending ต่อ session — เกินจะได้ข้อผิดพลาด too_many_session_pending
  • Timeout ต่อ QR: 5 หรือ 10 นาที (เลือกตอนสร้าง)

09ตั้งค่า iOS Shortcuts

สร้างคำสั่งลัดที่มี Action «รับเนื้อหาของ URL» (POST + x-api-key) ก่อน จากนั้นค่อยตั้ง Automation ให้รันลัดนั้นเมื่อมี SMS ตรงคีย์เวิร์ด

หน้าจอ Shortcut Sirasupa Payment: รับเนื้อหาของ URL — POST payment.sirasupa.com/api/sms/relay, Content-Type, x-api-key, body JSON message
1) คำสั่งลัด — รับเนื้อหาของ URL

กดปุ่ม + เพิ่มคำสั่งลัดใหม่ → ค้นหา รับเนื้อหาของ URL → ตั้ง https://payment.sirasupa.com/api/sms/relay · POST · Content-Type + x-api-key · body message

หน้าจอ Automation: เมื่อได้รับข้อความที่มี ‘บช X-1234’ → สั่งทำงานทันที → รัน Sirasupa Payment
2) Automation

ทริกเกอร์ข้อความ + «สั่งทำงานทันที» → รันคำสั่งลัดข้างบน

ตัวอย่างที่ถูกต้อง — คัดลอกได้

// ใน 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 ถ้ามี]"
  }
Preflight — ใน /portal/ ตรวจคีย์ กฎ และตัวอย่าง Shortcut

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+

4.05 MB · signed release · SHA-256 325d1fde…a7ef2a
ดาวน์โหลด APK
อัปเดตจาก v2.0.2 — ถ้าติดตั้งทับไม่ได้ ให้ถอนแอปเวอร์ชันเก่าก่อน แล้วติดตั้ง APK ใหม่ (ลายเซ็น release เปลี่ยนในรอบ build นี้)
ใหม่ใน v2.0.3 — โหมด companion สำหรับ Meta Quest / Horizon OS และอุปกรณ์ที่ไม่มี SMS: กด «ใช้ API key จากพอร์ทัล» → วาง srs_… → ทดสอบ relay ด้วยปุ่ม «ทดสอบส่ง» (ไม่รับ SMS จริงบนหูฟัง VR) · มือถือที่มีซิมยังใช้ Google Sign-In + รับ SMS ตามเดิม
ใหม่ใน v2.0 — รีดีไซน์ทั้งแอป (ไอคอนโล่ของ payment.sirasupa.com · ฟอนต์ Prompt · ไล่สีส้ม-ชมพูบนปุ่ม) · หน้าแรก splash แตะโลโก้เพื่อเริ่ม · Login Google บัญชีเดียวกับ payment.sirasupa.com — เข้าครั้งแรกระบบออก API Key ให้อัตโนมัติ ถ้ามีคีย์เดิมแล้ววางในช่อง «วางคีย์ srs_… ที่มีอยู่» หรือกด «หมุน API key ใหม่» (จะทำให้คีย์เดิมใช้ไม่ได้ทันที)
ทำไมต้องเป็น APK ตรง — Google Play จำกัดสิทธิ์ RECEIVE_SMS / READ_SMS อย่างเข้มงวด แอป relay ส่วนตัวมักไม่ผ่านการรีวิว ฉะนั้นเราเผยแพร่เป็น APK ติดตั้งตรง ที่เซ็นแล้วสำหรับใช้ภายในเท่านั้น

ภาพตัวอย่างหน้าจอ

หน้า Splash ของแอป SRSP SMS Gateway บน Android — โล่ payment.sirasupa.com + ข้อความ ‘รับ SMS ธนาคาร · ส่งต่อ Webhook’ และ ‘แตะโลโก้เพื่อเริ่ม’
1) หน้า Splash — แตะโลโก้เพื่อเริ่ม

เปิดแอปครั้งแรกจะเห็นโล่ payment.sirasupa.com เต้นเบา ๆ แตะโลโก้ เพื่อไปหน้า เข้าสู่ระบบด้วย Google (บัญชีเดียวกับเว็บพอร์ทัล)

หน้า Dashboard หลังล็อกอิน — สถานะ ‘พร้อมใช้งาน’ + URL relay + API key srs_… + การ์ด ‘หมุน API key ใหม่’ / ‘วางคีย์ srs_… ที่มีอยู่’ + การตั้งค่า relay พร้อมตัวกรอง ‘บช X-0…’ + ปุ่ม ‘บันทึก’ และ ‘ทดสอบส่ง’
2) Dashboard — สถานะ · คีย์ · ตัวกรอง

หลังล็อกอิน Google แอปจะ ออก API key ให้อัตโนมัติ (หรือ «วางคีย์ srs_… ที่มีอยู่» ก็ได้) → ใส่คำที่ต้องมีใน SMS เช่น บช X-1234 → เปิดสวิตช์ → กด บันทึก → ทดสอบด้วย ทดสอบส่ง

ขั้นตอนติดตั้ง (5 นาที)

  1. บนมือถือ Android เปิด URL https://payment.sirasupa.com/downloads/sirasupa-sms-relay.apk เพื่อโหลด APK โดยตรง (หรือกดปุ่ม «ดาวน์โหลด APK» ด้านบนจากเครื่องที่จะติดตั้ง)
  2. เปิดไฟล์ APK → อนุญาต «ติดตั้งแอปจากแหล่งที่ไม่รู้จัก» สำหรับแอปที่ใช้เปิดไฟล์ (เช่น Chrome / ตัวจัดการไฟล์)
  3. เปิดแอป SRSP SMS Gateway → แตะโลโก้บนหน้า splash → กด «เข้าสู่ระบบด้วย Google» ใช้บัญชีเดียวกับเว็บ
  4. เข้าครั้งแรก: ระบบจะออก API Key ให้อัตโนมัติ · มีคีย์อยู่แล้ว: กด «วางคีย์ srs_… ที่มีอยู่» และวางคีย์เดิม · ต้องการคีย์ใหม่: กด «หมุน API key ใหม่» (ยืนยัน warning จะทำลายคีย์เดิม)
  5. ในการ์ด «สถานะ» — กด «ขอสิทธิ์ SMS / การแจ้งเตือน» และอนุญาตทุกข้อ
  6. (เลือก) ใส่ คำที่ต้องมีใน SMS เช่น บช X-1234 เพื่อกรองฝั่งเครื่อง (กฎจริงตั้งในพอร์ทัลเว็บ) บรรทัดละ 1 คำ — เว้นว่างจะส่งทุกข้อความเข้า relay
  7. เปิดสวิตช์ «เปิด relay เมื่อมี SMS เข้า» → กด «บันทึก» → กด «ทดสอบส่ง» เพื่อดูว่ากฎใน Sirasupa Portal จับคู่ได้

Meta Quest / Horizon OS (โหมด companion)

Quest ไม่มี SMS และไม่มี Google Play Services — ใช้แอปเป็นเครื่องมือ ทดสอบ relay และจัดการคีย์เท่านั้น (SMS จริงยังต้องใช้มือถือที่มีซิม)

  1. Sideload APK บน Quest (หรือ hzdb app install … จากเครื่อง dev)
  2. หน้า login → «ใช้ API key จากพอร์ทัล»
  3. วาง srs_… จาก /portal/
  4. กด «ทดสอบส่ง» แล้วดู log ในแอปและใน Portal
เจ้าของบัญชีเท่านั้น — ติดตั้ง APK บนเครื่องที่คุณควบคุมเท่านั้น ห้ามเผยแพร่ APK พร้อม srs_… ฝังในโค้ดและห้าม sideload ลงเครื่องลูกค้าโดยไม่ได้รับ ความยินยอมเป็นลายลักษณ์อักษร
ความน่าเชื่อถือ background — บางยี่ห้อ (Xiaomi / Oppo / Vivo) ปิด background app เชิงรุก ควรปิด Battery optimization ของแอปนี้ และเปิด Autostart ในเมนูระบบของรุ่นนั้น

11ตัวอย่างเว็บรับ webhook

สมมติเว็บรับชำระของคุณมีหน้าตั้งค่าให้ใส่ API Key / Secret สำหรับลายเซ็น webhook และกำหนด Webhook URL ที่ Sirasupa จะยิงเข้ามา — ขั้นตอนโดยรวมอาจเป็นแบบนี้ (แทนที่ URL ด้วยของจริงตามเอกสารของระบบคุณ):

  1. เข้าแดชบอร์ด / หน้าตั้งค่ารับชำระของเว็บคุณ (ตัวอย่าง URL: https://your-domain.example/admin/payments)
  2. ในช่องที่ให้ใส่คีย์จากผู้ให้บริการ relay → วาง srs_… จาก Sirasupa Portal
  3. เปิดส่วนขยายถ้ามี → ในช่อง «Secret key / Webhook signing secret» (หรือชื่อเทียบเท่า) วางค่าจากพาเนล «Secret key» ใน Portal — ไม่ใช่ค่า srs_…
  4. กดบันทึก → ใน Sirasupa Portal สร้างกฎ โดย Webhook URL = https://your-domain.example/api/sirasupa/webhook · หัวเพิ่มเติม {} ถ้าไม่ต้องการส่ง Bearer เพิ่ม
HTTP 400 จากปลายทาง — มักวาง srs_… ในช่อง Secret โดยเข้าใจผิด · ต้องใช้ Secret key (signing) จากพอร์ทัล
จับคู่ QR ต้องยอดตรง exact บน QR + ภายในเวลา + เลขบัญชีในกฎตรง PromptPay

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) รอช่วงเวลาปกติ หรือใช้บัญชีธนาคารสำรอง