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

# Add Virtual Accounts

> Request Virtual Accounts and retrieve deposit instructions

The customer must already be onboarded and active before you add a feature. You get `customerId` from the `application.approved` webhook — see [Onboard a Customer](/guides/onboard-customer) and [The Onboarding Lifecycle](/guides/onboarding-lifecycle). Calling features before the customer is active returns [`CUSTOMER_NOT_ONBOARDED`](/errors/customer-not-onboarded).

<Note>
  **Test this flow in sandbox.** Drive it end-to-end with simulated money and deterministic controls — start with the [sandbox quickstart](/sandbox/quickstart), then [deposit simulation](/sandbox/deposits) for this flow, and the [cheat sheet](/sandbox/cheat-sheet) for every magic value and simulate endpoint.
</Note>

## Flow

Add Virtual Accounts by submitting a feature application against an existing customer. The integration:

1. Discover the customer's feature requirements.
2. Submit a `virtual_account` feature application.
3. Listen for `application.approved` or `application.rejected` webhooks (with `applicationType: "virtual_account"`).
4. Listen for `virtual_account.activated`.
5. Fetch the customer's Virtual Accounts and read `balances[]` plus `depositInstructions[]`.

## Request The Feature

Discover any extra requirements for the customer:

```bash theme={null}
curl 'https://api.conduit.financial/v2/customers/{customerId}/features/requirements?type=virtual_account' \
  -H "x-api-key: YOUR_API_KEY"
```

Like the onboarding flow, the discovery response lists any required `fields` and `documents`. When present, collect them and include them in the submit body below. When the response asks for nothing extra, submit with just `type` and `asset`.

Submit the Virtual Account feature application for the target asset. `Idempotency-Key` is required — without it the call returns `IDEMPOTENCY_KEY_REQUIRED`.

```bash theme={null}
curl https://api.conduit.financial/v2/customers/{customerId}/features \
  -X POST \
  -H "x-api-key: YOUR_API_KEY" \
  -H "content-type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "type": "virtual_account",
    "asset": { "code": "USD" }
  }'
```

The endpoint returns `202 Accepted` with a Virtual Account feature application carrying its own application id. Track it through the `application.approved` and `application.rejected` webhooks with `applicationType: "virtual_account"`. A rejection carries `resubmittable`: when it is `true`, correct the data and request the feature again; when it is `false`, the decision is final.

## Listen For Activation

Once the feature application is approved, listen for `virtual_account.activated` to know the Virtual Account is usable. Deposit instructions populate once the Virtual Account's `status` is `active`. See [Webhooks](/webhooks) and [Virtual Accounts](/concepts/virtual-accounts).

## Retrieve Deposit Instructions

After activation, fetch the Virtual Accounts for the customer. See [Virtual Accounts](/concepts/virtual-accounts) for the full deposit-block union.

```bash theme={null}
curl https://api.conduit.financial/v2/customers/{customerId}/virtual-accounts \
  -H "x-api-key: YOUR_API_KEY"
```

The response contains VA-level balances and deposit instructions. It does not include provider bank accounts.

```json theme={null}
{
  "data": [
    {
      "id": "vac_...",
      "asset": { "code": "USD" },
      "status": "active",
      "balances": [
        {
          "available": { "code": "USD", "amount": "0.00" },
          "pending": { "code": "USD", "amount": "0.00" },
          "frozen": { "code": "USD", "amount": "0.00" }
        }
      ],
      "depositInstructions": [
        {
          "type": "us_domestic",
          "currency": "USD",
          "accountNumber": "123456789",
          "beneficiaryName": "Example Customer",
          "beneficiaryAddress": "1 Main St\nNew York, NY, 10001\nUSA",
          "beneficiaryPostalAddress": {
            "addressLine1": "1 Main St",
            "city": "New York",
            "state": "NY",
            "postalCode": "10001",
            "country": "US"
          },
          "bank": {
            "legalName": "Example Bank",
            "address": "2 Bank St, New York, NY",
            "postalAddress": {
              "addressLine1": "2 Bank St",
              "city": "New York",
              "state": "NY",
              "postalCode": "10005",
              "country": "US"
            }
          },
          "rails": [
            { "rail": "ach", "routingNumber": "021000021", "sameDayEligible": false },
            { "rail": "fedwire", "routingNumber": "021000021" },
            { "rail": "rtp", "routingNumber": "021000021", "networks": ["tch"] }
          ]
        }
      ],
      "activatedAt": "2026-04-30T00:00:00.000Z",
      "createdAt": "2026-04-30T00:00:00.000Z",
      "updatedAt": "2026-04-30T00:00:00.000Z"
    }
  ],
  "meta": {
    "mode": "cursor",
    "nextCursor": null,
    "previousCursor": null,
    "total": 1
  }
}
```

A EUR Virtual Account returns a `sepa` block on the same endpoint. Send to the `iban` and the `bic`:

```json theme={null}
{
  "type": "sepa",
  "currency": "EUR",
  "iban": "DE89370400440532013000",
  "bic": "EXMPDEFFXXX",
  "beneficiaryName": "Example Customer",
  "rails": [{ "rail": "sepa" }]
}
```

Retrieve one Virtual Account when you have its id:

```bash theme={null}
curl https://api.conduit.financial/v2/customers/{customerId}/virtual-accounts/{virtualAccountId} \
  -H "x-api-key: YOUR_API_KEY"
```

<Warning>
  The block `type` values were previously `domestic_usd` and `swift_usd`, and blocks carried no `currency` field. If your integration branches on the old names, switch to `us_domestic` and `swift` and read the currency from `currency`.
</Warning>
