PayMeNow

รายการ Endpoint

รายละเอียดทุก endpoint ของ Payment API ทั้งการสร้างรายการรับเงิน จ่ายเงินออก ตรวจยอดคงเหลือ ยกเลิกรายการ และแนบสลิป

สร้างจาก public-api.md โดยอัตโนมัติเวอร์ชัน 1.2.0ปรับปรุงล่าสุด 2026-09-20

#สรุป Endpoint

MethodPathวัตถุประสงค์
POST/v1/payments/depositสร้างรายการรับเงิน (PromptPay QR)
POST/v1/payments/withdrawสร้างรายการจ่ายเงินออกเข้าบัญชีธนาคาร
GET/v1/payments/get-balanceสรุปยอดคงเหลือปัจจุบัน
GET/v1/payments/{id}ดึงข้อมูลรายการเดียว
POST/v1/payments/{id}/cancelยกเลิกรายการที่ยังรอชำระ
POST/v1/payments/{id}/upload-slipกู้รายการรับเงินที่ หมดอายุ ด้วยสลิปโอนเงิน
GET/v1/merchant-reports/*รายงานสำหรับ ERP — ดู merchant-reports-api.md
GET/health, /health/detailedตรวจสถานะเกตเวย์ (ไม่ต้องยืนยันตัวตน)
GET/sandbox/test, /sandbox/credentials, /sandbox/test-amountsตัวช่วยของ sandbox (เฉพาะโฮสต์ sandbox ไม่ต้องยืนยันตัวตน)

API รับ-จ่ายเงินไม่มี endpoint สำหรับค้นหาหรือแสดงรายการธุรกรรม และไม่มี endpoint สำหรับคืนเงิน หากต้องการดูประวัติแบบอ่านอย่างเดียว ให้ใช้ /v1/merchant-reports/transactions และ /v1/merchant-reports/refunds

#สร้างรายการรับเงิน (Create Deposit)

สร้างคำขอรับเงินรายการใหม่ ระบบจะคืน PromptPay QR สำหรับให้ลูกค้าชำระเงิน

POST /v1/payments/deposit → 201 Created

#Request Body

ฟิลด์ชนิดจำเป็นการตรวจสอบ / คำอธิบาย
amountnumberใช่ต้อง > 0 ที่เกตเวย์ ดูหัวข้อ ขีดจำกัดจำนวนเงิน ด้านล่าง
currencystringใช่ความยาว 3 ตัวอักษรพอดี ระบบประมวลผลเฉพาะ THB
reference_idstringใช่เลขอ้างอิงคำสั่งซื้อของคุณ ยาว 1–64 ตัวอักษร ไม่ มีการตัดรายการซ้ำ ดูหมายเหตุ
bank_codestringใช่รหัสธนาคาร ของผู้ชำระเงิน ความยาว 3 ตัวอักษรพอดี ดูหัวข้อรหัสธนาคาร
bank_account_nostringใช่เลขบัญชีธนาคาร ของผู้ชำระเงิน ยาว 10–20 ตัวอักษร
bank_account_namestringใช่ชื่อเจ้าของบัญชี ของผู้ชำระเงิน ยาว 1–100 ตัวอักษร
customer_emailstringไม่ต้องอยู่ในรูปแบบอีเมลที่ถูกต้อง
customer_phonestringไม่ยาวไม่เกิน 20 ตัวอักษร
descriptionstringไม่ยาวไม่เกิน 255 ตัวอักษร
webhook_urlstringไม่ต้องอยู่ในรูปแบบ URL ที่ถูกต้อง ระบบจะส่ง webhook ก็ต่อเมื่อมีฟิลด์นี้

การเปลี่ยนแปลงที่กระทบของเดิม — 2026-05-13: bank_code, bank_account_no และ bank_account_name เป็นฟิลด์ จำเป็น ให้ส่งข้อมูลธนาคารของ ผู้ฝากเงิน (ลูกค้า) มาด้วย เพื่อให้ระบบจับคู่การแจ้งเตือนจากธนาคารเข้ากับรายการที่ถูกต้อง คำขอที่ขาดฟิลด์ใดฟิลด์หนึ่ง ในสามฟิลด์นี้จะถูกปฏิเสธด้วย MISSING_PAYER_INFO (400) ดู Migration: payer info required

reference_id ไม่ใช่กุญแจกันรายการซ้ำ การส่ง reference_id เดิมซ้ำจะสร้าง รายการที่สองแยกอีกรายการหนึ่ง ระบบไม่มีการตรวจจับรายการซ้ำและไม่ตอบ 409 เมื่อส่งซ้ำ ดังนั้นอย่าสั่งรับเงินซ้ำเมื่อเกิด timeout ก่อนตรวจสอบว่ารายการแรกสำเร็จไปแล้วหรือยัง

#ขีดจำกัดจำนวนเงิน

เกตเวย์ตรวจเพียงว่า amount > 0 จากนั้นระบบชำระเงินจะบังคับเงื่อนไขเพิ่ม:

  • ขั้นต่ำเด็ดขาดที่ 50.00 บาท สำหรับการรับเงิน ใช้กับทุกบัญชีไม่ว่าตั้งค่าไว้อย่างไร
  • ขั้นต่ำและขั้นสูงของการรับเงินที่ตั้งไว้ในบัญชีร้านค้าของคุณ (ค่าเริ่มต้น 1 ถึง 1,000,000 บาท โดยขั้นต่ำเด็ดขาดด้านบนยังมีผลเหนือกว่าในฝั่งต่ำ)

หากผิดเงื่อนไขจะได้ 400 INVALID_AMOUNT พร้อมช่วงที่ใช้ได้จริงในข้อความ เช่น Amount must be between 50.00 and 1000000.00 THB

#ตัวอย่างคำขอ

json
{
  "amount": 1000.00,
  "currency": "THB",
  "reference_id": "ORD888888888",
  "bank_code": "004",
  "bank_account_no": "1234567890",
  "bank_account_name": "นาย ทดสอบ ตัวอย่าง",
  "webhook_url": "https://example.com/path/to/your/webhook"
}

#ข้อผิดพลาด: ข้อมูลผู้ชำระเงินไม่ครบ

json
{
  "code": "MISSING_PAYER_INFO",
  "message": "กรุณาส่งข้อมูลผู้ฝาก (bank_code, bank_account_no, bank_account_name) ครบทั้ง 3 ฟิลด์ — จำเป็นสำหรับการตรวจสอบรายการกับ SMS ของธนาคาร",
  "details": {
    "bank_code":         "ต้องระบุ — รหัสธนาคารผู้ฝาก 3 หลัก เช่น 004 (KBANK), 014 (SCB), 030 (TTB)",
    "bank_account_no":   "ต้องระบุ — เลขบัญชีผู้ฝาก 10-20 หลัก (ผู้ที่จะโอนเงินเข้ามา)",
    "bank_account_name": "ต้องระบุ — ชื่อบัญชีผู้ฝาก 1-100 ตัวอักษร"
  }
}

ค่าใน details ใช้ชื่อฟิลด์ JSON เป็นคีย์และเขียนคำอธิบายเป็นภาษาไทย หากฟิลด์อื่นนอกเหนือจาก สามฟิลด์ของผู้ชำระเงินไม่ผ่านการตรวจสอบ ค่า code ระดับบนสุดจะเป็น INVALID_REQUEST แทน

#Response

json
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "reference_id": "ORD888888888",
  "type": "deposit",
  "status": "pending",
  "amount": 1000.00,
  "paid_amount": 1000.37,
  "currency": "THB",
  "qr_code": "00020101021129370016A000000677010111011300668123456785802TH5303764...",
  "qr_code_image": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA...",
  "payment_url": "https://pay.paymenow.asia/p/THMTrerxgEc08n-tgadZ5a8FeIoIuwDHFo8OqmGsO-4",
  "created_at": "2026-09-20T17:30:00+07:00",
  "expires_at": "2026-09-20T17:40:00+07:00"
}

#ฟิลด์ใน Response

ฟิลด์ชนิดคำอธิบาย
idstringรหัสรายการที่ไม่ซ้ำ (UUID)
reference_idstringเลขอ้างอิงคำสั่งซื้อของคุณ
typestringdeposit
statusstringเป็น pending เมื่อสร้าง (ใน sandbox อาจคืนสถานะสุดท้ายมาทันที)
amountnumberจำนวนเงินที่คุณขอมา
paid_amountnumberจำนวนเงินที่ลูกค้าต้องโอนจริง ดูคำอธิบายด้านล่าง
currencystringรหัสสกุลเงิน
qr_codestringข้อความ payload ของ PromptPay QR
qr_code_imagestringรูป QR แบบ data:image/png;base64,… (เฉพาะ production ส่วน sandbox เป็นค่าว่าง)
payment_urlstringหน้าชำระเงินที่โฮสต์ให้สำหรับรายการนี้ — ดูด้านล่าง ได้ "" เมื่อไม่ได้ตั้งค่า
created_atstringเวลาที่สร้างรายการ (RFC 3339 เวลาไทย)
expires_atstringเวลาที่หมดอายุ (RFC 3339 เวลาไทย ค่าเริ่มต้น 10 นาที)

paid_amount คือจำนวนเงินที่ต้องโอนจริง ระบบจับคู่รายการรับเงินกับการแจ้งเตือนของธนาคาร ด้วยบัญชีผู้โอนร่วมกับจำนวนเงินระดับ สตางค์ที่ไม่ซ้ำกัน ตัว QR จึงเข้ารหัสยอด amount บวกเศษสตางค์สุ่มเล็กน้อย ให้แสดง paid_amount (หรือ QR) แก่ลูกค้าเสมอ อย่าแสดง amount มิฉะนั้นการโอนอาจจับคู่ไม่ได้ ส่วนใน sandbox ค่า paid_amount จะเท่ากับ amount

#payment_url — หน้าชำระเงินที่แพลตฟอร์มโฮสต์ให้

แทนที่จะเรนเดอร์ QR เอง ส่งลิงก์นี้ให้ลูกค้าได้เลย หน้านี้แพลตฟอร์มเป็นผู้ให้บริการ มีทั้งภาษาไทยและอังกฤษ และจัดการส่วนที่พลาดกันบ่อยให้:

  • แสดงถูกตามบัญชีที่ได้รับ แพลตฟอร์มหมุนบัญชีรับเงินให้แต่ละรายการ ถ้าบัญชีนั้นมีเลข PromptPay หน้าจะแสดง QR ถ้าไม่มีจะแสดงเลขบัญชีพร้อมปุ่มคัดลอก คุณไม่ต้องเขียนเงื่อนไขเอง และกรณีหลัง qr_code อย่างเดียวบอกไม่ได้
  • แสดงยอดที่ต้องโอนแบบตรงทุกสตางค์ ปุ่มคัดลอกจะคัดลอก 1000.37 ไม่ใช่ 1,000.37 ที่แอปธนาคารไม่รับ
  • บอกว่าต้องโอนจากบัญชีไหน การจับคู่ใช้บัญชีต้นทางและเศษสตางค์ร่วมกัน หน้านี้จึงย้ำ ธนาคารและเลข 4 ตัวท้ายของบัญชีที่ลูกค้าแจ้งไว้ เงินที่โอนจากบัญชีอื่นจะเข้าแต่จับคู่ไม่ได้
  • บันทึกรูป QR ได้ ลิงก์มักถูกเปิดบนมือถือเครื่องเดียวกับแอปธนาคาร ซึ่งสแกนหน้าจอตัวเองไม่ได้ บันทึกรูปแล้วเลือกจากคลังภาพในแอปได้เลย
  • อัปเดตตัวเอง หน้าจะเปลี่ยนเป็น "ชำระเงินสำเร็จ" เองโดยไม่ต้องรีเฟรช และมีนับถอยหลังถึง expires_at
  • ให้ลูกค้ายืนยันการโอนเองได้ ทั้งระหว่างที่ QR ยังไม่หมดเวลาและหลังหมดเวลาแล้ว ลูกค้าอัปโหลด สลิปได้ ระบบตรวจยอด บัญชีปลายทาง ธนาคารต้นทาง และอายุสลิป (ไม่เกิน 24 ชม.) แล้วปิดรายการให้ทันที ตรงนี้คือความต่างระหว่างการโอนช้าที่ได้รับเครดิต กับการโอนช้าที่กลายเป็นเรื่องร้องเรียน

ให้ถือว่าลิงก์นี้เป็นความลับ กุญแจเดียวของมันคือโทเคนสุ่มขนาด 256 บิตที่สร้างเฉพาะรายการนั้น ไม่ใช่รหัสรายการ และไม่ปรากฏในฟิลด์อื่นใด ใครถือลิงก์ก็เห็นยอดเงิน บัญชีรับเงิน และสถานะ จึงควรส่งให้ลูกค้าผ่านช่องทางเดียวกับที่คุณส่งใบแจ้งหนี้ และอย่าใส่ไว้ใน log ที่แชร์ออกไป ในระบบวิเคราะห์ข้อมูล หรือหน้าที่ search engine เข้าถึงได้

สิ่งที่หน้านั้นไม่เปิดเผย: ชื่อร้านค้า ค่าธรรมเนียม และเลขบัญชีเต็มของผู้โอน (ปิดบังเหลือ 4 ตัวท้าย) ข้อมูลที่หน้านั้นได้รับแคบกว่าที่ API นี้คืนให้โดยตั้งใจ

รูปแบบการแสดงผล เป็นไปตามที่ร้านค้าตั้งไว้ในแดชบอร์ดร้านค้า (ตั้งค่า › ทั่วไป › หน้าชำระเงินของลูกค้า) — สว่าง มืด หรือตามเครื่องของลูกค้า ไม่ต้องส่งค่าใดมาที่นี่

ร้านค้าปิดการใช้งานได้ ที่แดชบอร์ดร้านค้า ตั้งค่า › ทั่วไป สวิตช์นี้เปลี่ยนสองอย่างพร้อมกัน และแยกจากกันไม่ได้:

เปิด (ค่าเริ่มต้น)ปิด
payment_urlลิงก์หน้าชำระเงิน""
บัญชีรับเงินที่ระบบเลือกใช้ทุกบัญชีที่ตั้งไว้ว่ารับฝากเฉพาะบัญชีที่มีพร้อมเพย์
qr_code / qr_code_imageคืนให้คืนให้

กติกาเรื่องบัญชีเป็นผลจากฟิลด์นั้นโดยตรง เมื่อเปิดหน้าชำระเงิน บัญชีที่ไม่มีเลขพร้อมเพย์ยังใช้ได้ เพราะหน้านั้นจะแสดงเลขบัญชีให้โอนแทน QR แต่เมื่อปิด คุณต้องนำ qr_code ไปแสดงเอง ซึ่งบัญชีแบบนั้น สร้าง QR ไม่ได้ การส่งลูกค้าไปที่บัญชีนั้นจึงเท่ากับส่งไปที่หน้าจอว่าง ระบบจึงจำกัดการหมุนบัญชี ให้เหลือเฉพาะบัญชีที่มีพร้อมเพย์ตลอดเวลาที่ปิดอยู่

สิ่งที่ระบบของคุณต้องรองรับ: ถ้าคุณเรนเดอร์ QR เอง ให้คาดหวังว่า payment_url เป็น "" แล้วข้ามไป ถ้าคุณใช้ลิงก์ อย่าบังคับว่า qr_code ต้องไม่ว่าง เพราะเมื่อเปิดหน้าชำระเงิน รายการหนึ่งอาจไม่มี QR เลย โดยถูกต้อง และลิงก์คือทางเดียวที่จ่ายได้ — อ่านทั้งสองฟิลด์แล้วเลือกอันที่มีค่า ใช้ได้ทุกกรณี

และจะได้ "" เช่นกันเมื่อการติดตั้งนั้นไม่มีหน้านี้เลย

#สร้างรายการจ่ายเงินออก (Create Withdraw)

สร้างคำขอถอน/จ่ายเงินออกไปยังบัญชีธนาคาร

POST /v1/payments/withdraw → 201 Created

การจ่ายเงินออกใช้เงินจากยอดคงเหลือที่ใช้ได้ของคุณ ระบบจะกันยอด (จำนวนเงิน + ค่าธรรมเนียม) ไว้ล่วงหน้า หากยอดคงเหลือไม่พอ คำขอจะถูกปฏิเสธทันที

#Request Body

ฟิลด์ชนิดจำเป็นการตรวจสอบ / คำอธิบาย
amountnumberใช่ต้อง > 0 ที่เกตเวย์ ขั้นต่ำเด็ดขาด 100.00 บาท และต้องอยู่ในช่วงขั้นต่ำ/ขั้นสูงที่ตั้งไว้ในบัญชีของคุณ
currencystringใช่ความยาว 3 ตัวอักษรพอดี
reference_idstringใช่เลขอ้างอิงของคุณ ยาว 1–64 ตัวอักษร ไม่มีการตัดรายการซ้ำ
bank_codestringใช่ความยาว 3 ตัวอักษรพอดี ดูหัวข้อรหัสธนาคาร
account_numberstringใช่เลขบัญชีปลายทาง ยาว 10–20 ตัวอักษร
account_holder_namestringใช่ชื่อเจ้าของบัญชีปลายทาง ยาว 1–100 ตัวอักษร
webhook_urlstringไม่ต้องอยู่ในรูปแบบ URL ที่ถูกต้อง ระบบส่ง webhook ก็ต่อเมื่อมีฟิลด์นี้

การจ่ายเงินออกไม่มีฟิลด์ description — ตัวถอดรหัส JSON รับค่านี้ได้แต่ระบบจะไม่นำไปใช้

การกันจ่ายซ้ำ หากมีรายการจ่ายเงินออกที่เหมือนกันทุกประการ (ร้านค้าเดียวกัน รหัสธนาคาร เลขบัญชี และจำนวนเงินเดียวกัน) ถูกสร้างขึ้นภายใน 5 นาที ที่ผ่านมา รายการใหม่จะ ไม่ถูกส่งออก แต่จะถูกสร้างไว้ กันยอดไว้ และรออยู่ในสถานะ pending เพื่อให้ตรวจสอบด้วยคน มาตรการนี้กันกรณีที่ระบบต้นทางส่งซ้ำด้วย reference_id ใหม่แล้วทำให้จ่ายเงินซ้ำสองครั้ง ให้ติดตามผลด้วย GET /v1/payments/{id} หรือรอ webhook แทนการส่งคำขอซ้ำ

#รหัสธนาคาร

รหัสเหล่านี้คือรหัสที่ระบบรู้จักเมื่อต้องแปลงเป็นชื่อธนาคาร (bankName) ใน webhook ให้ส่งเป็นรหัสธนาคาร 3 หลักของธนาคารแห่งประเทศไทย

CodeThai NameEnglish Name
002ธนาคารกรุงเทพBangkok Bank PCL (BBL)
004ธนาคารกสิกรไทยKasikornbank PCL (KBank)
006ธนาคารกรุงไทยKrungthai Bank PCL (KTB)
011ธนาคารทหารไทยธนชาตTMBThanachart Bank PCL (TTB)
014ธนาคารไทยพาณิชย์Siam Commercial Bank PCL (SCB)
017ธนาคารซิตี้แบงก์Citibank N.A.
020ธนาคารสแตนดาร์ดชาร์เตอร์ด (ไทย)Standard Chartered Bank (Thai) PCL
022ธนาคารซีไอเอ็มบี ไทยCIMB Thai Bank PCL
024ธนาคารยูโอบีUnited Overseas Bank (Thai) PCL
025ธนาคารกรุงศรีอยุธยาBank of Ayudhya PCL (Krungsri)
026ธนาคารเมกะสากลพาณิชย์Mega International Commercial Bank
030ธนาคารออมสินGovernment Savings Bank (GSB)
031ธนาคารฮ่องกงและเซี่ยงไฮ้HSBC Thailand
032ธนาคารดอยซ์แบงก์Deutsche Bank
033ธนาคารอาคารสงเคราะห์Government Housing Bank (GHB)
034ธนาคารเพื่อการเกษตรฯBAAC
039ธนาคารมิซูโฮMizuho Bank
045ธนาคารบีเอ็นพี พารีบาส์BNP Paribas
052ธนาคารแห่งประเทศจีนBank of China (Thai)
065ธนาคารธนชาตThanachart Bank PCL
066ธนาคารอิสลามแห่งประเทศไทยIslamic Bank of Thailand
067ธนาคารทิสโก้TISCO Bank PCL
069ธนาคารเกียรตินาคินภัทรKiatnakin Phatra Bank PCL (KKP)
070ธนาคารไอซีบีซี (ไทย)ICBC (Thai) PCL
071ธนาคารไทยเครดิตThai Credit Retail Bank
073ธนาคารแลนด์ แอนด์ เฮ้าส์Land and Houses Bank PCL (LH Bank)

รหัสที่อยู่นอกตารางนี้ระบบยังรับได้ตราบใดที่ยาว 3 ตัวอักษรพอดี แต่ค่า bankName ใน webhook จะสะท้อนกลับเป็นตัวรหัสนั้นเอง

#การจ่ายเงินออกแบบ PromptPay — ยังไม่รองรับผ่าน API นี้

ระบบตรวจ bank_code ว่าต้อง ยาว 3 ตัวอักษรพอดี ค่าตรงตัวอย่าง PROMPTPAY จึงถูกปฏิเสธ ด้วย 400 INVALID_REQUEST แม้ผู้ให้บริการจ่ายเงินปลายทางจะรองรับ PromptPay proxy อยู่ (เลขบัญชี 10 หลักจะถูกส่งเป็น proxy แบบ MOBILE ส่วนที่ยาวกว่านั้นเป็น TXID) แต่ปัจจุบันยังเรียกใช้เส้นทางนั้นผ่าน public API ไม่ได้ ให้ใช้รหัสธนาคารกับเลขบัญชีธนาคารแทน

#ตัวอย่างคำขอ

json
{
  "amount": 5000.00,
  "currency": "THB",
  "reference_id": "ORD888888889",
  "bank_code": "014",
  "account_number": "1234567890",
  "account_holder_name": "John Doe",
  "webhook_url": "https://example.com/path/to/your/webhook"
}

#Response

json
{
  "id": "660e8400-e29b-41d4-a716-446655440000",
  "reference_id": "ORD888888889",
  "type": "withdraw",
  "status": "pending",
  "amount": 5000.00,
  "currency": "THB",
  "created_at": "2026-09-20T18:00:00+07:00"
}

ค่า status ตอนสร้างจะเป็น pending เมื่อรายการเข้าคิวรอตรวจสอบหรือถูกกันไว้เพราะสงสัยว่าซ้ำ และเป็น processing เมื่อส่งต่อให้ผู้ให้บริการจ่ายเงินแล้ว ทั้งสองค่ายังไม่ใช่สถานะสุดท้าย ให้รอ webhook หรือติดตามผลเอง

การจ่ายเงินออกจะไม่คืนค่า qr_code, qr_code_image, paid_amount หรือ expires_at

#ตัวอย่างโค้ด

#Python
python
# Create withdraw
response = make_request("POST", "/v1/payments/withdraw", {
    "amount": 5000.00,
    "currency": "THB",
    "reference_id": "ORD888888889",
    "bank_code": "014",
    "account_number": "1234567890",
    "account_holder_name": "John Doe",
    "webhook_url": "https://example.com/path/to/your/webhook"
})
print(response.json())
#Node.js
javascript
// Create withdraw
makeRequest("POST", "/v1/payments/withdraw", {
  amount: 5000.0,
  currency: "THB",
  reference_id: "ORD888888889",
  bank_code: "014",
  account_number: "1234567890",
  account_holder_name: "John Doe",
  webhook_url: "https://example.com/path/to/your/webhook",
}).then((res) => console.log(res.data));
#PHP
php
// Create withdraw
$response = makeRequest('POST', '/v1/payments/withdraw', [
    'amount' => 5000.00,
    'currency' => 'THB',
    'reference_id' => 'ORD888888889',
    'bank_code' => '014',
    'account_number' => '1234567890',
    'account_holder_name' => 'John Doe',
    'webhook_url' => 'https://example.com/path/to/your/webhook'
]);
print_r($response);
#Go
go
// Create withdraw
result, _ := makeRequest("POST", "/v1/payments/withdraw", map[string]interface{}{
    "amount":              5000.00,
    "currency":            "THB",
    "reference_id":        "ORD888888889",
    "bank_code":           "014",
    "account_number":      "1234567890",
    "account_holder_name": "John Doe",
    "webhook_url":         "https://example.com/path/to/your/webhook",
})
fmt.Printf("%+v\n", result)

#ดูยอดคงเหลือ (Get Balance)

คืนสรุปยอดคงเหลือของร้านค้าที่เรียกใช้ ตาม environment ของร้านค้านั้น

GET /v1/payments/get-balance → 200 OK

ไม่มีพารามิเตอร์ — ระบบดูว่าเป็นร้านค้าใดจาก API key

json
{
  "available_balance": 125340.50,
  "pending_balance": 3000.00,
  "total_deposited": 980000.00,
  "total_withdrawn": 854659.50
}
ฟิลด์ชนิดคำอธิบาย
available_balancenumberเงินที่ถอนออกได้ทันที
pending_balancenumberเงินที่ถูกกันไว้โดยรายการถอนที่กำลังดำเนินการ หรือยังไม่เคลียร์
total_depositednumberยอดรับเงินสะสมทั้งหมด
total_withdrawnnumberยอดจ่ายเงินออกสะสมทั้งหมด

การเซ็นทำเหมือน GET อื่น ๆ คือ GET|/v1/payments/get-balance|<timestamp>

#ดูรายการชำระเงิน (Get Payment)

ดึงรายละเอียดของรายการชำระเงินจากรหัสรายการ

GET /v1/payments/{id} → 200 OK

#พารามิเตอร์ใน path

พารามิเตอร์ชนิดคำอธิบาย
idstringรหัสรายการ (UUID) ที่ได้ตอนสร้างรายการ

การค้นหาจำกัดอยู่เฉพาะร้านค้าของคุณและ environment ของคุณ หากเป็นรายการของร้านค้าอื่น ระบบจะตอบ 404 NOT_FOUND เหมือนกับกรณีที่ไม่มีรายการนั้นอยู่จริง

#ตัวอย่าง Response

json
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "reference_id": "ORD888888888",
  "type": "deposit",
  "status": "completed",
  "amount": 1500.00,
  "currency": "THB",
  "created_at": "2026-09-20T17:30:00+07:00",
  "expires_at": "2026-09-20T17:40:00+07:00"
}

ข้อมูล QR คืนให้เฉพาะตอนสร้างรายการเท่านั้น endpoint นี้ ไม่ คืน qr_code, qr_code_image, paid_amount และ payment_url ให้เก็บค่าเหล่านี้จาก response ตอนสร้างรายการรับเงินไว้เอง ส่วน expires_at จะไม่มีในรายการจ่ายเงินออก

API รับ-จ่ายเงินไม่มีการค้นหาด้วย reference_id หากต้องการค้นด้วยเลขที่คำสั่งซื้อของคุณเอง ให้ใช้ GET /v1/merchant-reports/transactions?q=<order id>

#ยกเลิกรายการ (Cancel Payment)

ยกเลิกรายการที่ยังรอชำระ ยกเลิกได้เฉพาะรายการที่สถานะเป็น pending เท่านั้น สถานะอื่นจะได้ 400 PAYMENT_CANNOT_BE_CANCELLED

POST /v1/payments/{id}/cancel → 200 OK

คำขอนี้ ไม่มี body จึงเซ็นเพียงสามส่วน: POST|/v1/payments/<id>/cancel|<timestamp>

#พารามิเตอร์ใน path

พารามิเตอร์ชนิดคำอธิบาย
idstringรหัสรายการที่ต้องการยกเลิก

#ตัวอย่าง Response

json
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "reference_id": "ORD888888888",
  "type": "deposit",
  "status": "failed",
  "amount": 1500.00,
  "currency": "THB",
  "created_at": "2026-09-20T17:30:00+07:00"
}

รายการที่ยกเลิกแล้วจะรายงานสถานะเป็น status: "failed" โดยมีเหตุผลความล้มเหลว ภายในระบบว่า Cancelled by merchant API จะไม่คืนสถานะ cancelled สำหรับรายการ ที่สร้างผ่าน API นี้ ให้ถือว่า failed หลังการยกเลิกสำเร็จคือ "ยกเลิกโดยฉันเอง"

#อัปโหลดสลิป (กู้รายการรับเงินที่หมดอายุ)

อัปโหลดรูปสลิปโอนเงินให้กับรายการรับเงินที่เข้าสู่สถานะ expired แล้ว เพื่อให้ระบบตรวจสอบ และเข้ายอดให้ โดยไม่ต้องผ่านแดชบอร์ดหรือผู้ดูแลระบบ

POST /v1/payments/{id}/upload-slip → 200 OK ชนิดเนื้อหา: multipart/form-data มีฟิลด์ไฟล์เดียวชื่อ file (ไม่เกิน 10 MB)

#รูปแบบลายเซ็นที่ต่างออกไป

body แบบ multipart ไม่สามารถสร้างซ้ำให้ตรงกันทุกไบต์ได้ในทุก HTTP client เส้นทางนี้ จึงเซ็น ค่าแฮชของไฟล์ แทน body:

text
SignatureData = METHOD|PATH|TIMESTAMP|X-Content-SHA256

X-Content-SHA256 คือ SHA-256 ของไบต์ไฟล์ในรูปเลขฐานสิบหกตัวพิมพ์เล็ก และเป็นค่าที่ จำเป็นต้องส่ง เซิร์ฟเวอร์จะคำนวณแฮชของไฟล์ที่ได้รับใหม่และปฏิเสธหากไม่ตรงกัน

bash
TXN_ID="550e8400-e29b-41d4-a716-446655440000"
REQ_PATH="/v1/payments/$TXN_ID/upload-slip"
TS=$(date +%s)
HASH=$(sha256sum slip.jpg | cut -d' ' -f1)
SIG=$(printf "POST|%s|%s|%s" "$REQ_PATH" "$TS" "$HASH" \
      | openssl dgst -sha256 -hmac "$SECRET_KEY" -hex | sed 's/^.* //')

curl -X POST "https://api.paymenow.asia$REQ_PATH" \
  -H "X-API-Key: $API_KEY" \
  -H "X-Timestamp: $TS" \
  -H "X-Content-SHA256: $HASH" \
  -H "X-Signature: $SIG" \
  -F "[email protected]"

#กติกา

  • รายการต้องอยู่ในสถานะ expired เท่านั้น หากเป็น pending หรือสำเร็จไปแล้ว ระบบจะปฏิเสธโดยไม่ตรวจสลิปเลย
  • ต้องอัปโหลดสลิปภายใน 24 ชั่วโมง นับจากเวลาที่รายการหมดอายุ
  • เมื่ออัปโหลดสำเร็จ รายการจะเปลี่ยนเป็น completed และเข้ายอดคงเหลือทันที หากอัปโหลดซ้ำจะได้ NOT_ELIGIBLE และจะไม่มีการเข้ายอดซ้ำ — หนึ่งสลิปเข้ายอดได้ครั้งเดียว

#Response

json
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "reference": "ORD888888888",
  "type": "deposit",
  "status": "completed",
  "amount": 1000.00,
  "fee": 25.00,
  "net_amount": 975.00,
  "currency": "THB",
  "slip_trans_ref": "01490000...",
  "credited": true
}

#เหตุผลที่ถูกปฏิเสธ

HTTPcodeความหมาย
400NOT_ELIGIBLEรายการไม่ได้อยู่ในสถานะ expired
400EXPIRED_TOO_OLDเลย 24 ชั่วโมงนับจากเวลาหมดอายุแล้ว
400AMOUNT_MISMATCHจำนวนเงินในสลิปไม่ตรงกับรายการ
400RECEIVER_NOT_RECOGNIZEDสลิปไม่ได้โอนเข้าบัญชีรับเงินของรายการนี้
400SLIP_TOO_OLDเวลาโอนบนสลิปอยู่นอกช่วงที่อนุญาต
400SLIP_ALREADY_USEDสลิปนี้ถูกใช้ไปแล้ว (โดยคุณเองหรือร้านค้าอื่น)
400PAYER_BANK_MISMATCHธนาคารต้นทางบนสลิปต่างจากธนาคารของผู้ชำระเงินที่แจ้งไว้
400SLIP_INVALIDอ่านสลิปไม่ได้ หรือไม่ใช่สลิปที่ถูกต้อง
400CONTENT_HASH_MISMATCHไบต์ของไฟล์ที่อัปโหลดไม่ตรงกับ X-Content-SHA256
400FILE_REQUIREDไม่มีฟิลด์ file ใน body แบบ multipart
401MISSING_CONTENT_HASHไม่มี header X-Content-SHA256
404NOT_FOUNDไม่พบรายการรหัสนี้ของร้านค้าคุณ
413FILE_TOO_LARGEไฟล์ใหญ่เกิน 10 MB

#รายงานสำหรับร้านค้า (ERP)

GET /v1/merchant-reports/daily-summary, /transactions, /statement, /statement/entries และ /refunds ยืนยันตัวตนเหมือน API รับ-จ่ายเงินทุกประการ (คีย์เดียวกัน ลายเซ็นแบบเดียวกัน รายการ IP ชุดเดียวกัน) และให้บริการบนโฮสต์เดียวกัน คืนข้อมูลเป็น JSON, CSV หรือ XLSX มีโควตาการเรียกแยกของตัวเองต่อร้านค้า และเป็นวิธีที่ รองรับอย่างเป็นทางการสำหรับการดึงรายการธุรกรรม กระทบยอดคงเหลือ และดูประวัติการคืนเงิน

รายละเอียดทั้งหมดอยู่ใน Merchant Reports API (ERP)

#Health

GET /health และ GET /health/detailed ไม่ต้องยืนยันตัวตน และรายงานว่าเกตเวย์กับ Redis ที่เกตเวย์ใช้งานอยู่ทำงานปกติหรือไม่:

json
{ "status": "healthy", "environment": "production" }

หากมีส่วนประกอบใดล่มจะตอบ 503 พร้อม "status": "unhealthy" ค่าเหล่านี้สะท้อนเฉพาะ ตัวโปรเซสของ API gateway เท่านั้น ไม่ใช่หน้าสถานะของทั้งแพลตฟอร์ม และไม่ได้บอกอะไร เกี่ยวกับผู้ให้บริการชำระเงินหรือการเชื่อมต่อกับธนาคาร

หน้านี้แปลจากเอกสารต้นฉบับภาษาอังกฤษ ส่วนที่เป็นค่าทางเทคนิค — path, ชื่อฟิลด์, header, รหัสข้อผิดพลาด และชื่อคอลัมน์ในไฟล์ส่งออก — คงไว้เป็นภาษาอังกฤษตามที่ระบบใช้จริง