Deposit Flow

Recommended : use Create Payment — FLEX (Hosted Payment Page) — one API call that automatically uses every payment channel we have, returning a hosted payment_url that handles the entire customer flow (instructions, QR code or destination bank account, exact transfer amount, countdown, slip submission, and live status).

This document explains the end-to-end deposit workflow when integrating with the payment gateway using the FLEX endpoint.

Overview

The deposit flow describes the complete process — from when a customer initiates a deposit on the merchant's website, through to the final credit confirmation. With FLEX, the merchant makes one API call and redirects the customer to the hosted payment page; that page walks the customer through the whole payment, and the merchant is notified via webhook when the payment is confirmed.

Deposit Workflow Steps

Step 1: Customer Initiates Deposit Request

The deposit process begins when a customer on the merchant's website decides to make a deposit:

  1. Customer navigates to the deposit page on the merchant's website
  2. Customer enters the desired deposit amount
  3. Customer submits the deposit request

Step 2: Merchant Backend Creates a FLEX Order

Upon receiving the customer's deposit request, the merchant's backend system must:

  1. Prepare the payment request payload including:

    • Merchant credentials (merchant_id, token)
    • Current timestamp (time)
    • Unique merchant order ID (merchant_order_id)
    • Deposit amount (amount)
    • Webhook notification URL (notify_url)
    • (optional) redirect_url — where to send the customer back after payment
    • (optional) payment_theme — visual theme for the hosted page
  2. Generate the HMAC-SHA256 signature using the merchant's secret key

  3. Send a POST request to the API endpoint: /payment-flex/create

Example API 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: The Payment Gateway Returns a Hosted Payment URL

The payment gateway processes the request and:

  1. Validates the merchant credentials and signature
  2. Generates a unique platform order ID
  3. Picks the best available payment channel for the order
  4. Returns a hosted payment_url to the merchant

Example API Response:

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

Important Response Fields:

Pending-order guard (409) : only one open FLEX order is allowed per customer account at a time. If the customer already has an open order, the API returns 409 with data.pending_order_id — reuse/await that order, let the customer cancel it on the payment page, or cancel it from your backend via Cancel Payment Order, before creating a new one.

Step 4: Merchant Opens the Payment URL for the Customer

The merchant simply sends the customer to payment_url — there is nothing else to render:

  1. Redirect the customer's browser to payment_url, or
  2. Embed it as an iframe inside your own page

Step 5: The Hosted Page Handles the Entire Customer Flow

The hosted payment page walks the customer through everything:

The customer pays from their banking app and (where applicable) submits the slip — all on the hosted page. You do not need to build any of this yourself.

Step 6: The Payment Gateway Detects and Verifies Payment

Once the customer completes the transfer:

  1. The gateway's system detects the incoming transaction
  2. The system validates the amount and matches it to the open order
  3. Payment status is updated to paid

Step 7: The Payment Gateway Sends Webhook Notification

After successful payment verification, the payment gateway sends a webhook notification to the merchant:

  1. POST request sent to the notify_url provided in the original request
  2. Webhook payload contains payment confirmation details (mode: PAYMENT, status: PAID)
  3. The payment gateway retries until it receives HTTP 200, so your handler must be idempotent

For detailed webhook specifications, see Payment Callback documentation.

Step 8: Merchant Credits Customer Account

Upon receiving the webhook notification, the merchant's system should:

  1. Validate the webhook:

    • Verify the signature
    • Confirm the merchant_order_id matches the original order
    • Check the order hasn't been processed already (prevent duplicate crediting)
  2. Update order status: mark the order as paid; record the platform_order_id

  3. Credit the customer: add the deposit amount to the customer's balance

  4. Send confirmation response: return HTTP 200 OK to acknowledge the webhook

After payment, the hosted page redirects the customer back to your redirect_url (if provided).

Alternative Flow: Webhook Not Received

If the webhook notification is not received (network issues, server downtime, etc.), there are two alternative verification paths:

Option 1: Query Payment Status

The merchant can actively query the payment status:

  1. Send a request to /payment/query with the merchant_order_id or platform_order_id
  2. Receive the current payment status
  3. Process accordingly

For detailed specifications, see Query Payment Order documentation.

Option 2: Customer Submits Payment Slip

On the hosted FLEX page the customer can upload a slip directly. If you need to submit a slip server-to-server, use the Slip Upload API:

  1. Include the payment slip image and order reference
  2. The payment gateway verifies the slip against transaction records and confirms

For detailed specifications, see Slip Upload documentation.

Important Considerations

Payment Timing Critical

  1. Decimal Variance Matching: the hosted page shows the customer an exact transfer_amount (e.g. 1000.03 instead of 1000.00), locked to that order and time window for accurate matching.

  2. Consequences of Late Payment: if a customer transfers after the expiry time, the system may have reassigned that exact amount to another order. The payment might be credited to the wrong order, and the payment gateway cannot reverse such misallocated payments. The hosted page's countdown is there to prevent this.

  3. One Transfer Only: the customer must transfer once, the exact amount, before expiry.

Idempotency Critical

Because the payment gateway retries the webhook until it gets HTTP 200, your handler will receive the same platform_order_id more than once. Always make crediting idempotent — credit a given order exactly once, no matter how many callbacks arrive.

Error Handling

Common Scenarios

  1. Order Expired: customer didn't pay in time. Action: customer creates a new deposit request (the 409 pending guard is released once the previous order is closed/cancelled).

  2. Pending Order (409): the customer already has an open FLEX order. Action: reuse data.pending_order_id, or cancel it (on the page or via the cancel API) before retrying — do not retry-loop.

  3. Customer Cancelled: the customer pressed Cancel on the hosted page. A CANCELLED callback fires. A cancel is not always final — a later PAID callback may still arrive for the same order (treat PAID as authoritative); otherwise create a new order on retry.

  4. Webhook Delivery Failure: payment succeeded but the merchant wasn't notified. Action: use the query API or slip upload above. Prevention: implement a robust, idempotent webhook endpoint and a fallback poll.

Best Practices for Merchants

  1. Order Handling:

    • Persist platform_order_id from the create response for reconciliation
    • Handle the 409 pending-order response by reusing data.pending_order_id
  2. Hosted Page:

    • Just redirect (or iframe) the customer to payment_url — don't extract the QR / bank account and render it in your own UI
    • Provide a redirect_url so the customer returns to your site after paying
  3. Webhook Implementation:

    • Implement idempotent webhook handling (prevent duplicate credits)
    • Return HTTP 200 quickly; process asynchronously if needed
    • Verify the webhook signature and log all receipts for audit
  4. Error Recovery:

    • Implement payment-query polling as a backup to webhooks (e.g. for orders pending > 1h)
    • Store all API responses for troubleshooting
  5. Customer Communication:

    • Send email/SMS confirmation upon successful deposit
    • Provide a customer-support channel for payment issues

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]------------------------------------------------------------------|

Related Documentation