Skip to main content
A Virtual Account is a dedicated bank account that automatically converts fiat deposits into stablecoins. When users send money to a virtual account via bank transfer, the funds are instantly converted to stablecoins and delivered to their wallet.

How Virtual Accounts Work

Virtual accounts enable fiat-to-stablecoin onramps through a simple three-step process:
1

Create the account

Generate a unique bank account number for the user.
2

Deposits fiat

User receives funds via ACH, wire, or RTP.
3

Automatic conversion

Fiat is automatically converted to stablecoins and delivered to the user’s wallet.
Each virtual account is configured for a specific conversion pair (e.g., USD → USDC on Polygon). You can create multiple virtual accounts per user for different currencies and chains.

Creating Virtual Accounts

Create a virtual account using the Create Virtual Account endpoint. Request:
curl -X POST "https://sandbox.hifibridge.com/v2/users/usr_abc123/virtual-accounts" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "sourceCurrency": "usd",
    "destinationCurrency": "usdc",
    "destinationChain": "POLYGON"
  }'
Request Fields:
sourceCurrency
string
required
Fiat currency to accept. Currently only usd is supported.
destinationCurrency
string
required
Stablecoin to receive after conversion. Options: usdc, usdt
destinationChain
string
required
Blockchain where stablecoins will be sent. Options: POLYGON, ETHEREUM, BASE
externalWalletId
string
Optional. If provided, stablecoins are sent to this external wallet instead of the user’s HIFI wallet.
USD Only: Virtual accounts currently support USD deposits only. For other currencies, use the Onramp API.
Response:
{
  "message": "Virtual account created successfully",
  "accountInfo": {
    "id": "va_abc123",
    "userId": "usr_abc123",
    "source": {
      "paymentRail": ["ach", "wire", "rtp"],
      "currency": "usd"
    },
    "destination": {
      "chain": "POLYGON",
      "currency": "usdc",
      "walletAddress": "0xd102C4130985B7fcB95697616eaf5542c4f98d49",
      "externalWalletId": null
    },
    "status": "activated",
    "depositInstructions": {
      "bankName": "Cross River Bank",
      "bankAddress": "885 Teaneck Road, Teaneck, NJ 07666",
      "beneficiary": {
        "name": "John Doe",
        "address": "123 Main St, New York, NY, 10010, US"
      },
      "ach": {
        "routingNumber": "021214891",
        "accountNumber": "344176915009"
      },
      "wire": {
        "routingNumber": "021214891",
        "accountNumber": "344176915009"
      },
      "rtp": {
        "routingNumber": "021214891",
        "accountNumber": "344176915009"
      }
    }
  }
}
Response Fields:
accountInfo.id
string
Unique virtual account ID. Save this for managing the account and monitoring deposits.
accountInfo.status
string
Account status. activated means ready to receive deposits.
accountInfo.source
object
Source configuration for the virtual account.
accountInfo.destination
object
Destination configuration for converted stablecoins.
accountInfo.depositInstructions
object
Most Important: Bank account details for users to send deposits. Share these instructions with your users.

Payment Rails

Virtual accounts support multiple payment methods to accommodate different use cases:
Payment RailSpeedCostUse Case
ACH1-3 business daysLowDomestic US bank transfers
WireSame dayMediumLarger amounts, faster processing
RTPReal-timeMediumInstant transfers
Users can deposit via any supported rail using the same account number. The conversion and delivery happens automatically regardless of which payment method is used.

Deposit Processing

When a deposit is detected, HIFI automatically:
  1. Validates the deposit - Confirms amount and sender details
  2. Converts to stablecoin - Exchanges fiat for stablecoins at current rates
  3. Sends to wallet - Delivers stablecoins to the configured destination
  4. Triggers webhooks - Sends ONRAMP.CREATE and ONRAMP.UPDATE events
Processing times vary by payment rail:
  • ACH: 1-3 business days for funds to clear, then instant conversion
  • Wire: Same-day processing, then instant conversion
  • RTP: Real-time processing and instant conversion
Webhook Notifications: Subscribe to ONRAMP.CREATE and ONRAMP.UPDATE events to track deposits in real-time. See Webhooks for setup instructions.

Tracking Onramps

When deposits arrive at a virtual account, HIFI creates an onramp transaction to handle the conversion. You can see which virtual account was used by checking the onramp’s virtualAccountId field. List onramps for a user:
curl -X GET "https://sandbox.hifibridge.com/v2/onramps?userId=usr_abc123" \
  -H "Authorization: Bearer YOUR_API_KEY"
Response (excerpt):
{
  "count": 1,
  "records": [
    {
      "transferType": "ONRAMP",
      "transferDetails": {
        "id": "onr_xyz789",
        "status": "COMPLETED",
        "source": {
          "currency": "usd",
          "amount": 100
        },
        "destination": {
          "currency": "usdc",
          "chain": "POLYGON",
          "amount": 100
        },
        "virtualAccountId": "va_abc123",
        "receipt": {
          "transactionHash": "0xe5284c4cb35ae9b5eb0ae23b840032f320b87b63f8967ee9b67ee09dfe6a194a"
        }
      }
    }
  ]
}
Key Fields:
transferDetails.virtualAccountId
string
The virtual account ID that received the deposit. If null, this onramp was created through a different method (not via virtual account).
transferDetails.status
string
Onramp status. See Onramps for complete status documentation.
transferDetails.receipt.transactionHash
string
Blockchain transaction hash (available when status is COMPLETED)

Managing Virtual Accounts

Update Configuration

Change the destination chain or currency for an existing virtual account using the Update Virtual Account endpoint. Request:
curl -X PATCH "https://sandbox.hifibridge.com/v2/users/usr_abc123/virtual-accounts/va_abc123" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "destinationCurrency": "usdt",
    "destinationChain": "ETHEREUM"
  }'
Updating the configuration only affects future deposits. Existing pending deposits will complete with the original configuration.

Deactivate Account

Temporarily disable a virtual account to prevent new deposits using the Deactivate Virtual Account endpoint. Request:
curl -X POST "https://sandbox.hifibridge.com/v2/users/usr_abc123/virtual-accounts/va_abc123/deactivate" \
  -H "Authorization: Bearer YOUR_API_KEY"
When deactivated:
  • New deposits are rejected
  • Existing pending deposits continue processing
  • Account can be reactivated later
Reactivate:
curl -X POST "https://sandbox.hifibridge.com/v2/users/usr_abc123/virtual-accounts/va_abc123/activate" \
  -H "Authorization: Bearer YOUR_API_KEY"

Key Concepts

Each virtual account is tied to a specific conversion pair (source currency + destination currency + destination chain). To support multiple conversion options, create separate virtual accounts.Example: If you need both USD→USDC on Polygon and USD→USDT on Ethereum, create two virtual accounts.
The beneficiary name on the virtual account must match the user’s KYC name. Deposits from accounts with mismatched names may be rejected for compliance reasons.
USDT conversions incur an additional 0.1% exchange fee beyond standard conversion rates. This fee appears on your monthly invoice.
By default, stablecoins are sent to the user’s HIFI wallet. Use the externalWalletId parameter to send to an external wallet address instead. The external wallet must be pre-registered via the External Wallets API.
Registration Required: Unlike regular wallet transfers (which can send directly to any address), virtual accounts require external wallets to be registered first when using the externalWalletId parameter. If you prefer not to register, create a standard virtual account without externalWalletId and then transfer funds to the external wallet using the Wallet Transfer API.

Sandbox Testing

In sandbox, simulate deposits without real bank transfers using the Simulate Deposit endpoint. Request:
curl -X POST "https://sandbox.hifibridge.com/v2/users/usr_abc123/virtual-accounts/va_abc123/simulate-deposit" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "paymentRail": "wire",
    "source": {
      "routingNumber": "021000021",
      "accountNumber": "516843515316",
      "name": "Jane Doe",
      "bankName": "JP Morgan Chase"
    },
    "amount": "100",
    "requestId": "32639f89-5fcc-4e31-8abe-0e710ba2e4a1",
    "reference": "Test deposit"
  }'
Response:
{
  "message": "Sandbox deposit triggered"
}
The sandbox will process this deposit as if real money arrived, triggering the full onramp flow including webhooks.
Sandbox Processing Times: Simulated deposits in sandbox are processed automatically after a delay: - Wire: ~5 minutes - ACH: ~8 minutes In production, actual processing times depend on the payment rail used (ACH: 1-3 business days, Wire: same day, RTP: real-time).

Sample Code

Get deposit instructions

1

Create virtual account

curl -X POST "https://sandbox.hifibridge.com/v2/users/usr_abc123/virtual-accounts" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "sourceCurrency": "usd",
    "destinationCurrency": "usdc",
    "destinationChain": "POLYGON"
  }'
2

Extract and display instructions

Extract the depositInstructions object from the response and present the relevant bank details to your user. Example:ACH Deposit InstructionsBank Name: Cross River Bank Routing Number: 021214891 Account Number: 344176915009 Beneficiary: John DoeWire Deposit InstructionsBank Name: Cross River Bank Routing Number: 021214891 Account Number: 344176915009 Beneficiary: John Doe Bank Address: 885 Teaneck Road, Teaneck, NJ 07666
3

Track onramp transactions

List onramps to see which virtual account was used and track conversion status:
curl -X GET "https://sandbox.hifibridge.com/v2/onramps?userId=usr_abc123" \
  -H "Authorization: Bearer YOUR_API_KEY"
Or subscribe to ONRAMP.CREATE and ONRAMP.UPDATE webhooks for real-time notifications.

Send to external wallet

Option 1: Direct to external wallet Use an externalWalletId instead of destinationChain when creating a virtual account. Funds will be deposited directly into the specified wallet address.
curl -X POST "https://sandbox.hifibridge.com/v2/users/usr_abc123/virtual-accounts" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "sourceCurrency": "usd",
    "destinationCurrency": "usdc",
    "externalWalletId": "ew_abc123"
  }'
Deposits to this virtual account will be converted to USDC and sent directly to the external wallet address. Option 2: Route through HIFI wallet
1

Create virtual account

Create a standard virtual account without externalWalletId. Funds will arrive in the user’s HIFI wallet first.
curl -X POST "https://sandbox.hifibridge.com/v2/users/usr_abc123/virtual-accounts" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "sourceCurrency": "usd",
    "destinationCurrency": "usdc",
    "destinationChain": "POLYGON"
  }'
2

Send to external wallet

Send funds to any external address using the Wallet Transfer API:
curl -X POST "https://sandbox.hifibridge.com/v2/wallets/transfers" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "source": {
      "userId": "usr_abc123"
    },
    "destination": {
      "address": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb"
    },
    "amount": 10,
    "currency": "usdc",
    "chain": "POLYGON",
    "requestId": "b51fb3bb-8a48-5cfa-cc2g-c86g2589cdd7"
  }'

Getting Help

  • Quickstart Guide - Step-by-step tutorial including virtual account setup
  • Users - Understand user creation and KYC requirements
  • Onramps - Alternative onramp methods for non-USD currencies
  • Webhooks - Subscribe to account and onramp events
  • API Reference - Complete endpoint documentation