Recent regulations in Indonesia require additional verification steps for payments made through selected Virtual Accounts on crypto platforms. All payments made to selected Virtual Accounts must include payer verification data for crypto merchant. 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 to the selected channels for crypto merchant. Other payment channels continue to work as before.
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.
Available Payment Channels with Payer Verification
The features presented here will be tailored specifically for crypto merchants; other functionalities should adhere to the configurations of each channel on a different page.
Channel Name | Minimum and Maximum Amount (Specific for Crypto) | Interbank Capabilities |
|---|---|---|
| IDR 1 - IDR 30,000,000 | |
| IDR 1 - IDR 9,999,999,999 | |
| IDR 1 - IDR 50,000,000,000 | via RTOL, BI-FAST, SKN/LLG, RTGS |
Integration Flow
Overall Processes
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
How to Integrate
Virtual Account Creation
When creating virtual accounts with payer verification, you'll now need to include verification data in the channel_properties. This data helps verify that payments come from the correct source.
All existing 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": "BRI_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": "BRI_VIRTUAL_ACCOUNT",
"actions": [
{
"type": "PRESENT_TO_CUSTOMER",
"descriptor": "VIRTUAL_ACCOUNT_NUMBER",
"value": "87909123456789"
}
]
}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.
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 the selected Virtual Account channels 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": {
"type": "REUSABLE_PAYMENT_CODE",
"status": "SUCCEEDED",
"country": "ID",
"created": "2025-07-03T07:00:30.200Z",
"updated": "2025-07-03T07:00:30.200Z",
"captures": [
{
"capture_id": "cptr-3ab8f72e-8811-4e34-81a9-a0f3bdbad6c1",
"capture_amount": 10001,
"capture_timestamp": "2025-07-03T07:00:30.200Z"
}
],
"currency": "IDR",
"payment_id": "py-889cfe14-8a20-4fe6-823e-2363fc22ba9e",
"business_id": "5f27a14a9bf05c73dd040bc8",
"channel_code": "BRI_VIRTUAL_ACCOUNT",
"reference_id": "crypto-user-12345",
"capture_method": "AUTOMATIC",
"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"
}
}
},
"payment_request_id": "pr-90392f42-d98a-49ef-a7f3-abcezas123"
},
"api_version": "v3"
}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:
|
Important Note on UNKNOWN Status
The
UNKNOWNverification 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 anUNKNOWNresult, the payment should not be considered successful and you should either verify it manually or process a refund to the registered withdrawal account.
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}/cancelStep 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": "BRI_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.
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_nameUnknown 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.
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.
Frequently Asked Questions
Q: What happens if I don't include verification data?
A: Payments to the selected 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 channels that required payer verification process.
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.