Skip to content

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.

MethodPathPurpose
POST/v1/payoutsCreate a payout
GET/v1/payouts/{id}Retrieve a payout
GET/v1/payoutsSearch payouts (same parameters as searching pay-ins)
POST/v1/payouts/{id}/cancelCancel a payout
POST /v1/payouts
FieldRequiredDescription
payerone of payer / payerIdThe recipient’s bank account: bankCode, accountNumber, accountName, optional accountNameEn. Reused if you already have a payer with this account, otherwise created; see Inline payer
payerIdone of payer / payerIdAn existing recipient’s payer_... id. Money goes to this payer’s bank account
amountyesDecimal string, between your account’s payoutMinimum and payoutMaximum
currencyyesTHB, USD, USDT or LAK
methodnoauto (default), bank_transfer, crypto, lao_qr
referencenoYour reference, max 128 characters
webhookUrlnoURL that receives webhooks. Without it there are no webhooks for this payout and you must check the status yourself
walletAddresscrypto onlyDestination wallet. Required when method is crypto or currency is USDT
networknoWallet 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 payerId and payer (both: 400 parameters_exclusive; neither: 400 parameter_missing). An inline payer works exactly as for pay-ins: an existing payer with the same bankCode and accountNumber is reused without changing its stored name (the response then carries a payer_name_differs warning if the name differs), otherwise a new payer is created with the same checks as POST /v1/payers. The money is sent to the stored account of the payer used.
  • Your available balance (balance.available from GET /v1/account) must cover the payout, otherwise 422 insufficient_balance.
  • One open payout per payer. Otherwise 409 pending_payout_exists.
  • Send an Idempotency-Key header 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_review and waits for an operator. Once approved it returns to pending (with a payout.pending webhook) and continues; if it is not approved it is canceled.

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"
}
StatusMeaningFinal
pendingCreated, waiting to be processedno
processingQueued or submitted to the bankno
in_reviewAbove the automatic threshold, waiting for an operatorno
succeededTransferredyes
canceledCanceled by you, an operator or the systemyes
rejectedRejectedyes
failedThe transfer failed; see failureReason. You can cancel it, or the team may resubmit itnot necessarily
POST /v1/payouts/{id}/cancel

No body. A payout can be canceled when it is:

  • pending or failed,
  • processing and 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.

HTTPcodeMeaning and what to do
400parameter_missing (param: walletAddress)Crypto and USDT payouts need walletAddress
400parameter_missing, parameter_invalidNeither payerId nor payer was sent, or a payer field is malformed; see error.param
400parameters_exclusiveBoth payerId and payer were sent
400unsupported_currency, unsupported_methodCurrency or channel not supported
403payouts_disabledPayouts are disabled for your account
404payer_not_foundpayerId does not exist or is not yours
422bank_not_foundpayer.bankCode is not a code from GET /v1/banks
409pending_payout_existsThe payer already has an open payout
409payout_not_cancelableCannot be canceled in its current status
422insufficient_balanceNot enough available balance
422amount_below_minimum, amount_above_maximumOutside your account limits
422amount_below_feeThe amount is lower than the fee
422payer_inactive, payer_blockedThe payer is inactive or blocked
422no_payout_account_availableNo payout account is free right now; try again later
422not_available_now, maintenanceOutside service hours or under maintenance

Every code is listed in Errors.