> ## Documentation Index
> Fetch the complete documentation index at: https://docs.hifi.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Virtual Accounts

> A persistent USD deposit account - every deposit automatically mints stablecoins to a wallet.

A Virtual Account is a persistent USD bank account bound to one user, one destination [HIFI Wallet](/v3/core/wallets/hifi-wallet) or [External Wallet](/v3/core/wallets/external-wallet), and one destination stablecoin. Once created, it keeps its deposit instructions forever - the user (or anyone paying them) can send USD to it via ACH, Wire, or RTP at any time, and each deposit automatically mints the equivalent stablecoin to the destination wallet as an [Onramp](/v3/core/transactions/onramps) transaction. There's no quote or accept step per deposit.

<Tip>
  Virtual account accepts both first-party and third-party deposits.
</Tip>

## How it works

<Steps>
  <Step title="Create the Virtual Account">
    Call [create](#create-a-virtual-account) once, specifying the destination wallet and the stablecoin it should mint. HIFI provisions a dedicated bank sub-account behind the scenes and returns its `depositInstructions` immediately.
  </Step>

  <Step title="Share the deposit instructions">
    Pass the returned `depositInstructions` to whoever is going to send USD - your user, or a third party paying them. Unlike an Onramp, there's no specific expected amount or deadline attached.
  </Step>

  <Step title="Funds arrive, any time">
    The sender sends USD via wire, ACH, or RTP to those instructions whenever they want, for any amount. No API call is needed to "expect" the deposit - the account is always listening.
  </Step>

  <Step title="HIFI detects the deposit">
    The bank notifies HIFI, which matches the incoming payment to this Virtual Account's sub-account. If it's a small (under \$1.00) bank verification payment instead of a real deposit, it surfaces as a [microdeposit](#microdeposits) rather than triggering a conversion.
  </Step>

  <Step title="HIFI converts automatically">
    HIFI creates an [Onramp](/v3/core/transactions/onramps) transaction on the user's behalf at the live rate - no quote, no accept call, no action required from you. Subscribe to the `ONRAMP.CREATED` webhook to get notified when there's a new incoming deposit.
  </Step>

  <Step title="Stablecoin lands in the destination wallet">
    Once the Onramp completes, the destination wallet's balance updates. Subscribe to `ONRAMP.STATUS.*` [webhooks](#webhooks) to track an individual deposit's progress instead of polling.
  </Step>
</Steps>

Steps 3 through 6 repeat automatically for every future deposit - the Virtual Account never needs to be recreated or re-armed.

<Tip>
  For supported pairs check out [Virtual Account Routing](/v3/core/eligibility/virtual-account-routing)
</Tip>

## Create a Virtual Account

Provisions the account and returns its deposit instructions immediately - the account is `ACTIVE` and ready to receive funds as soon as this call returns. Requires an `Idempotency-Key` header. Set `destination.walletId` to land on a HIFI Wallet, or `destination.externalWalletId` to land on an External Wallet - exactly one is required.

**Request**

```shell theme={null}
curl -X POST https://sandbox.hifi.com/v3/users/usr_gBlMyGTbuyknSPXlZtwlS/virtual-accounts \
  -H "Idempotency-Key: <unique-key>" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d '{
    "source": {
      "currency": "USD",
      "country": "USA",
      "transferType": "ACH"
    },
    "destination": {
      "currency": "USDC",
      "walletId": "wlt_wOm1XYoNqj4WwJUeL58SI"
    }
  }'
```

**Response**

```json theme={null}
{
    "id": "va_HtgURm58uWMF0EzmG8DAl",
    "userId": "usr_gBlMyGTbuyknSPXlZtwlS",
    "source": {
        "transferTypes": ["ACH", "WIRE", "RTP"],
        "currency": "USD"
    },
    "destination": {
        "chain": "POLYGON",
        "currency": "USDC",
        "walletAddress": "0xDE49949a9f590421b529c83b339635d5B5783727",
        "walletId": "wlt_wOm1XYoNqj4WwJUeL58SI",
        "externalWalletId": null
    },
    "status": "ACTIVE",
    "microDeposits": {
        "count": 0,
        "data": []
    },
    "depositInstructions": {
        "bankName": "Cross River Bank",
        "bankAddress": "885 Teaneck Road, Teaneck, NJ 07666",
        "beneficiary": {
            "name": "Random Bizz",
            "address": "Example St 3., Hoboken, NJ, 07030, US"
        },
        "ach": {
            "routingNumber": "021214891",
            "accountNumber": "393523564374"
        },
        "wire": {
            "routingNumber": "021214891",
            "accountNumber": "393523564374"
        },
        "rtp": {
            "routingNumber": "021214891",
            "accountNumber": "393523564374"
        },
        "reference": null,
        "depositBy": null,
        "instruction": "Please deposit USD to the bank account provided. Please ensure that the beneficiary name matches the account holder name provided, or the payment may be rejected."
    },
    "settlementRuleId": null,
    "createdAt": "2026-07-25T23:54:02.679Z",
    "updatedAt": "2026-07-25T23:54:02.679Z"
}
```

<Info>
  Unlike an Onramp's deposit instructions, `reference` and `depositBy` are always `null` here - a Virtual Account isn't tied to one expected amount or deadline. Deposit any amount, any time, and it converts automatically.
</Info>

<Note>
  If `destination.currency` is `USDT`, a \$10 minimum deposit applies - smaller deposits are returned to sender rather than converted (fees applied).
</Note>

## Deactivate a Virtual Account

Closes the account so it no longer accepts deposits. All future deposits will automatically bounce back to the original sender.

<Tip>
  Fails with a `409` if the virtual account still holds a non-zero balance. Contact HIFI for account closure support.
</Tip>

```shell theme={null}
curl -X DELETE https://sandbox.hifi.com/v3/users/usr_gBlMyGTbuyknSPXlZtwlS/virtual-accounts/va_HtgURm58uWMF0EzmG8DAl \
  -H "Authorization: Bearer YOUR_API_KEY"
```

```json theme={null}
{
    "message": "Virtual account deactivated successfully"
}
```

## Status

| Status     | Meaning                                               |
| ---------- | ----------------------------------------------------- |
| `ACTIVE`   | Accepting deposits and converting them automatically. |
| `INACTIVE` | Deactivated - no longer accepts deposits.             |

## Microdeposits

Some sending banks require the account holder to confirm small (under \$1.00) verification deposits in their own banking app before releasing the real payment. When this happens, `microDeposits` populates on the Virtual Account - pass the amount(s) along to your user so they can complete that verification step.

```json theme={null}
"microDeposits": {
    "count": 1,
    "data": [
        {
            "createdAt": "2026-07-24T22:05:00.000Z",
            "currency": "USD",
            "amount": "0.32",
            "sourceBankInfo": {
                "bankName": "Chase",
                "senderName": "Jane Doe",
                "routingNumber": "021000021",
                "accountNumber": "000123456789",
                "paymentRail": "ach"
            }
        }
    ]
}
```

<Info>
  A microdeposit never counts toward a real payment and never changes the account's `status`. Subscribe to the `VIRTUAL_ACCOUNT.MICRODEPOSIT` webhook to get notified the moment one lands, instead of polling.
</Info>

## Simulate deposits (sandbox only)

Mocks an inbound deposit hitting the Virtual Account's bank sub-account, so you can trigger the mint flow in sandbox without a real bank transfer.

**Request**

```shell theme={null}
curl -X POST https://sandbox.hifi.com/v3/users/usr_gBlMyGTbuyknSPXlZtwlS/virtual-accounts/va_HtgURm58uWMF0EzmG8DAl/simulate-deposits \
  -H "Idempotency-Key: <unique-key>" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d '{
    "amount": 500,
    "transferType": "ACH",
    "source": {
      "routingNumber": "021000021",
      "accountNumber": "000123456789",
      "name": "Jane Doe",
      "bankName": "Chase"
    }
  }'
```

<Tip>
  use `RTP` as the `transferType` for faster simulation
</Tip>

**Response**

```json theme={null}
{
    "message": "Sandbox deposit triggered"
}
```

## Additional information

<AccordionGroup>
  <Accordion title="Settlement Rules">
    A Virtual Account can have a Settlement Rule attached that automatically splits each incoming deposit across multiple destination wallets (e.g. by percentage or fixed amount, with tiered breakpoints).

    Check out Settlement Rules for more information.
  </Accordion>

  <Accordion title="Routing Eligibility">
    Before creating a Virtual Account, you can check whether a given country/currency/transfer-rail/destination-chain combination is currently supported via `GET /v3/virtual-accounts/routes/eligibility`.

    Check out [Virtual Account Routing](/v3/core/eligibility/virtual-account-routing) for more information.
  </Accordion>
</AccordionGroup>

## Getting Help

* 📧 **Email:** [support@hifi.com](mailto:support@hifi.com)
* 💬 **Slack:** Message us in our shared Slack channel

## Related Resources

* [Orchestration Overview](/v3/core/orchestration/overview) - Orchestration resources
* [Orchestration Address](/v3/core/orchestration/orchestration-address) - The inverse: automated crypto-to-fiat
* [Onramps](/v3/core/transactions/onramps) - The transaction each deposit produces
* [HIFI Wallet](/v3/core/wallets/hifi-wallet) / [External Wallet](/v3/core/wallets/external-wallet) - Valid destinations
* [Virtual Account Routes](/v3/core/eligibility/virtual-account-routes) - Available routes for virtual account
