Skip to main content

Xendit Module

The xendit module provides comprehensive Xendit payment gateway functionality for Indonesian market including withdrawals, virtual accounts, reconciliation, and webhook management.

Import

const xendit = await brdzSDK.xendit;

Methods Overview

MethodDescriptionAuth RequiredHTTP Endpoint
processWalletWithdrawProcess bank withdrawalPOST /xendit/wallet/withdraw
getWithdrawStatusGet withdrawal statusGET /xendit/wallet/withdraw/status/:reference_id
requestFixedVARequest Fixed VAPOST /xendit/fixed-va/request
getFixedVAListGet Fixed VA listGET /xendit/fixed-va/list/:wallet_id
getBalanceGet account balance✅ AdminGET /xendit/balance
getAllBalancesGet all balances✅ AdminGET /xendit/balance/all
listTransactionsList transactions✅ AdminGET /xendit/transactions
getTransactionGet transaction details✅ AdminGET /xendit/transactions/:transaction_id
getTransactionCountCount transactions✅ AdminGET /xendit/transactions/count
generateBalanceReportGenerate balance report✅ AdminGET /xendit/reports/balance
generateTransactionReportGenerate transaction report✅ AdminGET /xendit/reports/transactions
runDailyReconciliationRun reconciliation✅ AdminPOST /xendit/reconciliation/run
reconcileWalletBalanceReconcile walletPOST /xendit/reconciliation/wallet/:wallet_id
resolveReconciliationResolve discrepancy✅ AdminPOST /xendit/reconciliation/resolve
getReconciliationDetailsGet reconciliation detailsGET /xendit/reconciliation/:reconciliation_id
processWebhookProcess webhookPublicPOST /xendit/webhook
processDLQProcess DLQ✅ AdminPOST /xendit/webhook/dlq/process
getWebhookStatsGet webhook statistics✅ AdminGET /xendit/webhook/stats
healthCheckHealth checkPublicGET /xendit/health
validateConfigurationValidate config✅ AdminGET /xendit/config/validate
getDashboardDataGet dashboard data✅ AdminGET /xendit/admin/dashboard

Withdrawal Operations

processWalletWithdraw

Process withdrawal from wallet to Indonesian bank account with automatic ledger integration.

const withdrawal = await brdzSDK.xendit.processWalletWithdraw({
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"
});

console.log(`Payout ID: ${withdrawal.data.payout_id}`);
console.log(`Reference: ${withdrawal.data.reference_id}`);
console.log(`Status: ${withdrawal.data.status}`);

Parameters:

  • wallet_id (string, required): Wallet ID to withdraw from
  • amount (number, required): Withdrawal amount in IDR
  • currency (string, optional): Currency code (default: IDR)
  • bank_code (string, required): Bank code (BCA, BNI, BRI, MANDIRI, etc.)
  • account_number (string, required): Bank account number
  • account_holder_name (string, required): Account holder name
  • description (string, optional): Withdrawal description
  • user_email (string, optional): User email for notifications

Returns: Withdrawal initiation response with payout details

getWithdrawStatus

Check the current status of a withdrawal transaction.

const status = await brdzSDK.xendit.getWithdrawStatus("WALLET-PAYOUT-456789-1705123456");

console.log(`Status: ${status.data.status}`);
console.log(`Amount: ${status.data.amount} ${status.data.currency}`);

if (status.data.status === 'COMPLETED') {
console.log(`Completed at: ${status.data.completed_at}`);
}

Parameters:

  • reference_id (string, required): Withdrawal reference ID

Returns: Current withdrawal status with transfer details

Fixed Virtual Account Operations

requestFixedVA

Request a Fixed Virtual Account for wallet top-up.

const fixedVA = await brdzSDK.xendit.requestFixedVA({
wallet_id: "wallet_456789",
bank_code: "BCA",
is_single_use: false
});

console.log(`VA Number: ${fixedVA.data.va_number}`);
console.log(`Bank: ${fixedVA.data.bank_name}`);
console.log(`Status: ${fixedVA.data.status}`);

Parameters:

  • wallet_id (string, required): Wallet ID to link VA to
  • bank_code (string, required): Bank code (BCA, BNI, BRI, MANDIRI, PERMATA, CIMB)
  • amount (number, optional): Expected amount for single-use VA
  • is_single_use (boolean, optional): Single-use VA flag (default: false)

Returns: Fixed VA creation response with VA number

getFixedVAList

Retrieve all Fixed Virtual Accounts for a wallet.

const vaList = await brdzSDK.xendit.getFixedVAList("wallet_456789");

console.log(`Total VAs: ${vaList.data.total_vas}`);

vaList.data.fixed_vas.forEach(va => {
console.log(`${va.bank_name}: ${va.va_number}`);
console.log(` Status: ${va.status}`);
});

Parameters:

  • wallet_id (string, required): Wallet ID to get VAs for

Returns: List of Fixed VAs with bank details

Balance Operations

getBalance

Get Xendit account balance for a specific account type.

// Get CASH balance (default)
const cashBalance = await brdzSDK.xendit.getBalance();
console.log(`CASH: IDR ${cashBalance.data.balance.toLocaleString()}`);

// Get HOLDING balance
const holdingBalance = await brdzSDK.xendit.getBalance({
account_type: 'HOLDING'
});
console.log(`HOLDING: IDR ${holdingBalance.data.balance.toLocaleString()}`);

Parameters:

  • params (object, optional): Query parameters
    • account_type (string): CASH, HOLDING, or TAX (default: CASH)

Returns: Account balance information

getAllBalances

Get balances for all Xendit account types in a single request.

const allBalances = await brdzSDK.xendit.getAllBalances();

console.log(`Total: IDR ${allBalances.data.total_balance.toLocaleString()}`);

allBalances.data.balances.forEach(account => {
console.log(`${account.account_type}: IDR ${account.balance.toLocaleString()}`);
});

Returns: All account balances with total

Transaction Operations

listTransactions

List Xendit transactions with pagination and filtering.

const transactions = await brdzSDK.xendit.listTransactions({
limit: 20,
created_gte: '2024-01-01T00:00:00Z',
types: 'DISBURSEMENT',
statuses: 'COMPLETED'
});

console.log(`Found ${transactions.data.data.length} transactions`);
console.log(`Has more: ${transactions.data.has_more}`);

transactions.data.data.forEach(txn => {
console.log(`${txn.type}: ${txn.amount} - ${txn.status}`);
});

Parameters:

  • params (object, optional): Filter parameters
    • created_gte (string): Start date (ISO 8601)
    • created_lte (string): End date (ISO 8601)
    • limit (number): Results per page (default: 50, max: 100)
    • after_id (string): Pagination cursor
    • types (string): Comma-separated transaction types
    • statuses (string): Comma-separated status values

Returns: Paginated transaction list

getTransaction

Get detailed information for a specific transaction.

const transaction = await brdzSDK.xendit.getTransaction("txn_1234567890");

console.log(`Type: ${transaction.data.type}`);
console.log(`Amount: ${transaction.data.amount} ${transaction.data.currency}`);
console.log(`Status: ${transaction.data.status}`);
console.log(`Reference: ${transaction.data.reference_id}`);

Parameters:

  • transaction_id (string, required): Transaction ID to retrieve

Returns: Transaction details

getTransactionCount

Get the total count of transactions matching filters.

const count = await brdzSDK.xendit.getTransactionCount({
created_gte: '2024-01-01T00:00:00Z',
types: 'DISBURSEMENT',
statuses: 'COMPLETED'
});

console.log(`Total completed disbursements: ${count.data.count}`);

Parameters:

  • params (object, optional): Filter parameters
    • created_gte (string): Start date
    • created_lte (string): End date
    • types (string): Transaction types
    • statuses (string): Status values

Returns: Transaction count with applied filters

Report Operations

generateBalanceReport

Generate a comprehensive balance report for a date range.

const report = await brdzSDK.xendit.generateBalanceReport({
start_date: '2024-01-01T00:00:00Z',
end_date: '2024-01-31T23:59:59Z',
format: 'json'
});

console.log(`Opening: IDR ${report.data.balances.opening_balance.toLocaleString()}`);
console.log(`Closing: IDR ${report.data.balances.closing_balance.toLocaleString()}`);
console.log(`Inflow: IDR ${report.data.balances.total_inflow.toLocaleString()}`);
console.log(`Outflow: IDR ${report.data.balances.total_outflow.toLocaleString()}`);

Parameters:

  • params (object, optional): Report parameters
    • start_date (string): Report start date (ISO 8601)
    • end_date (string): Report end date (ISO 8601)
    • format (string): json, csv, or pdf (default: json)

Returns: Balance report with breakdown

generateTransactionReport

Generate a detailed transaction report with filtering.

const report = await brdzSDK.xendit.generateTransactionReport({
start_date: '2024-01-01T00:00:00Z',
end_date: '2024-01-31T23:59:59Z',
transaction_types: 'DISBURSEMENT,VA_PAYMENT',
format: 'json'
});

console.log(`Total Transactions: ${report.data.summary.total_transactions}`);
console.log(`Total Amount: IDR ${report.data.summary.total_amount.toLocaleString()}`);
console.log(`Success Rate: ${(report.data.summary.successful_transactions / report.data.summary.total_transactions * 100).toFixed(2)}%`);

Parameters:

  • params (object, optional): Report parameters
    • start_date (string): Report start date
    • end_date (string): Report end date
    • transaction_types (string): Transaction types filter
    • format (string): json, csv, or pdf

Returns: Transaction report with statistics

Reconciliation Operations

runDailyReconciliation

Run automated daily reconciliation to match internal and Xendit balances.

const reconciliation = await brdzSDK.xendit.runDailyReconciliation({
date: '2024-01-15',
force_rerun: false
});

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}`);

if (reconciliation.data.discrepancies_found > 0) {
console.log(`Total Discrepancy: IDR ${reconciliation.data.total_discrepancy_amount.toLocaleString()}`);
}

Parameters:

  • data (object, optional): Reconciliation parameters
    • date (string): Reconciliation date (default: today)
    • force_rerun (boolean): Force rerun flag (default: false)

Returns: Reconciliation results with discrepancies

reconcileWalletBalance

Run reconciliation for a specific wallet.

const result = await brdzSDK.xendit.reconcileWalletBalance("wallet_456789", {
force_update: false
});

console.log(`Internal Balance: IDR ${result.data.internal_balance.toLocaleString()}`);
console.log(`Xendit Balance: IDR ${result.data.xendit_balance.toLocaleString()}`);
console.log(`Matched: ${result.data.is_matched}`);

if (!result.data.is_matched) {
console.log(`Discrepancy: IDR ${result.data.discrepancy_amount.toLocaleString()}`);
}

Parameters:

  • wallet_id (string, required): Wallet ID to reconcile
  • data (object, optional): Reconciliation options
    • force_update (boolean): Force balance update (default: false)

Returns: Wallet reconciliation result

resolveReconciliation

Manually resolve a reconciliation discrepancy.

const resolution = await brdzSDK.xendit.resolveReconciliation({
reconciliation_id: 123,
resolved_by: 1,
resolution_notes: "Verified with Xendit support - pending transaction settlement",
manual_adjustment_amount: 0
});

console.log(`Status: ${resolution.data.status}`);
console.log(`Resolved at: ${resolution.data.resolved_at}`);

Parameters:

  • data (object, required): Resolution data
    • reconciliation_id (number): Reconciliation ID
    • resolved_by (number): User ID resolving
    • resolution_notes (string): Resolution explanation
    • manual_adjustment_amount (number, optional): Adjustment amount (default: 0)

Returns: Resolution confirmation

getReconciliationDetails

Get detailed information about a reconciliation.

const details = await brdzSDK.xendit.getReconciliationDetails("123");

console.log(`Date: ${details.data.date}`);
console.log(`Status: ${details.data.status}`);
console.log(`Discrepancies: ${details.data.discrepancies_found}`);

details.data.discrepancies.forEach(disc => {
console.log(`\nWallet: ${disc.wallet_id}`);
console.log(` Difference: IDR ${disc.discrepancy.toLocaleString()}`);
});

Parameters:

  • reconciliation_id (string, required): Reconciliation ID

Returns: Reconciliation details with discrepancy list

Webhook Operations

processWebhook

Process incoming webhook from Xendit servers.

// Note: This is typically called by Xendit servers, not client applications

const result = await brdzSDK.xendit.processWebhook({
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"
}
});

console.log(`Webhook ID: ${result.webhook_id}`);

Parameters:

  • data (object, required): Webhook payload from Xendit
    • event (string): Webhook event type
    • data (object): Event data

Returns: Webhook processing confirmation

processDLQ

Manually process failed webhooks from dead letter queue.

const result = await brdzSDK.xendit.processDLQ();

console.log(`Total Processed: ${result.data.total_processed}`);
console.log(`Successful: ${result.data.successful}`);
console.log(`Failed: ${result.data.failed}`);
console.log(`Remaining: ${result.data.remaining_in_queue}`);

Returns: DLQ processing results

getWebhookStats

Get webhook processing statistics.

const stats = await brdzSDK.xendit.getWebhookStats({
start_date: '2024-01-01T00:00:00Z',
end_date: '2024-01-31T23:59:59Z'
});

console.log(`Total Webhooks: ${stats.data.total_webhooks}`);
console.log(`Success Rate: ${(stats.data.success_rate * 100).toFixed(2)}%`);
console.log(`DLQ Count: ${stats.data.dlq_count}`);

stats.data.by_event_type.forEach(event => {
console.log(`${event.event}: ${event.count} (${(event.success_rate * 100).toFixed(2)}%)`);
});

Parameters:

  • params (object, optional): Statistics parameters
    • start_date (string): Start date (ISO 8601)
    • end_date (string): End date (ISO 8601)

Returns: Webhook statistics with event breakdown

Administrative Operations

healthCheck

Perform health check for Xendit integration.

const health = await brdzSDK.xendit.healthCheck();

console.log(`Service: ${health.data.service}`);
console.log(`Status: ${health.data.status}`);

Object.entries(health.data.checks).forEach(([check, result]) => {
console.log(`${check}: ${result.status}`);
if (result.issues && result.issues.length > 0) {
console.log(` Issues: ${result.issues.join(', ')}`);
}
});

Returns: Health check results with component status

validateConfiguration

Validate Xendit API configuration.

const validation = await brdzSDK.xendit.validateConfiguration();

console.log(`Valid: ${validation.data.valid}`);

if (!validation.data.valid) {
console.error('Configuration Issues:');
validation.data.issues.forEach(issue => {
console.error(` - ${issue}`);
});
}

Returns: Configuration validation result

getDashboardData

Get comprehensive dashboard data for monitoring.

const dashboard = await brdzSDK.xendit.getDashboardData();

// Balances
console.log('=== BALANCES ===');
console.log(`Total: IDR ${dashboard.data.balances.total_balance.toLocaleString()}`);

// Webhook Stats
console.log('\n=== WEBHOOKS ===');
console.log(`Total: ${dashboard.data.webhook_stats.total_webhooks}`);
console.log(`Success Rate: ${(dashboard.data.webhook_stats.success_rate * 100).toFixed(2)}%`);

// Connectivity
console.log('\n=== CONNECTIVITY ===');
console.log(`Status: ${dashboard.data.connectivity.success ? 'Connected' : 'Failed'}`);

Returns: Dashboard data with balances, webhooks, and connectivity

Complete Usage Examples

Basic Xendit Setup

// Configure SDK
const config = await brdzSDK.config;
config.setApiKey('your-api-key');
config.setToken('your-jwt-token');

// Check Xendit health
const health = await brdzSDK.xendit.healthCheck();

if (health.data.status === 'healthy') {
console.log('Xendit integration ready');

// Check balance
const balance = await brdzSDK.xendit.getBalance();
console.log(`Available balance: IDR ${balance.data.balance.toLocaleString()}`);
} else {
console.error('Xendit integration has issues');
}

Complete Withdrawal Workflow

async function processWithdrawal(walletId, amount, bankDetails) {
// Step 1: Check Xendit balance
const balance = await brdzSDK.xendit.getBalance();

if (balance.data.balance < amount) {
throw new Error('Insufficient Xendit balance');
}

// 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',
user_email: bankDetails.email
});

console.log(`Withdrawal initiated: ${withdrawal.data.reference_id}`);

// Step 3: Track status
let status = 'PENDING';
let attempts = 0;

while (status === 'PENDING' && attempts < 60) {
await new Promise(resolve => setTimeout(resolve, 5000));

const statusCheck = await brdzSDK.xendit.getWithdrawStatus(
withdrawal.data.reference_id
);
status = statusCheck.data.status;

console.log(`Status: ${status}`);
attempts++;
}

return { status, reference_id: withdrawal.data.reference_id };
}

Fixed VA Management

async function setupFixedVAs(walletId) {
const banks = ['BCA', 'BNI', 'MANDIRI'];

for (const bankCode of banks) {
const va = await brdzSDK.xendit.requestFixedVA({
wallet_id: walletId,
bank_code: bankCode,
is_single_use: false
});

console.log(`${bankCode} VA: ${va.data.va_number}`);
}

// Get all VAs
const vaList = await brdzSDK.xendit.getFixedVAList(walletId);
console.log(`Total VAs: ${vaList.data.total_vas}`);

return vaList.data.fixed_vas;
}

Daily Reconciliation

async function performReconciliation(adminUserId) {
// Run reconciliation
const reconciliation = await brdzSDK.xendit.runDailyReconciliation();

console.log(`Wallets Checked: ${reconciliation.data.total_wallets_checked}`);
console.log(`Discrepancies: ${reconciliation.data.discrepancies_found}`);

if (reconciliation.data.discrepancies_found > 0) {
// Get details
const details = await brdzSDK.xendit.getReconciliationDetails(
reconciliation.data.reconciliation_id
);

// Auto-resolve small discrepancies
for (const disc of details.data.discrepancies) {
if (Math.abs(disc.discrepancy) < 1000) {
await brdzSDK.xendit.resolveReconciliation({
reconciliation_id: reconciliation.data.reconciliation_id,
resolved_by: adminUserId,
resolution_notes: `Auto-resolved: Small discrepancy (${disc.discrepancy} IDR)`,
manual_adjustment_amount: 0
});
}
}
}

return reconciliation.data;
}

Monitoring Dashboard

async function displayDashboard() {
const dashboard = await brdzSDK.xendit.getDashboardData();

// Display balances
console.log('=== ACCOUNT BALANCES ===');
dashboard.data.balances.balances.forEach(acc => {
console.log(`${acc.account_type}: IDR ${acc.balance.toLocaleString()}`);
});

// Display webhook stats
console.log('\n=== WEBHOOK STATISTICS ===');
const stats = dashboard.data.webhook_stats;
console.log(`Total: ${stats.total_webhooks}`);
console.log(`Success Rate: ${(stats.success_rate * 100).toFixed(2)}%`);
console.log(`DLQ: ${stats.dlq_count}`);

// Check for issues
if (stats.dlq_count > 10) {
console.warn('⚠️ High DLQ count - processing required');
await brdzSDK.xendit.processDLQ();
}

if (stats.success_rate < 0.95) {
console.warn('⚠️ Low webhook success rate');
}
}

Error Handling

// Robust error handling for Xendit operations
async function safeXenditOperation(operation) {
try {
return await operation();
} catch (error) {
if (error.message.includes('Insufficient Xendit balance')) {
return {
error: 'insufficient_balance',
suggestion: 'top_up_xendit_account'
};
} else if (error.message.includes('Invalid bank code')) {
return {
error: 'invalid_bank',
suggestion: 'use_supported_bank'
};
} else if (error.message.includes('Wallet not found')) {
return {
error: 'wallet_not_found',
suggestion: 'verify_wallet_id'
};
} else if (error.message.includes('Xendit API')) {
return {
error: 'xendit_unavailable',
suggestion: 'retry_later'
};
} else {
console.error('Unexpected Xendit error:', error.message);
throw error;
}
}
}

// Usage
const result = await safeXenditOperation(() =>
brdzSDK.xendit.processWalletWithdraw({
wallet_id: "wallet_123",
amount: 500000,
bank_code: "BCA",
account_number: "1234567890",
account_holder_name: "John Doe"
})
);

Platform-Specific Integration

// Automated balance monitoring
class XenditMonitor {
static async checkBalanceAlert(threshold = 10000000) {
const balance = await brdzSDK.xendit.getBalance();

if (balance.data.balance < threshold) {
console.warn(`⚠️ Balance below threshold: IDR ${balance.data.balance.toLocaleString()}`);
await this.notifyAdmin('Low Balance Alert', {
current_balance: balance.data.balance,
threshold: threshold
});
}

return balance.data.balance;
}

static async 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('⚠️ High DLQ count, processing...');
await brdzSDK.xendit.processDLQ();
}

return stats.data;
}

static async notifyAdmin(subject, data) {
console.log(`🚨 ADMIN ALERT: ${subject}`);
console.log(JSON.stringify(data, null, 2));
}
}

// Schedule monitoring
setInterval(async () => {
await XenditMonitor.checkBalanceAlert(10000000);
await XenditMonitor.monitorWebhooks();
}, 60 * 60 * 1000); // Every hour