ขั้นตอนการฝาก (Deposit Flow)

แนะนำ : ใช้ สร้างคำสั่งชำระเงิน — FLEX (หน้าชำระเงิน) — เรียก API ครั้งเดียว ระบบจะเลือกใช้ทุกช่องทางการชำระเงินที่มีโดยอัตโนมัติ และคืน payment_url ของหน้าชำระเงินที่จัดการ flow ของลูกค้าให้ทั้งหมด (วิธีใช้งาน, QR Code หรือบัญชีปลายทาง, ยอดที่ต้องโอนเป๊ะ, countdown, แจ้งสลิป และสถานะ real-time)

เอกสารนี้อธิบายขั้นตอนการฝากเงินแบบครบวงจร เมื่อเชื่อมต่อกับ Payment Gateway ผ่าน endpoint FLEX

ภาพรวม

Deposit flow คือกระบวนการตั้งแต่ลูกค้ากดฝากเงินบนเว็บไซต์ของร้านค้า ไปจนถึงการยืนยันเครดิตยอดเงิน สำเร็จ ด้วย FLEX ร้านค้าเรียก API เพียง ครั้งเดียว แล้วพาลูกค้าไปยังหน้าชำระเงินที่ระบบ โฮสต์ให้ หน้านั้นจะพาลูกค้าทำรายการทั้งหมด และร้านค้าจะได้รับแจ้งผ่าน webhook เมื่อการชำระเงินสำเร็จ

ขั้นตอน

Step 1: ลูกค้าเริ่มทำรายการฝาก

กระบวนการเริ่มเมื่อลูกค้าบนเว็บไซต์ร้านค้าต้องการฝากเงิน:

  1. ลูกค้าเข้าหน้าฝากเงินบนเว็บไซต์ร้านค้า
  2. ลูกค้ากรอกจำนวนเงินที่ต้องการฝาก
  3. ลูกค้ากดยืนยันคำสั่งฝาก

Step 2: Backend ร้านค้าสร้างคำสั่ง FLEX

เมื่อรับคำสั่งฝากจากลูกค้า ระบบ backend ของร้านค้าต้อง:

  1. เตรียม payload ของคำขอ ประกอบด้วย:

    • Credential ของ merchant (merchant_id, token)
    • timestamp ปัจจุบัน (time)
    • merchant order id ที่ไม่ซ้ำ (merchant_order_id)
    • จำนวนเงินฝาก (amount)
    • URL สำหรับ webhook (notify_url)
    • (optional) redirect_url — หน้าที่จะพาลูกค้ากลับมาหลังชำระเงิน
    • (optional) payment_theme — ธีมของหน้าชำระเงิน
  2. สร้าง signature แบบ HMAC-SHA256 ด้วย secret key ของร้านค้า

  3. ส่ง POST request ไปยัง API endpoint: /payment-flex/create

ตัวอย่าง Request:

{
  "merchant_id": "AA12345678",
  "token": "testtokentesttokentesttokentesttokentesttoken",
  "time": 1656272222,
  "merchant_order_id": "ORDER0123456789789445566",
  "amount": "1000.00",
  "notify_url": "https://merchant.com/callback/payment",
  "redirect_url": "https://merchant.com/return",
  "payment_theme": "halo"
}

Step 3: ระบบคืน Payment URL ของหน้าชำระเงิน

ระบบจะประมวลผลคำขอและ:

  1. ตรวจสอบ credential และ signature
  2. สร้าง platform order id ที่ไม่ซ้ำ
  3. เลือกช่องทางการชำระเงินที่ดีที่สุดให้ออเดอร์นั้น
  4. คืน payment_url ของหน้าชำระเงินกลับมา

ตัวอย่าง Response:

{
    "success": 200,
    "data": {
        "platform_order_id": "THBP202605061004030AAAA001",
        "payment_method": "FLEX",
        "payment_url": "https://payment.example.com/THBP202605061004030AAAA001/<hash>"
    }
}

ฟิลด์สำคัญใน Response:

Pending-order guard (409) : ลูกค้าหนึ่งบัญชีเปิด FLEX order ค้างได้ครั้งละ 1 รายการ ถ้าลูกค้ามี order ค้างอยู่ API จะคืน 409 พร้อม data.pending_order_id — ให้ใช้ order เดิมต่อ, ให้ลูกค้ายกเลิกบนหน้าชำระเงิน, หรือยกเลิกจาก backend ผ่าน ยกเลิกคำสั่งชำระเงิน ก่อนสร้างรายการใหม่

Step 4: ร้านค้าเปิด Payment URL ให้ลูกค้า

ร้านค้าเพียงพาลูกค้าไปที่ payment_urlไม่ต้อง render อะไรเองเลย:

  1. redirect browser ของลูกค้าไปที่ payment_url หรือ
  2. ฝังเป็น iframe ในหน้าเว็บของคุณเอง

Step 5: หน้าชำระเงินจัดการ Flow ลูกค้าให้ทั้งหมด

หน้าชำระเงินที่ระบบโฮสต์ให้จะพาลูกค้าทำทุกอย่าง:

ลูกค้าจ่ายผ่านแอปธนาคารและ (ถ้าจำเป็น) แจ้งสลิป — ทั้งหมดบนหน้าชำระเงิน คุณไม่ต้องสร้างส่วนเหล่านี้เอง

Step 6: ระบบตรวจจับและยืนยันการชำระเงิน

เมื่อลูกค้าโอนเงินเสร็จ:

  1. ระบบตรวจจับรายการเงินเข้า
  2. ระบบตรวจสอบยอดและจับคู่กับออเดอร์ที่เปิดอยู่
  3. สถานะการชำระเงินถูกอัปเดตเป็น paid

Step 7: ระบบส่ง Webhook แจ้งร้านค้า

หลังยืนยันการชำระเงินสำเร็จ ระบบจะส่ง webhook ไปที่ร้านค้า:

  1. ยิง POST request ไปที่ notify_url ที่ส่งมาตอนสร้างออเดอร์
  2. payload มีรายละเอียดยืนยันการชำระเงิน (mode: PAYMENT, status: PAID)
  3. ระบบจะ retry จนกว่าจะได้ HTTP 200 ดังนั้น handler ของคุณต้อง idempotent

ดูรายละเอียด webhook ที่ Payment Callback

Step 8: ร้านค้าเครดิตยอดให้ลูกค้า

เมื่อได้รับ webhook ระบบร้านค้าควร:

  1. ตรวจสอบ webhook:

    • ตรวจ signature
    • ยืนยันว่า merchant_order_id ตรงกับออเดอร์เดิม
    • เช็คว่ายังไม่ได้ประมวลผลออเดอร์นี้มาก่อน (กันเครดิตซ้ำ)
  2. อัปเดตสถานะออเดอร์: mark ว่าจ่ายแล้ว เก็บ platform_order_id

  3. เครดิตให้ลูกค้า: เพิ่มยอดฝากเข้ายอดเงินของลูกค้า

  4. ตอบกลับ: คืน HTTP 200 OK เพื่อยืนยันว่าได้รับ webhook แล้ว

หลังชำระเงิน หน้าชำระเงินจะพาลูกค้ากลับไปที่ redirect_url (ถ้าระบุ)

Flow สำรอง: กรณี Webhook ไม่มา

ถ้าไม่ได้รับ webhook (ปัญหา network, server ล่ม ฯลฯ) มี 2 วิธีตรวจสอบสำรอง:

วิธีที่ 1: Query สถานะการชำระเงิน

ร้านค้า query สถานะการชำระเงินได้เอง:

  1. ส่งคำขอไปที่ /payment/query พร้อม merchant_order_id หรือ platform_order_id
  2. รับสถานะปัจจุบัน
  3. ประมวลผลตามสถานะที่ได้

ดูรายละเอียดที่ ตรวจสอบคำสั่งชำระเงิน

วิธีที่ 2: ลูกค้าแจ้งสลิป

บนหน้า FLEX ลูกค้าสามารถอัปโหลดสลิปได้โดยตรง ถ้าต้องการส่งสลิปแบบ server-to-server ใช้ Slip Upload API:

  1. แนบรูปสลิปและ order reference
  2. ระบบตรวจสอบสลิปกับรายการธุรกรรมแล้วยืนยัน

ดูรายละเอียดที่ อัปโหลดสลิป

ข้อควรระวัง

เรื่องเวลาสำคัญมาก

  1. Decimal Variance Matching: หน้าชำระเงินจะแสดงยอด transfer_amount เป๊ะให้ลูกค้า (เช่น 1000.03 แทน 1000.00) ซึ่งล็อกกับออเดอร์และช่วงเวลานั้นเพื่อจับคู่ให้แม่นยำ

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

  3. โอนครั้งเดียว: ลูกค้าต้องโอนครั้งเดียว ยอดเป๊ะ ก่อนหมดเวลา

Idempotency สำคัญมาก

เพราะระบบจะ retry webhook จนกว่าจะได้ HTTP 200 handler ของคุณ จะ ได้รับ platform_order_id เดิมมากกว่าหนึ่งครั้ง ให้เครดิตแบบ idempotent เสมอ — เครดิตแต่ละออเดอร์เพียงครั้งเดียว ไม่ว่าจะมี callback เข้ามากี่ครั้ง

การจัดการ Error

กรณีที่พบบ่อย

  1. ออเดอร์หมดอายุ: ลูกค้าไม่จ่ายทันเวลา → ลูกค้าสร้างคำสั่งฝากใหม่ (pending guard 409 จะถูกปลดเมื่อออเดอร์เดิมปิด/ถูกยกเลิก)

  2. มีออเดอร์ค้าง (409): ลูกค้ามี FLEX order เปิดอยู่แล้ว → ใช้ data.pending_order_id เดิม หรือยกเลิก (บนหน้าชำระเงิน หรือผ่าน cancel API) ก่อนสร้างใหม่ อย่า retry วน

  3. ลูกค้ายกเลิก: ลูกค้ากด ยกเลิก บนหน้าชำระเงิน → มี callback CANCELLED การยกเลิกอาจไม่ถือเป็น ที่สิ้นสุดเสมอไป อาจมี callback PAID ตามมาภายหลังสำหรับออเดอร์เดิมได้ (ให้ถือว่า PAID ถูกต้อง) มิฉะนั้นให้สร้างออเดอร์ใหม่เมื่อลูกค้าลองอีกครั้ง

  4. Webhook ส่งไม่สำเร็จ: จ่ายสำเร็จแต่ร้านค้าไม่ได้รับแจ้ง → ใช้ query API หรือ slip upload ข้างต้น ป้องกันด้วยการทำ webhook endpoint ที่ทนทานและ idempotent พร้อม fallback poll

Best Practice สำหรับร้านค้า

  1. การจัดการออเดอร์:

    • เก็บ platform_order_id จาก response ไว้กระทบยอด
    • จัดการ 409 ด้วยการใช้ data.pending_order_id เดิม
  2. หน้าชำระเงิน:

    • แค่ redirect (หรือ iframe) ลูกค้าไปที่ payment_url — อย่าดึง QR / เลขบัญชีออกมา render เองใน UI
    • ระบุ redirect_url เพื่อพาลูกค้ากลับมาที่เว็บคุณหลังจ่ายเสร็จ
  3. การทำ Webhook:

    • ทำ webhook handler แบบ idempotent (กันเครดิตซ้ำ)
    • ตอบ HTTP 200 เร็ว ๆ แล้วค่อยประมวลผลแบบ async ถ้าจำเป็น
    • ตรวจ signature และ log ทุก webhook ไว้ตรวจสอบ
  4. การกู้คืนเมื่อ Error:

    • ทำ payment-query polling เป็น backup ของ webhook (เช่น ออเดอร์ที่ค้าง > 1 ชม.)
    • เก็บ API response ทั้งหมดไว้ debug
  5. การสื่อสารกับลูกค้า:

    • ส่ง email/SMS ยืนยันเมื่อฝากสำเร็จ
    • มีช่องทางติดต่อ support สำหรับปัญหาการชำระเงิน

Sequence Diagram

Customer          Merchant Website          Merchant Backend          Payment API           Payment Page
   |                     |                          |                         |                    |
   |--[Enter Amount]---->|                          |                         |                    |
   |                     |----[Create Deposit]----->|                         |                    |
   |                     |                          |--[POST /payment-flex]-->|                    |
   |                     |                          |<--[payment_url]---------|                    |
   |                     |<---[payment_url]---------|                         |                    |
   |--[Open payment_url]-|--------------------------|-------------------------|------------------->|
   |<--[Instructions + QR or bank account + countdown]------------------------|--------------------|
   |--[Transfer & submit slip on the page]------------------------------------|------------------->|
   |                     |                          |                    [Verify Payment]          |
   |                     |                          |<--[Webhook Callback]---|                    |
   |                     |                    [Credit Account]                |                    |
   |                     |                          |---[HTTP 200 OK]-------->|                    |
   |<--[Redirect to redirect_url]------------------------------------------------------------------|

เอกสารที่เกี่ยวข้อง