It’s a popular financing option that improves conversion rates and average order values by offering customers greater payment flexibility without upfront burden. Monxa’s BNPL integration simplifies the process by standardizing diverse provider APIs into a unified Charge API experience. Developers can enable multiple BNPL providers (e.g., Atome, Kredivo, PayLater) using the same flow, parameters, and webhook structure — without worrying about each provider’s technical nuances. BNPL payments on Monxa are direct-capture only, meaning that once the customer confirms the payment plan with the provider, the transaction is immediately captured. There is no authorisation or delayed capture step. Refunds, if supported, are handled through Monxa’s Refund API, and settlement follows the provider’s remittance schedule to your Monxa Balance or bank account.
Key Benefits
- 💳 Increase conversion: Offer instalment options at checkout for affordability.
- 🛒 Higher order value: Customers are more likely to spend more when paying later.
- ⚙️ Unified API: Same request/response structure across providers and regions.
- 🧾 Automatic capture: Simplifies fulfilment since funds are captured immediately.
- 🔄 Refund support: Full or partial refunds available depending on provider policy.
- 🌏 Regional reach: Support for major BNPL providers in Southeast Asia and beyond
1. Create a Charge
Initiate the payment by creating a charge in your system with the transaction details.
2. Redirect Customer to BNPL App
Use the
redirect_url from Monxa to send the customer to their BNPL app or platform.3. Customer Authorizes Payment
The customer confirms the transaction by entering their PASSWORD / PIN / OTP or using biometric authentication in their BNPL app.
4. Handle Webhooks
Once the e-wallet provider processes the payment, Monxa sends a webhook notification to update your system with the final status.
Supported Channels
- 🇮🇩 Indonesia
| Channel | Code | Currency | Refund | Settlement | Min Amount | Max Amount |
|---|---|---|---|---|---|---|
| Kredivo | bnpl_kredivo | IDR | Full | T+4 | 1,000 | 30,000,000 |
| Akulaku | bnpl_akulaku | IDR | Full | T+2 | 1,000 | 25,000,000 |
| Atome | bnpl_atome | IDR | Full | T+2 | 50,000 | 6,000,000 |
| Indodana | bnpl_indodana | IDR | Full | T+2 | 10,000 | 25,000,000 |
Payment Flow
Status Lifecycle (BNPL)
| Monxa Status | When it Occurs | Merchant Action |
|---|---|---|
| pending | Charge created; awaiting provider approval | Redirect customer; wait for webhook |
| succeeded | Provider approved & captured | Fulfill order |
| failed | Provider rejected / canceled / technical error | Offer retry or alternate method |
| expired | Customer did not complete within session | Create a new charge if neede |
Step 1: Create a Charge
Create a charge with a BNPLchannel_code (examples: bnpl_atome, bnpl_kredivo, etc.) and include a return_url so we can return customers to your site/app after they complete the BNPL flow.
Request Parameters
Request Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| amount | string | required | The amount to be paid. |
| currency | string | required | The currency of the payment (e.g., “sgd”). |
| channel_code | string | required | Payment method code used to select the payment method provider. (e.g. “qr_qris”). |
| channel_properties | object | conditional | Parameters that contain information required by the payment route provider to initiate payment processing. |
| reference_id | string | optional | Merchant’s payment reference ID |
| order_id | string | optional | Order ID in Monxa associated with this charge |
| customer_id | string | optional | Customer ID in Monxa associated with this charge |
| description | string | optional | A custom description for the charge. |
| metadata | object | optional | Key-value entries for your custom data. You can specify up to 50 keys, with key names up to 40 characters and values up to 500 characters. This is for your convenience. Monxa will not use this data for any processing. |
Request Example
Request Example
Response Example
Response Example
Step 2: Redirect the Customer
Useactions.redirect_url to send the customer to the BNPL provider’s hosted checkout. Do not generate a QR code—BNPL is a redirect + hosted authentication flow (KYC/eligibility and plan selection happen on the provider’s side).
- Web: HTTP 302 or client-side redirect.
- Mobile: Open in an in-app webview or external browser; handle the
return_urlto resume your flow.
Step 3: Customer Authorizes & Selects a Plan
On the provider page, the customer:- Logs in or signs up (provider KYC/eligibility).
- Selects an installment plan (tenor/fees shown by the provider).
- Confirms the payment.
Step 4: Handle Webhooks & Update Your Order
Rely on webhooks to make authoritative updates to your order or fulfillment state. Key eventscharge.succeeded— BNPL approved & captured; safe to deliver goods/services.charge.failed— Rejected, canceled, or provider error.charge.expired— Customer didn’t complete within the session window.refund.succeeded/refund.failed— If you initiate a refund later (subject to provider rules).
Sample Webhook (charge.succeeded)
Sample Webhook (charge.succeeded)
Sample Webhook (charge.failed)
Sample Webhook (charge.failed)
Refunds (Provider-Dependent)
- Supported: Usually allowed post-capture; partial refunds may be supported depending on the BNPL provider and time window.
- Not Supported / Window Lapsed: Some providers restrict partial refunds or disallow refunds beyond a certain number of days.
-
API: Use
POST /v1/refundswithcharge_id,amount(optional for partial), andreason. Monitorrefund.succeeded/refund.failed.
Error Handling & Retries
- Idempotency: Always set a unique
Idempotency-Keyper create attempt. Reuse the same key on client/network retries to avoid double charges. - Common errors:
400 invalid_channel_properties— Missing/invalidreturn_url.400 unsupported_channel— BNPL provider not enabled for your account/country.402 provider_declined— Eligibility/credit check failed.409 duplicate_reference— If your environment enforces uniquereference_id.
- Recovery: On
failed/expired, offer retry (create a new charge with a freshIdempotency-Key).