POST /api/create/va
Request
| Name | Type | Required | Validation | Description |
|---|---|---|---|---|
| merchant_transaction_id | string | true | Merchant-provided unique transaction identifier. | |
| amount | string | true | Numeric, 1-12 digits | Transaction amount expressed as a numeric value. |
| currency | string | true | Allowed value: "IDR" | Transaction currency (only Indonesian Rupiah is supported). |
| bank_code | string | true | Allowed value: see the table below | Bank code used for the transaction |
| customer_name | string | true | Between 5 - 25 characters. Allowed chars: a-z, A-Z, 0-9, - (dash), (space) | Customer name linked to the transaction. |
| product_name | string | true | Between 5 - 25 characters. Allowed chars: a-z, A-Z, 0-9, - (dash), (space) | Product name linked to the transaction. |
| description | string | false | Optional transaction information. | |
| success_redirect_url | string | false | URL to redirect the customer upon successful payment. Also supports mobile deep link URLs. |
Supported bank_code values
| bank_code | Numeric code | Bank |
|---|---|---|
| BCA | 014 | Bank Central Asia |
| BRI | 002 | Bank Rakyat Indonesia |
| BNI | 009 | Bank Negara Indonesia |
| MDR | 008 | Bank Mandiri |
| PRMT | 013 | Bank Permata |
| CIMB | 022 | CIMB Niaga |
| BNC | 490 | Bank Neo Commerce |
| BDM | 011 | Bank Danamon |
| BSI | 451 | Bank Syariah Indonesia |
| MUA | 147 | Bank Muamalat |
| SNM | 153 | Bank Sinarmas |
| OCBC | 028 | Bank OCBC |
| FINPAY | — | Finpay |
| NOBU | 503 | Bank Nationalnobu |
| INA | 513 | Bank Ina Perdana |
| CIMBS | — | CIMB Niaga Syariah |
Each bank can be sent as its letter code or its numeric code; both resolve to the same channel, and responses and webhooks always return the letter code. CIMBS and FINPAY accept the letter code only.
{
"merchant_transaction_id": "ICZ10000001",
"amount": "100000",
"currency": "IDR",
"bank_code": "BRI",
"description": "Lorem Ipsum",
"customer_name": "John Doe",
"product_name": "Product Test",
"success_redirect_url": "https://example.com/success"
}
Response
| Name | Description |
|---|---|
| status | Request status indicator. true indicates success, false indicates failure. |
| message | Result message for the request. Usually "success" when the request succeeds. |
| data.transaction_id | System-generated unique transaction identifier. |
| data.va_number | Generated Virtual Account (VA) number for customer payment. This field can be empty if no virtual account number is available. |
| data.channel | Bank or payment channel used for the Virtual Account. |
| data.redirect_url | Redirect URL for users (when applicable). This field can be null if no redirect URL is available. |
| data.expired_at | Payment expiry datetime, server time (UTC+7), no offset, format YYYY-MM-DD HH:MM:SS (e.g. "2025-02-26 19:00:00"). null if not applicable. |
| data.expired_at_iso | Same expiry as expired_at, as ISO 8601 with offset (e.g. "2025-02-26T19:00:00+07:00"). Same format on every channel. null when expired_at is null. |
| data.payment_channel | Normalized payment channel, one format for every payment type and provider: a value such as QRIS, VA_BRI, BANK_BCA, or EWALLET_DANA (payment type prefix + code from the Appendix). null when the channel cannot be determined. Prefer this over channel. |
| data.success_redirect_url | URL to redirect the customer upon successful payment. Also supports mobile deep link URLs. |
{
"status": true,
"message": "success",
"data": {
"transaction_id": "9e536777-2bfa-4161-9931-35f5c4b23faf",
"payment_channel": "VA_MDR",
"va_number": "8999817535253527",
"channel": "MDR",
"redirect_url": "{host}/checkout/9e536777-2bfa-4161-9931-35f5c4b23faf/va/MDR",
"success_redirect_url": "https://example.com/success",
"expired_at": "2025-02-26 19:00:00",
"expired_at_iso": "2025-02-26T19:00:00+07:00"
}
}
A 403 response is returned when:
Unknown bank_code— thebank_codeis not in the supported list above.VA payment for this bank is not configured.— the bank is supported, but Virtual Account for it is not enabled for your account.
{
"status": false,
"message": "string"
}
The request body failed validation. message summarizes the errors and errors lists the messages per field.
{
"status": false,
"message": "The amount field is required.",
"errors": {
"amount": ["The amount field is required."]
}
}