Skip to main content

IDRX Module

The idrx module provides comprehensive IDR onramp and offramp functionality for Indonesian market, enabling seamless conversion between Indonesian Rupiah (IDR) and digital currencies (IDRX/USDC). Built with BRDZ System branding for enterprise-grade operations with automated payment processing, bank account management, and real-time transaction tracking.

Import

const idrx = await brdzSDK.idrx;

Methods Overview

MethodDescriptionAuth RequiredHTTP Endpoint
initiateOnrampCreate onramp payment requestPOST /idrx/onramp/initiate
getOnrampStatusGet onramp transaction statusGET /idrx/onramp/status/:reference_id
initiateOfframpCreate offramp withdrawal requestPOST /idrx/offramp/initiate
getOfframpStatusGet offramp transaction statusGET /idrx/offramp/status/:reference_id
addBankAdd bank account for withdrawalsPOST /idrx/banks/add
listBanksGet all bank accountsGET /idrx/banks/list
deleteBankDelete bank accountDELETE /idrx/banks/:bank_id
getMintTransactionsGet mint transaction historyGET /idrx/transactions/mint
getRedeemTransactionsGet redeem transaction historyGET /idrx/transactions/redeem
processAdminRefundProcess refund (admin only)✅ AdminPOST /idrx/admin/refund
getPaymentMethodsGet available payment methodsGET /idrx/payment-methods
getFeesGet fee informationGET /idrx/fees

Onramp Operations (IDR → Digital Currency)

initiateOnramp

Create payment request to convert IDR to IDRX/USDC. User pays via payment gateway (QRIS, Virtual Account, or E-Wallet), and receives digital currency in their wallet after payment confirmation.

const idrx = await brdzSDK.idrx;

const onramp = await idrx.initiateOnramp({
amount: 100000,
paymentMethod: "VA",
walletAddress: "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb"
});

console.log('Reference ID:', onramp.data.referenceId);
console.log('Amount:', onramp.data.amount.toLocaleString('id-ID'));
console.log('Fee:', onramp.data.fee.toLocaleString('id-ID'));
console.log('Total to Pay:', onramp.data.totalAmount.toLocaleString('id-ID'));
console.log('Payment URL:', onramp.data.paymentUrl);
console.log('Expires at:', onramp.data.expiresAt);

// Open payment URL for user
window.open(onramp.data.paymentUrl, '_blank');

Parameters:

  • amount (number, required): Amount in IDR (minimum 20,000, maximum 100,000,000)
  • paymentMethod (string, required): Payment method: 'QRIS', 'VA', or 'EWALLET'
  • walletAddress (string, required): Destination wallet address (0x... for EVM chains)

Returns: Payment request details with payment URL and expiry

getOnrampStatus

Track onramp transaction status by reference ID. Monitor payment confirmation, minting process, and final completion.

const idrx = await brdzSDK.idrx;

const status = await idrx.getOnrampStatus('MINT-1705308000000-123');

console.log('Reference ID:', status.data.referenceId);
console.log('Status:', status.data.status);
console.log('Payment Status:', status.data.paymentStatus);
console.log('Amount:', status.data.amount.toLocaleString('id-ID'));
console.log('Fee:', status.data.fee.toLocaleString('id-ID'));

// Status indicators
const statusEmoji = {
'PENDING': '⏳ Waiting for payment',
'PAID': '✅ Payment received, minting in progress',
'MINTED': '🎉 IDRX minted to blockchain',
'SUCCESS': '✅ Transaction completed',
'FAILED': '❌ Transaction failed'
};

console.log(statusEmoji[status.data.status]);

Parameters:

  • referenceId (string, required): Transaction reference ID (e.g., MINT-1705308000000-123)

Returns: Transaction status with payment details

Offramp Operations (Digital Currency → IDR)

initiateOfframp

Create withdrawal request to convert IDRX to IDR and send to bank account. User must first burn IDRX tokens on blockchain, then provide burn transaction hash to initiate offramp.

const idrx = await brdzSDK.idrx;

// Step 1: Get user's banks
const banks = await idrx.listBanks();
const primaryBank = banks.data.find(b => b.is_primary);

// Step 2: Burn IDRX on blockchain (using ethers.js)
const { ethers } = require('ethers');
const provider = new ethers.providers.Web3Provider(window.ethereum);
const signer = provider.getSigner();

const idrxContract = new ethers.Contract(
IDRX_CONTRACT_ADDRESS,
IDRX_ABI,
signer
);

const amount = ethers.utils.parseUnits('100000', 18);

// Create bank account hash
const bankAccountString = `${primaryBank.bank_name}_${primaryBank.bank_account_number}`;
const bankAccountHash = ethers.utils.keccak256(
ethers.utils.toUtf8Bytes(bankAccountString)
);

// Execute burn
const burnTx = await idrxContract.burnWithAccountNumber(
amount,
bankAccountHash
);

console.log('Burning IDRX...');
await burnTx.wait();
console.log('✅ Burn confirmed:', burnTx.hash);

// Step 3: Initiate offramp
const offramp = await idrx.initiateOfframp({
burnTxHash: burnTx.hash,
amount: 100000,
bankId: primaryBank.idrx_bank_id,
walletAddress: await signer.getAddress()
});

console.log('Reference ID:', offramp.data.referenceId);
console.log('Amount:', offramp.data.amount.toLocaleString('id-ID'));
console.log('Fee:', offramp.data.fee.toLocaleString('id-ID'));
console.log('Net to Bank:', offramp.data.netAmount.toLocaleString('id-ID'));
console.log('Bank:', offramp.data.bankAccount.bankName);
console.log('Account:', offramp.data.bankAccount.accountNumber);

Parameters:

  • burnTxHash (string, required): Burn transaction hash from blockchain
  • amount (number, required): Amount in IDRX to redeem (minimum 20,000)
  • bankId (number, required): Bank account ID from user's registered banks
  • walletAddress (string, required): Wallet address that performed the burn

Returns: Withdrawal request details with bank information

getOfframpStatus

Track offramp transaction status by reference ID. Monitor withdrawal processing and bank transfer confirmation.

const idrx = await brdzSDK.idrx;

const status = await idrx.getOfframpStatus('REDEEM-1705308000000-123');

console.log('Reference ID:', status.data.referenceId);
console.log('Status:', status.data.status);
console.log('Bank Transfer:', status.data.bankTransferStatus);
console.log('Amount:', status.data.amount.toLocaleString('id-ID'));
console.log('Fee:', status.data.fee.toLocaleString('id-ID'));
console.log('Net Amount:', status.data.netAmount.toLocaleString('id-ID'));

// Status indicators
const statusEmoji = {
'PENDING': '⏳ Processing withdrawal',
'PROCESSING': '🔄 Bank transfer in progress',
'COMPLETED': '✅ IDR transferred to bank',
'FAILED': '❌ Transfer failed'
};

console.log(statusEmoji[status.data.status]);

Parameters:

  • referenceId (string, required): Transaction reference ID (e.g., REDEEM-1705308000000-123)

Returns: Transaction status with bank transfer details

Bank Account Management

addBank

Register bank account for offramp withdrawals. Users can add multiple bank accounts and set one as primary.

const idrx = await brdzSDK.idrx;

const bank = await idrx.addBank({
bankName: "BANK CENTRAL ASIA",
bankCode: "014",
accountNumber: "1234567890",
accountName: "JOHN SMITH",
isPrimary: true
});

console.log('Bank ID:', bank.data.idrx_bank_id);
console.log('Bank:', bank.data.bank_name);
console.log('Account:', bank.data.bank_account_number);
console.log('Holder:', bank.data.bank_account_name);
console.log('Primary:', bank.data.is_primary);

Parameters:

  • bankName (string, required): Bank name (e.g., 'BANK CENTRAL ASIA')
  • bankCode (string, required): Bank code (e.g., '014' for BCA)
  • accountNumber (string, required): Bank account number
  • accountName (string, required): Account holder name (must match user's name)
  • isPrimary (boolean, optional): Set as primary account (default: false)

Returns: Bank account details with ID

listBanks

Retrieve all active bank accounts for the authenticated user.

const idrx = await brdzSDK.idrx;

const banks = await idrx.listBanks();

console.log(`Total banks: ${banks.data.length}\n`);

banks.data.forEach((bank, index) => {
const primaryFlag = bank.is_primary ? '⭐ PRIMARY' : '';
console.log(`${index + 1}. ${bank.bank_name} ${primaryFlag}`);
console.log(` Account: ${bank.bank_account_number}`);
console.log(` Holder: ${bank.bank_account_name}`);
console.log(` Status: ${bank.status}\n`);
});

// Find primary bank
const primaryBank = banks.data.find(b => b.is_primary);
if (primaryBank) {
console.log('Primary bank for withdrawals:');
console.log(` ${primaryBank.bank_name}`);
console.log(` ${primaryBank.bank_account_number}`);
}

Returns: List of all user bank accounts with primary designation

deleteBank

Soft delete (deactivate) a bank account. Cannot delete if it's the only bank account or if there are pending transactions.

const idrx = await brdzSDK.idrx;

const result = await idrx.deleteBank(2);
console.log(result.message);

// Get updated list
const banks = await idrx.listBanks();
console.log(`Remaining banks: ${banks.data.length}`);

Parameters:

  • bankId (number, required): Bank account ID to delete

Returns: Deletion confirmation

Transaction History

getMintTransactions

Retrieve user's mint (onramp) transaction history with pagination and status filtering.

const idrx = await brdzSDK.idrx;

const history = await idrx.getMintTransactions();

console.log(`Total transactions: ${history.pagination.total}\n`);

history.data.forEach((tx, index) => {
console.log(`${index + 1}. Reference: ${tx.reference_id}`);
console.log(` Amount: IDR ${tx.amount_idr.toLocaleString('id-ID')}`);
console.log(` Fee: IDR ${tx.fee_amount.toLocaleString('id-ID')}`);
console.log(` Method: ${tx.payment_method}`);
console.log(` Status: ${tx.status}`);
console.log(` Date: ${new Date(tx.created_at).toLocaleString('id-ID')}\n`);
});

// Filter by status
const successTx = await idrx.getMintTransactions({
status: 'SUCCESS',
page: 1,
limit: 20
});

console.log(`Successful transactions: ${successTx.data.length}`);

Parameters:

  • status (string, optional): Filter by status: PENDING, PAID, MINTED, SUCCESS, FAILED
  • page (number, optional): Page number (default: 1)
  • limit (number, optional): Items per page (default: 10)

Returns: List of mint transactions with pagination

getRedeemTransactions

Retrieve user's redeem (offramp) transaction history with pagination and status filtering.

const idrx = await brdzSDK.idrx;

const history = await idrx.getRedeemTransactions();

console.log(`Total transactions: ${history.pagination.total}\n`);

history.data.forEach((tx, index) => {
console.log(`${index + 1}. Reference: ${tx.reference_id}`);
console.log(` Amount: IDR ${tx.amount_idr.toLocaleString('id-ID')}`);
console.log(` Fee: IDR ${tx.fee_amount.toLocaleString('id-ID')}`);
console.log(` Net to Bank: IDR ${tx.net_amount_idr.toLocaleString('id-ID')}`);
console.log(` Bank: ${tx.bank_name}`);
console.log(` Account: ${tx.bank_account_number}`);
console.log(` Status: ${tx.status}`);
console.log(` Date: ${new Date(tx.created_at).toLocaleString('id-ID')}\n`);
});

// Filter by status
const completed = await idrx.getRedeemTransactions({
status: 'COMPLETED',
page: 1,
limit: 20
});

console.log(`Completed withdrawals: ${completed.data.length}`);

Parameters:

  • status (string, optional): Filter by status: PENDING, PROCESSING, COMPLETED, FAILED
  • page (number, optional): Page number (default: 1)
  • limit (number, optional): Items per page (default: 10)

Returns: List of redeem transactions with pagination

Admin Operations

processAdminRefund

Process refund for failed mint or redeem transaction. Refunds user's funds minus refund fee. Admin-only operation.

const idrx = await brdzSDK.idrx;

// Refund failed mint transaction
const refund = await idrx.processAdminRefund({
transactionType: "MINT",
transactionId: 123,
reason: "Payment received but minting failed due to technical error"
});

console.log('Refund Transaction ID:', refund.data.refundTransactionId);
console.log('Refund Fee:', refund.data.refundFee.toLocaleString('id-ID'));
console.log('Net Refund to User:', refund.data.netRefund.toLocaleString('id-ID'));

Parameters:

  • transactionType (string, required): Transaction type: 'MINT' or 'REDEEM'
  • transactionId (number, required): Original transaction ID
  • reason (string, required): Refund reason for audit trail

Returns: Refund details with transaction ID

Utility Operations

getPaymentMethods

Fetch live payment methods with current fee structures.

const idrx = await brdzSDK.idrx;

const methods = await idrx.getPaymentMethods();

console.log(`Payment methods (${methods.source}):\n`);

methods.data.forEach(method => {
const feeDisplay = method.fee_type === 'PERCENTAGE'
? `${method.fee}%`
: `IDR ${method.fee.toLocaleString('id-ID')}`;

console.log(`${method.name}`);
console.log(` Fee: ${feeDisplay}`);
console.log(` Description: ${method.description}\n`);
});

Returns: List of payment methods with fees and descriptions

getFees

Fetch comprehensive fee information for all operations.

const idrx = await brdzSDK.idrx;

const allFees = await idrx.getFees();

console.log('=== IDRX FEE STRUCTURE ===\n');

// Display mint fees
console.log('ONRAMP (Mint) Fees:');
allFees.data.mint.methods.forEach(m => {
console.log(` ${m.method}: ${m.fee}`);
console.log(` ${m.description}`);
});
console.log(` Processing: ${allFees.data.mint.processingTime}\n`);

// Display redeem fees
console.log('OFFRAMP (Redeem) Fees:');
allFees.data.redeem.fees.forEach(f => {
console.log(` ${f.range}: ${f.fee}`);
console.log(` Processing: ${f.processingTime}`);
});
console.log(` Max: ${allFees.data.redeem.maxProcessingTime}\n`);

// Get specific fee type
const mintFees = await idrx.getFees({ type: 'MINT' });
console.log('Mint Fees Only:', mintFees.data);

Parameters:

  • type (string, optional): Fee type: 'MINT', 'REDEEM', 'REFUND', or 'BRIDGE'

Returns: Fee structure for specified type or all fees

Complete Usage Examples

Basic IDRX Setup

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

const idrx = await brdzSDK.idrx;

// Check payment methods
const methods = await idrx.getPaymentMethods();
console.log('Available methods:', methods.data.map(m => m.method));

// Check fees
const fees = await idrx.getFees({ type: 'MINT' });
console.log('Mint fees:', fees.data);

Complete Onramp Flow

async function completeOnrampFlow(amount, paymentMethod, walletAddress) {
console.log('=== STARTING ONRAMP FLOW ===\n');

const idrx = await brdzSDK.idrx;

try {
// Step 1: Initiate onramp
console.log('Step 1: Creating payment request...');
const onramp = await idrx.initiateOnramp({
amount,
paymentMethod,
walletAddress
});

console.log('✅ Payment request created');
console.log(`Reference: ${onramp.data.referenceId}`);
console.log(`Amount: IDR ${onramp.data.amount.toLocaleString('id-ID')}`);
console.log(`Fee: IDR ${onramp.data.fee.toLocaleString('id-ID')}`);
console.log(`Total: IDR ${onramp.data.totalAmount.toLocaleString('id-ID')}`);
console.log(`Payment URL: ${onramp.data.paymentUrl}`);

// Step 2: Open payment page
console.log('\nStep 2: Opening payment page...');
window.open(onramp.data.paymentUrl, '_blank');

// Step 3: Monitor status
console.log('\nStep 3: Monitoring transaction status...');

const referenceId = onramp.data.referenceId;
let completed = false;
let attempts = 0;
const maxAttempts = 288;

while (!completed && attempts < maxAttempts) {
await new Promise(resolve => setTimeout(resolve, 5000));

const status = await idrx.getOnrampStatus(referenceId);

console.log(`[${new Date().toLocaleTimeString()}] Status: ${status.data.status}`);

if (status.data.status === 'SUCCESS') {
console.log('\n✅ ONRAMP COMPLETED!');
console.log(`IDRX Amount: ${status.data.amount.toLocaleString('id-ID')}`);
console.log(`Wallet: ${walletAddress}`);
completed = true;

return {
success: true,
referenceId,
amount: status.data.amount,
status: status.data.status
};
} else if (status.data.status === 'FAILED') {
console.log('\n❌ Payment failed');
completed = true;

return {
success: false,
referenceId,
status: status.data.status
};
}

attempts++;
}

} catch (error) {
console.error('\n❌ Onramp flow failed:', error.message);
return {
success: false,
error: error.message
};
}
}

// Usage
await completeOnrampFlow(
100000,
"VA",
"0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb"
);

Complete Offramp Flow

async function completeOfframpFlow(amount, walletAddress) {
console.log('=== STARTING OFFRAMP FLOW ===\n');

const idrx = await brdzSDK.idrx;
const { ethers } = require('ethers');

try {
// Step 1: Check/add bank account
console.log('Step 1: Checking bank accounts...');
let banks = await idrx.listBanks();

if (banks.data.length === 0) {
console.log('No bank accounts found. Adding bank...');

const bankData = {
bankName: "BANK CENTRAL ASIA",
bankCode: "014",
accountNumber: "1234567890",
accountName: "JOHN SMITH",
isPrimary: true
};

await idrx.addBank(bankData);
banks = await idrx.listBanks();
console.log('✅ Bank account added');
}

const primaryBank = banks.data.find(b => b.is_primary);
console.log(`Primary bank: ${primaryBank.bank_name}`);
console.log(`Account: ${primaryBank.bank_account_number}\n`);

// Step 2: Burn IDRX on blockchain
console.log('Step 2: Burning IDRX on blockchain...');

const provider = new ethers.providers.Web3Provider(window.ethereum);
const signer = provider.getSigner();

const idrxContract = new ethers.Contract(
IDRX_CONTRACT_ADDRESS,
IDRX_ABI,
signer
);

const amountWei = ethers.utils.parseUnits(amount.toString(), 18);

const bankString = `${primaryBank.bank_name}_${primaryBank.bank_account_number}`;
const bankHash = ethers.utils.keccak256(
ethers.utils.toUtf8Bytes(bankString)
);

console.log('Executing burn transaction...');
const burnTx = await idrxContract.burnWithAccountNumber(amountWei, bankHash);

console.log(`Burn TX: ${burnTx.hash}`);
console.log('Waiting for confirmation...');

await burnTx.wait();
console.log('✅ Burn confirmed\n');

// Step 3: Initiate offramp
console.log('Step 3: Creating withdrawal request...');

const offramp = await idrx.initiateOfframp({
burnTxHash: burnTx.hash,
amount,
bankId: primaryBank.idrx_bank_id,
walletAddress
});

console.log('✅ Withdrawal request created');
console.log(`Reference: ${offramp.data.referenceId}`);
console.log(`Amount: IDR ${offramp.data.amount.toLocaleString('id-ID')}`);
console.log(`Fee: IDR ${offramp.data.fee.toLocaleString('id-ID')}`);
console.log(`Net to Bank: IDR ${offramp.data.netAmount.toLocaleString('id-ID')}\n`);

// Step 4: Monitor status
console.log('Step 4: Monitoring withdrawal status...');

const referenceId = offramp.data.referenceId;
let completed = false;
let attempts = 0;
const maxAttempts = 288;

while (!completed && attempts < maxAttempts) {
await new Promise(resolve => setTimeout(resolve, 10000));

const status = await idrx.getOfframpStatus(referenceId);

console.log(`[${new Date().toLocaleTimeString()}] Status: ${status.data.status}`);

if (status.data.status === 'COMPLETED') {
console.log('\n✅ OFFRAMP COMPLETED!');
console.log(`Net Amount: IDR ${status.data.netAmount.toLocaleString('id-ID')}`);
console.log(`Bank: ${primaryBank.bank_name}`);
console.log(`Account: ${primaryBank.bank_account_number}`);
console.log('💰 Check your bank account for funds');
completed = true;

return {
success: true,
referenceId,
netAmount: status.data.netAmount,
status: status.data.status
};
} else if (status.data.status === 'FAILED') {
console.log('\n❌ Withdrawal failed');
completed = true;

return {
success: false,
referenceId,
status: status.data.status
};
}

attempts++;
}

} catch (error) {
console.error('\n❌ Offramp flow failed:', error.message);
return {
success: false,
error: error.message
};
}
}

// Usage
await completeOfframpFlow(
100000,
"0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb"
);

Transaction Status Tracker

async function trackTransaction(referenceId) {
console.log(`=== TRACKING TRANSACTION: ${referenceId} ===\n`);

const idrx = await brdzSDK.idrx;

try {
const txType = referenceId.startsWith('MINT') ? 'ONRAMP' : 'OFFRAMP';

console.log(`Transaction Type: ${txType}\n`);

const status = txType === 'ONRAMP'
? await idrx.getOnrampStatus(referenceId)
: await idrx.getOfframpStatus(referenceId);

console.log('Current Status:', status.data.status);
console.log('Amount:', `IDR ${status.data.amount.toLocaleString('id-ID')}`);
console.log('Fee:', `IDR ${status.data.fee.toLocaleString('id-ID')}`);

if (txType === 'ONRAMP') {
console.log('Payment Method:', status.data.paymentMethod || 'N/A');
console.log('Payment Status:', status.data.paymentStatus);

if (status.data.expiresAt) {
const expiresAt = new Date(status.data.expiresAt);
const timeLeft = Math.round((expiresAt - new Date()) / 1000 / 60);
console.log(`Expires in: ${timeLeft > 0 ? timeLeft + ' minutes' : 'EXPIRED'}`);
}
} else {
console.log('Net Amount:', `IDR ${status.data.netAmount.toLocaleString('id-ID')}`);
console.log('Bank Transfer:', status.data.bankTransferStatus || 'N/A');
}

console.log('Created:', new Date(status.data.createdAt).toLocaleString('id-ID'));

const statusSteps = txType === 'ONRAMP'
? ['PENDING', 'PAID', 'MINTED', 'SUCCESS']
: ['PENDING', 'PROCESSING', 'COMPLETED'];

const currentIndex = statusSteps.indexOf(status.data.status);

console.log('\nProgress:');
statusSteps.forEach((step, index) => {
const icon = index < currentIndex ? '✅'
: index === currentIndex ? '🔄'
: '⏳';
console.log(`${icon} ${step}`);
});

return status.data;

} catch (error) {
console.error('Error tracking transaction:', error.message);
return null;
}
}

// Usage
await trackTransaction('MINT-1705308000000-123');
await trackTransaction('REDEEM-1705308000000-456');

Bank Account Management

async function manageBankAccounts() {
console.log('=== BANK ACCOUNT MANAGEMENT ===\n');

const idrx = await brdzSDK.idrx;

try {
// Add multiple banks
const banksToAdd = [
{
bankName: "BANK CENTRAL ASIA",
bankCode: "014",
accountNumber: "1234567890",
accountName: "JOHN SMITH",
isPrimary: true
},
{
bankName: "BANK MANDIRI",
bankCode: "008",
accountNumber: "9876543210",
accountName: "JOHN SMITH",
isPrimary: false
}
];

console.log('Adding bank accounts...');
for (const bankData of banksToAdd) {
const result = await idrx.addBank(bankData);
console.log(`✅ Added: ${result.data.bank_name}`);
}

console.log('\n');

// List all banks
const banks = await idrx.listBanks();
console.log(`Total banks: ${banks.data.length}\n`);

banks.data.forEach((bank, index) => {
const primaryFlag = bank.is_primary ? '⭐ PRIMARY' : '';
console.log(`${index + 1}. ${bank.bank_name} ${primaryFlag}`);
console.log(` Account: ${bank.bank_account_number}`);
console.log(` Holder: ${bank.bank_account_name}`);
console.log(` Status: ${bank.status}\n`);
});

// Delete a bank (if more than one exists)
if (banks.data.length > 1) {
const nonPrimaryBank = banks.data.find(b => !b.is_primary);
if (nonPrimaryBank) {
console.log(`Deleting: ${nonPrimaryBank.bank_name}...`);
await idrx.deleteBank(nonPrimaryBank.idrx_bank_id);
console.log('✅ Bank deleted\n');

const updatedBanks = await idrx.listBanks();
console.log(`Remaining banks: ${updatedBanks.data.length}`);
}
}

} catch (error) {
console.error('Error managing banks:', error.message);
}
}

// Usage
await manageBankAccounts();

Admin Refund Process

async function adminRefundProcess(txType, txId) {
console.log('=== ADMIN REFUND PROCESS ===\n');

const idrx = await brdzSDK.idrx;

try {
// Step 1: Get transaction details
console.log('Step 1: Retrieving transaction details...');

const refId = txType === 'MINT'
? `MINT-${txId}`
: `REDEEM-${txId}`;

const status = txType === 'MINT'
? await idrx.getOnrampStatus(refId)
: await idrx.getOfframpStatus(refId);

console.log('Transaction found:');
console.log(` Reference: ${status.data.referenceId}`);
console.log(` Status: ${status.data.status}`);
console.log(` Amount: IDR ${status.data.amount.toLocaleString('id-ID')}`);
console.log(` Fee: IDR ${status.data.fee.toLocaleString('id-ID')}\n`);

// Step 2: Check if refund eligible
console.log('Step 2: Checking refund eligibility...');

if (status.data.status === 'SUCCESS' || status.data.status === 'COMPLETED') {
console.log('❌ Cannot refund completed transaction');
return { success: false, reason: 'Transaction already completed' };
}

console.log('✅ Transaction eligible for refund\n');

// Step 3: Calculate refund amount
console.log('Step 3: Calculating refund amount...');

const originalAmount = status.data.amount;
const refundFee = 10000; // Simplified
const netRefund = originalAmount - refundFee;

console.log(`Original Amount: IDR ${originalAmount.toLocaleString('id-ID')}`);
console.log(`Refund Fee: IDR ${refundFee.toLocaleString('id-ID')}`);
console.log(`Net Refund: IDR ${netRefund.toLocaleString('id-ID')}\n`);

// Step 4: Process refund
console.log('Step 4: Processing refund...');

const reason = `Failed ${txType} transaction - technical error during processing`;

const refund = await idrx.processAdminRefund({
transactionType: txType,
transactionId: txId,
reason
});

console.log('✅ REFUND PROCESSED!\n');
console.log('Refund Details:');
console.log(` Refund TX ID: ${refund.data.refundTransactionId}`);
console.log(` Refund Fee: IDR ${refund.data.refundFee.toLocaleString('id-ID')}`);
console.log(` Net Refund: IDR ${refund.data.netRefund.toLocaleString('id-ID')}`);

return {
success: true,
refundTransactionId: refund.data.refundTransactionId,
netRefund: refund.data.netRefund
};

} catch (error) {
console.error('\n❌ Refund process failed:', error.message);
return {
success: false,
error: error.message
};
}
}

// Usage
await adminRefundProcess('MINT', 123);

Error Handling

class IdrxErrorHandler {
static async safeOnramp(amount, paymentMethod, walletAddress) {
try {
const idrx = await brdzSDK.idrx;
return await idrx.initiateOnramp({
amount,
paymentMethod,
walletAddress
});
} catch (error) {
return this.handleError(error, 'ONRAMP');
}
}

static async safeOfframp(burnTxHash, amount, bankId, walletAddress) {
try {
const idrx = await brdzSDK.idrx;
return await idrx.initiateOfframp({
burnTxHash,
amount,
bankId,
walletAddress
});
} catch (error) {
return this.handleError(error, 'OFFRAMP');
}
}

static handleError(error, operation) {
const errorMap = {
'Missing required fields': {
message: 'Please provide all required information',
action: 'Check your input and try again',
retry: true
},
'Amount must be between': {
message: 'Amount is outside allowed range',
action: 'Minimum: Rp 20,000, Maximum: Rp 100,000,000',
retry: true
},
'Bank account not found': {
message: 'Bank account not registered',
action: 'Please add a bank account first',
retry: false
},
'Invalid burn transaction': {
message: 'Burn transaction is invalid or not found',
action: 'Please verify the transaction hash',
retry: false
},
'Transaction not found': {
message: 'Transaction reference not found',
action: 'Please check the reference ID',
retry: false
}
};

let errorInfo = null;

for (const [key, value] of Object.entries(errorMap)) {
if (error.message && error.message.includes(key)) {
errorInfo = value;
break;
}
}

if (!errorInfo) {
errorInfo = {
message: error.message || 'An unexpected error occurred',
action: 'Please try again or contact support',
retry: false
};
}

console.error(`\n❌ ${operation} Error:`);
console.error(`Message: ${errorInfo.message}`);
console.error(`Action: ${errorInfo.action}`);
console.error(`Can Retry: ${errorInfo.retry ? 'Yes' : 'No'}`);

return {
success: false,
operation,
error: errorInfo.message,
action: errorInfo.action,
canRetry: errorInfo.retry
};
}
}

// Usage
const result = await IdrxErrorHandler.safeOnramp(
100000,
'VA',
'0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb'
);

if (!result.success && result.canRetry) {
console.log('You can try again');
}

Platform-Specific Integration

class IdrxMonitor {
static async monitorPendingTransactions() {
const idrx = await brdzSDK.idrx;

// Monitor mint transactions
const pendingMints = await idrx.getMintTransactions({
status: 'PENDING'
});

console.log(`Pending mints: ${pendingMints.data.length}`);

// Monitor redeem transactions
const pendingRedeems = await idrx.getRedeemTransactions({
status: 'PENDING'
});

console.log(`Pending redeems: ${pendingRedeems.data.length}`);

// Check for expired payments
const allMints = await idrx.getMintTransactions({ status: 'PENDING' });

const expired = allMints.data.filter(tx => {
const expiresAt = new Date(tx.expired_at);
return expiresAt < new Date();
});

if (expired.length > 0) {
console.warn(`⚠️ ${expired.length} expired payment requests`);
}

return {
pending_mints: pendingMints.data.length,
pending_redeems: pendingRedeems.data.length,
expired_payments: expired.length
};
}

static async checkTransactionHealth() {
const idrx = await brdzSDK.idrx;

const statusCounts = {
mint: { PENDING: 0, PAID: 0, MINTED: 0, SUCCESS: 0, FAILED: 0 },
redeem: { PENDING: 0, PROCESSING: 0, COMPLETED: 0, FAILED: 0 }
};

// Get mint stats
const mints = await idrx.getMintTransactions({ limit: 100 });
mints.data.forEach(tx => {
if (statusCounts.mint[tx.status] !== undefined) {
statusCounts.mint[tx.status]++;
}
});

// Get redeem stats
const redeems = await idrx.getRedeemTransactions({ limit: 100 });
redeems.data.forEach(tx => {
if (statusCounts.redeem[tx.status] !== undefined) {
statusCounts.redeem[tx.status]++;
}
});

console.log('Transaction Health Summary:');
console.log('Mint:', statusCounts.mint);
console.log('Redeem:', statusCounts.redeem);

return statusCounts;
}

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

// Schedule monitoring
setInterval(async () => {
await IdrxMonitor.monitorPendingTransactions();
await IdrxMonitor.checkTransactionHealth();
}, 60 * 60 * 1000); // Every hour

Transaction Flow States

Onramp Flow

  1. PENDING: Payment request created, awaiting user payment
  2. PAID: Payment received, minting in progress
  3. MINTED: IDRX minted on blockchain
  4. SUCCESS: IDRX delivered to wallet
  5. FAILED: Transaction failed

Offramp Flow

  1. PENDING: Withdrawal request created
  2. PROCESSING: Bank transfer in progress
  3. COMPLETED: IDR transferred to bank account
  4. FAILED: Transaction failed

Payment Methods

Supported Payment Methods

  • QRIS: Free, instant QR code payment
  • Virtual Account (VA): Rp 3,000 flat fee, all major banks
  • E-Wallet: 1.67% fee, GoPay/OVO/DANA/ShopeePay

Fee Structure

  • Onramp Fees: Varies by payment method (0% - 1.67%)
  • Offramp Fees: Rp 5,000 - Rp 35,000 based on amount
  • Refund Fees: Rp 5,000 + applicable redeem fee

Important Notes

  • Users must provide a valid wallet address before initiating onramp
  • Bank account holder name must match user's registered name
  • Payment requests expire after 24 hours
  • Complete onramp typically takes up to 24 hours
  • Complete offramp typically takes up to 24 hours
  • Burn transaction must be confirmed before initiating offramp
  • All operations require proper authentication
  • Admin operations require admin role

Best Practices

  1. Always verify wallet address format before initiating transactions
  2. Use error handling for all operations
  3. Monitor transaction statuses regularly
  4. Set up proper bank accounts before offramp
  5. Implement retry logic for failed operations
  6. Log all operations for audit trails
  7. Validate amounts are within limits
  8. Check payment expiry times
  9. Provide clear user feedback during long operations
  10. Implement admin notifications for critical errors