Bridge Virtual Accounts
Quick Reference
typescript
type VirtualAccountCurrency = 'usd' | 'eur' | 'mxn'; type PaymentRail = 'ach_push' | 'wire' | 'sepa' | 'spei';
Create Virtual Account
USD Virtual Account
typescript
interface CreateVirtualAccountRequest {
source: {
currency: VirtualAccountCurrency;
payment_rail?: PaymentRail;
};
destination: {
payment_rail: 'ethereum' | 'solana' | 'polygon' | 'base' | 'arbitrum';
currency: string; // 'usdc', 'usdb'
address: string;
};
developer_fee_percent?: string;
}
interface VirtualAccount {
id: string;
status: 'activated' | 'pending' | 'closed';
developer_fee_percent: string;
customer_id: string;
created_at: string;
source_deposit_instructions: {
currency: VirtualAccountCurrency;
bank_name: string;
bank_address: string;
bank_routing_number?: string;
bank_account_number?: string;
bank_beneficiary_name?: string;
bank_beneficiary_address?: string;
iban?: string;
bic?: string;
account_holder_name?: string;
payment_rail: PaymentRail;
payment_rails: PaymentRail[];
clabe?: string; // For MXN
};
destination: {
currency: string;
payment_rail: string;
address: string;
};
}
async function createVirtualAccount(
customerId: string,
request: CreateVirtualAccountRequest
): Promise<VirtualAccount> {
const response = await fetch(`${BRIDGE_API_URL}/customers/${customerId}/virtual_accounts`, {
method: 'POST',
headers: {
'Api-Key': API_KEY,
'Idempotency-Key': crypto.randomUUID(),
'Content-Type': 'application/json',
},
body: JSON.stringify(request),
});
if (!response.ok) {
const error = await response.json();
throw new Error(`Virtual account creation failed: ${error.message}`);
}
return response.json();
}
USD Account Example
typescript
async function createUSDVirtualAccount(
customerId: string,
cryptoAddress: string
): Promise<VirtualAccount> {
return createVirtualAccount(customerId, {
source: {
currency: 'usd',
},
destination: {
payment_rail: 'ethereum',
currency: 'usdc',
address: cryptoAddress,
},
developer_fee_percent: '1.0', // 1% fee
});
}
// Usage
const usdAccount = await createUSDVirtualAccount(
'cust_sender',
'0x3f5CE5FBFe3E9af3971dD833D26BA9b5C936f0bE'
);
console.log('Account ID:', usdAccount.id);
console.log('Bank Name:', usdAccount.source_deposit_instructions.bank_name);
console.log('Routing Number:', usdAccount.source_deposit_instructions.bank_routing_number);
console.log('Account Number:', usdAccount.source_deposit_instructions.bank_account_number);
console.log('Beneficiary:', usdAccount.source_deposit_instructions.bank_beneficiary_name);
console.log('Available Rails:', usdAccount.source_deposit_instructions.payment_rails);
EUR (SEPA) Virtual Account
typescript
async function createEURVirtualAccount(
customerId: string,
cryptoAddress: string
): Promise<VirtualAccount> {
return createVirtualAccount(customerId, {
source: {
currency: 'eur',
},
destination: {
payment_rail: 'ethereum',
currency: 'usdc',
address: cryptoAddress,
},
developer_fee_percent: '0.5',
});
}
// Usage
const eurAccount = await createEURVirtualAccount(
'cust_european',
'0x3f5CE5FBFe3E9af3971dD833D26BA9b5C936f0bE'
);
console.log('IBAN:', eurAccount.source_deposit_instructions.iban);
console.log('BIC:', eurAccount.source_deposit_instructions.bic);
console.log('Account Holder:', eurAccount.source_deposit_instructions.account_holder_name);
console.log('Bank:', eurAccount.source_deposit_instructions.bank_name);
MXN (SPEI) Virtual Account
typescript
async function createMXNVirtualAccount(
customerId: string,
cryptoAddress: string
): Promise<VirtualAccount> {
return createVirtualAccount(customerId, {
source: {
currency: 'mxn',
},
destination: {
payment_rail: 'ethereum',
currency: 'usdc',
address: cryptoAddress,
},
developer_fee_percent: '0.5',
});
}
// Usage
const mxnAccount = await createMXNVirtualAccount(
'cust_mexico',
'0x3f5CE5FBFe3E9af3971dD833D26BA9b5C936f0bE'
);
console.log('CLABE:', mxnAccount.source_deposit_instructions.clabe);
console.log('Bank:', mxnAccount.source_deposit_instructions.bank_name);
Multi-Currency Setup
typescript
class MultiCurrencyAccountManager {
private customerId: string;
private cryptoAddress: string;
constructor(customerId: string, cryptoAddress: string) {
this.customerId = customerId;
this.cryptoAddress = cryptoAddress;
}
async createAllAccounts(): Promise<Record<VirtualAccountCurrency, VirtualAccount>> {
const [usd, eur, mxn] = await Promise.all([
createVirtualAccount(this.customerId, {
source: { currency: 'usd' },
destination: { payment_rail: 'ethereum', currency: 'usdc', address: this.cryptoAddress },
}),
createVirtualAccount(this.customerId, {
source: { currency: 'eur' },
destination: { payment_rail: 'ethereum', currency: 'usdc', address: this.cryptoAddress },
}),
createVirtualAccount(this.customerId, {
source: { currency: 'mxn' },
destination: { payment_rail: 'ethereum', currency: 'usdc', address: this.cryptoAddress },
}),
]);
return { usd, eur, mxn };
}
generateDepositInstructions(account: VirtualAccount): string {
const instructions = account.source_deposit_instructions;
if (instructions.iban) {
return `
Bank Transfer (SEPA):
- IBAN: ${instructions.iban}
- BIC: ${instructions.bic}
- Account Holder: ${instructions.account_holder_name}
- Bank: ${instructions.bank_name}
- Amount in EUR
`.trim();
}
if (instructions.clabe) {
return `
SPEI Transfer (Mexico):
- CLABE: ${instructions.clabe}
- Bank: ${instructions.bank_name}
- Beneficiary: ${instructions.bank_beneficiary_name}
- Amount in MXN
`.trim();
}
return `
ACH/Wire Transfer (US):
- Routing Number: ${instructions.bank_routing_number}
- Account Number: ${instructions.bank_account_number}
- Beneficiary: ${instructions.bank_beneficiary_name}
- Bank: ${instructions.bank_name}
- Available Rails: ${instructions.payment_rails.join(', ')}
`.trim();
}
}
// Usage
const manager = new MultiCurrencyAccountManager(
'cust_global',
'0x3f5CE5FBFe3E9af3971dD833D26BA9b5C936f0bE'
);
const accounts = await manager.createAllAccounts();
console.log('USD Account:', accounts.usd.id);
console.log('EUR Account:', accounts.eur.id);
console.log('MXN Account:', accounts.mxn.id);
List Virtual Accounts
typescript
async function listVirtualAccounts(customerId: string): Promise<VirtualAccount[]> {
const response = await fetch(`${BRIDGE_API_URL}/customers/${customerId}/virtual_accounts`, {
headers: {
'Api-Key': API_KEY,
},
});
if (!response.ok) {
throw new Error('Failed to list virtual accounts');
}
const data = await response.json();
return data.virtual_accounts || data;
}
// Filter by currency
async function getUSDAccounts(customerId: string): Promise<VirtualAccount[]> {
const accounts = await listVirtualAccounts(customerId);
return accounts.filter(a => a.source_deposit_instructions.currency === 'usd');
}
Deposit Flow
typescript
interface DepositEvent {
virtual_account_id: string;
amount: string;
currency: string;
status: 'pending' | 'completed' | 'failed';
transaction_id?: string;
created_at: string;
}
async function handleIncomingDeposit(
customerId: string,
amount: string
): Promise<DepositEvent> {
const accounts = await listVirtualAccounts(customerId);
const usdAccount = accounts.find(
a => a.source_deposit_instructions.currency === 'usd'
);
if (!usdAccount) {
throw new Error('No USD virtual account found');
}
// Monitor for deposit completion via webhook
return {
virtual_account_id: usdAccount.id,
amount,
currency: 'usd',
status: 'pending',
created_at: new Date().toISOString(),
};
}
// Customer deposit instructions display
function generateCustomerDepositPage(customerId: string): string {
const instructions = `
<h2>Deposit Funds</h2>
<p>Send funds to any of these accounts and we'll convert and send to your crypto wallet.</p>
${['usd', 'eur', 'mxn'].map(currency => `
<h3>${currency.toUpperCase()} Account</h3>
<pre>${manager.generateDepositInstructions(accounts[currency])}</pre>
`).join('')}
`.trim();
return instructions;
}
Remittance Use Case
typescript
interface RemittanceRequest {
senderCustomerId: string;
senderCurrency: VirtualAccountCurrency;
recipientCryptoAddress: string;
developerFeePercent?: string;
}
async function setupRemittanceFlow(
request: RemittanceRequest
): Promise<VirtualAccount> {
return createVirtualAccount(request.senderCustomerId, {
source: {
currency: request.senderCurrency,
},
destination: {
payment_rail: 'ethereum',
currency: 'usdc',
address: request.recipientCryptoAddress,
},
developer_fee_percent: request.developerFeePercent || '1.0',
});
}
// Global remittance service
class RemittanceService {
async receiveFromUS(senderCustomerId: string, recipientAddress: string) {
return setupRemittanceFlow({
senderCustomerId,
senderCurrency: 'usd',
recipientCryptoAddress: recipientAddress,
});
}
async receiveFromEU(senderCustomerId: string, recipientAddress: string) {
return setupRemittanceFlow({
senderCustomerId,
senderCurrency: 'eur',
recipientCryptoAddress: recipientAddress,
});
}
async receiveFromMexico(senderCustomerId: string, recipientAddress: string) {
return setupRemittanceFlow({
senderCustomerId,
senderCurrency: 'mxn',
recipientCryptoAddress: recipientAddress,
});
}
}
Fee Configuration
typescript
interface FeeConfiguration {
developer_fee_percent: string;
effectiveRate(amount: string): string {
return (parseFloat(amount) * (parseFloat(this.developer_fee_percent) / 100)).toFixed(2);
}
}
async function configureFees(
customerId: string,
feePercent: string
): Promise<VirtualAccount> {
return createVirtualAccount(customerId, {
source: { currency: 'usd' },
destination: {
payment_rail: 'ethereum',
currency: 'usdc',
address: '0xplaceholder',
},
developer_fee_percent: feePercent,
});
}
// Fee tiers
const FEE_TIERS = {
standard: '1.0',
premium: '0.5',
enterprise: '0.25',
};
Webhook Events
- •
virtual_account.created- New virtual account created - •
virtual_account.deposit_received- Fiat deposit received - •
virtual_account.conversion_completed- Fiat converted to crypto - •
virtual_account.funds_sent- Crypto sent to destination
Best Practices
- •Save account IDs - Required for tracking and management
- •Display complete instructions - Include all bank details
- •Handle both rails - Support ACH and Wire for USD
- •Webhook monitoring - Track deposits in real-time
- •Fee transparency - Show fees to customers upfront