Mandiri Virtual Account is a payment solution provided by Bank Mandiri, enabling customers to make payments using a unique virtual account number generated for each transaction. As one of Indonesia's leading banks with a strong reputation for innovation, Bank Mandiri is a popular choice for secure and efficient payment solutions.
When customers select Mandiri Virtual Account at checkout, they are provided with a virtual account number. They can complete the payment through mobile banking, internet banking, or ATMs. Once the payment is processed, you receive an instant confirmation, ensuring a seamless and reliable transaction experience for you and your customers.
Features
Channel code |
|
Currency | IDR |
Minimum amount | 1 |
Maximum amount | 50,000,000,000 |
User approval flow | PRESENT TO CUSTOMER |
Reusable payment code | ✅ |
Custom payment code | ✅ |
Display merchant name | MERCHANT |
Display user name | ✅ |
Set expiry | ✅ |
Settlement time | Instant |
Refund | ❌ |
Partial refund | ❌ |
Multiple partial refund | ❌ |
Refund validity | N/A |
Compatible integration | Payment API, Payment Links |
Payment flow
Mobile banking
Log in to Livin’ by Mandiri app
Select IDR Transfer > Transfer to new recipient
Enter virtual account number (e.g. 8860863623046)
Enter or confirm payment amount
Click Continue
Enter MPIN
ATM
Insert ATM Card
Select preferred language
Enter ATM PIN
Select PAYMENT > MULTI PAYMENT
Enter company code 88608 (XENDIT), then press CORRECT
Enter virtual account number (e.g. 8860863623046), then press CORRECT
Enter payment amount, then press CORRECT
Confirm payment details
Crypto Merchant Integration: Payer Verification
Recent regulations in Indonesia require additional verification steps for payments made through BRI and Mandiri virtual accounts on crypto platforms. This guide will help you implement the necessary changes to comply with these requirements while maintaining a smooth payment experience for your end users.
Pilot Feature Notice
Payer verification is currently in pilot phase. You may encounter incomplete features, unexpected behavior, or changes to the API during development. We recommend thorough testing in sandbox environment and staying updated with our documentation for the latest changes.
Crypto Platform Exclusive
This feature is only available for crypto platforms. If you operate a crypto platform and need access to this feature, please contact us at help@xendit.co.
What's Changed
Starting in August 2025 (pending bank approval), all payments made to BRI_VIRTUAL_ACCOUNT
and MANDIRI_VIRTUAL_ACCOUNT
must include payer verification data. This means you'll need to collect and verify the identity of end users making payments to ensure they match the registered account holder.
This requirement only affects BRI and Mandiri virtual accounts. Other payment channels continue to work as before.
New Prefixes/MID
As part of this change, new prefixes will be introduced:
Mandiri VA: 87910 (closed payment), 87909 (open payment)
BRI VA: Waiting for bank confirmation (will be updated)
Existing virtual accounts cannot be used with the new verification system and must be recreated using the new flow.
A. Integration Flow
The verification process works by comparing the payer's bank account details with the information you provide when creating the virtual account. Here's how it flows:
Create Virtual Account: Include customer verification data when setting up the virtual account
End User Makes Payment: When an end user pays, their bank details are automatically checked
Verification Result: You receive the verification status in the payment webhook
Handle Result: Take appropriate action based on whether verification passed or failed
B. How to Integrate
1. Virtual Account Creation
When creating virtual accounts for BRI or Mandiri, you'll now need to include verification data in the channel_properties
. This data helps verify that payments come from the correct source. See routing payment channels for full list of required information.
All existing BRI and Mandiri virtual accounts must be recreated using this new flow. Previously created virtual accounts will not work with the verification system.
Request - POST /v3/payment_requests
{
"reference_id": "crypto-user-12345",
"type": "REUSABLE_PAYMENT_CODE",
"country": "ID",
"currency": "IDR",
"channel_code": "MANDIRI_VIRTUAL_ACCOUNT",
"channel_properties": {
"expires_at": "2024-12-31T23:59:59Z",
"display_name": "John Doe",
"verification_data": {
"customer_name": "John Doe",
"accepted_name_variations": ["Jogn Doe", "John D", "J. Doe"],
"allowed_bank_accounts": [
{
"bank_name": "BCA",
"account_number": "2876783233",
"account_name": "John Doe"
},
{
"bank_name": "MANDIRI",
"account_number": "1234567890",
"account_name": "John Doe"
}
]
}
}
}
Response
{
"payment_request_id": "pr-90392f42-d98a-49ef-a7f3-abcezas123",
"status": "ACCEPTING_PAYMENTS",
"channel_code": "MANDIRI_VIRTUAL_ACCOUNT",
"actions": [
{
"type": "PRESENT_TO_CUSTOMER",
"descriptor": "VIRTUAL_ACCOUNT_NUMBER",
"value": "87910123456789"
}
]
}
Understanding Verification Fields
customer_name
: The exact name registered for this crypto account.accepted_name_variations
: Common variations of the customer's name (typos, abbreviations, etc.).allowed_bank_accounts
: List of bank accounts that are permitted to send payments to this virtual account. You can refer to Indonesia bank channel names forbank_name
, however we won’t do any validation for that parameter.
2. Handle Verification Results
When an end user makes a payment, you'll receive a webhook with verification results. The webhook includes information about whether the payer's details match your verification criteria.
Note: The verification_result
object will only be present for BRI_VIRTUAL_ACCOUNT
and MANDIRI_VIRTUAL_ACCOUNT
payments using the new verification system.
For comprehensive guidance on implementing webhooks, refer to our webhook handling documentation. If you experience webhook delivery issues, check our delayed webhooks guide.
Webhook Example
{
"event": "payment.capture",
"business_id": "5f27a14a9bf05c73dd040bc8",
"created": "2025-07-03T07:00:27.200Z",
"data": {
"payment_id": "py-889cfe14-8a20-4fe6-823e-2363fc22ba9e",
"status": "SUCCEEDED",
"channel_code": "MANDIRI_VIRTUAL_ACCOUNT",
"reference_id": "crypto-user-12345",
"request_amount": 1000000,
"payment_details": {
"payer_name": "John Doe",
"payer_account_number": "2876783233",
"issuer_name": "MANDIRI",
"verification_result": {
"is_eligible": true,
"sender_verification": {
"result": "SENDER_MATCHED",
"reason": "Name matched"
},
"risk_assessment": {
"result": "NONE",
"reason": "No alert"
}
}
}
}
}
Verification Status Types
Status | Description | Action Required |
---|---|---|
| Payer details match your verification data | Process payment normally |
| Verification couldn't determine if details match due to network timeout or other technical issues | Do not treat as successful payment, instead do a refund |
Important Note on UNKNOWN Status
The
UNKNOWN
verification result is unlikely to occur under normal circumstances, as ineligible payments should typically be rejected outright. However, network timeouts during the verification process may occasionally result in this status. When you receive an UNKNOWN result, the payment should not be considered successful and you should either process a refund.
3. Updating Virtual Account Details
If you need to update the verification data for an existing virtual account (for example, when an end user adds a new bank account or changes their registered name), follow these steps:
Step 1: Cancel the Current Payment Request
POST /v3/payment_requests/{payment_request_id}/cancel
Step 2: Create a New Payment Request
Create a new payment request using the same virtual account number but with updated verification data:
{
"reference_id": "crypto-user-12345-updated",
"type": "REUSABLE_PAYMENT_CODE",
"country": "ID",
"currency": "IDR",
"channel_code": "MANDIRI_VIRTUAL_ACCOUNT",
"channel_properties": {
"expires_at": "2024-12-31T23:59:59Z",
"display_name": "John Doe",
"virtual_account_number": "87910123456789",
"verification_data": {
"customer_name": "John Doe",
"accepted_name_variations": ["Jogn Doe", "John D", "J. Doe"],
"allowed_bank_accounts": [
{
"bank_name": "BCA",
"account_number": "2876783233",
"account_name": "John Doe"
},
{
"bank_name": "MANDIRI",
"account_number": "1234567890",
"account_name": "John Doe"
},
{
"bank_name": "BNI",
"account_number": "9876543210",
"account_name": "John Doe"
}
]
}
}
}
This approach allows you to maintain the same virtual account number while updating the verification criteria.
4. Testing Your Integration
Simulate Successful Payments
You can test successful payments in sandbox using the simulation endpoint:
Request - POST /v3/payment_requests/{payment_request_id}/simulate
{
"amount": 100000
}
Response
{
"status": "PENDING",
"message": "A simulated payment for the specified payment request id is being processed. You will be informed of the result via a webhook."
}
Test Verification Scenarios
To test different verification outcomes, you can create virtual accounts with specific customer names:
Successful Verification: Use the exact name you specify in
customer_name
Unknown Verification: Create a virtual account with customer name "Josua Doe" - this will return
verification_result.sender_verification.result: "UNKNOWN"
Example for Unknown Verification
{
"channel_properties": {
"verification_data": {
"customer_name": "Josua Doe",
"accepted_name_variations": ["J. Doe"],
"allowed_bank_accounts": [...]
}
}
}
This will generate a webhook with "result": "UNKNOWN"
for testing purposes.
C. Additional Notes
Recommended Rollout Plan
To minimize risk during implementation, we recommend a phased rollout approach, start with a small percentage of your user base and scale up as confidence grows. This approach allows you to catch and fix issues before they affect your entire user base.
Availability
Sandbox Environment: Available now for testing and development
Production Environment: Live activation for
BRI_VIRTUAL_ACCOUNT
andMANDIRI_VIRTUAL_ACCOUNT
is scheduled for the second week of August 2025, pending bank approval.
Frequently Asked Questions
Q: What happens if I don't include verification data?
A: Payments to BRI and Mandiri virtual accounts will fail if verification data is missing after the feature goes live.
Q: Can end users use any bank account to pay?
A: Only bank accounts listed in the allowed_bank_accounts
field will be accepted. Payments from other accounts will be rejected.
Q: What if an end user's name doesn't exactly match?
A: Use the accepted_name_variations
field to include common variations of the end user's name.
Q: Can I still use my existing virtual accounts?
A: No, existing virtual accounts cannot be used with the new verification system. You must recreate them using the new flow with verification data.
Q: Do I need to implement this for all payment channels?
A: No, this requirement only applies to BRI_VIRTUAL_ACCOUNT
and MANDIRI_VIRTUAL_ACCOUNT
channels.
Q: What should I do with "UNKNOWN" verification results?
A: Do not treat these as successful payments. Either process a refund automatically or conduct manual review before accepting the payment, as UNKNOWN results typically indicate network timeouts during verification.
Q: Will the API change during the pilot phase?
A: Yes, since this is a pilot feature, there may be changes to the API structure, new fields, or modified behavior. Monitor our documentation for updates.
Q: Can I keep the same virtual account number when updating verification details?
A: Yes, you can specify the same virtual_account_number
in the new payment request after canceling the previous one.
Q: How often do UNKNOWN verification results occur?
A: UNKNOWN results are rare and typically only occur due to network timeouts during the verification process. Under normal circumstances, ineligible payments should be rejected outright.