AgentSkillsCN

Bridge Virtual Accounts

通过Bridge.xyz API为美元、欧元和墨西哥比索创建并管理虚拟账户。自动生成本地银行账户信息,自动完成法币转加密货币的兑换,并提供存款指引。适用场景包括:接收法币存款、跨境支付、汇款业务,以及货币兑换操作。

SKILL.md
--- frontmatter
name: Bridge Virtual Accounts
description: Virtual account creation and management for USD, EUR, and MXN with Bridge.xyz API. Generate local bank details, automatic fiat-to-crypto conversion, and deposit instructions. Use for: receiving fiat deposits, cross-border payments, remittances, and currency conversion.

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

  1. Save account IDs - Required for tracking and management
  2. Display complete instructions - Include all bank details
  3. Handle both rails - Support ACH and Wire for USD
  4. Webhook monitoring - Track deposits in real-time
  5. Fee transparency - Show fees to customers upfront