Merchant Integration · v1
คู่มือหลังบ้านภาษาไทย → · เข้าสู่ระบบ
คู่มือเชื่อมต่อระบบรับชำระเงินสำหรับร้านค้า — สร้างรายการ รับ QR PromptPay และรับแจ้งผลผ่าน webhook
ทุก request ที่ขึ้นต้นด้วย /v1/ ต้องแนบ API key ของร้านใน header:
X-Api-Key: gw_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
gw_live_ ใช้ฝั่งเซิร์ฟเวอร์เท่านั้น ห้ามฝังในเว็บ/แอปฝั่งลูกค้า หากรั่วให้แจ้งเพื่อ rotate ทันที (ระบบออก key ใหม่พร้อม webhook secret ใหม่ในคราวเดียว — key เดิมและ secret เดิมใช้ไม่ได้ทันที)POST /v1/payments ระบุยอดเงิน → ได้ checkout_url (หน้าจ่ายเงินพร้อม QR) และ qr_data_url (รูป QR)checkout_url หรือฝัง QR เอง — ลูกค้าสแกนจ่ายด้วยแอปธนาคาร (PromptPay)payment.paid มาที่ URL ที่ร้านตั้งไว้ (เซ็นด้วย HMAC)Idempotency-Key (สตริงไม่ซ้ำต่อ 1 ออร์เดอร์ เช่นเลขออร์เดอร์ของร้าน) — ยิงซ้ำด้วย key เดิมจะได้รายการเดิม ไม่เกิดรายการซ้ำ| Header | คำอธิบาย | |
|---|---|---|
| X-Api-Key | จำเป็น | API key ของร้าน |
| Idempotency-Key | จำเป็น | สตริงไม่ซ้ำต่อออร์เดอร์ (1–128 ตัวอักษร) |
| Content-Type | จำเป็น | application/json |
| Field | Type | คำอธิบาย | |
|---|---|---|---|
| amount | number | จำเป็น | ยอดเงิน (บาท) ตั้งแต่ 20 ถึง 100,000 ทศนิยมไม่เกิน 2 ตำแหน่ง (วงเงินต่อรายการของ Alpha / Quest PROD; นอกช่วงตอบ 422 invalid_amount) |
| merchant_ref | string | จำเป็น | รหัสอ้างอิงของร้าน (1–64 ตัวอักษร) เช่นเลขออร์เดอร์ |
| description | string | ไม่บังคับ | คำอธิบายรายการ (≤255) |
| return_url | string | ไม่บังคับ | URL ให้ลูกค้ากลับหลังชำระ (ต้องเป็น http/https) |
curl -X POST https://gateway.alphaquestcom.com/v1/payments \
-H "X-Api-Key: gw_live_xxxxxxxx" \
-H "Idempotency-Key: ORDER-10023" \
-H "Content-Type: application/json" \
-d '{"amount": 800.00, "merchant_ref": "ORDER-10023"}'
{
"payment_id": "pay_01M1J9...",
"status": "pending",
"amount": 300,
"currency": "THB",
"checkout_url": "https://gateway.alphaquestcom.com/p/pay_01M1J9...",
"qr_data_url": "data:image/png;base64,iVBOR...",
"fee_amount": null,
"net_amount": null
}
fee_amount / net_amount เป็น null จนกว่าจะชำระสำเร็จ (ค่าธรรมเนียมคำนวณตอนจ่ายจริง)
curl https://gateway.alphaquestcom.com/v1/payments/pay_01M1J9... \
-H "X-Api-Key: gw_live_xxxxxxxx"
คืน object เดียวกับตอนสร้าง โดย status เป็นค่าใดค่าหนึ่ง:
pending รอชำระ · paid ชำระแล้ว · cancelled ยกเลิก · expired หมดอายุ (ไม่จ่ายใน 60 นาที)
ยกเลิกได้เฉพาะรายการที่ยังไม่ชำระ — ถ้าจ่ายไปแล้วจะได้ 409 already_paid
curl -X POST https://gateway.alphaquestcom.com/v1/payments/pay_01M1J9.../cancel \
-H "X-Api-Key: gw_live_xxxxxxxx"
ยอดสุทธิสะสมของร้าน (หลังหักค่าธรรมเนียม)
{ "balance": 1782.50, "currency": "THB" }
balance เป็นตัวเลข JSON ซึ่งแสดงค่าได้ถูกต้องไม่เกิน 15 หลัก (รวมทศนิยม 2 ตำแหน่ง) หากยอดเกินกว่านั้น endpoint จะตอบ HTTP 500 พร้อม {"error":"...","code":"balance_not_representable"} แทนการส่งตัวเลขที่ถูกปัดเศษ ให้ตรวจยอดจริงในหน้าหลังบ้าน
เมื่อสถานะรายการเปลี่ยน ระบบยิง POST ไปที่ webhook URL ของร้าน (ตั้งค่าตอนสมัคร) พร้อม headers:
| Header | ค่า |
|---|---|
| X-Gateway-Event | payment.paid หรือ payment.cancelled |
| X-Gateway-Signature | sha256=<hex> — HMAC-SHA256 ของ raw body ด้วย webhook secret |
payment.paid{
"event": "payment.paid",
"payment_id": "pay_01M1J9...",
"merchant_ref": "ORDER-10023",
"amount": 300,
"paid_amount": 300,
"fee_amount": 3,
"net_amount": 297,
"currency": "THB",
"paid_at": "2026-09-03T09:42:09.382Z"
}
payment.cancelled{
"event": "payment.cancelled",
"payment_id": "pay_01M1J9...",
"merchant_ref": "ORDER-10023",
"amount": 300,
"status": "cancelled" // หรือ "expired"
}
const crypto = require('crypto')
// rawBody = ตัว body ดิบ (Buffer/string) ก่อน JSON.parse
function verify(rawBody, signatureHeader, webhookSecret) {
const expected = 'sha256=' +
crypto.createHmac('sha256', webhookSecret)
.update(rawBody, 'utf8').digest('hex')
return crypto.timingSafeEqual(
Buffer.from(expected), Buffer.from(signatureHeader))
}
18.136.50.160 เสมอ — เปิดรับได้เฉพาะ IP นี้ · ควรตอบ 200 ทันทีที่รับได้ แล้วค่อยประมวลผลเบื้องหลังข้อผิดพลาดคืน JSON รูปแบบ { "error": "...", "code": "..." }
| HTTP | code | ความหมาย |
|---|---|---|
| 401 | invalid_api_key | API key ผิดหรือร้านถูกปิด |
| 403 | merchant_suspended | ร้านถูกระงับ |
| 403 | ip_not_allowed | IP ต้นทางไม่อยู่ในรายการที่ร้านอนุญาตไว้ |
| 422 | missing_idempotency_key | ไม่ได้แนบ Idempotency-Key |
| 422 | invalid_amount | amount ไม่ถูกต้อง (20–100,000 บาทต่อรายการ ทศนิยมไม่เกิน 2 ตำแหน่ง) |
| 409 | idempotency_conflict | ใช้ Idempotency-Key เดิมแต่ยอดเงินไม่ตรง |
| 409 | already_paid | ยกเลิกรายการที่ชำระแล้วไม่ได้ |
| 404 | — | ไม่พบรายการ (route not found) |
| 502 | — | ระบบชำระเงินปลายทางขัดข้องชั่วคราว |
ภาพประกอบจากหน้าจอ Quest วันที่ 15 กันยายน 2026 ใช้ร้านที่ยังไม่มีรายการชำระและยังไม่ได้ตั้งบัญชีธนาคาร จึงแสดงยอดศูนย์หรือไม่มีรายการ ชื่อร้านและข้อมูลบนหน้าจอของคุณอาจต่างจากภาพ
ชื่อผู้ใช้ข้างต้นใช้สำหรับล็อกอิน ไม่ได้หมายความว่ามีกล่องอีเมลสำหรับรับส่งข้อความ เมื่อเลิกใช้งานเครื่องที่ใช้ร่วมกับคนอื่น ให้กดออกจากระบบ
| สิ่งที่ต้องการทำ | เมนู |
| ดูยอดรับและภาพรวมร้าน | ภาพรวม |
| หารายการของลูกค้า ตรวจว่าจ่ายหรือยัง | รายการชำระเงิน |
| ตั้งบัญชีรับเงินและดูรอบโอน | ยอดจ่ายและบัญชี |
| เพิ่มคนเข้ามาช่วยดูร้าน | สมาชิก |
| เปิดร้านย่อยแยกจากร้านหลัก | ร้านลูก |
| ตรวจว่า Quest ส่งผลชำระไปให้เว็บร้านหรือยัง | Webhooks |
| ดูว่าใครทำอะไรในระบบ | ประวัติการใช้งาน |
ทุกครั้งที่มีช่องเลือกร้าน ให้ตรวจว่าเลือกร้านหลักหรือร้านลูกที่ต้องการอยู่ คำว่า “ทุกร้าน” หมายถึงร้านในสิทธิ์ของบัญชีคุณ
หน้าจอจะแสดงยอดหลัก 3 ช่อง:
ตัวเลขเหล่านี้เป็นยอดสะสม ไม่ใช่ยอดเงินที่จะโอนเข้าธนาคารวันนี้ หากต้องการดูเงินที่จะได้รับ ให้ไป ยอดจ่ายและบัญชี
กราฟแนวโน้มแสดงยอดรับ 30 วันล่าสุด ส่วนรายการล่าสุดช่วยให้เห็นรายการที่เพิ่งเกิดขึ้น กด ดูรายการทั้งหมด เพื่อค้นหารายการเพิ่มเติม
ถ้าไม่พบ ให้ล้างข้อความค้นหา ขยายช่วงวันที่ และตรวจร้านที่เลือกก่อน เวลา BKK บนหน้าจอคือเวลาประเทศไทย
| คำบนหน้าจอ | ความหมาย |
| ID | หมายเลขรายการของ Quest มักขึ้นต้นด้วย pay_ |
| Ref | เลขอ้างอิงหรือเลขออร์เดอร์ที่เว็บร้านส่งมา |
| ยอด | ยอดเงินของรายการ |
| Fee | ค่าธรรมเนียมรับชำระของรายการนั้น; — หมายถึงยังไม่มีค่าที่บันทึก |
| สร้างเมื่อ | เวลาที่สร้างรายการ |
| จ่ายเมื่อ | เวลาที่ระบบบันทึกว่าชำระสำเร็จ |
| สถานะ | ภาษาไทยง่าย ๆ | ควรทำอย่างไร |
created | เพิ่งสร้างรายการ | ยังไม่ถือว่าจ่ายแล้ว |
pending | รอชำระหรือรอผลยืนยัน | ยังไม่ถือว่าจ่ายแล้ว |
paid | ระบบยืนยันว่าชำระแล้ว | ตรวจ Ref และยอดให้ตรง ก่อนดำเนินการตามออร์เดอร์ |
cancelled | รายการถูกยกเลิก | ไม่ใช่สถานะคืนเงิน |
expired | หมดเวลาชำระ | ถ้าลูกค้ายังไม่ได้จ่าย ให้เริ่มรายการใหม่จากเว็บร้าน |
ถ้าลูกค้าส่งสลิป แต่รายการยังไม่เป็น paid: เก็บ ID, Ref, ยอด, เวลาจ่าย และสลิป ส่งให้ผู้ดูแลตรวจสอบ อย่าให้ลูกค้าจ่ายซ้ำทันที และอย่าอาศัยภาพสลิปหรือการกลับมาหน้าเว็บอย่างเดียวเพื่อตัดสินว่าชำระสำเร็จ
เมนูนี้ใช้ดูและค้นหารายการ บัญชีร้านค้าไม่มีปุ่มยืนยันเงินเข้าด้วยตนเอง รายการชำระใหม่สร้างจากเว็บร้านหรือ API ที่เชื่อมกับ Quest
หัวข้อในหน้าจออาจเขียนว่า Settlement ซึ่งหมายถึงการสรุปยอดเพื่อโอนเงินให้ร้าน
ปุ่ม ปิดใช้ ทำให้บัญชีนั้นไม่พร้อมใช้งาน จึงควรตรวจบัญชีหลักก่อนกด หากมีรอบจ่ายที่สร้างไว้แล้ว ให้ตรวจบัญชีในรอบนั้นด้วย อย่าสมมติว่าการเปลี่ยนบัญชีหลักเปลี่ยนทุกรอบย้อนหลัง
| ตัวเลือก | ใช้อย่างไร |
เงินกันไว้ในบัญชี (reserve) | กันเงินส่วนหนึ่งไว้ในยอดร้าน เช่น กัน 500 บาท เงินส่วนนี้จะไม่ถูกนำออกไปรวมยอดจ่ายตามปกติ |
| ยอดที่ต้องการรับโอนรอบถัดไป | จำกัดยอดสำหรับรอบถัดไปครั้งเดียว ใส่ 0 เพื่อยกเลิกการจำกัด ไม่ใช่กดโอนทันที |
| แผนกระจายเงินโอน | แบ่งยอดไปหลายบัญชีตามลำดับ เงินที่เหลือไปบัญชีหลัก ถ้ายอดไม่พอจะจัดสรรเท่าที่มี |
แผนกระจายเงินใช้ซ้ำในแต่ละรอบจนกว่าจะแก้ไข หากรับเงินบัญชีเดียว ก็ไม่จำเป็นต้องเพิ่มแผนนี้
หน้าจอปัจจุบันระบุรอบตัดยอด 22:00 น. การตัดรอบหรือบันทึกยอดที่ต้องการรับ ไม่ใช่การรับประกันว่าเงินจะเข้าธนาคารทันที ให้ดูสถานะรอบจ่ายและเวลาที่ผู้ดูแลยืนยัน
| สถานะบนหน้าจอ | ความหมาย |
รอ admin review / pending | รอผู้ดูแลตรวจสอบ |
อนุมัติแล้ว รอโอน / approved | ผ่านการอนุมัติ แต่ยังไม่ใช่สถานะโอนแล้ว |
โอนแล้ว / paid | ระบบบันทึกว่าโอนแล้ว ตรวจบัญชีและเลขอ้างอิงประกอบ |
ปฏิเสธ / rejected | ผู้ดูแลไม่อนุมัติ ให้ดูเหตุผล |
ไม่มีบัญชี / no_account | ต้องเพิ่มหรือเลือกบัญชีรับเงินให้เรียบร้อย |
รวมในรอบถัดไปแล้ว / superseded | รอบเดิมถูกรวมเข้าในรอบถัดไป ให้ติดตามรอบใหม่ |
กด รายละเอียด ในแถวของรอบจ่ายเพื่อดูยอดและรายการประกอบ
| สิทธิ์ | เหมาะกับใคร |
พนักงาน (staff) | คนช่วยดูข้อมูลและรายการ ไม่มีสิทธิ์จัดการสมาชิกหรือบัญชีรับเงิน |
เจ้าของ (owner) | คนที่ได้รับอนุญาตให้จัดการร้าน สมาชิก และการตั้งค่ารับเงิน |
ปุ่ม ลบ ใช้ปิดการใช้งานบัญชีสมาชิก ไม่ใช่ลบประวัติรายการของร้าน และไม่สามารถลบบัญชีตัวเองจากหน้านี้ได้
ปุ่ม rotate API key ของร้าน: ออก API key ใหม่พร้อม webhook secret ใหม่ ในคราวเดียว และทำให้ key เดิมกับ secret เดิมใช้ไม่ได้ทันที ต้องยืนยันรหัส 2FA ก่อนทำ (บัญชีที่ยังไม่เปิด 2FA จะกดไม่ได้) ถ้าเว็บร้านเชื่อม API อยู่ ต้องให้คนดูแลเว็บเปลี่ยนทั้งสองค่าให้ตรงกัน จึงไม่ควรกดเพื่อทดลองหรือเข้าใจว่าเป็นการเปลี่ยนรหัสผ่านล็อกอิน
ร้านค้าย่อย (Sub-merchant) คือร้านที่อยู่ใต้ร้านหลัก โดยมี API key, webhook, ค่าธรรมเนียม และยอดเงินของตัวเอง เมนูบนหน้าจอยังใช้ชื่อ ร้านลูก ผู้ทำรายการต้องเป็น เจ้าของร้าน (owner) ของร้านหลัก
agent จะสร้างร้านลูกระดับ membermyshop-a ใช้ตัวอักษรอังกฤษพิมพ์เล็ก ตัวเลข ขีดกลาง หรือขีดล่าง รวม 2–32 ตัว และเริ่มด้วยตัวอักษรหรือตัวเลข100 = 1% หรือ 160 = 1.60% ฟอร์มเริ่มต้นที่ 100 ให้ตรวจและแก้เป็นอัตราที่ตกลงก่อนสร้างค่าถอนของร้านลูกจะสืบทอดจากร้านหลัก ตอนสร้างร้าน ช่อง fee_bps ในหน้านี้ใช้กำหนดค่ารับชำระเท่านั้น
ถ้าอีเมลซ้ำ: หากข้อความแจ้งว่า “สร้างร้านลูกแล้ว” ให้กลับไปตรวจรายการก่อน อย่าสร้างร้านซ้ำ ให้เพิ่มบัญชีด้วยอีเมลอื่นในร้านที่สร้างแล้ว หากไม่ได้รับ API key ให้ใช้ขั้นตอนออก key ใหม่ด้านล่าง
บัญชีที่เพิ่มจากหน้านี้เป็น พนักงาน (staff) ดูอย่างเดียว เห็นข้อมูลร้านของตัวเอง ไม่ใช่บัญชีเจ้าของร้าน และร้านระดับ member สร้างร้านลูกต่อไม่ได้
ขอบเขตการจัดการ: ร้านหลักจัดการได้เฉพาะร้านลูกระดับถัดลงมาโดยตรง ส่วนหน้าภาพรวมและรายการสามารถรวมข้อมูลร้านที่อยู่ใต้สิทธิ์ของตนได้
Webhook คือข้อความอัตโนมัติที่ Quest ส่งไปแจ้งเว็บร้าน เช่น แจ้งว่าลูกค้าจ่ายแล้ว จ่ายแล้วแต่เว็บร้านยังไม่เปลี่ยนสถานะ ให้เริ่มตรวจหน้านี้
| สถานะ | ความหมาย |
queued | รอส่ง หรือรอส่งซ้ำตามรอบ |
delivered | เว็บปลายทางตอบรับสำเร็จ แต่ควรตรวจด้วยว่าเว็บร้านบันทึกออร์เดอร์แล้ว |
failed | การส่งล้มเหลว ต้องตรวจข้อมูลการส่ง |
dead | ระบบหยุดส่งอัตโนมัติ เช่น ลองส่งครบจำนวนแล้ว |
HTTP คือผลตอบจากเว็บปลายทาง โดย 2xx เช่น 200 หมายถึงตอบรับสำเร็จ ส่วน — อาจหมายถึงไม่มีผลตอบ HTTP ที่บันทึกไว้ ต้องตรวจรายละเอียดเพิ่มเติม
บัญชีร้านไม่มีปุ่มส่งซ้ำเอง หากต้องการให้ส่งซ้ำ ให้ส่ง Payment ID และข้อมูลแถวนี้ให้ผู้ดูแล พร้อมให้คนดูแลเว็บร้านตรวจ URL และตัวรับข้อความ
สถานะจ่ายเงินกับสถานะส่งข้อความเป็นคนละเรื่อง: รายการอาจเป็น paid แล้ว แต่ webhook ยังส่งไม่สำเร็จได้ อย่าสร้างรายการจ่ายใหม่เพียงเพราะแจ้งผลไม่ถึงเว็บร้าน
หน้าจออาจเขียนว่า Audit ใช้ตรวจประวัติการทำงาน เช่น เพิ่มสมาชิก เปลี่ยน key หรือแก้ข้อมูลร้าน เลือกตัวกรองที่มีบนหน้าจอเพื่อหารายการที่ต้องการ
ถ้าพบการเปลี่ยนแปลงที่ไม่คุ้นเคย ให้บันทึกวันเวลา ผู้ทำรายการ และรายละเอียด ส่งให้ผู้ดูแลตรวจสอบ
| อาการ | เริ่มตรวจจากตรงไหน |
| เข้าไม่ได้ | ตรวจ URL ชื่อผู้ใช้ และรหัสผ่าน ระวังช่องว่างที่ติดมาตอนคัดลอก; ถ้ายังไม่ได้ให้ติดต่อผู้ดูแล |
| ไม่มีเมนูสมาชิกหรือร้านลูก | ตรวจว่าเข้าด้วยบัญชีเจ้าของร้าน ไม่ใช่พนักงาน; ร้านระดับ member ไม่มีเมนูสร้างร้านลูก |
| ไม่พบรายการลูกค้า | ตรวจ Ref ร้านที่เลือก ช่วงวันที่ และตัวกรองสถานะ |
| ลูกค้าบอกจ่ายแล้ว แต่ยัง pending | เก็บ ID/Ref ยอด เวลาและสลิป ส่งผู้ดูแลตรวจ ไม่ให้จ่ายซ้ำทันที |
| Quest เป็น paid แต่เว็บร้านยังไม่อัปเดต | ตรวจ Webhooks แล้วประสานคนดูแลเว็บร้าน |
| ยังไม่ได้รับเงินถอน | ตรวจบัญชีรับเงิน reserve ยอดจำกัดรอบถัดไป และสถานะรอบจ่าย |
| ไม่เห็นเมนูสลิปหรือตรวจสอบรายการ | เป็นเมนูของผู้ดูแลระบบ ไม่ได้เปิดให้บัญชีร้านค้า |
ไม่ต้องส่งรหัสผ่าน, API key หรือ webhook secret ในข้อความแจ้งปัญหา