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
The unique customer identifier (UUID format)
source_currency
'usd' | 'eur' | 'aed'
required
Fiat currency for deposits
Optional payment rails. Currently only swift is supported (for USD).
Cryptocurrency token to receive
Blockchain network: polygon, ethereum, solana, base, arbitrum,
tron
Wallet address to receive converted crypto.
Returns
Unique identifier for the virtual account
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}`);
}
const virtualAccount = await align.virtualAccounts.create(
"123e4567-e89b-12d3-a456-426614174000",
{
source_currency: "usd",
destination_token: "usdc",
destination_network: "polygon",
destination_address: "0x742d35Cc6634C0532925a3b844Bc9e7595f0aB42"
}
);
// Access nested properties
const instructions = virtualAccount.deposit_instructions;
if (instructions.us) {
console.log("Routing:", instructions.us.routing_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 Currency | Destination Token | Destination Networks |
|---|
| USD | USDC, USDT | Polygon, Ethereum, Base, Arbitrum, Solana |
| EUR | USDC | Polygon, Ethereum, Base |
| AED | USDC | Polygon, 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.