Payouts
A payout sends money from your balance to a payer’s bank account (or wallet), for example when one of your users withdraws funds from your service.
| Method | Path | Purpose |
|---|---|---|
POST | /v1/payouts | Create a payout |
GET | /v1/payouts/{id} | Retrieve a payout |
GET | /v1/payouts | Search payouts (same parameters as searching pay-ins) |
POST | /v1/payouts/{id}/cancel | Cancel a payout |
Create a payout
Section titled “Create a payout”POST /v1/payouts| Field | Required | Description |
|---|---|---|
payer | one of payer / payerId | The recipient’s bank account: bankCode, accountNumber, accountName, optional accountNameEn. Reused if you already have a payer with this account, otherwise created; see Inline payer |
payerId | one of payer / payerId | An existing recipient’s payer_... id. Money goes to this payer’s bank account |
amount | yes | Decimal string, between your account’s payoutMinimum and payoutMaximum |
currency | yes | THB, USD, USDT or LAK |
method | no | auto (default), bank_transfer, crypto, lao_qr |
reference | no | Your reference, max 128 characters |
webhookUrl | no | URL that receives webhooks. Without it there are no webhooks for this payout and you must check the status yourself |
walletAddress | crypto only | Destination wallet. Required when method is crypto or currency is USDT |
network | no | Wallet network, e.g. BSC |
{ "payer": { "bankCode": "SCB", "accountNumber": "1234567890", "accountName": "สมชาย สบายดี" }, "amount": "500.00", "currency": "THB", "reference": "withdraw-20001", "webhookUrl": "https://shop.example.com/webhooks/payments"}Or send "payerId": "payer_..." instead of payer for a payer you already have.
Good to know:
- Send exactly one of
payerIdandpayer(both:400 parameters_exclusive; neither:400 parameter_missing). An inlinepayerworks exactly as for pay-ins: an existing payer with the samebankCodeandaccountNumberis reused without changing its stored name (the response then carries apayer_name_differswarning if the name differs), otherwise a new payer is created with the same checks asPOST /v1/payers. The money is sent to the stored account of the payer used. - Your available balance (
balance.availablefromGET /v1/account) must cover the payout, otherwise422 insufficient_balance. - One open payout per payer. Otherwise
409 pending_payout_exists. - Send an
Idempotency-Keyheader so a retry after a timeout cannot create a second payout. See Retry a create safely. - A payout above your account’s automatic approval threshold goes to
in_reviewand waits for an operator. Once approved it returns topending(with apayout.pendingwebhook) and continues; if it is not approved it is canceled.
The payout object
Section titled “The payout object”Same fields as a pay-in except returnUrl, checkoutUrl, paymentImage and payTo. Here payerAccount is the destination account.
{ "object": "payout", "id": "pout_0f1e2d3c4b5a69788796a5b4c3d2e1f0", "reference": "withdraw-20001", "payerId": "payer_7c0a4b8e2f3d4a1b9c8d7e6f5a4b3c2d", "payer": { "object": "payer", "id": "payer_7c0a4b8e2f3d4a1b9c8d7e6f5a4b3c2d", "...": "..." }, "requestedAmount": "500.00", "amount": "500.00", "fee": "5.00", "currency": "THB", "method": "bank_transfer", "status": "processing", "failureReason": null, "webhookUrl": "https://shop.example.com/webhooks/payments", "payerAccount": { "bankCode": "SCB", "accountNumber": "1234567890", "accountName": "สมชาย สบายดี" }, "createdAt": "2026-01-01T01:00:00.000Z", "updatedAt": "2026-01-01T01:00:05.000Z"}Statuses
Section titled “Statuses”| Status | Meaning | Final |
|---|---|---|
pending | Created, waiting to be processed | no |
processing | Queued or submitted to the bank | no |
in_review | Above the automatic threshold, waiting for an operator | no |
succeeded | Transferred | yes |
canceled | Canceled by you, an operator or the system | yes |
rejected | Rejected | yes |
failed | The transfer failed; see failureReason. You can cancel it, or the team may resubmit it | not necessarily |
Cancel a payout
Section titled “Cancel a payout”POST /v1/payouts/{id}/cancelNo body. A payout can be canceled when it is:
pendingorfailed,processingand still queued,processing, already submitted to the bank, and created more than 30 minutes ago.
On success you get the payout with status canceled. If the bank refuses the cancellation, or the payout moved on in the meantime, you get 409 payout_not_cancelable. Cancels made through the API do not send a webhook.
Common errors
Section titled “Common errors”| HTTP | code | Meaning and what to do |
|---|---|---|
| 400 | parameter_missing (param: walletAddress) | Crypto and USDT payouts need walletAddress |
| 400 | parameter_missing, parameter_invalid | Neither payerId nor payer was sent, or a payer field is malformed; see error.param |
| 400 | parameters_exclusive | Both payerId and payer were sent |
| 400 | unsupported_currency, unsupported_method | Currency or channel not supported |
| 403 | payouts_disabled | Payouts are disabled for your account |
| 404 | payer_not_found | payerId does not exist or is not yours |
| 422 | bank_not_found | payer.bankCode is not a code from GET /v1/banks |
| 409 | pending_payout_exists | The payer already has an open payout |
| 409 | payout_not_cancelable | Cannot be canceled in its current status |
| 422 | insufficient_balance | Not enough available balance |
| 422 | amount_below_minimum, amount_above_maximum | Outside your account limits |
| 422 | amount_below_fee | The amount is lower than the fee |
| 422 | payer_inactive, payer_blocked | The payer is inactive or blocked |
| 422 | no_payout_account_available | No payout account is free right now; try again later |
| 422 | not_available_now, maintenance | Outside service hours or under maintenance |
Every code is listed in Errors.