Create Payment

Create a Payment — the primary endpoint for charging a customer. One endpoint serves two modes:

  • payment_type=DEBIT — immediate charge (funds captured right away)
  • payment_type=AUTH — pre-authorization (funds held; capture later via Capture Payment)

This endpoint also unifies multiple payment methods: cards (with optional 3DS), wallets (Binance Pay, Alipay+), and tokens (one-time tokens produced by your frontend SDK).

When to Use

  • Charging a customer for a purchase (DEBIT)
  • Reserving funds before fulfilment (AUTH + later Capture)
  • Resuming a paused 3DS challenge (pass three_ds_info.paused_payment_id)
  • Creating a wallet / QR-based payment (Binance Pay, Alipay+)

Endpoint

POST https://api.sandbox.build.app/api/v1/acq/payment

Integration Flow

Card payment with 3DS (full flow)

3DS Card Payment Flow

Wallet / QR payment (Binance Pay, Alipay+)

Wallet Payment Flow

Simple card payment (no 3DS)

Card Payment without 3DS


State Transitions

Payment Status


Currency Reference

All monetary amount fields in the API must be passed as integers in the smallest unit (minor unit) of the currency. The decimal scaling follows the currency's defined precision (ISO 4217).

Critical Rule

  • If the actual amount is 10.51 AUD, send 1051 (10.51 × 100).
  • If the actual amount is 100 JPY (zero-decimal), send 100 as-is.
  • If the actual amount is 1.500 BHD (three-decimal), send 1500 (1.5 × 1000).
  • Never send decimals or strings — always integer in minor units.

Conversion Rule

The integer transmitted = actual amount × 10^decimal_places. The receiving system divides it back when displaying.

// Examples
{ "amount": 1051,  "currency": "AUD" }   // ✓ Actual: 10.51 AUD  (2 decimals → x100)
{ "amount": 10000, "currency": "AUD" }   // ✓ Actual: 100.00 AUD
{ "amount": 100,   "currency": "JPY" }   // ✓ Actual: 100 JPY    (0 decimals → x1)
{ "amount": 1500,  "currency": "BHD" }   // ✓ Actual: 1.500 BHD  (3 decimals → x1000)
{ "amount": 100500000, "currency": "USDT" } // ✓ Actual: 100.500000 USDT (6 decimals → x1,000,000)

{ "amount": "10.51",  "currency": "AUD" }   // ✗ rejected (string with decimal)
{ "amount": 10.51,    "currency": "AUD" }   // ✗ rejected (float not allowed)

Primary Currencies (Most Common)

CurrencyISO CodeNumericSymbolDecimal PlacesAPI Example AmountActual Amount
Australian DollarAUD036A$2105110.51
US DollarUSD840$2105110.51
Chinese YuanCNY156¥2105110.51
Philippine PesoPHP6082105110.51
Malaysian RinggitMYR458RM2105110.51
Singapore DollarSGD702S$2105110.51
Hong Kong DollarHKD344HK$2105110.51
EuroEUR9782105110.51
British PoundGBP826£2105110.51

Zero-Decimal Currencies

Pass the integer as-is. No multiplication needed.

CurrencyISO CodeNumericSymbolDecimal PlacesAPI Example AmountActual Amount
Japanese YenJPY3920100100
Indonesian RupiahIDR360Rp05000050000
Vietnamese DongVND7040100000100000
Korean WonKRW410010001000

Three-Decimal Currencies

Multiply actual amount × 1000 to get the integer.

CurrencyISO CodeNumericSymbolDecimal PlacesAPI Example AmountActual Amount
Bahraini DinarBHD048.د.ب315001.500
Jordanian DinarJOD400JD315001.500
Omani RialOMR512ر.ع.315001.500
Iraqi DinarIQD368د.ع310000001000.000
Libyan DinarLYD434LD315001.500

Other Supported Currencies (2 Decimals)

Multiply actual amount × 100 to get the integer.

CurrencyISO CodeNumericSymbolDecimal PlacesAPI Example AmountActual Amount
Indian RupeeINR3562105110.51
Thai BahtTHB764฿2105110.51
Mexican PesoMXN484Mex$2105110.51
New Zealand DollarNZD554NZ$2105110.51
Turkish LiraTRY9492105110.51
UAE DirhamAED784د.إ2105110.51
Canadian DollarCAD124C$2105110.51
South African RandZAR710R2105110.51
Pakistani RupeePKR586P.Rs.2105110.51
Brazilian RealBRL986R$2105110.51

Crypto Assets

Multiply actual amount by 10^decimal_places to get the integer.

AssetCodeDecimal PlacesAPI Example AmountActual Amount
Tether USDUSDT6100500000100.500000
USD CoinUSDC6100500000100.500000

Need a currency not listed? Build supports 150+ currencies. Contact your account manager to enable additional currencies for your merchant account. The decimal precision follows the ISO 4217 standard.


Best Practices

  • merchant_request_id is sacred. Always generate one per intended payment. Mismatched payloads with the same ID return IDEM_REQ_PARAMS_CHANGED.
  • Always implement a next_action handler. Even if you think the flow is frictionless, some jurisdictions / issuers force 3DS. Your code must redirect or render QR when told.
  • Use AUTH + Capture for anything involving fulfilment. It lets you charge only when you ship, reducing refunds.
  • Respect expire_time. For wallet / QR flows, the entrance URL has a limited lifetime. Show a countdown or offer a refresh action.
  • Reconcile via webhooks, not polling. Treat DEBIT webhook as the source of truth.
  • Pass accurate billing for card payments. AVS / 3DS frictionless rates depend heavily on address and email. Sparse billing data means more challenges.
  • Validate success_url / cancel_url / error_url. Use HTTPS. Invalid URLs break the post-payment redirect.

FAQ

Q: Can I charge the cardholder without 3DS? A: Depends on the issuer / region. In many regions you can, but the liability for fraud remains on you. Consult your acquiring agreement.

Q: What is the difference between DEBIT and AUTH? A: DEBIT charges immediately — funds leave the customer at authorization time. AUTH places a hold; you must call /capture later to actually take the money, or /cancel to release the hold. Use AUTH whenever there is a fulfilment step.

Q: Can I combine 3DS with DEBIT? A: Yes. 3DS works with both DEBIT and AUTH. The flow is the same: /3ds/setup/payment.

Q: What does next_action.type=PAYMENT_ENTRANCE mean? A: The payment requires the customer to complete the flow in an external app or QR scan (typical of wallets like Binance Pay and Alipay+). Render the QR / deeplink / redirect to checkout_url and wait for the webhook.

Q: The payment response does not include next_action. Is the payment done? A: Yes. An absent next_action means the payment reached a terminal state for this API call. Check payment_status: SUCCEEDED means success.

Q: My 3DS challenge redirect completed, but the cardholder bounced back and my payment is still REQUIRES_ACTION. What now? A: Resume the payment by calling POST /payment again with the same merchant_request_id and adding three_ds_info.paused_payment_id. Do not create a new payment.

Q: Can I pass my own payment_id? A: No. payment_id is generated by Build. Use order_reference and merchant_request_id for your own identifiers.

Q: What is the maximum amount? A: Depends on your merchant limits and the payment method.

Q: Is there a test mode for BINANCE_PAY / ALIPAY_PLUS_PAY? A: Yes — the sandbox environment simulates wallet callbacks. See the sandbox guide for trigger values.


Next Steps