Merchant Integration Handbook
มาตรฐานการเชื่อมต่อ (Production Ready) — contract, endpoint, webhook, และ live testing
amount จะมี copy.amount และ/หรือ copy.account_number เพื่อให้ UI ทำปุ่มคัดลอกได้ทันทีPublic API Base
https://api.hyronpay.com/api/v1
Webhook Direction
Hyronpay → Your Callback URL (POST)
1) Authentication Matrix
เลือก credential ให้ตรง endpoint
Runtime Key Mode Rule
- ระบบบังคับ key mode ตาม
RUNTIME_ENVอัตโนมัติ (ตรวจตอน auth) - ตรวจ runtime ปัจจุบันได้จาก
GET /api/v1/payout/signature-settings(runtime.mode) - ตรวจว่า key ที่ใช้อยู่เป็นโหมดไหนได้จาก
GET /api/v1/profile(authenticated_with_mode)
| Runtime | Default Key | Allowed | Blocked | Note |
|---|---|---|---|---|
| production | live | live + legacy | test | เปิด test key ได้เฉพาะเมื่อ ALLOW_TEST_KEYS_IN_PRODUCTION=true |
| development | test | live + test + legacy | - | เหมาะกับ local integration test |
| Credential | Header | Used For | Requirement |
|---|---|---|---|
| Merchant Secret API Key (sk_live_ / sk_test_ / sk_legacy) | X-API-Key | /api/v1/profile, /api/v1/payment/*, /api/v1/payment/accounts, /api/v1/transactions, /api/v1/balance, /api/v1/balance/line-summary, /api/v1/webhooks, /api/v1/webhook/events, /api/v1/payout/signature-settings, /api/v1/payout/*, /api/v1/withdrawal/* | จำเป็น (ใช้สร้าง payment page ได้; ควรเก็บฝั่ง backend merchant เท่านั้น) |
| Merchant Session (Dashboard) | Cookie: connect.sid | /api/payment/create-link, /api/payment/recent-links | จำเป็นเมื่อเรียก dashboard API โดยตรง |
| Payout Signature | Idempotency-Key, X-Signature-Timestamp, X-Signature, X-Signature-Nonce(optional) | /api/v1/payout/create, /api/v1/payout/bulk, /api/v1/withdrawal/request/create, /api/v1/withdrawal/request/:requestRef/approve, /api/v1/withdrawal/request/:requestRef/reject | สร้างจาก backend merchant เอง (เปิด signature mode = ต้องมี timestamp + signature) |
| Webhook Signature (Callback Verify) | X-Webhook-Signature, X-Webhook-Event, X-Webhook-Timestamp, X-Webhook-Delivery-Id, X-Webhook-Idempotency-Key, X-Webhook-Id(legacy), X-Webhook-Version | Webhook callback ที่ส่งจาก Hyronpay ไปยังระบบของคุณ | แนะนำอย่างยิ่ง (verify ทุก callback) |
2) Endpoint Catalog
รูปแบบนี้อ้างอิงแนว Postman docs: ระบุ method, path, auth, purpose แบบอ่านจบในหน้าเดียว (รวมทั้ง Public API และ Hosted Checkout flow)
| Method | Path | Auth | Purpose |
|---|---|---|---|
| POST | /api/v1/payment/create | X-API-Key (secret) | สร้างรายการรับชำระ และใช้ transaction.id ไปประกอบ hosted checkout URL ได้ |
| POST | /api/payment/create-link | Session (merchant dashboard login) | สร้างลิงก์ชำระเงินแบบ hosted checkout สำหรับ dashboard/internal tooling |
| GET | /api/payment/pay/:transactionId | Public (no auth) | ดึงข้อมูลหน้าชำระเงินจริง (QR + บัญชีธนาคาร) |
| GET | /api/v1/profile | X-API-Key | ดึงข้อมูลร้านค้าและ config พื้นฐานของ key ปัจจุบัน |
| GET | /api/v1/webhooks | X-API-Key | ดู callback webhook ที่ตั้งอยู่ของ merchant ปัจจุบัน |
| GET | /api/v1/webhook/events | X-API-Key | ดึงรายการ webhook event ที่ระบบรองรับ |
| GET | /api/v1/payment/order/:orderId | X-API-Key | เช็กสถานะรายการจาก orderId |
| GET | /api/v1/withdrawal/requests | X-API-Key | ดูคำขอถอนจากสมาชิกของร้านค้า |
| POST | /api/v1/withdrawal/request/create | X-API-Key + Signature headers | สร้างคำขอถอนจากสมาชิก พร้อมเช็กยอดขั้นต่ำและ balance ร้านค้าทันที |
| POST | /api/v1/withdrawal/request/:requestRef/approve | X-API-Key + Signature headers | อนุมัติคำขอถอน (ใช้ค่า `request.id` จาก endpoint create) และ reserve balance แบบ atomic ก่อนเข้า payout queue |
| POST | /api/v1/withdrawal/request/:requestRef/reject | X-API-Key + Signature headers | ปฏิเสธคำขอถอนจากสมาชิก (ใช้ค่า `request.id` จาก endpoint create) ก่อนเข้า payout queue |
| GET | /api/v1/payment/accounts | X-API-Key | ดึงบัญชีรับฝากที่ active ของระบบ |
| GET | /api/v1/payout/ref/:merchantRef | X-API-Key | เช็กสถานะ payout รายตัวจาก merchantRef |
| POST | /api/v1/payout/create | X-API-Key + Signature headers | สร้างคำสั่งถอน 1 รายการ |
| POST | /api/v1/payout/bulk | X-API-Key + Signature headers | สร้างคำสั่งถอนหลายรายการ |
| GET | /api/payout | Merchant session (dashboard) | ดูรายการถอนเงินของร้านค้า (มี copy.amount/copy.account_number) |
| GET | /api/settlement | Merchant session (dashboard) | ดูรายการขอถอนเครดิต (มี copy.amount/copy.account_number) |
| GET | /api/admin/payouts | Admin/Payout operator session | ดูรายการ payout ทั้งระบบ (มี copy.amount/copy.account_number) |
| GET | /api/admin/settlements | Admin session | ดูรายการ settlement ทั้งระบบ (มี copy.amount/copy.account_number) |
| GET | /api/admin/transactions | Admin/Payout operator session | ดูรายการรับเงินทั้งระบบ (มี copy.amount) |
| GET | /api/admin/bank-accounts | Admin/Payout operator session | ดูบัญชีธนาคารระบบกลาง (มี copy.account_number) |
| GET | /api/v1/transactions | X-API-Key | ดึงรายการธุรกรรมย้อนหลังแบบ paginated |
| GET | /api/v1/balance | X-API-Key | เช็กยอดคงเหลือปัจจุบันของ merchant |
| GET | /api/v1/balance/line-summary | X-API-Key | เช็กยอดรวมทั้งสายงาน (self + downline) ของ merchant ปัจจุบัน |
| GET | /api/v1/payout/signature-settings | X-API-Key | ดูกติกา signature ปัจจุบันจากระบบจริง |
| POST | <your-webhook-url> | X-Webhook-Signature (+ webhook headers) | รับสถานะฝาก/ถอนอัตโนมัติจาก Hyronpay (callback) |
3) Create Payment Contract
| Field | Type | Required | Description | Example |
|---|---|---|---|---|
| amount | number | Required | ยอดที่ต้องชำระ (> 0) รองรับทศนิยม 2 ตำแหน่ง | 100.37 |
| orderId | string | Required | เลขอ้างอิงฝั่งร้านค้า (ไม่ซ้ำต่อ merchant) - production ต้องส่งทุกครั้ง | ORD-10001 |
| description | string | Optional | คำอธิบายรายการ | Topup |
| metadata.senderAccountNumber | string | Required | เลขบัญชีผู้โอนแบบเต็ม ต้องมีอย่างน้อย 8 หลัก | 1673585481 |
| metadata.senderAccountLast4 | string | Optional | เลขท้ายบัญชีผู้โอน 4 หลัก (ถ้าไม่ส่ง ระบบจะเติมให้อัตโนมัติจาก senderAccountNumber) | 5481 |
| metadata.senderBankCode | string | Required | รหัสธนาคารผู้โอน เช่น SCB, KBANK, KTB, GSB | GSB |
| metadata.memberName | string | Required | ชื่อสมาชิก/เจ้าของบัญชีผู้โอน | นาย ทองดี ใจงาม |
| metadata.memberNameEn | string | Recommended | ชื่อสมาชิกภาษาอังกฤษ (ช่วยเพิ่มความแม่นยำกรณีชื่อไทยถูกตัด) | THONGDEE JAINGAM |
| metadata.customerId | string | Optional | รหัสสมาชิกฝั่ง merchant เพื่อ trace | u_123 |
[Integration Update] Create Payment Contract (Effective Now)
ต้องส่งฟิลด์ต่อไปนี้ทุกครั้งเมื่อเรียก POST /api/v1/payment/create
orderIdmetadata.senderAccountNumber(อย่างน้อย 8 หลัก)metadata.senderBankCodemetadata.memberName
ถ้าส่งไม่ครบ ระบบจะตอบกลับ 400 PAYMENT_CONTRACT_POLICY_VIOLATION
Recommended & Notes
amountรองรับทศนิยม 2 ตำแหน่ง (เช่น100.37)- Recommended: ส่ง
metadata.memberNameEn senderAccountNumberต้องมีอย่างน้อย 8 หลัก- ถ้าไม่ส่ง
senderAccountLast4ระบบจะเติมให้อัตโนมัติ - ทำ
orderIdให้ unique ต่อ merchant เสมอ
No QR Mode (ใช้งานได้)
- merchant ที่ไม่ใช้ QR สามารถฝากผ่านบัญชีธนาคารได้ โดยดูจาก
paymentAccounts.bankAccounts - ตรวจจาก response เสมอ: ถ้า
transaction.qrCodeเป็นnullให้แสดงช่องทางโอนบัญชีแทน - ตรวจ
paymentAccounts.channels.promptPayEnabledและbankTransferEnabledก่อนแสดงปุ่มชำระเงิน - สถานะช่องทางจริงเป็นแบบผสม: global switch ของระบบ + ค่า override ราย merchant
curl -X POST 'https://api.hyronpay.com/api/v1/payment/create' \ -H 'X-API-Key: sk_test_xxxxxxxxx' \ -H 'Content-Type: application/json' \ -d '{ "amount": 100.37, "orderId": "ORD-10001", "description": "Topup", "metadata": { "customerId": "u_123", "senderAccountNumber": "1673585481", "senderBankCode": "GSB", "memberName": "นาย ทองดี ใจงาม", "memberNameEn": "THONGDEE JAINGAM" } }'{ "success": true, "transaction": { "id": "uuid", "orderId": "ORD-10001", "amount": 100.37, "fee": 2.01, "netAmount": 98.36, "status": "PENDING", "paymentMethod": "PROMPTPAY", "qrCode": "data:image/png;base64,...", "qrExpiry": "2026-03-05T08:15:00.000Z", "createdAt": "2026-03-05T08:00:00.000Z", "copy": { "amount": "100.37" } }, "paymentAccounts": { "channels": { "promptPayEnabled": true, "bankTransferEnabled": true }, "promptPay": { "id": "payin_pp_uuid", "type": "PROMPTPAY", "name": "Hyronpay PromptPay", "accountNumber": "0812345678", "bankCode": null, "bankName": null, "isDefault": true, "updatedAt": "2026-03-05T07:58:00.000Z", "copy": { "account_number": "0812345678" } }, "bankAccounts": [ { "id": "payin_bank_uuid", "type": "BANK", "name": "Hyronpay SCB Main", "accountNumber": "1234567890", "accountName": "Hyronpay SCB Main", "bankCode": "014", "bankName": "ธนาคารไทยพาณิชย์", "isDefault": true, "updatedAt": "2026-03-05T07:59:00.000Z", "copy": { "account_number": "1234567890" } } ] }, "paymentContractPolicy": { "mode": "enforce_all", "enforceForThisMerchant": true, "reason": "enforce_all mode", "enforceNewMerchantFrom": null }, "integrationWarnings": []}{ "success": true, "transaction": { "id": "uuid", "orderId": "ORD-10002", "amount": 200.55, "fee": 4.01, "netAmount": 196.54, "status": "PENDING", "paymentMethod": "PROMPTPAY", "qrCode": null, "qrExpiry": "2026-03-05T08:25:00.000Z", "createdAt": "2026-03-05T08:10:00.000Z", "copy": { "amount": "200.55" } }, "paymentAccounts": { "channels": { "promptPayEnabled": false, "bankTransferEnabled": true }, "promptPay": null, "bankAccounts": [ { "id": "payin_bank_uuid", "type": "BANK", "name": "Hyronpay SCB Main", "accountNumber": "1234567890", "accountName": "Hyronpay SCB Main", "bankCode": "014", "bankName": "ธนาคารไทยพาณิชย์", "isDefault": true, "updatedAt": "2026-03-05T07:59:00.000Z", "copy": { "account_number": "1234567890" } } ] }}3.5) Hosted Payment Link Flow
ใช้สำหรับหน้า checkout สำเร็จรูปของระบบ: merchant backend เรียก public API ด้วย X-API-Key แล้วนำ transaction.id ไปประกอบลิงก์ส่งลูกค้าเข้า /pay/:id
POST /api/v1/payment/create แล้วประกอบ hosted checkout URL เอง ไม่ต้องพึ่ง cookie/sessionSecret Key (sk_live_..., sk_test_..., หรือ legacy sk_...) เท่านั้น; Public Key (pk_live_...) ใช้สร้าง payment page ไม่ได้/pay/:id ได้จริงhttps://hyronpay.comtransaction.qrCode เป็น null หน้า /pay/:id จะยังใช้ paymentAccounts.bankAccounts แสดงบัญชีธนาคารกลางให้ลูกค้าโอนได้POST /api/payment/create-link ยังมีอยู่สำหรับ dashboard/internal tooling ที่ล็อกอินแล้ว แต่ไม่ใช่ public API contract สำหรับ merchant integration- Merchant backend เรียก
POST /api/v1/payment/createด้วยX-API-Key - รับค่า
transaction.idจาก response แล้วประกอบลิงก์https://hyronpay.com/pay/<transaction.id> - ลูกค้าเปิดลิงก์
/pay/:id - หน้า pay ดึงข้อมูลจาก
GET /api/payment/pay/:transactionIdแล้วแสดง QR/พร้อมเพย์/บัญชีธนาคารตาม channel ที่เปิดใช้งาน
curl -X POST 'https://api.hyronpay.com/api/v1/payment/create' \ -H 'X-API-Key: sk_test_xxxxxxxxx' \ -H 'Content-Type: application/json' \ -d '{ "amount": 300, "orderId": "LINK-30001", "description": "Topup via hosted page", "metadata": { "customerId": "u_456", "senderAccountNumber": "1234567890", "senderBankCode": "SCB", "memberName": "สมชาย ใจดี" } }'Hosted payment URL pattern 1) เรียก POST /api/v1/payment/create ด้วย X-API-Key2) รับค่า transaction.id จาก response3) ประกอบลิงก์เป็น https://hyronpay.com/pay/<transaction.id> Example:https://hyronpay.com/pay/2cda2e8e-7832-4a05-93fc-256c87612529{ "success": true, "transaction": { "id": "uuid", "orderId": "ORD-10001", "amount": 100.37, "fee": 2.01, "netAmount": 98.36, "status": "PENDING", "paymentMethod": "PROMPTPAY", "qrCode": "data:image/png;base64,...", "qrExpiry": "2026-03-05T08:15:00.000Z", "createdAt": "2026-03-05T08:00:00.000Z", "copy": { "amount": "100.37" } }, "paymentAccounts": { "channels": { "promptPayEnabled": true, "bankTransferEnabled": true }, "promptPay": { "id": "payin_pp_uuid", "type": "PROMPTPAY", "name": "Hyronpay PromptPay", "accountNumber": "0812345678", "bankCode": null, "bankName": null, "isDefault": true, "updatedAt": "2026-03-05T07:58:00.000Z", "copy": { "account_number": "0812345678" } }, "bankAccounts": [ { "id": "payin_bank_uuid", "type": "BANK", "name": "Hyronpay SCB Main", "accountNumber": "1234567890", "accountName": "Hyronpay SCB Main", "bankCode": "014", "bankName": "ธนาคารไทยพาณิชย์", "isDefault": true, "updatedAt": "2026-03-05T07:59:00.000Z", "copy": { "account_number": "1234567890" } } ] }, "paymentContractPolicy": { "mode": "enforce_all", "enforceForThisMerchant": true, "reason": "enforce_all mode", "enforceNewMerchantFrom": null }, "integrationWarnings": []}curl 'https://api.hyronpay.com/api/payment/pay/<transactionId>'{ "transaction": { "id": "2cda2e8e-7832-4a05-93fc-256c87612529", "orderId": "LINK-30001", "amount": "300", "status": "PENDING", "qrCode": null, "qrExpiry": "2026-03-08T07:18:51.322Z", "merchantName": "Demo Store", "description": "Topup via hosted page" }, "paymentAccounts": { "promptPay": null, "bankAccounts": [ { "id": "payin_bank_uuid", "name": "Hyronpay SCB Main", "accountNumber": "1234567890", "bankCode": "014", "bankName": "ธนาคารไทยพาณิชย์", "isDefault": true } ] }}4) Payout Contract
| Field | Type | Required | Description | Example |
|---|---|---|---|---|
| amount | number | Required | ยอดถอน (ต้องไม่น้อยกว่า minSettlementAmount ของระบบ) | 100 |
| destination.bankCode | string | Required | รหัสธนาคารของปลายทาง (ดูตาราง bankCode ด้านล่าง) | SCB |
| destination.bankName | string | Optional | ชื่อธนาคารปลายทาง (ถ้าไม่ส่ง ระบบ derive จาก bankCode ที่รองรับให้) | ธนาคารไทยพาณิชย์ |
| destination.accountNumber | string | Required | เลขบัญชีปลายทาง (8-20 หลัก) | 4190621964 |
| destination.accountName | string | Required | ชื่อบัญชีปลายทาง | เจษฎา |
| merchantRef | string | Optional | ถ้าไม่ส่ง ระบบ generate ให้ (แนะนำส่งถ้ามีเลขอ้างอิงฝั่ง merchant); รูปแบบต้องเป็น ^[A-Z0-9]{3,6}-[A-Z0-9]{3,13}$ | M01-WD240001 |
| metadata | object | Optional | ข้อมูลเสริมสำหรับ trace/reconcile | {"sourceSystem":"lotto-main"} |
Quick Rules ก่อนเรียก POST /api/v1/payout/create
- ต้องใช้
X-API-Keyที่เป็น secret key (sk_...) - ตั้งค่า
Idempotency-Keyต่อ 1 คำสั่งถอน (retry รายการเดิมให้ใช้ key เดิม) - ต้องส่ง
X-Signature-TimestampและX-Signature - ต้องมี
Idempotency-Key(หรือidempotencyKeyใน body) - ระบบจะเช็กยอดขั้นต่ำและ balance ร้านค้าก่อนรับคำสั่งถอน
Merchant ต้องสร้าง headers เองจาก backend ของตัวเอง (Hyronpay ไม่ได้ generate ให้): 1) X-API-Key- ใช้ secret key ของร้านค้า: sk_live_... / sk_test_... 2) Idempotency-Key- สร้างใหม่ต่อ 1 คำสั่งถอน (แนะนำ UUID v4)- ถ้า retry คำสั่งเดิม ให้ใช้ key เดิม 3) X-Signature-Timestamp- Unix time หน่วยวินาที ตอนที่ยิง request 4) X-Signature- hex(HMAC_SHA256(secret_api_key, "<timestamp>.<raw_body_json>")) 5) X-Signature-Nonce- optional, recommended (ช่วยกัน replay เพิ่มเติม) payload = "<X-Signature-Timestamp>.<raw_body_json>"X-Signature = hex(HMAC_SHA256(secret_api_key, payload)) Required Headers:- X-API-Key (secret key)- Idempotency-Key- X-Signature-Timestamp (unix seconds)- X-Signature- X-Signature-Nonce (optional, recommended) Tip: ตรวจค่ากติกาปัจจุบันผ่าน GET /api/v1/payout/signature-settingsconst crypto = require('crypto'); const secretApiKey = process.env.HYRONPAY_SECRET_KEY; // sk_live_... หรือ sk_test_...const body = { amount: 100, destination: { bankCode: 'SCB', accountNumber: '4190621964', accountName: 'เจษฎา', }, metadata: { sourceSystem: 'merchant-backoffice' },}; const rawBody = JSON.stringify(body);const timestamp = Math.floor(Date.now() / 1000).toString();const idempotencyKey = crypto.randomUUID();const signature = crypto .createHmac('sha256', secretApiKey) .update(`${timestamp}.${rawBody}`) .digest('hex'); const headers = { 'X-API-Key': secretApiKey, 'Content-Type': 'application/json', 'Idempotency-Key': idempotencyKey, 'X-Signature-Timestamp': timestamp, 'X-Signature': signature,}; // ส่งด้วย fetch/axios โดยใช้ headers + rawBody เดียวกันกับที่ signcurl -X POST 'https://api.hyronpay.com/api/v1/payout/create' \ -H 'X-API-Key: sk_test_xxxxxxxxx' \ -H 'Idempotency-Key: m01-wd-20260304-0001' \ -H 'X-Signature-Timestamp: <unix_seconds>' \ -H 'X-Signature: <hmac_sha256_hex>' \ -H 'Content-Type: application/json' \ -d '{ "amount": 100, "destination": { "bankCode": "SCB", "accountNumber": "4190621964", "accountName": "เจษฎา" }, "metadata": { "sourceSystem": "merchant-backoffice" } }'{ "success": true, "object": "payout", "idempotent": false, "payout": { "object": "payout", "id": "po_123", "merchant_id": "m_123", "merchant_ref": "M01-WD240001", "amount": 100, "fee": 0, "net_amount": 100, "currency": "THB", "destination": { "bank_code": "014", "bank_name": "ธนาคารไทยพาณิชย์", "account_number": "4190621964", "account_name": "เจษฎา" }, "status": "QUEUED", "status_reason": null, "external_ref": null, "requested_at": "2026-03-05T08:05:00.000Z", "processed_at": null, "created_at": "2026-03-05T08:05:00.000Z", "metadata": { "sourceSystem": "merchant-backoffice" }, "copy": { "amount": "100.00", "account_number": "4190621964" } }}{ "error": "idempotencyKey is required (send Idempotency-Key header or idempotencyKey field)", "code": "IDEMPOTENCY_KEY_REQUIRED", "details": null}4.5) Dashboard/Admin Copy Contract
สำหรับ endpoint ภายในระบบ (/api/payout, /api/settlement, /api/admin/*) ที่มีจำนวนเงินหรือเลขบัญชี ระบบจะส่ง copy field เพื่อให้ UI ใช้คัดลอกได้ทันที
| Endpoint | Field | Type | Availability | Description | Example |
|---|---|---|---|---|---|
| GET /api/payout | payouts[].copy.amount | string | Always | คัดลอกยอด payout เป็นทศนิยม 2 ตำแหน่ง | "100.00" |
| GET /api/payout | payouts[].copy.account_number | string | Always | คัดลอกเลขบัญชีปลายทาง | "4190621964" |
| GET /api/payout/summary | queued|inProgress|success|failed|cancelled|total.copy.amount | string | Always | คัดลอกยอดจากข้อมูลสรุป payout | - |
| GET /api/settlement | settlements[].copy.amount | string | Always | คัดลอกยอดถอนเป็นทศนิยม 2 ตำแหน่ง | "1200.50" |
| GET /api/settlement | settlements[].copy.account_number | string | Always | คัดลอก bankAccount ของรายการถอน | "1234567890" |
| GET /api/settlement/summary | pending|processing|completed|failed|total.copy.amount | string | Always | คัดลอกยอดจากข้อมูลสรุป settlement | - |
| GET /api/admin/payouts | payouts[].copy.amount / payouts[].copy.account_number | string | Always | คัดลอกยอดและเลขบัญชีในหน้าจัดการ payout | - |
| GET /api/admin/payouts/summary | summary.<status>.copy.amount | string | Always | คัดลอกยอดในกล่อง summary แยกสถานะ | - |
| GET /api/admin/payouts/batches | batches[].copy.amount | string | Always | คัดลอกยอดรวมของแต่ละ batch | "2500.00" |
| GET /api/admin/payouts/batches/:id | batch.copy.amount / batch.payouts[].copy.* | string | Always | คัดลอกยอด batch และข้อมูล payout ใน batch เดียวกัน | - |
| GET /api/admin/settlements | settlements[].copy.amount / settlements[].copy.account_number | string | Always | คัดลอกยอดและเลขบัญชีในหน้าจัดการ settlement | - |
| GET /api/admin/settlements/summary | total|pending|processing|completed|failed.copy.amount | string | Always | คัดลอกยอดสรุป settlement ฝั่งแอดมิน | - |
| GET /api/admin/transactions | transactions[].copy.amount | string | Always | คัดลอกยอดรับเงินในรายการธุรกรรม | "100.00" |
| GET /api/admin/bank-accounts | data[].copy.account_number | string | Always | คัดลอกเลขบัญชีระบบกลาง | "1234567890" |
| POST /api/payment/create-link | transaction.copy.amount | string | Always | คัดลอกยอดสำหรับหน้า dashboard create link | "300.00" |
copy field contract (internal APIs)- copy.amount: string ทศนิยม 2 ตำแหน่ง เช่น "100.00"- copy.account_number: string สำหรับคัดลอกเลขบัญชี- ถ้ามีเฉพาะ amount -> ส่งเฉพาะ copy.amount- ถ้ามีเฉพาะ accountNumber/account_number -> ส่งเฉพาะ copy.account_number{ "payouts": [ { "id": "po_001", "merchantId": "m_123", "merchantRef": "M01-WD240001", "amount": "100", "bankCode": "014", "bankName": "ธนาคารไทยพาณิชย์", "accountNumber": "4190621964", "accountName": "เจษฎา", "status": "QUEUED", "createdAt": "2026-03-09T10:00:00.000Z", "copy": { "amount": "100.00", "account_number": "4190621964" } } ], "pagination": { "page": 1, "limit": 20, "total": 1, "totalPages": 1 }, "filters": { "status": "all" }}{ "settlements": [ { "id": "st_001", "merchantId": "m_123", "amount": "1200.5", "fee": "12.01", "netAmount": "1188.49", "bankAccount": "1234567890", "bankName": "ธนาคารไทยพาณิชย์", "status": "PENDING", "createdAt": "2026-03-09T10:05:00.000Z", "copy": { "amount": "1200.50", "account_number": "1234567890" } } ], "pagination": { "page": 1, "limit": 20, "total": 1, "totalPages": 1 }, "filters": { "status": "all" }}{ "payouts": [ { "id": "po_001", "merchantId": "m_123", "merchantRef": "M01-WD240001", "amount": "100", "accountNumber": "4190621964", "status": "QUEUED", "merchant": { "businessName": "Demo Store", "username": "merchant_demo" }, "batch": null, "copy": { "amount": "100.00", "account_number": "4190621964" } } ], "pagination": { "page": 1, "limit": 100, "total": 1, "totalPages": 1 }}{ "settlements": [ { "id": "st_001", "merchantId": "m_123", "amount": "1200.5", "bankAccount": "1234567890", "bankName": "ธนาคารไทยพาณิชย์", "status": "PENDING", "merchant": { "id": "m_123", "businessName": "Demo Store", "username": "merchant_demo", "balance": "9500" }, "copy": { "amount": "1200.50", "account_number": "1234567890" } } ], "pagination": { "page": 1, "limit": 20, "total": 1, "totalPages": 1 }, "filters": { "status": "ALL", "q": "" }}{ "transactions": [ { "id": "tx_001", "merchantId": "m_123", "orderId": "ORD-10001", "amount": "100", "status": "PAID", "referenceId": "ORD-10001", "confirmedAt": "2026-03-09T10:10:00.000Z", "copy": { "amount": "100.00" } } ], "pagination": { "page": 1, "limit": 50, "total": 1, "totalItems": 1, "totalPages": 1 }}{ "success": true, "data": [ { "id": "acct_001", "type": "BANK", "usage": "PAYOUT", "name": "SCB Debit Main", "accountNumber": "1234567890", "bankCode": "014", "bankName": "ธนาคารไทยพาณิชย์", "isDefault": true, "copy": { "account_number": "1234567890" } } ]}5) Bank Code Reference
destination.bankCode ส่งเป็น alias (เช่น SCB, KBANK) หรือเป็นเลข 3 หลักได้
destination.bankName เป็น optional แล้วสำหรับ bankCode ที่ระบบรู้จัก — backend จะเติมชื่อธนาคารให้เองตามตารางด้านล่าง
| Input Accepted | Normalized SCB Code | Bank Name (TH) | Note |
|---|---|---|---|
| SCB | 014 | ธนาคารไทยพาณิชย์ | Siam Commercial Bank |
| KBANK, KASIKORN | 004 | ธนาคารกสิกรไทย | Kasikorn Bank |
| KTB, KRUNGTHAI | 006 | ธนาคารกรุงไทย | Krungthai Bank |
| BBL, BANGKOK | 002 | ธนาคารกรุงเทพ | Bangkok Bank |
| TTB | 011 | ธนาคารทีเอ็มบีธนชาต | TMBThanachart Bank |
| BAY | 025 | ธนาคารกรุงศรีอยุธยา | Bank of Ayudhya |
| GSB | 030 | ธนาคารออมสิน | Government Savings Bank |
| UOB | 024 | ธนาคารยูโอบี | United Overseas Bank |
| CIMB | 022 | ธนาคารซีไอเอ็มบี ไทย | CIMB Thai |
| BAAC | 034 | ธนาคารเพื่อการเกษตรและสหกรณ์การเกษตร | Bank for Agriculture and Agricultural Cooperatives |
| GHB | 033 | ธนาคารอาคารสงเคราะห์ | Government Housing Bank |
| TISCO | 067 | ธนาคารทิสโก้ | TISCO Bank |
| KKP | 069 | ธนาคารเกียรตินาคินภัทร | Kiatnakin Phatra Bank |
| LHBANK | 073 | ธนาคารแลนด์ แอนด์ เฮ้าส์ | Land and Houses Bank |
| SME | 098 | ธนาคารพัฒนาวิสาหกิจขนาดกลางและขนาดย่อมแห่งประเทศไทย | SME Development Bank |
| 001, 002, 004 ... | ตรงตามที่ส่ง | ส่งชื่อธนาคารให้ตรงกับบัญชีปลายทาง | ส่งเป็นเลข 3 หลักตรงๆ ได้เช่นกัน |
004, 014) เพื่อลดปัญหา alias ไม่ตรงกัน6) Operational + Webhook
Webhook Setup Checklist
- ตั้ง Callback URL ฝั่งระบบของคุณให้รับ
POSTและตอบ2xxเมื่อรับสำเร็จ - ตั้งค่า webhook ในระบบ Hyronpay (Dashboard > Webhooks) แล้วเลือก event ที่ต้องการ
- บันทึก webhook secret เพื่อตรวจลายเซ็น
X-Webhook-Signatureทุกครั้ง - dedupe callback ด้วย
X-Webhook-Idempotency-Keyและเก็บdeliveryIdสำหรับ audit/replay
Firewall / Callback IP Guidance
- ถ้าปลายทางมี firewall ให้ใช้ source IP allowlist เป็นชั้นเสริมเท่านั้น ไม่ใช่กลไกหลัก
- การยืนยันหลักต้องตรวจ
X-Webhook-Signatureจาก raw body ทุกครั้งก่อนประมวลผล - ถ้าต้อง allow IP จริง ให้ใช้ public egress IP ของ production runtime/NAT ที่ส่ง callback ออกไปจริง
- หากมีการย้าย infra หรือเปลี่ยน outbound route ค่า IP อาจเปลี่ยนได้
Balance Scope Guide
แยก endpoint ให้ชัดเจน: /balance = ยอดของร้านค้าปัจจุบันเท่านั้น, /balance/line-summary = สรุปยอดรวมทั้งสายงาน
Self Balance
GET /api/v1/balanceเหมาะกับ flow ตรวจยอดก่อน create payout/request approve
Line Summary
GET /api/v1/balance/line-summaryเหมาะกับ dashboard สรุปเครือข่าย: self, downline, totalLine
curl 'https://api.hyronpay.com/api/v1/payment/accounts' \ -H 'X-API-Key: sk_test_xxxxxxxxx'{ "object": "payment_accounts", "merchant": { "id": "merchant_uuid", "username": "merchant_demo", "business_name": "Demo Store", "status": "ACTIVE" }, "channels": { "promptpay_enabled": true, "bank_transfer_enabled": true }, "promptpay": { "id": "payin_pp_uuid", "type": "PROMPTPAY", "name": "Hyronpay PromptPay", "account_number": "0812345678", "bank_code": null, "bank_name": null, "is_default": true, "updated_at": "2026-03-06T09:10:00.000Z" }, "bank_accounts": [ { "id": "payin_bank_uuid", "type": "BANK", "name": "Hyronpay SCB Main", "account_number": "1234567890", "account_name": "Hyronpay SCB Main", "bank_code": "014", "bank_name": "ธนาคารไทยพาณิชย์", "is_default": true, "updated_at": "2026-03-06T09:12:00.000Z" } ], "updated_at": "2026-03-06T09:12:00.000Z"}{ "object": "payment_accounts", "merchant": { "id": "merchant_uuid", "username": "merchant_demo", "business_name": "Demo Store", "status": "ACTIVE" }, "channels": { "promptpay_enabled": false, "bank_transfer_enabled": true }, "promptpay": null, "bank_accounts": [ { "id": "payin_bank_uuid", "type": "BANK", "name": "Hyronpay SCB Main", "account_number": "1234567890", "account_name": "Hyronpay SCB Main", "bank_code": "014", "bank_name": "ธนาคารไทยพาณิชย์", "is_default": true, "updated_at": "2026-03-06T09:12:00.000Z" } ], "updated_at": "2026-03-06T09:12:00.000Z"}curl 'https://api.hyronpay.com/api/v1/balance' \ -H 'X-API-Key: sk_test_xxxxxxxxx'{ "object": "balance", "merchant": { "id": "merchant_uuid", "username": "merchant_demo", "businessName": "Demo Store", "status": "ACTIVE" }, "balance": 15234.5, "currency": "THB", "updatedAt": "2026-03-06T09:15:00.000Z"}curl 'https://api.hyronpay.com/api/v1/balance/line-summary' \ -H 'X-API-Key: sk_test_xxxxxxxxx'{ "object": "balance_line_summary", "merchant": { "id": "merchant_uuid", "username": "merchant_demo", "businessName": "Demo Store", "status": "ACTIVE" }, "scope": { "merchantCount": 7, "downlineCount": 6, "directChildrenCount": 2 }, "balances": { "self": 15234.5, "downline": 48765.5, "totalLine": 64000 }, "currency": "THB", "updatedAt": "2026-03-06T09:15:00.000Z", "lineUpdatedAt": "2026-03-06T09:16:10.000Z"}curl 'https://api.hyronpay.com/api/v1/profile' \ -H 'X-API-Key: sk_test_xxxxxxxxx'{ "object": "profile", "authenticated_with": "secret", "authenticated_with_mode": "live", "merchant": { "id": "merchant_uuid", "username": "merchant_demo", "email": "merchant@example.com", "business_name": "Demo Store", "owner_name": "demo.example.com", "phone": "0812345678", "status": "ACTIVE", "fee_percent": 2, "fee_fixed": 0, "balance": 15234.5, "parent_merchant_id": null, "parent_merchant": null, "capabilities": { "can_create_child": false, "can_child_create_child": false, "max_child_depth": null, "max_children": null }, "counters": { "child_merchants": 0, "webhooks": 1 }, "created_at": "2026-03-01T10:00:00.000Z", "updated_at": "2026-03-06T09:15:00.000Z" }}curl 'https://api.hyronpay.com/api/v1/webhooks' \ -H 'X-API-Key: sk_test_xxxxxxxxx'{ "object": "list", "merchant": { "id": "merchant_uuid", "username": "merchant_demo", "business_name": "Demo Store", "status": "ACTIVE" }, "total": 1, "webhooks": [ { "object": "webhook", "id": "wh_123", "url": "https://merchant.example.com/api/paygate/webhook", "events": ["payment.success", "payment.failed", "payout.success", "payout.failed"], "is_active": true, "created_at": "2026-03-01T10:10:00.000Z", "updated_at": "2026-03-06T09:20:00.000Z" } ], "updated_at": "2026-03-06T09:20:00.000Z"}curl 'https://api.hyronpay.com/api/v1/webhook/events' \ -H 'X-API-Key: sk_test_xxxxxxxxx'{ "object": "list", "events": [ { "name": "payment.created", "description": "เมื่อสร้างรายการชำระเงินใหม่" }, { "name": "payment.success", "description": "เมื่อชำระเงินสำเร็จ" }, { "name": "payment.failed", "description": "เมื่อชำระเงินล้มเหลวหรือถูกยกเลิก" }, { "name": "payment.expired", "description": "เมื่อรายการหมดอายุ" }, { "name": "settlement.created", "description": "เมื่อสร้างรายการถอนเงิน" }, { "name": "settlement.completed", "description": "เมื่อถอนเงินสำเร็จ" }, { "name": "payout.success", "description": "เมื่อโอนเงินให้ลูกค้าสำเร็จ" }, { "name": "payout.failed", "description": "เมื่อโอนเงินให้ลูกค้าล้มเหลว หรือยกเลิกการถอน (status=CANCELLED)" }, { "name": "*", "description": "รับทุก event" } ]}curl 'https://api.hyronpay.com/api/v1/payment/order/ORD-10001' \ -H 'X-API-Key: sk_test_xxxxxxxxx'{ "transaction": { "id": "tx_123", "merchantId": "m_123", "orderId": "ORD-10001", "amount": 100, "fee": 2, "netAmount": 98, "paymentMethod": "PROMPTPAY", "status": "PAID", "paidAt": "2026-03-05T08:02:10.000Z", "createdAt": "2026-03-05T08:00:00.000Z" }}curl 'https://api.hyronpay.com/api/v1/payout/ref/M01-WD240001' \ -H 'X-API-Key: sk_test_xxxxxxxxx'{ "payout": { "object": "payout", "id": "po_123", "merchant_id": "m_123", "merchant_ref": "M01-WD240001", "amount": 100, "fee": 0, "net_amount": 100, "currency": "THB", "destination": { "bank_code": "014", "bank_name": "ธนาคารไทยพาณิชย์", "account_number": "4190621964", "account_name": "เจษฎา" }, "status": "SUCCESS", "status_reason": null, "external_ref": "SCB202603050001", "requested_at": "2026-03-05T08:05:00.000Z", "processed_at": "2026-03-05T08:06:10.000Z", "created_at": "2026-03-05T08:05:00.000Z", "metadata": { "sourceSystem": "merchant-backoffice" }, "copy": { "amount": "100.00", "account_number": "4190621964" } }}curl 'https://api.hyronpay.com/api/v1/payout/signature-settings' \ -H 'X-API-Key: sk_test_xxxxxxxxx'Subject: Hyronpay Webhook Firewall Allowlist Please allow inbound HTTPS callback traffic to our webhook endpoint from Hyronpay production egress IP. - Protocol: HTTPS- Method: POST- Source IP: <production_egress_ip>- Path: /api/paygate/webhook Important:1. Source IP allowlist is an additional control only.2. Our system will verify X-Webhook-Signature on every callback before processing.3. If Hyronpay production infrastructure or outbound routing changes, the source IP may need to be updated.X-Webhook-Signature: <hmac_sha256_hex>X-Webhook-Event: payment.successX-Webhook-Timestamp: 2026-03-05T08:02:11.000ZX-Webhook-Delivery-Id: 4b50836d-5c5b-4d74-a6e3-70b87f5dfe4fX-Webhook-Idempotency-Key: payment.success:tx_123X-Webhook-Id: wh_123X-Webhook-Version: 1import crypto from 'crypto'; function verifyWebhook(rawBody, signatureHeader, webhookSecret) { const expected = crypto.createHmac('sha256', webhookSecret).update(rawBody).digest('hex'); const a = Buffer.from(expected, 'utf8'); const b = Buffer.from(String(signatureHeader || ''), 'utf8'); return a.length === b.length && crypto.timingSafeEqual(a, b);} // สำคัญ:// 1) verify จาก raw body เดิมที่รับเข้ามา// 2) ใช้ webhook secret (ไม่ใช่ sk_ API key)Webhook Event Payloads
{ "event": "payment.success", "deliveryId": "4b50836d-5c5b-4d74-a6e3-70b87f5dfe4f", "data": { "id": "tx_123", "transactionId": "tx_123", "orderId": "ORD-10001", "amount": 100, "fee": 2, "netAmount": 98, "status": "PAID", "paidAt": "2026-03-05T08:02:10.000Z", "idempotencyKey": "payment.success:tx_123", "idempotency_key": "payment.success:tx_123", "customerId": "u_123", "customer_id": "u_123", "memberName": "นาย ทองดี ใจงาม", "member_name": "นาย ทองดี ใจงาม", "senderAccountNumber": "1673585481", "sender_account_number": "1673585481", "senderAccountLast4": "5481", "sender_account_last4": "5481", "senderBankCode": "GSB", "sender_bank_code": "GSB" }, "timestamp": "2026-03-05T08:02:11.000Z", "webhookId": "wh_123"}{ "event": "payment.failed", "deliveryId": "80b5a8b8-88e2-45ec-8eaa-6a52d69f0d79", "data": { "id": "tx_124", "transactionId": "tx_124", "orderId": "ORD-10001", "amount": 100, "status": "CANCELLED", "idempotencyKey": "payment.failed:tx_124", "idempotency_key": "payment.failed:tx_124", "errorMessage": "Cancelled by merchant" }, "timestamp": "2026-03-05T08:06:10.000Z", "webhookId": "wh_123"}{ "event": "payment.expired", "deliveryId": "1719fbdb-0b72-4c2b-8d18-1c8dcd5fd3b7", "data": { "id": "tx_125", "transactionId": "tx_125", "orderId": "ORD-10001", "amount": 100, "status": "EXPIRED", "idempotencyKey": "payment.expired:tx_125", "idempotency_key": "payment.expired:tx_125" }, "timestamp": "2026-03-05T08:15:01.000Z", "webhookId": "wh_123"}{ "event": "settlement.created", "deliveryId": "5dfec3c3-8d24-447f-a60e-8ef4a0d72211", "data": { "id": "st_123", "settlementId": "st_123", "amount": 500, "fee": 8, "netAmount": 492, "status": "PENDING", "createdAt": "2026-03-05T08:40:00.000Z", "note": "Webhook test for Demo Store" }, "timestamp": "2026-03-05T08:40:01.000Z", "webhookId": "wh_123"}{ "event": "settlement.completed", "deliveryId": "1254b17f-41b0-4c80-a9f1-176dd88d68fd", "data": { "id": "st_123", "settlementId": "st_123", "amount": 500, "fee": 8, "netAmount": 492, "status": "COMPLETED", "processedAt": "2026-03-05T09:15:20.000Z", "reference": "RID-202603050001", "note": "Batch #B20260305-001" }, "timestamp": "2026-03-05T09:15:21.000Z", "webhookId": "wh_123"}{ "event": "payout.success", "deliveryId": "4b50836d-5c5b-4d74-a6e3-70b87f5dfe4f", "data": { "id": "po_123", "payoutId": "po_123", "merchant_ref": "M01-WD240001", "merchantRef": "M01-WD240001", "idempotency_key": "withdrawal-request:req_123", "idempotencyKey": "withdrawal-request:req_123", "status": "SUCCESS", "amount": 100, "external_ref": "SCB202603050001", "externalRef": "SCB202603050001" }, "timestamp": "2026-03-05T08:20:10.000Z", "webhookId": "wh_123"}{ "event": "payout.failed", "deliveryId": "21f80419-4f57-4d4a-8cdd-440ad9d548f9", "data": { "id": "po_124", "payoutId": "po_124", "merchant_ref": "M01-WD240002", "merchantRef": "M01-WD240002", "idempotency_key": "withdrawal-request:req_124", "idempotencyKey": "withdrawal-request:req_124", "status": "CANCELLED", "amount": 100, "external_ref": null, "externalRef": null, "errorMessage": "Cancelled by merchant" }, "timestamp": "2026-03-05T08:21:40.000Z", "webhookId": "wh_123"}Webhook Delivery Policy (Current Behavior: 2026-03-11)
- Hyronpay ส่ง callback แบบ best effort ต่อ webhook URL ที่ active และรองรับ event นั้น
- ระบบจะคำนวณ
X-Webhook-Signatureจาก JSON body ที่ส่งจริง (raw payload เดียวกัน) - ทุก callback มี
deliveryIdใหม่เสมอเมื่อ replay/manual resend แต่X-Webhook-Idempotency-Keyจะคงเดิมต่อ business event เดิม - เมื่อ retry/replay จาก queue ระบบจะ re-sign ด้วย webhook secret ล่าสุดก่อนส่งทุกครั้ง
- กรณียกเลิกถอน (
CANCELLED) จะส่งผ่าน eventpayout.failedโดย payload มีdata.status=CANCELLED - Webhook payout ส่งทั้งคีย์ canonical และ alias (
id+payoutId,merchant_ref+merchantRef,idempotency_key+idempotencyKey) - Timeout ต่อคำขอ default 10 วินาที (ปรับได้ด้วย
WEBHOOK_TIMEOUT_MS) - มี retry แบบ exponential backoff ตามค่า
WEBHOOK_MAX_ATTEMPTS(default 3) - ฝั่ง merchant ควร queue งานภายในและตอบ
2xxให้เร็วที่สุด
7) Webhook Field Matrix
ตารางนี้สรุป field ที่ควรรองรับใน callback payload แยกตาม event เพื่อให้ทีม backend mapping ได้ชัดเจน
| Event | Field | Type | Required | Description | Example |
|---|---|---|---|---|---|
| * (all events) | event | string | Required | ชื่อ event ที่ส่งมา | payment.success |
| * (all events) | deliveryId | string | Required | รหัส delivery ของ callback ครั้งนี้ (ใหม่ทุก replay/send) | 4b50836d-5c5b-4d74-a6e3-70b87f5dfe4f |
| * (all events) | timestamp | string (ISO-8601) | Required | เวลาที่สร้าง callback payload | 2026-03-05T08:02:11.000Z |
| * (all events) | webhookId | string | Required | ID ของ webhook config ในระบบ Hyronpay | wh_123 |
| payment.success | data.id | string | Required | ID รายการรับชำระ (alias ของ transactionId) | tx_123 |
| payment.success | data.transactionId | string | Required | ID รายการรับชำระ | tx_123 |
| payment.success | data.orderId | string | Required | orderId จากฝั่ง merchant | ORD-10001 |
| payment.success | data.amount | number | Required | ยอดที่ชำระ | 100 |
| payment.success | data.status | string | Required | สถานะรายการ | PAID |
| payment.success | data.paidAt | string (ISO-8601) | Required | เวลาชำระสำเร็จ | 2026-03-05T08:02:10.000Z |
| payment.success | data.customerId | data.customer_id | string | Optional | รหัสสมาชิก/ลูกค้าที่ merchant ส่งมาตอน create payment ถ้ามี | u_123 |
| payment.success | data.idempotency_key | data.idempotencyKey | string | Recommended | คีย์กันซ้ำฝั่ง callback (รูปแบบ `payment.success:<transactionId>`) | payment.success:tx_123 |
| payment.success | data.memberName | data.member_name | string | Optional | ชื่อสมาชิกที่ merchant ส่งมาตอน create payment ถ้ามี | นาย ทองดี ใจงาม |
| payment.success | data.senderAccountNumber | data.sender_account_number | string | Optional | เลขบัญชีผู้โอนที่ merchant ส่งมาตอน create payment ถ้ามี | 1673585481 |
| payment.success | data.senderAccountLast4 | data.sender_account_last4 | string | Optional | เลขท้ายบัญชีผู้โอน 4 หลัก ระบบจะเติมให้อัตโนมัติเมื่อคำนวณได้จาก senderAccountNumber | 5481 |
| payment.success | data.senderBankCode | data.sender_bank_code | string | Optional | รหัสธนาคารผู้โอนที่ merchant ส่งมาตอน create payment ถ้ามี | GSB |
| payment.failed | payment.expired | data.id | string | Required | ID รายการรับชำระ (alias ของ transactionId) | tx_124 |
| payment.failed | payment.expired | data.transactionId | string | Required | ID รายการรับชำระ | tx_124 |
| payment.failed | payment.expired | data.orderId | string | Required | orderId จากฝั่ง merchant | ORD-10002 |
| payment.failed | payment.expired | data.amount | number | Required | ยอดรายการ | 100 |
| payment.failed | payment.expired | data.idempotency_key | data.idempotencyKey | string | Recommended | คีย์กันซ้ำฝั่ง callback (รูปแบบ `<event>:<transactionId>`) | payment.failed:tx_124 |
| payment.failed | payment.expired | data.status | string | Required | สถานะรายการ (FAILED / CANCELLED / EXPIRED) | FAILED / CANCELLED / EXPIRED |
| payment.failed | data.errorMessage | string | Recommended | เหตุผลล้มเหลวหรือยกเลิก | Cancelled by merchant |
| settlement.created | settlement.completed | data.id | data.settlementId | string | Required | ID รายการถอนเครดิต (alias กันเอง) | st_123 |
| settlement.created | settlement.completed | data.amount | number | Required | ยอดถอนเครดิต | 500 |
| settlement.created | settlement.completed | data.fee | data.netAmount | number | Recommended | ค่าธรรมเนียมและยอดสุทธิ (มีใน payload มาตรฐานของระบบ) | fee=8, netAmount=492 |
| settlement.created | data.status | data.createdAt | data.note | string | Recommended | สถานะเริ่มต้น, เวลาเริ่มรายการ, และหมายเหตุ (ถ้ามี) | status=PENDING |
| settlement.completed | data.status | data.processedAt | data.reference | data.note | string | Recommended | สถานะสำเร็จ, เวลาที่ประมวลผลเสร็จ, เลขอ้างอิง, หมายเหตุ | status=COMPLETED |
| payout.success | payout.failed (includes CANCELLED) | webhookId | string | Required | ID ของ webhook endpoint ที่ถูกใช้ส่ง callback | wh_123 |
| payout.success | payout.failed (includes CANCELLED) | data.id | string | Required | ID payout | po_123 |
| payout.success | payout.failed (includes CANCELLED) | data.payoutId | string | Required | ID payout (alias ของ data.id) | po_123 |
| payout.success | payout.failed (includes CANCELLED) | data.merchant_ref | string | Required | merchant reference ของคำสั่งถอน | M01-WD240001 |
| payout.success | payout.failed (includes CANCELLED) | data.merchantRef | string | Required | merchant reference (alias ของ data.merchant_ref) | M01-WD240001 |
| payout.success | payout.failed (includes CANCELLED) | data.idempotency_key | data.idempotencyKey | string | null | Recommended | idempotency key เดิมจากตอน create payout/request approve ถ้ามี | withdrawal-request:req_123 |
| payout.success | payout.failed (includes CANCELLED) | data.status | string | Required | สถานะ payout | SUCCESS / FAILED / CANCELLED |
| payout.success | payout.failed (includes CANCELLED) | data.amount | number | Required | ยอดถอน | 100 |
| payout.failed (FAILED/CANCELLED) | data.errorMessage | string | Recommended | เหตุผลความล้มเหลวหรือการยกเลิก | Cancelled by merchant |
| payout.success | payout.failed (includes CANCELLED) | data.external_ref | data.externalRef | string | null | Optional | เลขอ้างอิงภายนอกของการโอน (ถ้ามี) | SCB202603050001 |
8) Error Catalog (Payment + Payout)
สรุป error ที่พบบ่อยจาก endpoint หลัก เพื่อให้ทำ error handling ได้ครบตั้งแต่รอบแรก
POST /api/v1/payment/create
| Code | HTTP | When |
|---|---|---|
| Invalid amount | 400 | amount ไม่ถูกต้องหรือ <= 0 |
| ยอดชำระขั้นต่ำคือ <min> บาท | 400 | amount ต่ำกว่าค่า minPaymentAmount |
| ยอดชำระสูงสุดคือ <max> บาท | 400 | amount เกินค่า maxPaymentAmount |
| PAYMENT_CONTRACT_POLICY_VIOLATION | 400 | ไม่ส่งข้อมูลตาม Create Payment Contract ที่ระบบบังคับ |
| Order ID already exists | 400 | orderId ซ้ำภายใน merchant เดียวกัน |
| Forbidden | 403 | ใช้ key ที่ไม่ใช่ secret key (sk_...) กับ endpoint แบบเขียนข้อมูล |
| Failed to create payment | 500 | ข้อผิดพลาดภายในระบบ |
GET /api/v1/payment/order/:orderId
| Code | HTTP | When |
|---|---|---|
| Transaction not found | 404 | ไม่พบรายการตาม orderId ของ merchant นี้ |
| Failed to get payment | 500 | ข้อผิดพลาดภายในระบบ |
Payout Endpoints
| Code | HTTP | When |
|---|---|---|
| IDEMPOTENCY_KEY_REQUIRED | 400 | ไม่ส่ง Idempotency-Key สำหรับ payout endpoint |
| INVALID_MERCHANT_REF_FORMAT | 400 | merchantRef ไม่ตรงรูปแบบ ^[A-Z0-9]{3,6}-[A-Z0-9]{3,13}$ (PREFIX 3-6, REFERENCE 3-13) |
| VALIDATION_ERROR | 400 | ข้อมูล request ไม่ครบหรือไม่ถูกต้อง |
| INSUFFICIENT_BALANCE | 400 | ยอดคงเหลือ merchant ไม่พอ |
| DUPLICATE_PAYOUT_REQUEST | 409 | merchantRef/idempotency ซ้ำกับคำขอเดิม |
9) End-to-End Integration Flow
- 1Merchant backend สร้าง payment ผ่าน
POST /api/v1/payment/create - 2เมื่อมีผลชำระ Hyronpay ส่ง webhook callback (
payment.success|failed|expired) ไปยัง callback URL - 3Merchant backend ยืนยันสถานะซ้ำผ่าน
GET /api/v1/payment/order/:orderIdก่อน credit/fulfillment - 4เมื่อมีคำสั่งถอน ให้เรียก
POST /api/v1/payout/createพร้อม signature และ idempotency - 5รอ webhook
payout.success|failedแล้วค่อยอัปเดตสถานะฝั่งสมาชิก (ยกเลิกถอนจะมาเป็นpayout.failed+status=CANCELLED)
curl -X POST 'https://api.hyronpay.com/api/v1/payment/create' \ -H 'X-API-Key: sk_test_xxxxxxxxx' \ -H 'Content-Type: application/json' \ -d '{ "amount": 100.37, "orderId": "ORD-10001", "description": "Topup", "metadata": { "customerId": "u_123", "senderAccountNumber": "1673585481", "senderBankCode": "GSB", "memberName": "นาย ทองดี ใจงาม", "memberNameEn": "THONGDEE JAINGAM" } }'{ "event": "payment.success", "deliveryId": "4b50836d-5c5b-4d74-a6e3-70b87f5dfe4f", "data": { "id": "tx_123", "transactionId": "tx_123", "orderId": "ORD-10001", "amount": 100, "fee": 2, "netAmount": 98, "status": "PAID", "paidAt": "2026-03-05T08:02:10.000Z", "idempotencyKey": "payment.success:tx_123", "idempotency_key": "payment.success:tx_123", "customerId": "u_123", "customer_id": "u_123", "memberName": "นาย ทองดี ใจงาม", "member_name": "นาย ทองดี ใจงาม", "senderAccountNumber": "1673585481", "sender_account_number": "1673585481", "senderAccountLast4": "5481", "sender_account_last4": "5481", "senderBankCode": "GSB", "sender_bank_code": "GSB" }, "timestamp": "2026-03-05T08:02:11.000Z", "webhookId": "wh_123"}curl 'https://api.hyronpay.com/api/v1/payment/order/ORD-10001' \ -H 'X-API-Key: sk_test_xxxxxxxxx'curl -X POST 'https://api.hyronpay.com/api/v1/payout/create' \ -H 'X-API-Key: sk_test_xxxxxxxxx' \ -H 'Idempotency-Key: m01-wd-20260304-0001' \ -H 'X-Signature-Timestamp: <unix_seconds>' \ -H 'X-Signature: <hmac_sha256_hex>' \ -H 'Content-Type: application/json' \ -d '{ "amount": 100, "destination": { "bankCode": "SCB", "accountNumber": "4190621964", "accountName": "เจษฎา" }, "metadata": { "sourceSystem": "merchant-backoffice" } }'{ "event": "payout.success", "deliveryId": "4b50836d-5c5b-4d74-a6e3-70b87f5dfe4f", "data": { "id": "po_123", "payoutId": "po_123", "merchant_ref": "M01-WD240001", "merchantRef": "M01-WD240001", "idempotency_key": "withdrawal-request:req_123", "idempotencyKey": "withdrawal-request:req_123", "status": "SUCCESS", "amount": 100, "external_ref": "SCB202603050001", "externalRef": "SCB202603050001" }, "timestamp": "2026-03-05T08:20:10.000Z", "webhookId": "wh_123"}10) Interactive Docs (Try API Live)
ใช้สำหรับทดสอบเชื่อมต่อแบบเร็วจากหน้า docs โดยตรง (ควรใช้ test key/สภาพแวดล้อมทดสอบ)
Response
ยังไม่มีผลลัพธ์
กด Send Request เพื่อทดสอบ
11) Integration Starter Pack
สำหรับทีม dev ที่ต้องการเชื่อมระบบเร็ว: ใช้ SDK + Postman ด้านล่าง แล้วเริ่ม flow แบบ create payment → /pay/:id → webhook
Quick Flow (แนะนำสำหรับขึ้นงานจริงเร็วที่สุด): 1) Merchant backend เรียก POST /api/v1/payment/create2) รับ transaction.id จาก response3) สร้างลิงก์ชำระเงิน: https://hyronpay.com/pay/<transaction.id>4) ส่งลิงก์ให้ลูกค้าเปิดหน้า UI ชำระเงินของ Hyronpay5) ฝั่ง merchant รอ webhook payment.success/payment.failed/payment.expired เพื่อปิดงาน หมายเหตุ:- วิธีนี้ไม่ต้องพัฒนา UI รับชำระเงินเอง- /api/payment/create-link เป็น route ฝั่ง dashboard session ไม่ใช่ public API key flowconst HyronpayClient = require('./paygate-node'); const client = new HyronpayClient({ apiKey: process.env.HYRONPAY_API_KEY, // sk_live_... baseUrl: 'https://api.hyronpay.com/api/v1',}); async function createDepositLink() { const result = await client.createPayment({ amount: 100, orderId: 'ORD-10001', description: 'Topup', metadata: { senderAccountNumber: '1673585481', senderBankCode: 'GSB', memberName: 'นาย ทองดี ใจงาม', memberNameEn: 'THONGDEE JAINGAM', customerId: 'u_123', }, }); const paymentUrl = HyronpayClient.buildHostedPaymentUrl({ frontendBaseUrl: 'https://hyronpay.com', transactionId: result.transaction.id, }); return { paymentUrl, transactionId: result.transaction.id, orderId: result.transaction.orderId, };}const express = require('express');const HyronpayClient = require('./paygate-node'); const app = express();app.use( express.json({ verify: (req, _res, buf) => { req.rawBody = buf.toString('utf8'); }, })); app.post('/api/paygate/webhook', (req, res) => { const signatureHeader = req.header('X-Webhook-Signature') || ''; const ok = HyronpayClient.verifyWebhookSignature({ rawBody: req.rawBody || '', signatureHeader, webhookSecret: process.env.HYRONPAY_WEBHOOK_SECRET, }); if (!ok) return res.status(401).json({ error: 'invalid signature' }); // TODO: dedupe ด้วย X-Webhook-Idempotency-Key (fallback: event+transactionId หรือ deliveryId) // แล้วค่อย map ธุรกิจด้วย payoutId/orderId return res.status(200).json({ received: true });});const HyronpayClient = require('./paygate-node');const client = new HyronpayClient({ apiKey: process.env.HYRONPAY_API_KEY }); async function createPayout() { return client.createPayout({ amount: 100, destination: { bankCode: 'SCB', accountNumber: '4190621964', accountName: 'เจษฎา', }, metadata: { sourceSystem: 'merchant-backoffice', memberId: 'member_1001', }, });}12) Security Baseline
- 🔑เก็บ
sk_...เฉพาะฝั่ง server (เช่น backend) ห้ามฝังใน frontend/browser - 🔒เปิดใช้ HTTPS และจำกัด IP/Origin ตามโครงสร้างระบบของคุณ — สำหรับ webhook ให้ถือ
signature verificationเป็นชั้นหลัก และ IP allowlist เป็นชั้นรอง - 🔄ใช้ idempotency และ signature ทุกคำสั่งถอนเงิน
- 📋กำหนด rotation policy สำหรับ API key และ webhook secret/signature key