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 ครั้งเดียวครอบคลุมทุกช่องทางที่แพลตฟอร์มเปิดใช้
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 อัตโนมัติ |
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/create —
merchant_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
{
"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
}
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
| Field | Type | Description | ฟิลด์ | ประเภท | คำอธิบาย |
|---|---|---|---|---|---|
| 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_domainflex จึงไม่มีหน้าให้ส่งลูกค้าไป รวมถึงกรณีทั่วไป: 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 |
service-unavailableservice-unavailableA 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_urlalways points at the platform's own hosted page (on thepayment_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 tonotify_urlconfirms 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 yournotify_urlall work exactly as for the other payment endpoints — matched byplatform_order_id. - วงจร order เหมือนกัน — Idempotency ด้วย
merchant_order_id(7 วัน), order TTL, การคิดค่าธรรมเนียม, /payment/query และ payment webhook ตอนจ่ายสำเร็จที่ยิงไปnotify_urlทำงานเหมือน endpoint การฝากอื่นทุกประการ
จับคู่ด้วยplatform_order_id - Prerequisite. A
payment_page_domainmust be configured for your platform (your platform admin sets this). Without it, flex returnsinvalid-inputsbefore creating anything. - เงื่อนไขก่อนใช้ — แพลตฟอร์มต้องตั้ง
payment_page_domainไว้ (admin ของแพลตฟอร์มเป็นผู้ตั้ง)
ถ้าไม่มี flex จะตอบinvalid-inputsก่อนสร้าง order ใด ๆ