Bridge External Accounts
Quick Reference
typescript
type AccountType = 'us' | 'iban' | 'swift' | 'clabe' | 'pix'; type OwnerType = 'individual' | 'business';
Create External Account (Direct API)
US Bank Account
typescript
interface CreateExternalAccountRequest {
currency: string;
bank_name: string;
account_owner_name: string;
account_number: string;
routing_number: string; // Required for US ACH
account_type: 'us';
address: {
street_line1: string;
street_line2?: string;
city: string;
state: string;
postal_code: string;
country: string;
};
account_owner_type?: OwnerType;
first_name?: string; // Required if individual
last_name?: string; // Required if individual
business_name?: string; // Required if business
}
interface ExternalAccount {
id: string;
customer_id: string;
type: AccountType;
currency: string;
bank_name: string;
account_owner_name: string;
account_number_masked: string;
routing_number_masked?: string;
account_type: string;
status: 'active' | 'pending' | 'failed';
created_at: string;
}
async function createUSBankAccount(
customerId: string,
account: Omit<CreateExternalAccountRequest, 'currency' | 'account_type'>
): Promise<ExternalAccount> {
const response = await fetch(`${BRIDGE_API_URL}/external_accounts`, {
method: 'POST',
headers: {
'Api-Key': API_KEY,
'Idempotency-Key': crypto.randomUUID(),
'Content-Type': 'application/json',
},
body: JSON.stringify({
currency: 'USD',
account_type: 'us',
...account,
}),
});
if (!response.ok) {
const error = await response.json();
throw new Error(`External account creation failed: ${error.message}`);
}
return response.json();
}
// Usage
const usAccount = await createUSBankAccount('cust_alice', {
bank_name: 'Chase Bank',
account_owner_name: 'John Doe',
account_number: '1234567890',
routing_number: '021000021',
address: {
street_line1: '123 Main St',
city: 'New York',
state: 'NY',
postal_code: '10001',
country: 'US',
},
account_owner_type: 'individual',
first_name: 'John',
last_name: 'Doe',
});
IBAN (SEPA/European)
typescript
interface IBANDetails {
country_code: string; // e.g., 'DE', 'FR', 'IE'
check_digits: string;
bank_code: string;
account_number: string;
}
async function createIBANAccount(
customerId: string,
details: {
bank_name: string;
account_owner_name: string;
iban: IBANDetails;
address: CreateExternalAccountRequest['address'];
account_owner_type: OwnerType;
first_name?: string;
last_name?: string;
business_name?: string;
}
): Promise<ExternalAccount> {
const response = await fetch(`${BRIDGE_API_URL}/external_accounts`, {
method: 'POST',
headers: {
'Api-Key': API_KEY,
'Idempotency-Key': crypto.randomUUID(),
'Content-Type': 'application/json',
},
body: JSON.stringify({
currency: 'EUR',
account_type: 'iban',
bank_name: details.bank_name,
account_owner_name: details.account_owner_name,
iban: details.iban,
address: details.address,
account_owner_type: details.account_owner_type,
first_name: details.first_name,
last_name: details.last_name,
business_name: details.business_name,
}),
});
if (!response.ok) {
throw new Error('IBAN account creation failed');
}
return response.json();
}
// Usage
const ibanAccount = await createIBANAccount('cust_european', {
bank_name: 'Deutsche Bank',
account_owner_name: 'Hans Mueller',
address: {
street_line1: 'Unter den Linden 77',
city: 'Berlin',
state: '',
postal_code: '10117',
country: 'DE',
},
account_owner_type: 'individual',
first_name: 'Hans',
last_name: 'Mueller',
iban: {
country_code: 'DE',
check_digits: '89',
bank_code: '50070000',
account_number: '0245478900',
},
});
SWIFT International
typescript
async function createSWIFTAccount(
customerId: string,
details: {
bank_name: string;
account_owner_name: string;
swift: { bic: string; account_number: string };
address: CreateExternalAccountRequest['address'];
account_owner_type: OwnerType;
}
): Promise<ExternalAccount> {
const response = await fetch(`${BRIDGE_API_URL}/external_accounts`, {
method: 'POST',
headers: {
'Api-Key': API_KEY,
'Idempotency-Key': crypto.randomUUID(),
'Content-Type': 'application/json',
},
body: JSON.stringify({
currency: 'USD',
account_type: 'swift',
bank_name: details.bank_name,
account_owner_name: details.account_owner_name,
swift: details.swift,
address: details.address,
account_owner_type: details.account_owner_type,
}),
});
if (!response.ok) {
throw new Error('SWIFT account creation failed');
}
return response.json();
}
Mexican CLABE (SPEI)
typescript
async function createCLABEAccount(
customerId: string,
details: {
bank_name: string;
account_owner_name: string;
clabe: { clabe: string };
address: CreateExternalAccountRequest['address'];
account_owner_type: OwnerType;
}
): Promise<ExternalAccount> {
const response = await fetch(`${BRIDGE_API_URL}/external_accounts`, {
method: 'POST',
headers: {
'Api-Key': API_KEY,
'Idempotency-Key': crypto.randomUUID(),
'Content-Type': 'application/json',
},
body: JSON.stringify({
currency: 'MXN',
account_type: 'clabe',
bank_name: details.bank_name,
account_owner_name: details.account_owner_name,
clabe: details.clabe,
address: details.address,
account_owner_type: details.account_owner_type,
}),
});
if (!response.ok) {
throw new Error('CLABE account creation failed');
}
return response.json();
}
Brazilian PIX
typescript
async function createPIXAccount(
customerId: string,
details: {
bank_name: string;
account_owner_name: string;
pix: {
tax_id: string; // CPF or CNPJ
account_number: string;
branch_id: string;
account_type: 'checking' | 'savings';
};
address: CreateExternalAccountRequest['address'];
account_owner_type: OwnerType;
}
): Promise<ExternalAccount> {
const response = await fetch(`${BRIDGE_API_URL}/external_accounts`, {
method: 'POST',
headers: {
'Api-Key': API_KEY,
'Idempotency-Key': crypto.randomUUID(),
'Content-Type': 'application/json',
},
body: JSON.stringify({
currency: 'BRL',
account_type: 'pix',
bank_name: details.bank_name,
account_owner_name: details.account_owner_name,
pix: details.pix,
address: details.address,
account_owner_type: details.account_owner_type,
}),
});
if (!response.ok) {
throw new Error('PIX account creation failed');
}
return response.json();
}
Plaid Integration
typescript
// Step 1: Create Plaid Link Token
interface PlaidLinkTokenResponse {
link_token: string;
link_token_expires_at: string;
callback_url: string;
}
async function createPlaidLinkToken(customerId: string): Promise<PlaidLinkTokenResponse> {
const response = await fetch(
`${BRIDGE_API_URL}/customers/${customerId}/plaid_link_requests`,
{
method: 'POST',
headers: {
'Api-Key': API_KEY,
'Idempotency-Key': crypto.randomUUID(),
'Content-Type': 'application/json',
},
}
);
if (!response.ok) {
throw new Error('Failed to create Plaid link token');
}
return response.json();
}
// Usage - Frontend integration
async function initiatePlaidLink(customerId: string) {
const { link_token, callback_url } = await createPlaidLinkToken(customerId);
// Send link_token to frontend
// Frontend uses Plaid Link SDK with link_token
// After user completes Plaid, they redirect to callback_url
return { link_token, callback_url };
}
Handle Plaid Callback
typescript
// Exchange public_token for access (handled by Bridge)
// Your webhook receives notification when account is linked
async function listLinkedAccounts(customerId: string): Promise<ExternalAccount[]> {
const response = await fetch(
`${BRIDGE_API_URL}/customers/${customerId}/external_accounts`,
{
headers: { 'Api-Key': API_KEY },
}
);
if (!response.ok) {
throw new Error('Failed to list external accounts');
}
return response.json();
}
// Usage
const accounts = await listLinkedAccounts('cust_alice');
accounts.forEach(acc => {
console.log(`Account: ${acc.bank_name} - ****${acc.account_number_masked}`);
console.log(`Status: ${acc.status}`);
});
Account Management
typescript
class ExternalAccountManager {
async getAccount(accountId: string): Promise<ExternalAccount> {
const response = await fetch(
`${BRIDGE_API_URL}/external_accounts/${accountId}`,
{ headers: { 'Api-Key': API_KEY } }
);
if (!response.ok) {
throw new Error('Account not found');
}
return response.json();
}
async deleteAccount(accountId: string): Promise<void> {
const response = await fetch(
`${BRIDGE_API_URL}/external_accounts/${accountId}`,
{
method: 'DELETE',
headers: { 'Api-Key': API_KEY },
}
);
if (!response.ok) {
throw new Error('Failed to delete account');
}
}
async listCustomerAccounts(customerId: string): Promise<ExternalAccount[]> {
return listLinkedAccounts(customerId);
}
async getDefaultAccount(customerId: string): Promise<ExternalAccount | null> {
const accounts = await this.listCustomerAccounts(customerId);
return accounts.find(a => a.status === 'active') || null;
}
}
Offramp to External Account
typescript
async function offrampToBank(
customerId: string,
externalAccountId: string,
amount: string,
cryptoAddress: string
): Promise<Transfer> {
return createTransfer({
amount,
on_behalf_of: customerId,
source: {
payment_rail: 'ethereum',
currency: 'usdc',
from_address: cryptoAddress,
},
destination: {
payment_rail: 'ach',
currency: 'usd',
external_account_id: externalAccountId,
},
});
}
// Offramp service
class OfframpService {
async cashOutUS(
customerId: string,
amount: string,
walletAddress: string
): Promise<Transfer> {
const accounts = await new ExternalAccountManager().listCustomerAccounts(customerId);
const usAccount = accounts.find(a => a.type === 'us');
if (!usAccount) {
throw new Error('No US bank account linked');
}
return offrampToBank(customerId, usAccount.id, amount, walletAddress);
}
async cashOutEU(
customerId: string,
amount: string,
walletAddress: string
): Promise<Transfer> {
const accounts = await new ExternalAccountManager().listCustomerAccounts(customerId);
const ibanAccount = accounts.find(a => a.type === 'iban');
if (!ibanAccount) {
throw new Error('No IBAN account linked');
}
return createTransfer({
amount,
on_behalf_of: customerId,
source: {
payment_rail: 'ethereum',
currency: 'usdc',
from_address: walletAddress,
},
destination: {
payment_rail: 'sepa',
currency: 'eur',
external_account_id: ibanAccount.id,
},
});
}
}
Multi-Region Setup
typescript
class GlobalBankingSetup {
async setupUSAccount(customerId: string): Promise<ExternalAccount> {
return createUSBankAccount(customerId, {
bank_name: '',
account_owner_name: '',
account_number: '',
routing_number: '',
address: { street_line1: '', city: '', state: '', postal_code: '', country: 'US' },
account_owner_type: 'individual',
first_name: '',
last_name: '',
});
}
async setupEUAccount(customerId: string): Promise<ExternalAccount> {
return createIBANAccount(customerId, {
bank_name: '',
account_owner_name: '',
address: { street_line1: '', city: '', state: '', postal_code: '', country: '' },
account_owner_type: 'individual',
iban: { country_code: '', check_digits: '', bank_code: '', account_number: '' },
});
}
async setupMXAccount(customerId: string): Promise<ExternalAccount> {
return createCLABEAccount(customerId, {
bank_name: '',
account_owner_name: '',
address: { street_line1: '', city: '', state: '', postal_code: '', country: 'MX' },
account_owner_type: 'individual',
clabe: { clabe: '' },
});
}
async setupBRAccount(customerId: string): Promise<ExternalAccount> {
return createPIXAccount(customerId, {
bank_name: '',
account_owner_name: '',
address: { street_line1: '', city: '', state: '', postal_code: '', country: 'BR' },
account_owner_type: 'individual',
pix: { tax_id: '', account_number: '', branch_id: '', account_type: 'checking' },
});
}
async setupAllRegions(customerId: string): Promise<ExternalAccount[]> {
return Promise.all([
this.setupUSAccount(customerId),
this.setupEUAccount(customerId),
this.setupMXAccount(customerId),
this.setupBRAccount(customerId),
]);
}
}
Webhook Events
- •
external_account.created- External account linked - •
external_account.verified- Account verification completed - •
external_account.deleted- Account removed - •
transfer.to_external_account.completed- Offramp completed
Best Practices
- •Plaid for US - Preferred for US bank linking
- •Direct API for others - IBAN, SWIFT, CLABE, PIX
- •Verify accounts - Check status before offramping
- •Store account IDs - Required for transfers
- •Multiple accounts - Support different regions
- •Idempotency - Use Idempotency-Key for all operations