Xendit API - Complete Payment Gateway Integration
The Xendit API provides comprehensive payment gateway functionality for Indonesian market including bank transfers, virtual accounts, disbursements, and reconciliation. Built for enterprise-grade financial applications with webhook support, balance monitoring, and comprehensive reporting.
🎯 What Can You Manage?
Your complete payment gateway ecosystem with these powerful tools:
- Withdrawals: Bank transfers and disbursements with real-time status tracking
- Virtual Accounts: Fixed VA creation and management for seamless top-ups
- Balance Operations: Multi-account balance monitoring (CASH, HOLDING, TAX)
- Transactions: Complete transaction history with filtering and pagination
- Reconciliation: Automated daily reconciliation with manual resolution support
- Webhooks: Event-driven payment notifications with DLQ handling
- Reporting: Balance and transaction reports for compliance and analytics
- Administration: Health checks, configuration validation, and dashboard monitoring
🧩 Your Payment Building Blocks
💸 Withdrawal & Disbursement Blocks
POST /xendit/wallet/withdraw- Process bank withdrawalGET /xendit/wallet/withdraw/status/:reference_id- Check withdrawal status
🏦 Virtual Account Blocks
POST /xendit/fixed-va/request- Request Fixed VA for top-upGET /xendit/fixed-va/list/:wallet_id- List wallet Fixed VAs
💰 Balance & Transaction Blocks
GET /xendit/balance- Get account balance by typeGET /xendit/balance/all- Get all account balancesGET /xendit/transactions- List transactions with filtersGET /xendit/transactions/:transaction_id- Get transaction detailsGET /xendit/transactions/count- Count transactions
📊 Report & Reconciliation Blocks
GET /xendit/reports/balance- Generate balance reportGET /xendit/reports/transactions- Generate transaction reportPOST /xendit/reconciliation/run- Run daily reconciliationPOST /xendit/reconciliation/wallet/:wallet_id- Reconcile walletPOST /xendit/reconciliation/resolve- Resolve discrepancyGET /xendit/reconciliation/:reconciliation_id- Get reconciliation details
🔔 Webhook & Admin Blocks
POST /xendit/webhook- Process Xendit webhookPOST /xendit/webhook/dlq/process- Process failed webhooksGET /xendit/webhook/stats- Webhook statisticsGET /xendit/health- Health checkGET /xendit/config/validate- Validate configurationGET /xendit/admin/dashboard- Admin dashboard data
🏗️ Common Payment Patterns
Pattern 1: "I want to withdraw money to a bank account"
Balance check → processWalletWithdraw → getWithdrawStatus → Confirmation
Use: /xendit/balance → /xendit/wallet/withdraw → /xendit/wallet/withdraw/status/:reference_id
Pattern 2: "I want to enable VA top-ups for my wallet"
Request Fixed VA → User transfers to VA → Webhook notification → Balance update
Use: /xendit/fixed-va/request → /xendit/webhook
Pattern 3: "I want to reconcile my balances"
Run reconciliation → Check discrepancies → Manual resolution if needed
Use: /xendit/reconciliation/run → /xendit/reconciliation/:id → /xendit/reconciliation/resolve
Pattern 4: "I want to monitor payment operations"
Check health → View dashboard → Generate reports
Use: /xendit/health → /xendit/admin/dashboard → /xendit/reports/transactions
💸 Withdrawal Operations
Process Wallet Withdrawal
Process Wallet Withdrawal to Bank
Process withdrawal from wallet to Indonesian bank account with automatic ledger integration, balance validation, and Xendit disbursement. Supports all major Indonesian banks with real-time status tracking.
Parameters
wallet_idstringrequiredWallet ID to withdraw from
amountnumberrequiredWithdrawal amount in IDR
currencystringCurrency code (default: IDR)
bank_codestringrequiredBank code (BCA, BNI, BRI, MANDIRI, etc.)
account_numberstringrequiredBank account number
account_holder_namestringrequiredAccount holder name
descriptionstringWithdrawal description
user_emailstringUser email for notifications
Request Body
{
"wallet_id": "wallet_456789",
"amount": 500000,
"currency": "IDR",
"bank_code": "BCA",
"account_number": "1234567890",
"account_holder_name": "John Doe",
"description": "Withdrawal to personal account",
"user_email": "john@example.com"
}Response
{
"success": true,
"message": "Withdrawal initiated successfully",
"data": {
"payout_id": "disb_1234567890",
"reference_id": "WALLET-PAYOUT-456789-1705123456",
"status": "PENDING",
"amount": 500000,
"currency": "IDR",
"bank_code": "BCA",
"bank_channel": "ID_BCA",
"account_number": "1234567890",
"account_holder_name": "John Doe",
"estimated_arrival": "2024-01-15T12:00:00Z",
"created_at": "2024-01-15T10:00:00Z"
}
}{
"error": "Insufficient Xendit balance",
"available_balance": 400000,
"requested_amount": 500000
}{
"error": "Wallet not found or access denied"
}{
"error": "Failed to process withdrawal",
"details": "Xendit API error"
}Get Withdrawal Status
Get Withdrawal Status
Check the current status of a withdrawal transaction using its reference ID. Returns real-time status from Xendit with transfer details.
Parameters
reference_idstringrequiredWithdrawal reference ID
Response
{
"success": true,
"message": "Withdrawal status retrieved successfully",
"data": {
"id": "disb_1234567890",
"reference_id": "WALLET-PAYOUT-456789-1705123456",
"status": "COMPLETED",
"amount": 500000,
"currency": "IDR",
"bank_code": "BCA",
"account_number": "1234567890",
"account_holder_name": "John Doe",
"completed_at": "2024-01-15T12:30:00Z"
}
}{
"error": "Withdrawal not found"
}{
"error": "Failed to get withdrawal status"
}🏦 Fixed Virtual Account Operations
Request Fixed VA
Request Fixed Virtual Account
Request a Fixed Virtual Account for wallet top-up. Creates a permanent or single-use VA number that users can transfer to for automatic wallet funding.
Parameters
wallet_idstringrequiredWallet ID to link VA to
bank_codestringrequiredBank code (BCA, BNI, BRI, MANDIRI, PERMATA, CIMB)
amountnumberExpected amount (for single-use VA)
is_single_usebooleanSingle-use VA flag (default: false)
Request Body
{
"wallet_id": "wallet_456789",
"bank_code": "BCA",
"is_single_use": false
}Response
{
"success": true,
"message": "Fixed VA created successfully",
"data": {
"va_number": "1234567890123456",
"bank_code": "BCA",
"bank_name": "Bank Central Asia",
"customer_name": "John Doe",
"currency": "IDR",
"status": "ACTIVE",
"is_single_use": false,
"created_at": "2024-01-15T10:00:00Z",
"bank_info": {
"min_amount": 10000,
"max_amount": 50000000,
"settlement_time": "Real-time",
"instant_settlement": true
}
}
}{
"error": "Invalid bank code or wallet not found"
}{
"error": "Failed to create Fixed VA"
}Get Fixed VA List
Get Fixed VA List for Wallet
Retrieve all Fixed Virtual Accounts associated with a wallet including their status, bank details, and settlement information.
Parameters
wallet_idstringrequiredWallet ID to get VAs for
Response
{
"success": true,
"message": "Fixed VAs retrieved successfully",
"data": {
"wallet_id": 456789,
"total_vas": 2,
"fixed_vas": [
{
"va_number": "1234567890123456",
"bank_code": "BCA",
"bank_name": "Bank Central Asia",
"customer_name": "John Doe",
"currency": "IDR",
"status": "ACTIVE",
"created_at": "2024-01-15T10:00:00Z",
"bank_info": {
"min_amount": 10000,
"max_amount": 50000000,
"settlement_time": "Real-time",
"instant_settlement": true
}
},
{
"va_number": "9876543210987654",
"bank_code": "BNI",
"bank_name": "Bank Negara Indonesia",
"customer_name": "John Doe",
"currency": "IDR",
"status": "ACTIVE",
"created_at": "2024-01-14T09:00:00Z"
}
]
}
}{
"error": "Failed to get Fixed VA list"
}💰 Balance Operations
Get Balance
Get Xendit Account Balance
Get Xendit account balance for a specific account type (CASH, HOLDING, or TAX). Returns current balance with account details.
Parameters
account_typestringAccount type: CASH, HOLDING, or TAX (default: CASH)
Response
{
"success": true,
"message": "Balance retrieved successfully",
"data": {
"balance": 5000000,
"currency": "IDR",
"account_type": "CASH"
}
}{
"error": "Failed to get balance"
}Get All Balances
Get All Account Balances
Get balances for all Xendit account types (CASH, HOLDING, TAX) in a single request.
Response
{
"success": true,
"message": "All balances retrieved successfully",
"data": {
"balances": [
{
"account_type": "CASH",
"balance": 5000000,
"currency": "IDR"
},
{
"account_type": "HOLDING",
"balance": 500000,
"currency": "IDR"
},
{
"account_type": "TAX",
"balance": 100000,
"currency": "IDR"
}
],
"total_balance": 5600000
}
}{
"error": "Failed to get all balances"
}📊 Transaction Operations
List Transactions
List Transactions with Filters
List Xendit transactions with pagination and filtering support. Filter by date range, transaction types, and status.
Parameters
created_gtestringFilter transactions created after this date (ISO 8601)
created_ltestringFilter transactions created before this date (ISO 8601)
limitnumberNumber of results per page (default: 50, max: 100)
after_idstringPagination cursor (transaction ID)
typesstringComma-separated transaction types
statusesstringComma-separated status values
Response
{
"success": true,
"message": "Transactions retrieved successfully",
"data": {
"has_more": true,
"data": [
{
"id": "txn_1234567890",
"type": "DISBURSEMENT",
"status": "COMPLETED",
"amount": 500000,
"currency": "IDR",
"reference_id": "WALLET-PAYOUT-456789-1705123456",
"created": "2024-01-15T10:00:00Z",
"updated": "2024-01-15T12:30:00Z"
}
]
}
}{
"error": "Failed to list transactions"
}Get Transaction
Get Transaction Details
Get detailed information for a specific transaction by its ID.
Parameters
transaction_idstringrequiredTransaction ID to retrieve
Response
{
"success": true,
"message": "Transaction retrieved successfully",
"data": {
"id": "txn_1234567890",
"type": "DISBURSEMENT",
"status": "COMPLETED",
"amount": 500000,
"currency": "IDR",
"reference_id": "WALLET-PAYOUT-456789-1705123456",
"description": "Withdrawal to personal account",
"created": "2024-01-15T10:00:00Z",
"updated": "2024-01-15T12:30:00Z",
"completed": "2024-01-15T12:30:00Z",
"bank_code": "BCA",
"account_number": "1234567890"
}
}{
"error": "Transaction not found"
}{
"error": "Failed to get transaction"
}Get Transaction Count
Get Transaction Count
Get the total count of transactions matching the specified filters.
Parameters
created_gtestringFilter transactions created after this date
created_ltestringFilter transactions created before this date
typesstringComma-separated transaction types
statusesstringComma-separated status values
Response
{
"success": true,
"message": "Transaction count retrieved successfully",
"data": {
"count": 156,
"filters_applied": {
"created_gte": "2024-01-01T00:00:00Z",
"types": "DISBURSEMENT",
"statuses": "COMPLETED"
}
}
}{
"error": "Failed to get transaction count"
}📈 Report Operations
Generate Balance Report
Generate Balance Report
Generate a comprehensive balance report for a specified date range with account breakdown.
Parameters
start_datestringReport start date (ISO 8601)
end_datestringReport end date (ISO 8601)
formatstringReport format: json, csv, pdf (default: json)
Response
{
"success": true,
"message": "Balance report generated successfully",
"data": {
"report_period": {
"start_date": "2024-01-01T00:00:00Z",
"end_date": "2024-01-31T23:59:59Z"
},
"balances": {
"opening_balance": 4500000,
"closing_balance": 5000000,
"total_inflow": 2000000,
"total_outflow": 1500000
},
"account_breakdown": [
{
"account_type": "CASH",
"opening": 4000000,
"closing": 4500000,
"inflow": 1500000,
"outflow": 1000000
},
{
"account_type": "HOLDING",
"opening": 400000,
"closing": 400000,
"inflow": 400000,
"outflow": 400000
},
{
"account_type": "TAX",
"opening": 100000,
"closing": 100000,
"inflow": 100000,
"outflow": 100000
}
],
"generated_at": "2024-02-01T10:00:00Z"
}
}{
"error": "Failed to generate balance report"
}Generate Transaction Report
Generate Transaction Report
Generate a detailed transaction report with filtering by date range and transaction types.
Parameters
start_datestringReport start date (ISO 8601)
end_datestringReport end date (ISO 8601)
transaction_typesstringComma-separated transaction types
formatstringReport format: json, csv, pdf (default: json)
Response
{
"success": true,
"message": "Transaction report generated successfully",
"data": {
"report_period": {
"start_date": "2024-01-01T00:00:00Z",
"end_date": "2024-01-31T23:59:59Z"
},
"summary": {
"total_transactions": 156,
"total_amount": 78000000,
"successful_transactions": 150,
"failed_transactions": 6,
"pending_transactions": 0
},
"by_type": [
{
"type": "DISBURSEMENT",
"count": 100,
"total_amount": 50000000,
"success_rate": 0.98
},
{
"type": "VA_PAYMENT",
"count": 56,
"total_amount": 28000000,
"success_rate": 0.95
}
],
"generated_at": "2024-02-01T10:00:00Z"
}
}{
"error": "Failed to generate transaction report"
}🔄 Reconciliation Operations
Run Daily Reconciliation
Run Daily Reconciliation
Run automated daily reconciliation process to match internal wallet balances with Xendit account balances. Identifies discrepancies for manual review.
Parameters
datestringReconciliation date (default: today)
force_rerunbooleanForce rerun if already executed (default: false)
Request Body
{
"date": "2024-01-15",
"force_rerun": false
}Response
{
"success": true,
"message": "Daily reconciliation completed",
"data": {
"reconciliation_id": 123,
"date": "2024-01-15",
"total_wallets_checked": 45,
"matched_wallets": 42,
"discrepancies_found": 3,
"total_discrepancy_amount": 15000,
"status": "COMPLETED",
"completed_at": "2024-01-15T10:30:00Z"
}
}{
"error": "Reconciliation already run for this date"
}{
"error": "Failed to run reconciliation"
}Reconcile Wallet Balance
Reconcile Specific Wallet
Run reconciliation for a specific wallet to verify balance accuracy against Xendit records.
Parameters
wallet_idstringrequiredWallet ID to reconcile
force_updatebooleanForce balance update (default: false)
Request Body
{
"force_update": false
}Response
{
"success": true,
"message": "Wallet reconciliation completed",
"data": {
"wallet_id": "wallet_456789",
"internal_balance": 500000,
"xendit_balance": 500000,
"is_matched": true,
"discrepancy_amount": 0,
"last_reconciled": "2024-01-15T10:30:00Z"
}
}{
"error": "Wallet not found"
}{
"error": "Failed to reconcile wallet"
}Resolve Reconciliation
Manually Resolve Reconciliation
Manually resolve a reconciliation discrepancy with notes and optional manual adjustment.
Parameters
reconciliation_idnumberrequiredReconciliation ID to resolve
resolved_bynumberrequiredUser ID who is resolving
resolution_notesstringrequiredNotes explaining the resolution
manual_adjustment_amountnumberManual adjustment amount if needed (default: 0)
Request Body
{
"reconciliation_id": 123,
"resolved_by": 1,
"resolution_notes": "Discrepancy due to pending transaction settlement. Verified with Xendit support.",
"manual_adjustment_amount": 0
}Response
{
"success": true,
"message": "Reconciliation resolved successfully",
"data": {
"reconciliation_id": 123,
"status": "RESOLVED",
"resolved_by": 1,
"resolution_notes": "Discrepancy due to pending transaction settlement",
"manual_adjustment_amount": 0,
"resolved_at": "2024-01-15T14:00:00Z"
}
}{
"error": "Reconciliation already resolved"
}{
"error": "Failed to resolve reconciliation"
}Get Reconciliation Details
Get Reconciliation Details
Get detailed information about a specific reconciliation including all discrepancies found.
Parameters
reconciliation_idstringrequiredReconciliation ID
Response
{
"success": true,
"message": "Reconciliation details retrieved successfully",
"data": {
"reconciliation_id": 123,
"date": "2024-01-15",
"status": "PENDING_REVIEW",
"total_wallets_checked": 45,
"matched_wallets": 42,
"discrepancies_found": 3,
"total_discrepancy_amount": 15000,
"discrepancies": [
{
"wallet_id": "wallet_111",
"internal_balance": 100000,
"xendit_balance": 105000,
"discrepancy": 5000
},
{
"wallet_id": "wallet_222",
"internal_balance": 200000,
"xendit_balance": 195000,
"discrepancy": -5000
},
{
"wallet_id": "wallet_333",
"internal_balance": 50000,
"xendit_balance": 55000,
"discrepancy": 5000
}
],
"completed_at": "2024-01-15T10:30:00Z"
}
}{
"error": "Reconciliation not found"
}{
"error": "Failed to get reconciliation details"
}🔔 Webhook Operations
Process Webhook
Process Xendit Webhook
Process incoming webhook from Xendit servers. This endpoint is called automatically by Xendit when payment events occur. Includes signature verification and DLQ handling for failed processing.
Parameters
eventstringrequiredWebhook event type (e.g., virtual_account.paid, disbursement.completed)
dataobjectrequiredWebhook payload data from Xendit
Request Body
{
"event": "virtual_account.paid",
"data": {
"payment_id": "pay_1234567890",
"external_id": "WALLET-TOPUP-456789",
"account_number": "1234567890123456",
"bank_code": "BCA",
"amount": 1000000,
"currency": "IDR",
"status": "COMPLETED",
"paid_at": "2024-01-15T10:00:00Z"
}
}Response
{
"success": true,
"message": "Webhook processed successfully",
"webhook_id": "whk_1234567890",
"processed_at": "2024-01-15T10:00:01Z"
}Process Dead Letter Queue
Process Webhook Dead Letter Queue
Manually process failed webhooks from the dead letter queue. Retries webhook processing for events that failed initial processing.
Response
{
"success": true,
"message": "DLQ processing completed",
"data": {
"total_processed": 5,
"successful": 4,
"failed": 1,
"remaining_in_queue": 1
}
}{
"error": "Failed to process dead letter queue"
}Get Webhook Statistics
Get Webhook Statistics
Get webhook processing statistics including success rates, event types, and processing times.
Parameters
start_datestringStatistics start date (ISO 8601)
end_datestringStatistics end date (ISO 8601)
Response
{
"success": true,
"message": "Webhook statistics retrieved successfully",
"data": {
"period": {
"start_date": "2024-01-01T00:00:00Z",
"end_date": "2024-01-31T23:59:59Z"
},
"total_webhooks": 1250,
"successful": 1230,
"failed": 20,
"success_rate": 0.984,
"by_event_type": [
{
"event": "virtual_account.paid",
"count": 800,
"success_rate": 0.99
},
{
"event": "disbursement.completed",
"count": 400,
"success_rate": 0.975
},
{
"event": "disbursement.failed",
"count": 50,
"success_rate": 0.96
}
],
"avg_processing_time_ms": 150,
"dlq_count": 5
}
}{
"error": "Failed to get webhook statistics"
}🔧 Administrative Operations
Health Check
Xendit Integration Health Check
Perform comprehensive health check for Xendit integration including configuration validation, API connectivity, and database connection.
Response
{
"success": true,
"message": "Xendit integration is healthy",
"data": {
"service": "xendit_integration",
"status": "healthy",
"timestamp": "2024-01-15T10:00:00Z",
"checks": {
"configuration": {
"status": "pass",
"issues": []
},
"api_connectivity": {
"status": "pass",
"message": "Xendit API connection successful",
"error": null
},
"database": {
"status": "pass",
"message": "Database connection active"
}
}
}
}{
"success": false,
"message": "Xendit integration is unhealthy",
"data": {
"service": "xendit_integration",
"status": "unhealthy",
"error": "Configuration validation failed"
}
}Validate Configuration
Validate Xendit Configuration
Validate Xendit API configuration including API keys, webhook tokens, and base URL settings.
Response
{
"success": true,
"message": "Configuration is valid",
"data": {
"valid": true,
"issues": [],
"timestamp": "2024-01-15T10:00:00Z"
}
}{
"success": false,
"message": "Configuration has issues",
"data": {
"valid": false,
"issues": [
"API_KEY_XENDIT not set",
"WEBHOOK_TOKEN_XENDIT_TEST not set"
],
"timestamp": "2024-01-15T10:00:00Z"
}
}Get Dashboard Data
Get Admin Dashboard Data
Get comprehensive dashboard data for monitoring Xendit operations including balances, webhook stats, and connectivity status.
Response
{
"success": true,
"message": "Dashboard data retrieved successfully",
"data": {
"balances": {
"balances": [
{
"account_type": "CASH",
"balance": 5000000,
"currency": "IDR"
},
{
"account_type": "HOLDING",
"balance": 500000,
"currency": "IDR"
},
{
"account_type": "TAX",
"balance": 100000,
"currency": "IDR"
}
],
"total_balance": 5600000
},
"webhook_stats": {
"total_webhooks": 1250,
"successful": 1230,
"failed": 20,
"success_rate": 0.984,
"dlq_count": 5
},
"connectivity": {
"success": true,
"message": "Xendit API connection successful",
"balance_retrieved": true
},
"last_updated": "2024-01-15T10:00:00Z"
}
}{
"error": "Failed to get dashboard data"
}🚀 Complete Xendit Workflows
Workflow 1: Complete Withdrawal Process
// Complete withdrawal workflow with status tracking
async function completeWithdrawal(walletId, amount, bankDetails) {
console.log('Starting withdrawal process...');
// Step 1: Check Xendit balance
const balance = await brdzSDK.xendit.getBalance();
if (balance.data.balance < amount) {
throw new Error(`Insufficient Xendit balance. Available: ${balance.data.balance}, Required: ${amount}`);
}
console.log(`Balance check passed: IDR ${balance.data.balance.toLocaleString()}`);
// Step 2: Process withdrawal
const withdrawal = await brdzSDK.xendit.processWalletWithdraw({
wallet_id: walletId,
amount: amount,
currency: 'IDR',
bank_code: bankDetails.bank_code,
account_number: bankDetails.account_number,
account_holder_name: bankDetails.account_holder_name,
description: 'User withdrawal request',
user_email: bankDetails.email
});
console.log(`Withdrawal initiated: ${withdrawal.data.payout_id}`);
console.log(`Reference: ${withdrawal.data.reference_id}`);
// Step 3: Track status until completion
let status = 'PENDING';
let attempts = 0;
const maxAttempts = 60; // 5 minutes with 5-second intervals
while (status === 'PENDING' && attempts < maxAttempts) {
await new Promise(resolve => setTimeout(resolve, 5000)); // Wait 5 seconds
const statusCheck = await brdzSDK.xendit.getWithdrawStatus(withdrawal.data.reference_id);
status = statusCheck.data.status;
console.log(`Status check ${attempts + 1}: ${status}`);
attempts++;
}
if (status === 'COMPLETED') {
console.log('Withdrawal completed successfully!');
return {
success: true,
payout_id: withdrawal.data.payout_id,
reference_id: withdrawal.data.reference_id,
status: status
};
} else if (status === 'FAILED') {
console.error('Withdrawal failed!');
return {
success: false,
error: 'Withdrawal failed',
reference_id: withdrawal.data.reference_id
};
} else {
console.log('Withdrawal still pending after timeout');
return {
success: false,
error: 'Timeout waiting for completion',
reference_id: withdrawal.data.reference_id,
status: status
};
}
}
Workflow 2: Fixed VA Management
// Complete Fixed VA setup and monitoring
async function setupFixedVAForWallet(walletId, banks = ['BCA', 'BNI', 'MANDIRI']) {
console.log('Setting up Fixed VAs for wallet...');
const createdVAs = [];
// Create Fixed VA for each bank
for (const bankCode of banks) {
try {
const va = await brdzSDK.xendit.requestFixedVA({
wallet_id: walletId,
bank_code: bankCode,
is_single_use: false
});
createdVAs.push({
bank: bankCode,
va_number: va.data.va_number,
status: va.data.status
});
console.log(`✅ ${bankCode} VA created: ${va.data.va_number}`);
} catch (error) {
console.error(`❌ Failed to create ${bankCode} VA:`, error.message);
}
}
// Get complete VA list
const vaList = await brdzSDK.xendit.getFixedVAList(walletId);
console.log(`\nTotal VAs for wallet: ${vaList.data.total_vas}`);
return {
created_vas: createdVAs,
all_vas: vaList.data.fixed_vas
};
}
Workflow 3: Daily Reconciliation Process
// Automated daily reconciliation with discrepancy resolution
async function performDailyReconciliation(adminUserId) {
console.log('Starting daily reconciliation...');
// Step 1: Run reconciliation
const reconciliation = await brdzSDK.xendit.runDailyReconciliation();
console.log(`Reconciliation ID: ${reconciliation.data.reconciliation_id}`);
console.log(`Wallets Checked: ${reconciliation.data.total_wallets_checked}`);
console.log(`Matched: ${reconciliation.data.matched_wallets}`);
console.log(`Discrepancies: ${reconciliation.data.discrepancies_found}`);
// Step 2: If discrepancies found, get details
if (reconciliation.data.discrepancies_found > 0) {
const details = await brdzSDK.xendit.getReconciliationDetails(
reconciliation.data.reconciliation_id
);
console.log('\n🔍 Discrepancy Details:');
details.data.discrepancies.forEach(disc => {
console.log(`\nWallet: ${disc.wallet_id}`);
console.log(` Internal: IDR ${disc.internal_balance.toLocaleString()}`);
console.log(` Xendit: IDR ${disc.xendit_balance.toLocaleString()}`);
console.log(` Difference: IDR ${disc.discrepancy.toLocaleString()}`);
});
// Step 3: Auto-resolve small discrepancies (< 1000 IDR)
for (const disc of details.data.discrepancies) {
if (Math.abs(disc.discrepancy) < 1000) {
console.log(`\n⚡ Auto-resolving small discrepancy for ${disc.wallet_id}`);
await brdzSDK.xendit.resolveReconciliation({
reconciliation_id: reconciliation.data.reconciliation_id,
resolved_by: adminUserId,
resolution_notes: `Auto-resolved: Small discrepancy within tolerance (${disc.discrepancy} IDR)`,
manual_adjustment_amount: 0
});
} else {
console.log(`\n⚠️ Manual review required for ${disc.wallet_id} (${disc.discrepancy} IDR)`);
}
}
} else {
console.log('\n✅ All wallets matched! No discrepancies found.');
}
return reconciliation.data;
}
Workflow 4: Monitoring Dashboard
// Complete monitoring dashboard
async function displayMonitoringDashboard() {
console.log('=== XENDIT MONITORING DASHBOARD ===\n');
// Get all dashboard data
const dashboard = await brdzSDK.xendit.getDashboardData();
// Display balances
console.log('💰 ACCOUNT BALANCES');
console.log(`Total: IDR ${dashboard.data.balances.total_balance.toLocaleString()}`);
dashboard.data.balances.balances.forEach(acc => {
console.log(` ${acc.account_type.padEnd(8)}: IDR ${acc.balance.toLocaleString()}`);
});
// Display webhook stats
console.log('\n🔔 WEBHOOK STATISTICS');
const stats = dashboard.data.webhook_stats;
console.log(`Total Processed: ${stats.total_webhooks}`);
console.log(`Success Rate: ${(stats.success_rate * 100).toFixed(2)}%`);
console.log(`Failed: ${stats.failed}`);
console.log(`In DLQ: ${stats.dlq_count}`);
// Health status
console.log('\n🏥 SYSTEM HEALTH');
const health = await brdzSDK.xendit.healthCheck();
console.log(`Status: ${health.data.status.toUpperCase()}`);
Object.entries(health.data.checks).forEach(([check, result]) => {
const icon = result.status === 'pass' ? '✅' : '❌';
console.log(` ${icon} ${check}: ${result.status}`);
});
// Recent transactions
console.log('\n📊 RECENT TRANSACTIONS');
const transactions = await brdzSDK.xendit.listTransactions({
limit: 5
});
transactions.data.data.forEach(txn => {
console.log(` ${txn.type}: IDR ${txn.amount.toLocaleString()} - ${txn.status}`);
});
// Check for DLQ items
if (stats.dlq_count > 0) {
console.log('\n⚠️ WARNING: Failed webhooks in DLQ!');
console.log(' Run processDLQ() to retry failed webhooks');
}
console.log(`\n📅 Last Updated: ${dashboard.data.last_updated}`);
}
Workflow 5: Error Handling Best Practices
// Robust error handling for Xendit operations
class XenditErrorHandler {
static async safeWithdraw(walletId, amount, bankDetails) {
try {
return await brdzSDK.xendit.processWalletWithdraw({
wallet_id: walletId,
amount: amount,
currency: 'IDR',
...bankDetails
});
} catch (error) {
return this.handleWithdrawError(error);
}
}
static handleWithdrawError(error) {
const errorMessage = error.message || error.toString();
if (errorMessage.includes('Insufficient Xendit balance')) {
return {
success: false,
error_code: 'INSUFFICIENT_BALANCE',
message: 'Not enough balance in Xendit account',
suggestion: 'Top up Xendit balance before processing withdrawals',
retry: false
};
} else if (errorMessage.includes('Invalid bank code')) {
return {
success: false,
error_code: 'INVALID_BANK',
message: 'Bank code not supported',
suggestion: 'Use valid Indonesian bank code (BCA, BNI, BRI, MANDIRI, etc.)',
retry: false
};
} else if (errorMessage.includes('Wallet not found')) {
return {
success: false,
error_code: 'WALLET_NOT_FOUND',
message: 'Wallet does not exist or access denied',
suggestion: 'Verify wallet ID and user permissions',
retry: false
};
} else if (errorMessage.includes('Xendit API')) {
return {
success: false,
error_code: 'XENDIT_API_ERROR',
message: 'Xendit service temporarily unavailable',
suggestion: 'Retry after a few minutes',
retry: true
};
} else {
return {
success: false,
error_code: 'UNKNOWN_ERROR',
message: errorMessage,
suggestion: 'Check logs and contact support if issue persists',
retry: false
};
}
}
static async safeReconciliation() {
try {
return await brdzSDK.xendit.runDailyReconciliation();
} catch (error) {
console.error('Reconciliation failed:', error.message);
// Send alert to admin
await this.notifyAdmin('Reconciliation Failed', {
error: error.message,
timestamp: new Date().toISOString()
});
return {
success: false,
error: error.message
};
}
}
static async notifyAdmin(subject, data) {
// Implement your notification logic here
console.log(`🚨 ADMIN ALERT: ${subject}`);
console.log(JSON.stringify(data, null, 2));
}
}
// Usage
const result = await XenditErrorHandler.safeWithdraw(
'wallet_456789',
500000,
{
bank_code: 'BCA',
account_number: '1234567890',
account_holder_name: 'John Doe'
}
);
if (!result.success) {
console.error(`Error: ${result.message}`);
console.log(`Suggestion: ${result.suggestion}`);
if (result.retry) {
console.log('This error is temporary, safe to retry');
}
}
🔐 Authentication & Authorization
All Xendit endpoints require authentication and specific role permissions:
// Configure authentication
const config = await brdzSDK.config;
config.setToken('your-jwt-token');
config.setApiKey('your-api-key');
// User-level operations (user or admin role)
await brdzSDK.xendit.processWalletWithdraw(data);
await brdzSDK.xendit.getWithdrawStatus(reference_id);
await brdzSDK.xendit.requestFixedVA(data);
await brdzSDK.xendit.getFixedVAList(wallet_id);
await brdzSDK.xendit.reconcileWalletBalance(wallet_id);
await brdzSDK.xendit.getReconciliationDetails(id);
// Admin-only operations (admin role required)
await brdzSDK.xendit.getBalance();
await brdzSDK.xendit.getAllBalances();
await brdzSDK.xendit.listTransactions();
await brdzSDK.xendit.getTransaction(id);
await brdzSDK.xendit.getTransactionCount();
await brdzSDK.xendit.generateBalanceReport();
await brdzSDK.xendit.generateTransactionReport();
await brdzSDK.xendit.runDailyReconciliation();
await brdzSDK.xendit.resolveReconciliation(data);
await brdzSDK.xendit.processDLQ();
await brdzSDK.xendit.getWebhookStats();
await brdzSDK.xendit.validateConfiguration();
await brdzSDK.xendit.getDashboardData();
// Public operations (no auth required)
await brdzSDK.xendit.healthCheck();
await brdzSDK.xendit.processWebhook(data); // Called by Xendit servers
🌍 Supported Banks & Features
Indonesian Bank Support
- BCA (Bank Central Asia) - Real-time settlement
- BNI (Bank Negara Indonesia) - Real-time settlement
- BRI (Bank Rakyat Indonesia) - Real-time settlement
- MANDIRI (Bank Mandiri) - Real-time settlement
- PERMATA (Bank Permata) - Real-time settlement
- CIMB (CIMB Niaga) - Real-time settlement
Virtual Account Features
- Fixed VA: Permanent VA numbers for recurring top-ups
- Single-use VA: One-time VA with specific amount
- Multi-bank support: Create VAs for multiple banks
- Real-time settlement: Instant wallet funding on payment
- Webhook notifications: Automatic payment notifications
Disbursement Features
- Bank transfers: Support for all major Indonesian banks
- Real-time status: Track withdrawal status in real-time
- Balance validation: Automatic balance checking before disbursement
- Ledger integration: Automatic ledger updates
- Fee transparency: Clear fee breakdown
💡 Pro Tips for Xendit Integration
Balance Management
// Always check balance before withdrawals
async function safeWithdrawal(walletId, amount, bankDetails) {
const balance = await brdzSDK.xendit.getBalance();
if (balance.data.balance < amount) {
throw new Error(`Insufficient balance: ${balance.data.balance} < ${amount}`);
}
return await brdzSDK.xendit.processWalletWithdraw({
wallet_id: walletId,
amount: amount,
...bankDetails
});
}
Webhook Monitoring
// Regular webhook health monitoring
async function monitorWebhooks() {
const stats = await brdzSDK.xendit.getWebhookStats({
start_date: new Date(Date.now() - 24 * 60 * 60 * 1000).toISOString()
});
if (stats.data.success_rate < 0.95) {
console.warn('⚠️ Webhook success rate below 95%');
}
if (stats.data.dlq_count > 10) {
console.warn('⚠️ More than 10 webhooks in DLQ');
await brdzSDK.xendit.processDLQ();
}
}
Reconciliation Automation
// Schedule daily reconciliation
const cron = require('node-cron');
// Run at 2 AM every day
cron.schedule('0 2 * * *', async () => {
console.log('Running daily reconciliation...');
await performDailyReconciliation(adminUserId);
});
Configure your webhook URL in Xendit Dashboard to point to https://api.brdz.link/api/xendit/webhook. Ensure your server can handle POST requests from Xendit's IP addresses.
Always monitor your Xendit balance to avoid withdrawal failures. Set up alerts when balance falls below threshold (e.g., 10M IDR).
Run daily reconciliation during off-peak hours (e.g., 2-4 AM). Auto-resolve small discrepancies (< 1000 IDR) and flag larger ones for manual review.