1. Partner Flow
BPN OpenAPI
  • Get started
    • Introduction to BPN
    • Introduction to API
    • Architecture Overview
    • Authentication
    • Environments
    • Response envelope
    • Idempotency
  • Guides
    • Virtual Account
      • Virtual Account Overview
      • VA · Payin
      • VA · Statuses
      • VA · Payout
      • VA · RFI
      • VA · Currencies & limits
      • VA Opening
        • VND VA Opening
        • BRL VA Opening
    • Wallet
      • Wallet · Transfer
      • Wallet · Assets & limits
      • Wallet · Deposit whitelist
      • Wallet · PaymentLink
      • Wallet Overview
      • Wallet · Deposit
      • Wallet · Statuses
      • Wallet · Withdraw
    • Convert
      • Convert Overview
      • Convert · Quote & submit
      • Convert · Business types
      • Convert · Pairs & limits
      • Convert · Statuses
  • API Reference
    • Virtual Account
      • Virtual Account field notes
      • Inquiry Master VA Balance
      • List Primary Virtual Accounts
      • Create Virtual Account
      • Get Virtual Account Detail
      • List Virtual Account
      • List Virtual Account Orders
      • Get Virtual Account Order Detail
      • Refund Virtual Account Order
      • List RFI Sub Virtual Account
      • Get Sub Virtual Account RFI Template Info
      • Sub Virtual Account Submit RFI
      • Add Bank Account
      • List Bank Account
      • List Banks
      • Payout via Virtual Account
      • Send Email Verify Code
    • Wallet
      • Wallet field notes
      • Deposit Whitelist
        • Get Deposit Whitelist Options
        • Register Deposit Source Address
        • List Deposit Source Addresses
        • Get Deposit Source Address
        • Disable Deposit Source Address
        • Submit Payer Details for a Received Deposit
        • Save Sub-wallet Payer Profile
        • Update Sub-wallet Payer Profile
        • Get Sub-wallet Payer Profile
        • Get Deposit Whitelist Case
      • Get Asset Balance
      • Get Deposit Address
      • Add Deposit Sender
      • Add Withdraw Whitelist
      • Delete Withdraw Whiltelist
      • Request Withdraw
      • Query Wallet Internal Transfer Detail
      • List Wallet Internal Transfer order
      • Wallet Internal Transfer
      • Create Sub Account
      • Query Transaction History
      • List Wallets
      • List Sub Account
      • Get Transaction Detail
      • List Wallet Transactions
      • Get Wallet Transaction Detail
    • Payment Link
      • Abnormal fund
        • Abnormal funds
        • Matchable Payment links
        • Link Order(Abnormal fund)
        • Submit to platform
      • Create Payment Link
      • List Payment links
      • Get Curreny Network Config
      • Prepay Whitelist for One-Time Payment Link
      • Prepay Whitelist for Permanent Payment Link
    • Convert
      • Convert field notes
      • Inquery FX Rate
      • Get Stablecoin Quote
      • Create Stable Order
      • Get Order (Single) Detail
      • List Orders(Batch)
    • KYB
      • Share KYB/KYC Info For Sub User
      • Get KYB Sub User Status
    • Reconciliation
      • Get Reconciliation Order List By Page
    • External Provider
      • FE: Create stablecoin collection sub-account link
      • FE: Deposit Travel Rule
      • External Provider · Deposit whitelist
      • Create stablecoin collection sub-account link
      • Get sub wallet account
      • List sub wallet accounts
      • Change sub wallet status
      • Query stablecoin collection order list
      • Query stablecoin collection order status
      • Get quote
      • Accept stablecoin collection order
      • Reject stablecoin collection order
      • Query USD balance
      • USD Payout (withdrawal)
      • Query USD Payout order status
      • Query USD Payout order list
      • Create deposit Travel Rule link
      • Create deposit Travel Rule detail link
    • Mock
      • Mock Virtual account Payin Order
      • Mock wallet deposit transaction
      • Mock Payment Link deposit
      • Mock Payin Order Refund
      • Mock Payout Order Update Status
    • Pay Session
      • Request Pay Session
    • Files
      • Request File Upload URL
  • Webhooks
    • Webhooks Overview
    • KYB notifications
    • Event catalogue
    • Resend Fail Webhook
    • Open Virtual Account Status
    • Virtual Account Payment Status
    • Virtual Account Invoice update
    • Transaction Status Notification
    • KYB Status Notification
    • Deposit Sender Detail Required
    • Abnormal Fund Notification
    • WALLET_TRANSFER_ORDER_UPDATED
    • Sub Virtual Account RFI Required
    • Sub Wallet Update
    • wallet address whitelist Update
    • Crypto Deposit Order Notification
    • Collect Order Updated
    • Usd Payout Order Updated
    • onboard result
    • partner order status
    • PaymentLink Notification
    • Deposit Whitelist Notification
  • Partner Flow
    • Share KYB/KYC and open account directly
      POST
    • Get KYB/KYC submit + open account status
      GET
    • List Banks
      GET
    • Check Account
      POST
    • Add Account
      POST
    • Get Stablecoin Quote
      POST
    • Create Stable Order
      POST
    • Get Order (Single) Detail
      GET
    • List Orders(Batch)
      GET
    • Submit hash
      POST
    • Order Status Notification (STABLE_ORDER_UPDATED)
  • Appendix
    • Enums quick reference
    • Enum
    • Virtual Account(VA) Support List & KYB requirement
  • Release Notes & Changelog
  • Errors
    • Error codes catalogue
  • Change Log
    • 2026-09-21 Virtual Account independent refund orders
    • Wallet deposit source-address whitelist
  1. Partner Flow

Create Stable Order

POST
/v1/stable/order/submit-order

Submit Order (Partner Flow · STABLE_SELL)#

POST /v1/stable/order/submit-order — create a stablecoin → fiat order from an unexpired quote. Fiat is paid out to targetAccountId (bound via add-account), taken from this request or, if omitted, from the quote.

Supported combinations#

paymentMethodKESUGXTZS
MOBILE_MONEY✅✅✅
BANK_TRANSFER✅❌❌

Request#

fieldrequiredvalue
businessTypeyesSTABLE_SELL
paymentMethodyesBANK_TRANSFER / MOBILE_MONEY
sourceAccountIdnonull (or omit) for STABLE_SELL
sourceCurrencyyesUSDC / USDT
targetCurrencyyesKES / UGX / TZS
targetAccountIdnoaccountId returned by POST /v1/account/add-account; omit to use the targetAccountId sent in get-quote
quoteIdyesquoteId returned by get-quote; must not be expired
merchantOrderIdyesyour order number; unique per order, used for idempotency and reconciliation
transactionIdyesid of the transfer that moved the end user's funds to the BPN account: the on-chain transaction hash, or your internal transfer id. Each transactionId can be used for one order only
userRefundCryptoAddressyeswhere stablecoin is refunded if the order cannot be completed
userRefundCryptoAddress.addressyeson-chain address
userRefundCryptoAddress.networkyeschain network, e.g. TRON, ETH
userRefundCryptoAddress.currencynoUSDC / USDT; defaults to sourceCurrency
userRefundCryptoAddress.memonotag / memo for chains that require it
remarksnofree text
Validation:
businessType, paymentMethod, sourceCurrency and targetCurrency must match the values used in get-quote for quoteId.
Send targetAccountId in get-quote or in submit-order (at least one of them). If submit-order omits it, the targetAccountId of the quote is used; if both are sent, the submit-order value is used. The account must have the same paymentMethod + targetCurrency as the quote.
transactionId is required for KES / UGX / TZS. Send either the on-chain transaction hash or your internal transfer id of the transfer that moved the end user's funds to the BPN account.
A transactionId can be used for one order only. Submitting a new merchantOrderId with a transactionId that is already linked to another order is rejected (status != 200).
Do not send beneficiaryBank for KES / UGX / TZS: the payout account is targetAccountId.

Idempotency#

merchantOrderId is the idempotency key. Retrying with the same merchantOrderId (e.g. after a timeout) does not create a second order; query the order with GET /v1/stable/order/query-detail?merchantOrderId=... instead of submitting a new one. Do not reuse a merchantOrderId for a different order. transactionId is not an idempotency key: a retry must send the same merchantOrderId and the same transactionId.

Response data#

merchantOrderId, orderId, orderStatus (see query-detail for all statuses).
HTTP 200 only means the order was accepted; it does not mean fiat was paid out. Track the final state with GET /v1/stable/order/query-detail (and the order status webhook).

Bank code validation (submit-time)#

The bank / operator code of targetAccountId is validated before the order is created:
ODR00001047 — bank code is not in the quote channel's currency catalog.
ODR00001048 — bank catalog is unavailable; the order is not created.
ODR00001049 — beneficiary account format is invalid.

HKD (RD Wallet) partners#

HKD off-ramp keeps its existing contract: send quoteId, merchantOrderId, userRefundCryptoAddress, optional beneficiaryBank (HK clearing code in bankId; omit to use the KYB default) and extInfo.travelRule. redirectUrl / nextAction / externalOrderId in the response are HKD only.

Request

Body Params application/json

Examples
{
    "businessType": "STABLE_SELL",
    "paymentMethod": "BANK_TRANSFER",
    "sourceAccountId": null,
    "sourceCurrency": "USDT",
    "targetCurrency": "KES",
    "targetAccountId": "12991",
    "quoteId": "c1f0a7e2b9d84c51a6e3f2d1b0c9a8e7",
    "merchantOrderId": "PARTNER_ORDER_20261020_0001",
    "transactionId": "7c2e9f4b1a8d3c6e5f0a2b4d6e8f1a3c5b7d9e0f2a4c6e8b1d3f5a7c9e2b4d6f",
    "userRefundCryptoAddress": {
        "address": "TQ5NmRkKJ8b3H6x1YpW2sVfZ4nC7dE9aBc",
        "network": "TRON",
        "currency": "USDT",
        "memo": ""
    }
}

Request Code Samples

Shell
JavaScript
Java
Swift
Go
PHP
Python
HTTP
C
C#
Objective-C
Ruby
OCaml
Dart
R
Request Request Example
Shell
JavaScript
Java
Swift
cURL
curl --location '/v1/stable/order/submit-order' \
--header 'Content-Type: application/json' \
--data '{
    "businessType": "STABLE_SELL",
    "paymentMethod": "BANK_TRANSFER",
    "sourceAccountId": null,
    "sourceCurrency": "USDT",
    "targetCurrency": "KES",
    "targetAccountId": "12991",
    "quoteId": "c1f0a7e2b9d84c51a6e3f2d1b0c9a8e7",
    "merchantOrderId": "PARTNER_ORDER_20261020_0001",
    "transactionId": "7c2e9f4b1a8d3c6e5f0a2b4d6e8f1a3c5b7d9e0f2a4c6e8b1d3f5a7c9e2b4d6f",
    "userRefundCryptoAddress": {
        "address": "TQ5NmRkKJ8b3H6x1YpW2sVfZ4nC7dE9aBc",
        "network": "TRON",
        "currency": "USDT",
        "memo": ""
    }
}'

Responses

🟢200OK
application/json
Bodyapplication/json

Examples
{
    "status": 200,
    "code": null,
    "msg": "OK",
    "data": {
        "merchantOrderId": "PARTNER_ORDER_20261020_0001",
        "orderId": "ST2026102014120391827364519283",
        "orderStatus": "INIT",
        "redirectUrl": null,
        "nextAction": null,
        "externalOrderId": null
    },
    "traceId": "Auto:9c0d1e2f3a4b45c6d7e8f9a0b1c2d3e4",
    "success": true
}
Previous
Get Stablecoin Quote
Next
Get Order (Single) Detail
Built with