POST https://<your-api-domain>/payment/create-flex

Creates a deposit order without you choosing a channel. The gateway runs the platform's configured selection algorithm over all of the platform's deposit accounts, picks the best account for this order, and returns a single hosted payment_url. You redirect the customer there; the page shows whatever the selection picked — a QR, bank-transfer details, or an automatic redirect onward to the selected channel's payment page. When the customer pays, you receive a webhook callback to your notify_url, exactly like the other payment endpoints — one integration covers every channel the platform enables.

สร้างคำสั่งฝากเงินโดยที่ คุณไม่ต้องเลือก channel เอง
ระบบจะเลือกบัญชีรับเงินที่ดีที่สุดสำหรับ order นี้จากบัญชีทั้งหมดของแพลตฟอร์ม ตาม algorithm ที่ตั้งไว้ แล้วส่งกลับ payment_url ลิงก์เดียว
คุณแค่ redirect ลูกค้าไปที่หน้านั้น หน้าจะแสดง channel ที่ระบบเลือก: QR, ข้อมูลการโอน หรือ redirect ต่อไปยังหน้าชำระของช่องทางที่ถูกเลือก
เมื่อลูกค้าจ่ายเงินสำเร็จ ระบบจะ POST callback ไปที่ notify_url เหมือน endpoint การฝากอื่น ๆ
integrate ครั้งเดียวครอบคลุมทุกช่องทางที่แพลตฟอร์มเปิดใช้

How flex differs from /payment/create and /payment/create-transfer
flex ต่างจาก /payment/create และ /payment/create-transfer อย่างไร

The two original endpoints make you pick the channel and hand you channel-specific details to render yourself (a QR string, or destination bank account + transfer_amount). Flex flips that: the server picks the channel per order and hides all channel details — you only ever get a payment_url to redirect to. One integration path covers every channel.

endpoint เดิมสองตัวให้ คุณ เป็นคนเลือก channel และส่งรายละเอียดเฉพาะ channel นั้นกลับมาให้คุณ render เอง (QR string หรือบัญชีปลายทาง + transfer_amount)
flex กลับด้าน: ฝั่ง server เลือก channel ให้ต่อ order และซ่อนรายละเอียด channel ทั้งหมด
คุณได้แค่ payment_url ไว้ redirect เท่านั้น
เขียน integration ครั้งเดียวครอบทุก channel

Side-by-side comparison

ตารางเปรียบเทียบ

Aspect /payment/create (QR) /payment/create-transfer /payment/create-flex หัวข้อ /payment/create (QR) /payment/create-transfer /payment/create-flex
Who picks the channel You (call the QR endpoint) You (call the transfer endpoint) The gateway, per order ใครเลือก channel คุณ (เรียก endpoint QR) คุณ (เรียก endpoint โอน) ระบบเลือกให้ ต่อ order
Request body 8 fields Same 8 fields Same 8 fields (drop-in) Request body 8 ฟิลด์ 8 ฟิลด์เดียวกัน 8 ฟิลด์เดียวกัน (เปลี่ยนแค่ path)
Response payload qrcode + transfer_amount deposit_bank/account_no + transfer_amount payment_url only ข้อมูลที่ตอบกลับ qrcode + transfer_amount deposit_bank/account_no + transfer_amount payment_url อย่างเดียว
payment_type "QR" "TRANSFER" "FLEX" payment_type "QR" "TRANSFER" "FLEX"
What you do with the response Render the QR yourself, or redirect to payment_url Show the bank account, or redirect to payment_url Redirect to payment_url (only option) เอา response ไปทำอะไร render QR เอง หรือ redirect ไป payment_url แสดงบัญชีเอง หรือ redirect ไป payment_url redirect ไป payment_url (ทางเดียว)
payment_page_domain Optional (payment_url is null if unset) Optional Required (400 if unset) payment_page_domain ไม่บังคับ (payment_url = null ถ้าไม่ตั้ง) ไม่บังคับ บังคับ (ได้ 400 ถ้าไม่ตั้ง)
Channel pool QR-capable accounts Transfer-capable accounts All channels compete + auto-fallback pool ของ channel บัญชีที่รองรับ QR บัญชีที่รองรับการโอน ทุก channel แข่งกัน + fallback อัตโนมัติ
When to use flex
ควรใช้ flex เมื่อไหร่

Use flex when you want a single, future-proof integration — one API instead of two (create + create-transfer) — and are happy to redirect the customer to the hosted payment page. Whatever accounts the platform enables are picked up automatically, with no code change on your side; it also lets the platform spread orders across all of its accounts, instead of being limited by which payment type your call asked for. Use the dedicated /payment/create or /payment/create-transfer when you need to render the QR / bank details inside your own checkout UI.

ใช้ flex เมื่ออยากเขียน integration ครั้งเดียวจบ — เรียก API เดียวแทนที่จะต่อ 2 ตัว (create + create-transfer) และรับได้กับการ redirect ลูกค้าไปหน้า payment page ของระบบ
แพลตฟอร์มเพิ่ม/เปลี่ยนบัญชีรับเงินภายหลังได้โดยฝั่งคุณไม่ต้องแก้โค้ด และยังช่วยให้แพลตฟอร์มกระจาย order ได้ทุกบัญชี ไม่ติดข้อจำกัดว่า call ของคุณระบุประเภทไหน
ถ้าต้องการ render QR / เลขบัญชีในหน้า checkout ของคุณเอง ให้ใช้ /payment/create หรือ /payment/create-transfer แทน

Request

Request

Body fields are identical to /payment/createmerchant_id, token, time, merchant_order_id, amount, bank, account_name, account_no, and optional notify_url. Same validation rules (alphanumeric merchant_order_id ≤ 40 chars, amount ≥ 20.00, valid bank code, account_no 10–15 digits). Only the path changes.

Body fields เหมือนกับ /payment/create ทุกประการ: merchant_id, token, time, merchant_order_id, amount, bank, account_name, account_no และ notify_url (ไม่บังคับ)
กติกา validation เดียวกัน (merchant_order_id เป็นตัวอักษร/ตัวเลข ≤ 40 ตัว, amount ≥ 20.00, bank ถูกต้อง, account_no 10–15 หลัก)
เปลี่ยนแค่ path เท่านั้น

Code samples

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

TIME=$(date +%s)
BODY="{\"merchant_id\":\"AA12345678\",\"token\":\"YOUR_TOKEN\",\"time\":$TIME,\"merchant_order_id\":\"ORDER-2026-001\",\"amount\":\"500.00\",\"bank\":\"KBANK\",\"account_name\":\"สมชาย ใจดี\",\"account_no\":\"1234567890\",\"notify_url\":\"https://<your-merchant-webhook-URL>/payment-callback\"}"
SIG=$(printf '%s' "$BODY" | openssl dgst -sha256 -hmac "YOUR_SECRET" | awk '{print $2}')

curl -X POST https://<your-api-domain>/payment/create-flex \
  -H "Content-Type: application/json" \
  -H "X-SIGNATURE: $SIG" \
  -d "$BODY"
import crypto from 'node:crypto';

const SECRET = 'YOUR_SECRET';
const body = JSON.stringify({
  merchant_id:       'AA12345678',
  token:             'YOUR_TOKEN',
  time:             Math.floor(Date.now() / 1000),
  merchant_order_id: 'ORDER-2026-001',
  amount:            '500.00',
  bank:              'KBANK',
  account_name:      'สมชาย ใจดี',
  account_no:        '1234567890',
  notify_url:        'https://<your-merchant-webhook-URL>/payment-callback',
});
const sig = crypto.createHmac('sha256', SECRET).update(body).digest('hex');

const r = await fetch('https://<your-api-domain>/payment/create-flex', {
  method:  'POST',
  headers: { 'Content-Type': 'application/json', 'X-SIGNATURE': sig },
  body
});
const { data } = await r.json();
// Redirect the customer to the hosted payment page:
// res.redirect(data.payment_url)
console.log(data.payment_url);
<?php
$secret = 'YOUR_SECRET';
$body = json_encode([
    'merchant_id'       => 'AA12345678',
    'token'             => 'YOUR_TOKEN',
    'time'              => time(),
    'merchant_order_id' => 'ORDER-2026-001',
    'amount'            => '500.00',
    'bank'              => 'KBANK',
    'account_name'      => 'สมชาย ใจดี',
    'account_no'        => '1234567890',
    'notify_url'        => 'https://<your-merchant-webhook-URL>/payment-callback',
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);

$sig = hash_hmac('sha256', $body, $secret);

$ch = curl_init('https://<your-api-domain>/payment/create-flex');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST           => true,
    CURLOPT_POSTFIELDS     => $body,
    CURLOPT_HTTPHEADER     => [
        'Content-Type: application/json',
        "X-SIGNATURE: $sig",
    ],
]);
$res = json_decode(curl_exec($ch), true);
// header('Location: ' . $res['data']['payment_url']);  // redirect the customer
echo $res['data']['payment_url'];

Response

Response

Success — HTTP 200

สำเร็จ — HTTP 200

JSON
{
  "code":    200,
  "message": "Success",
  "data":    {
    "platform_order_id": "ABCP20260508abc123XYZ456",
    "merchant_order_id": "ORDER-2026-001",
    "uuid":              "0190b4a2-7c1d-7000-9f3a-2c8e5b1a4d6f",
    "order_datetime":    "2026-05-08 10:30:00",
    "expire_datetime":   "2026-05-08 10:45:00",
    "amount":            500.00,
    "payment_type":      "FLEX",
    "payment_url":       "https://<your-payment-page-domain>/p/0190b4a2-7c1d-7000-9f3a-2c8e5b1a4d6f"
  },
  "success": true
}
The flex response is deliberately minimal
response ของ flex ตัดข้อมูล channel ออกโดยตั้งใจ

There is no qrcode, no transfer_amount, and no deposit_bank / deposit_account_no — because the channel is decided server-side and may differ per order. All of that lives on the hosted payment_url page. Your only job is to send the customer to payment_url.

จะ ไม่มี qrcode, ไม่มี transfer_amount และ ไม่มี deposit_bank / deposit_account_no
เพราะ channel ถูกตัดสินฝั่ง server และอาจต่างกันในแต่ละ order
ข้อมูลเหล่านั้นอยู่บนหน้า payment_url แล้ว
หน้าที่ของคุณคือพาลูกค้าไปที่ payment_url อย่างเดียว

Response fields

Response fields

FieldTypeDescription ฟิลด์ประเภทคำอธิบาย
data.platform_order_id string Order ID assigned by the gateway (24 chars). Use this for /payment/query and to match the callback's platform_order_id. data.platform_order_id string Order ID ที่ออกโดย gateway (24 ตัวอักษร) — ใช้กับ /payment/query และจับคู่ platform_order_id ใน callback
data.merchant_order_id string Echo of your input. data.merchant_order_id string Echo ค่าที่คุณส่งมา
data.uuid string (UUID v7) Globally-unique order UUID, embedded in payment_url. You typically don't need to store it separately. data.uuid string (UUID v7) UUID v7 ของ order ฝังอยู่ใน payment_url โดยทั่วไปฝั่งคุณไม่ต้องเก็บแยก
data.order_datetime string Datetime the order was created (YYYY-MM-DD HH:mm:ss, GMT+7). data.order_datetime string เวลาที่สร้าง order (YYYY-MM-DD HH:mm:ss GMT+7)
data.expire_datetime string Datetime after which the order is no longer accepted (YYYY-MM-DD HH:mm:ss, GMT+7). The hosted page shows a countdown to this time. data.expire_datetime string เวลาที่ order หมดอายุ (YYYY-MM-DD HH:mm:ss GMT+7) — หน้า payment page จะแสดง countdown ถึงเวลานี้
data.amount number The amount you requested. data.amount number จำนวนเงินที่คุณ request มา
data.payment_type enum Always "FLEX" for this endpoint. data.payment_type enum เป็น "FLEX" เสมอสำหรับ endpoint นี้
data.payment_url string The hosted payment page for this order. Redirect the customer here. The page renders the chosen channel (QR / transfer instructions / provider redirect) with a live countdown. Always present for flex (a payment-page domain is required — see Errors). data.payment_url string หน้า payment page ของ order นี้
redirect ลูกค้ามาที่นี่
หน้าจะแสดง channel ที่ระบบเลือก (QR / คำแนะนำการโอน / redirect ไปผู้ให้บริการ) พร้อม countdown
สำหรับ flex จะมีค่านี้เสมอ (เพราะบังคับให้ตั้ง payment-page domain — ดูหัวข้อ Errors)

Errors

Errors

Same set as /payment/create, plus one flex-specific case:

ชุดเดียวกับ /payment/create เพิ่มกรณีเฉพาะของ flex อีกหนึ่ง:

HTTP Error code When it happens Error code เกิดเมื่อ
400 invalid-inputs Flex-specific: no payment_page_domain is configured for your platform — flex has nowhere to send the customer. Also the usual: missing/invalid field, amount < 20, invalid bank, malformed URL. invalid-inputs เฉพาะ flex: แพลตฟอร์มยังไม่ได้ตั้ง payment_page_domain
flex จึงไม่มีหน้าให้ส่งลูกค้าไป
รวมถึงกรณีทั่วไป: field ขาด/ผิด, amount < 20, bank ผิด, URL ผิดรูปแบบ
409 duplicate-entry A previous order used the same merchant_order_id within the past 7 days. duplicate-entry merchant_order_id ซ้ำกับ order เดิมในช่วง 7 วันที่ผ่านมา
403 permission-denied Payment is disabled on your merchant account. permission-denied Merchant ของคุณถูกปิดการรับชำระเงิน
503 service-unavailable No deposit channel across the whole pool could accept this order. Try again shortly. service-unavailable ไม่มี channel รับเงินไหนใน pool ที่รับ order นี้ได้ — ลองใหม่ในอีกสักครู่
429 channel-limit-reached Every eligible channel has reached its hourly or daily limit. channel-limit-reached ทุก channel ที่ใช้ได้ถึงโควตารายชั่วโมงหรือรายวันแล้ว
404 not-found Partner configuration not found for this merchant — contact your admin. not-found ไม่พบ Partner config ของ merchant — ติดต่อ admin
Reading a 503 service-unavailable
การอ่าน 503 service-unavailable

A 503 has two distinct causes — check data.code. The platform gate rejects the request up-front with data.code = killswitch_off (the platform admin has switched the deposit API off) or outside_open_period (the request arrived outside the platform's configured operating hours). Otherwise it means no channel in the whole pool could accept this order (the row above) — retry shortly. The first two are platform-state, not a per-order problem, so blind retries won't help until the platform re-enables the API or you're back inside operating hours.

503 มีได้ 2 สาเหตุที่ต่างกัน ให้ดู data.code ประกอบ:
แพลตฟอร์มปฏิเสธ request ตั้งแต่ต้นด้วย data.code = killswitch_off (admin ของแพลตฟอร์มปิด API ฝั่งฝากเงินไว้) หรือ outside_open_period (request เข้ามานอกเวลาทำการที่แพลตฟอร์มตั้งไว้)
นอกเหนือจากนั้นคือ ไม่มี channel ใน pool ที่รับ order นี้ได้ (แถวด้านบน) ให้ลองใหม่ในอีกสักครู่
สองกรณีแรกเป็นสถานะของแพลตฟอร์ม ไม่ใช่ปัญหาของ order
retry ไปก็ไม่ช่วยจนกว่าแพลตฟอร์มจะเปิด API อีกครั้งหรือกลับเข้าเวลาทำการ

Behavior & notes

พฤติกรรม & หมายเหตุ

  • Server-side channel selection. Flex runs the platform's configured selection algorithm over one combined pool of all the platform's deposit accounts — the account's type doesn't matter — honouring the same per-account amount / daily / hourly limits and deposit-group rules as the dedicated endpoints. Which channel a given order uses depends on which account wins selection, so it varies per order.
  • เลือก channel ฝั่ง server — flex ใช้อัลกอริทึมการเลือกที่แพลตฟอร์มตั้งไว้กับ pool รวมเดียวของบัญชีรับเงินทั้งหมดของแพลตฟอร์ม (ไม่สนใจว่าบัญชีเป็นประเภทไหน) โดยเคารพลิมิตต่อบัญชี (จำนวนเงิน/รายวัน/รายชั่วโมง) และกติกา deposit-group เดียวกับ endpoint เฉพาะทาง
    order ไหนใช้ channel ใดขึ้นกับว่าบัญชีไหนชนะการเลือก จึงต่างกันไปในแต่ละ order
  • Automatic fallback. When the selected channel requires a network call to an external service, that call can momentarily fail; flex then drops that account and re-selects onto another available channel — so a single call still succeeds where possible.
  • Fallback อัตโนมัติ — ช่องทางที่ต้องเรียกข้ามเครือข่ายไปบริการภายนอกอาจล้มชั่วขณะได้
    flex จะตัดบัญชีนั้นออกแล้วเลือก channel อื่นที่ว่างให้
    เรียกครั้งเดียวก็ยังสำเร็จเท่าที่เป็นไปได้
  • You must redirect to payment_url. Don't try to render a QR or bank details from the flex response — they aren't there by design. If you need to render channel details in your own UI, use /payment/create or /payment/create-transfer instead.
  • ต้อง redirect ไป payment_url — อย่าพยายาม render QR หรือเลขบัญชีจาก response ของ flex เพราะไม่มีมาให้โดยตั้งใจ
    ถ้าต้องการ render รายละเอียด channel ในหน้าของคุณเอง ให้ใช้ /payment/create หรือ /payment/create-transfer แทน
  • The hosted page may forward the customer off-site. payment_url always points at the platform's own hosted page (on the payment_page_domain). For some channels, that page then redirects the customer onward to that channel's own payment page. That onward hop is part of paying — it is not a return/back-to-merchant link, and its target is never a URL you supply. Your customer returns to you through your normal flow only after the payment webhook to notify_url confirms the payment.
  • หน้า payment page อาจพาลูกค้าออกไปเว็บภายนอกpayment_url ชี้ไปหน้า hosted page ของแพลตฟอร์มเองเสมอ (บน payment_page_domain)
    บางช่องทาง หน้าดังกล่าวจะ redirect ลูกค้า ต่อไปยังหน้าชำระของช่องทางนั้น
    การ redirect ต่อนี้เป็นส่วนหนึ่งของการจ่ายเงิน ไม่ใช่ ลิงก์ return/กลับมาหา merchant และปลายทางไม่ใช่ URL ที่คุณกำหนดเอง
    ลูกค้าจะกลับมาหาคุณผ่าน flow ปกติของคุณหลังจาก payment webhook ที่ยิงไป notify_url ยืนยันการจ่ายแล้วเท่านั้น
  • Same order lifecycle. Idempotency by merchant_order_id (7 days), order TTL, fee handling, /payment/query, and the completion payment webhook to your notify_url all work exactly as for the other payment endpoints — matched by platform_order_id.
  • วงจร order เหมือนกัน — Idempotency ด้วย merchant_order_id (7 วัน), order TTL, การคิดค่าธรรมเนียม, /payment/query และ payment webhook ตอนจ่ายสำเร็จที่ยิงไป notify_url ทำงานเหมือน endpoint การฝากอื่นทุกประการ
    จับคู่ด้วย platform_order_id
  • Prerequisite. A payment_page_domain must be configured for your platform (your platform admin sets this). Without it, flex returns invalid-inputs before creating anything.
  • เงื่อนไขก่อนใช้ — แพลตฟอร์มต้องตั้ง payment_page_domain ไว้ (admin ของแพลตฟอร์มเป็นผู้ตั้ง)
    ถ้าไม่มี flex จะตอบ invalid-inputs ก่อนสร้าง order ใด ๆ