Skip to main content
Virtual accounts require the customer to have completed KYC verification. See Create KYC Session.

Method Signature

align.virtualAccounts.create(
  customerId: string,
  data: CreateVirtualAccountRequest
): Promise<VirtualAccount>

Parameters

customerId
string
required
The unique customer identifier (UUID format)
source_currency
'usd' | 'eur' | 'aed'
required
Fiat currency for deposits
source_rails
'swift'
Optional payment rails. Currently only swift is supported (for USD).
destination_token
'usdc' | 'usdt'
required
Cryptocurrency token to receive
destination_network
string
required
Blockchain network: polygon, ethereum, solana, base, arbitrum, tron
destination_address
string
required
Wallet address to receive converted crypto.

Returns

id
string
Unique identifier for the virtual account
status
string
Account status: active
deposit_instructions
object
Bank account details for depositing funds. Structure varies by currency/type.

Examples

Create USD Virtual Account

import Align, { isUSAccountDetails } from "@tolbel/align";

const align = new Align({
  apiKey: process.env.ALIGN_API_KEY!,
  environment: "sandbox",
});

const virtualAccount = await align.virtualAccounts.create(
  "123e4567-e89b-12d3-a456-426614174000",
  {
    source_currency: "usd",
    source_rails: "swift", // Optional, strictly for SWIFT
    destination_token: "usdc",
    destination_network: "polygon",
    destination_address: "0x742d35Cc6634C0532925a3b844Bc9e7595f0aB42"
  }
);

console.log(`Account ID: ${virtualAccount.id}`);

// Use type-safe helper functions for narrowing
if (isUSAccountDetails(virtualAccount.deposit_instructions)) {
  console.log(`Routing: ${virtualAccount.deposit_instructions.us.routing_number}`);
  console.log(`Account: ${virtualAccount.deposit_instructions.us.account_number}`);
}

Create EUR Virtual Account (SEPA/IBAN)

import { isIBANAccountDetails } from "@tolbel/align";

const euroAccount = await align.virtualAccounts.create(customerId, {
  source_currency: "eur",
  destination_token: "usdc",
  destination_network: "polygon",
  destination_address: "0x...",
});

if (isIBANAccountDetails(euroAccount.deposit_instructions)) {
  console.log(`IBAN: ${euroAccount.deposit_instructions.iban.iban_number}`);
  console.log(`BIC: ${euroAccount.deposit_instructions.iban.bic}`);
}

Create SWIFT Virtual Account (International Wire)

import { isInternationalWireAccountDetails } from "@tolbel/align";

const swiftAccount = await align.virtualAccounts.create(customerId, {
  source_currency: "usd",
  source_rails: "swift",
  destination_token: "usdc",
  destination_network: "polygon",
  destination_address: "0x...",
});

if (isInternationalWireAccountDetails(swiftAccount.deposit_instructions)) {
  console.log(
    `SWIFT/BIC: ${swiftAccount.deposit_instructions.international_wire.bic}`
  );
  console.log(
    `Account: ${swiftAccount.deposit_instructions.international_wire.account_number}`
  );
}
Type-Safe Instruction Access: Since deposit_instructions is a discriminated union, we recommend using the SDK’s built-in type guards to safely narrow the type: - isUSAccountDetails(instr): For USD (ACH/Wire) accounts. - isIBANAccountDetails(instr): For EUR (SEPA) accounts. - isInternationalWireAccountDetails(instr): For USD (SWIFT) accounts.

Deposit Instructions

The deposit_instructions field contains the banking details. It is a union type:

US Account (ACH/Wire)

{
  "currency": "usd",
  "bank_name": "Example Bank",
  "us": {
    "account_number": "123456789",
    "routing_number": "021000021"
  }
}

IBAN Account (SEPA)

{
  "currency": "eur",
  "bank_name": "Commerzbank",
  "iban": {
    "iban_number": "DE89370400440532013000",
    "bic": "COBADEFFXXX"
  }
}

Supported Configurations

Source CurrencyDestination TokenDestination Networks
USDUSDC, USDTPolygon, Ethereum, Base, Arbitrum, Solana
EURUSDCPolygon, Ethereum, Base
AEDUSDCPolygon, Ethereum

Error Handling

import { AlignError, AlignValidationError } from "@tolbel/align";

try {
  const account = await align.virtualAccounts.create(customerId, {
    source_currency: "usd",
    destination_token: "usdc",
    destination_network: "polygon",
    destination_address: "0x...",
  });
} catch (error) {
  if (error instanceof AlignValidationError) {
    console.error("Invalid request:", error.errors);
  } else if (error instanceof AlignError) {
    if (error.statusCode === 403) {
      console.error("KYC verification required");
    }
  }
}
Creating a virtual account will fail with a 403 error if the customer hasn’t completed KYC verification.