Pay-ins (รับเงิน)
pay-in คือรายการเรียกเก็บเงินจาก payer หนึ่งคน คุณสร้างรายการ ระบบคืนช่องทางจ่าย (QR หรือบัญชีปลายทาง) ผู้จ่ายโอนเงิน แล้วระบบจับคู่การโอนและแจ้งผลผ่าน webhook
| Method | Path | ใช้ทำอะไร |
|---|---|---|
POST | /v1/payins | สร้าง pay-in |
GET | /v1/payins/{id} | ดู pay-in พร้อม payTo (ใส่ ?include=paymentImage เพื่อรับรูปด้วย) |
GET | /v1/payins | ค้นหารายการ |
POST | /v1/payins/{id}/cancel | ยกเลิกรายการที่ pending หรือ expired |
POST | /v1/payins/{id}/slip | อัปโหลดสลิปของผู้จ่าย (ดูตรวจสลิป) |
สร้าง pay-in
หัวข้อที่มีชื่อว่า “สร้าง pay-in”POST /v1/payins| ฟิลด์ | จำเป็น | คำอธิบาย |
|---|---|---|
payer | ส่ง payer หรือ payerId อย่างใดอย่างหนึ่ง | บัญชีธนาคารของผู้จ่าย: bankCode, accountNumber, accountName และ accountNameEn (ไม่บังคับ) ดูส่ง payer แบบ inline |
payerId | ส่ง payer หรือ payerId อย่างใดอย่างหนึ่ง | payer_... ของผู้จ่ายที่มีอยู่แล้ว (Payers) |
amount | ใช่ | สตริงทศนิยม เช่น "150.00" ต้องอยู่ในช่วง payinMinimum-payinMaximum ของบัญชีคุณ |
currency | ใช่ | THB, USD, USDT หรือ LAK |
method | ไม่ | auto (ค่าเริ่มต้น), promptpay_qr, bank_transfer, crypto, lao_qr |
reference | ไม่ | เลขคำสั่งซื้อของคุณ ไม่เกิน 128 ตัว ส่งกลับใน response และ webhook และใช้ค้นหาได้ |
webhookUrl | ใช่ | URL http(s) ที่จะรับ webhook ไม่เกิน 2048 ตัว |
returnUrl | ไม่ | URL ที่หน้าชำระเงินจะพาผู้จ่ายกลับไปหลังจ่ายเสร็จ |
{ "payer": { "bankCode": "SCB", "accountNumber": "1234567890", "accountName": "สมชาย สบายดี" }, "amount": "150.00", "currency": "THB", "reference": "order-10001", "webhookUrl": "https://shop.example.com/webhooks/payments", "returnUrl": "https://shop.example.com/orders/10001"}ถ้าคุณเก็บ ID ของ payer ไว้แล้ว ส่ง "payerId": "payer_7c0a4b8e2f3d4a1b9c8d7e6f5a4b3c2d" แทน payer ได้
query parameter: include=paymentImage เพิ่มรูปสำเร็จรูปใน response (ดูด้านล่าง)
สิ่งที่ควรรู้
- ยอดที่ต้องโอนคือ
amountใน response ระบบอาจเพิ่มเศษสตางค์เพื่อใช้จับคู่ ทำให้amount(เช่น150.37) ต่างจากrequestedAmount(150.00) ให้แสดงamountแก่ผู้จ่าย - ช่องทางจ่ายเลือกอัตโนมัติ สำหรับเงินบาท คำขอแบบ
promptpay_qrหรือbank_transferระบบจะเลือกช่องทางที่เหมาะให้ ดูช่องทางที่ใช้จริงได้จากmethodใน response - payer หนึ่งคนมี pay-in ที่รอจ่ายได้ครั้งละหนึ่งรายการ ถ้ายังมีรายการ
pendingอยู่ จะได้409 pending_payin_existsให้รอรายการเดิมจบ หรือยกเลิกก่อน - สำหรับ
cryptoข้อมูลปลายทางในpayToจะเป็นwalletAddressและnetwork - ส่ง header
Idempotency-Keyเพื่อให้การส่งซ้ำหลัง timeout ไม่สร้าง pay-in ซ้ำ ดูส่งคำขอสร้างรายการซ้ำอย่างปลอดภัย
ส่ง payer แบบ inline
หัวข้อที่มีชื่อว่า “ส่ง payer แบบ inline”ส่ง payerId หรือ payer อย่างใดอย่างหนึ่งเท่านั้น ถ้าส่งทั้งคู่จะได้ 400 parameters_exclusive ถ้าไม่ส่งเลยจะได้ 400 parameter_missing
- บัญชีที่มีอยู่แล้ว: ใช้ payer เดิม ถ้าคุณมี payer ที่
bankCodeและaccountNumberตรงกันอยู่แล้ว pay-in จะใช้ payer คนนั้น และไม่เปลี่ยนชื่อที่บันทึกไว้ เพราะระบบใช้ชื่อนี้จับคู่การโอนเข้า ถ้าชื่อที่ส่งมาต่างจากเดิม (ไม่นับตัวพิมพ์เล็กใหญ่และช่องว่างที่เกิน) ระบบยังสร้าง pay-in ให้ และใส่payer_name_differsไว้ในwarningsของ response ถ้าต้องการเปลี่ยนชื่อ ใช้PATCH /v1/payers/{id} - บัญชีใหม่: สร้าง payer ให้ ระบบสร้าง payer สถานะ
activeโดยตรวจสอบเหมือนPOST /v1/payersทุกอย่าง (รูปแบบฟิลด์ และบัญชีที่ถูกระงับ) ข้อผิดพลาดจะชี้ไปที่ฟิลด์ย่อย เช่นparam: "payer.accountNumber"ถ้ารหัสธนาคารไม่ถูกต้องจะได้422 bank_not_foundพร้อมparam: "payer.bankCode"คำขอที่เข้ามาพร้อมกันด้วยบัญชีเดียวกันจะสร้าง payer เพียงคนเดียว - payer ที่สร้างใหม่จะยังอยู่แม้ pay-in จะถูกปฏิเสธในขั้นต่อไป (เช่น
amount_below_minimum) เมื่อส่งใหม่ระบบจะใช้ payer คนเดิม - payer ที่ถูกปิดหรือถูกระงับจะได้ข้อผิดพลาดเดียวกับการใช้
payerId(payer_inactive,payer_blocked) โดยparamเป็น"payer" - response มี
payerIdและpayerเก็บ ID ไว้ถ้าต้องการใช้payerIdครั้งต่อไป
{ "data": { "object": "payin", "id": "pin_...", "payerId": "payer_7c0a4b8e2f3d4a1b9c8d7e6f5a4b3c2d", "...": "..." }, "warnings": [ { "code": "payer_name_differs", "message": "An existing payer with this bank account was used. Its stored account name differs from the one sent and was kept; it is used for payment matching.", "param": "payer.accountName" } ], "requestId": "req_..."}warnings มีเฉพาะเมื่อมีคำเตือนเท่านั้น
QR code และรูปสำหรับชำระเงิน
หัวข้อที่มีชื่อว่า “QR code และรูปสำหรับชำระเงิน”payTo.qrPayload คือข้อความที่อยู่ใน QR code สำหรับชำระเงิน นำไปสร้าง QR code เองด้วยไลบรารี QR ใดก็ได้
method | qrPayload |
|---|---|
promptpay_qr | payload แบบ EMVCo/PromptPay ซึ่งมี amount อยู่แล้ว |
lao_qr | payload ของ Lao QR |
bank_transfer, crypto | null (ให้แสดงบัญชีหรือ wallet จาก payTo) |
ระบบไม่ส่ง paymentImage (รูป PNG สำเร็จรูปของ QR code หรือบัตรข้อมูลการโอน) มาโดยอัตโนมัติ ถ้าต้องการ ให้ใส่ ?include=paymentImage กับ POST /v1/payins หรือ GET /v1/payins/{id} ค่า include ใส่ได้หลายค่าคั่นด้วย , และค่าที่ระบบไม่รู้จักจะถูกข้ามไป query string เป็นส่วนหนึ่งของลายเซ็น จึงต้องเซ็น /v1/payins?include=paymentImage ทั้งหมด
Object ของ pay-in
หัวข้อที่มีชื่อว่า “Object ของ pay-in”response ของการสร้างและการดูรายการ (GET /v1/payins/{id}) มี payTo ด้วย และมี paymentImage เมื่อขอด้วย ?include=paymentImage ส่วนผลการค้นหาและ webhook ไม่มีทั้งสองฟิลด์นี้
{ "object": "payin", "id": "pin_3f2b1c0d9e8f4a7b8c6d5e4f3a2b1c0d", "reference": "order-10001", "payerId": "payer_7c0a4b8e2f3d4a1b9c8d7e6f5a4b3c2d", "payer": { "object": "payer", "id": "payer_7c0a4b8e2f3d4a1b9c8d7e6f5a4b3c2d", "bankCode": "SCB", "bankName": "Siam Commercial Bank", "accountNumber": "1234567890", "accountName": "สมชาย สบายดี", "accountNameEn": "Somchai Sabuydee", "status": "active", "referralCode": null, "createdAt": "2026-01-01T00:00:00.000Z" }, "requestedAmount": "150.00", "amount": "150.37", "fee": "2.25", "currency": "THB", "method": "promptpay_qr", "status": "pending", "failureReason": null, "webhookUrl": "https://shop.example.com/webhooks/payments", "returnUrl": "https://shop.example.com/orders/10001", "checkoutUrl": "https://pay.example.com/3f2b1c0d-9e8f-4a7b-8c6d-5e4f3a2b1c0d", "payerAccount": { "bankCode": "SCB", "accountNumber": "1234567890", "accountName": "สมชาย สบายดี" }, "payTo": { "bankCode": "KBANK", "bankName": "Kasikorn Bank", "accountNumber": "0987654321", "accountName": "Example Co., Ltd.", "promptpayId": "0812345678", "qrPayload": "00020101021229370016A000000677010111011300668123456785802TH53037645406150.3763046572" }, "createdAt": "2026-01-01T00:00:00.000Z", "updatedAt": "2026-01-01T00:00:00.000Z"}| ฟิลด์ | คำอธิบาย |
|---|---|
requestedAmount | ยอดที่คุณขอ |
amount | ยอดที่ผู้จ่ายต้องโอน (รวมเศษสตางค์ที่ระบบเพิ่ม) |
fee | ค่าธรรมเนียมรวมของรายการ |
method | ช่องทางที่ใช้จริง |
failureReason | ข้อความสั้นๆ เมื่อรายการไม่สำเร็จ เช่น หมดเวลา หรือถูกยกเลิก เป็น null ในกรณีอื่น |
checkoutUrl | หน้าชำระเงินสำเร็จรูป อาจเป็น null ถ้าบริการนี้ไม่ได้เปิดไว้ ให้แสดง payTo (หรือ QR code ที่สร้างจาก payTo.qrPayload) เองแทน |
payerAccount | บัญชีของผู้จ่ายที่ใช้กับรายการนี้ |
payTo | บัญชีหรือ wallet ปลายทางที่ผู้จ่ายต้องโอนเข้า และ qrPayload |
payTo.qrPayload | ข้อความใน QR code สำหรับ promptpay_qr / lao_qr กรณีอื่นเป็น null |
paymentImage | มีเฉพาะเมื่อใส่ ?include=paymentImage: รูป PNG แบบ data URI (QR code หรือบัตรข้อมูลการโอน) ใส่ใน <img> ได้ทันที |
ส่วนการคิดยอดให้ลูกค้าของคุณจาก requestedAmount หรือ amount ให้เป็นไปตามสัญญาที่ตกลงกับทีมงาน
| สถานะ | ความหมาย | สิ้นสุดหรือยัง |
|---|---|---|
pending | สร้างแล้ว รอผู้จ่ายโอน | ยัง |
processing | กำลังดำเนินการ | ยัง |
succeeded | จับคู่การโอนได้แล้ว (จาก statement ธนาคาร สลิป หรือยืนยันโดยเจ้าหน้าที่) | สิ้นสุด |
expired | ผู้จ่ายไม่โอนภายในเวลาที่กำหนด | สิ้นสุด (ยังยกเลิกได้) |
canceled | ถูกยกเลิกโดยคุณหรือโดยระบบ | สิ้นสุด |
rejected | ถูกปฏิเสธ | สิ้นสุด |
failed | ดำเนินการไม่สำเร็จ ดู failureReason | สิ้นสุด |
อัปเดตคำสั่งซื้อจาก webhook เป็นหลัก และใช้ GET ตรวจซ้ำเมื่อไม่แน่ใจ ดู Webhooks
ค้นหา pay-in
หัวข้อที่มีชื่อว่า “ค้นหา pay-in”GET /v1/payins?status=pending,processing&createdFrom=2026-01-01T00:00:00Z&limit=50| พารามิเตอร์ | คำอธิบาย |
|---|---|
status | สถานะเดียวหรือหลายสถานะคั่นด้วย , |
reference | ตรงกับ reference ทุกตัวอักษร |
payerId | เฉพาะรายการของ payer คนนี้ |
createdFrom, createdTo | ช่วงเวลาที่สร้าง ISO-8601 รวมขอบ |
limit, cursor | การแบ่งหน้า ดูภาพรวม |
ยกเลิก pay-in
หัวข้อที่มีชื่อว่า “ยกเลิก pay-in”POST /v1/payins/{id}/cancelไม่มี body (hash สตริงว่างตอนเซ็น) ยกเลิกได้เฉพาะรายการที่ pending หรือ expired คืน object ของ pay-in ที่มีสถานะ canceled การยกเลิกผ่าน API ไม่ส่ง webhook เพราะคุณได้ผลจาก response แล้ว
ข้อผิดพลาดที่พบบ่อย
หัวข้อที่มีชื่อว่า “ข้อผิดพลาดที่พบบ่อย”| HTTP | code | ความหมายและสิ่งที่ควรทำ |
|---|---|---|
| 400 | parameter_missing, parameter_invalid | ฟิลด์ขาดหรือรูปแบบผิด (รวมถึงไม่ส่งทั้ง payerId และ payer) ดู error.param |
| 400 | parameters_exclusive | ส่งทั้ง payerId และ payer มา ให้ส่งอย่างใดอย่างหนึ่ง |
| 400 | unsupported_currency, unsupported_method | สกุลเงินหรือช่องทางที่ไม่รองรับ |
| 400 | invalid_webhook_url, invalid_return_url | URL ไม่ใช่ http(s) หรือรูปแบบผิด |
| 403 | payins_disabled | บัญชีของคุณปิดการรับเงินอยู่ ติดต่อซัพพอร์ต |
| 404 | payer_not_found | payerId ไม่มีอยู่หรือไม่ใช่ของบัญชีคุณ |
| 422 | bank_not_found | payer.bankCode ไม่ใช่รหัสจาก GET /v1/banks |
| 404 | resource_not_found | ID ของ pay-in ไม่ถูกต้อง |
| 409 | pending_payin_exists | payer มี pay-in ที่รอจ่ายอยู่แล้ว |
| 409 | payin_not_cancelable | สถานะปัจจุบันยกเลิกไม่ได้ |
| 422 | amount_below_minimum, amount_above_maximum | ยอดนอกช่วงที่บัญชีกำหนด ข้อความระบุค่าขีดจำกัด |
| 422 | amount_below_fee | ยอดต่ำกว่าค่าธรรมเนียม |
| 422 | payer_inactive, payer_blocked | payer ถูกปิดหรือถูกระงับ |
| 422 | no_collection_account_available | ขณะนี้ไม่มีบัญชีรับเงินว่าง ลองใหม่ภายหลัง |
| 422 | not_available_now, maintenance | อยู่นอกเวลาให้บริการหรือปิดปรับปรุง ลองใหม่ภายหลัง |
รายการรหัสทั้งหมดดูที่รหัสข้อผิดพลาด