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

# Create a virtual account

> POST /v1/virtual-accounts - issue permanent bank details that convert and settle to a wallet.

Creates a virtual account: a permanent set of bank details on an incoming rail and
currency, tied to a destination wallet. Money that arrives on the account is
converted to the output asset and settled to that wallet - see
[Virtual accounts](/products/virtual-accounts) for what the product does.

<Note>
  Creating virtual accounts needs the **virtual-accounts permission** on your API
  key. It is granted separately from the rest of your key's setup - ask us. A key
  without it gets `403 permission_denied` from every endpoint in this section. See
  [Authentication](/api-reference/authentication).
</Note>

## Request

The account is opened for a user you have already onboarded, and it inherits the
corridor agreed on your account: which rail and currency it accepts, which asset the
incoming money is converted into, and which network it settles on. Those are not
passed per request, so a browser cannot redirect where money lands.

<ParamField body="accountId" type="string" required>
  The id returned when the user was onboarded and their identity result shared with
  the banking partner. See [Bank transfers](/api-reference/bank-transfer).
</ParamField>

<ParamField body="walletId" type="string" required>
  The id of the wallet registered for that user at onboarding. It is the wallet the
  settled stablecoin is delivered to.
</ParamField>

## Response

<ResponseField name="id" type="string">
  The virtual account id. Keep it - see the note on reading accounts back below.
</ResponseField>

<ResponseField name="details" type="object">
  The bank details to display, plus the reference that ties a transfer to this
  account. The fields depend on the rail: an IBAN with a SWIFT code for SEPA, an
  account number with a routing number for ACH, an account number with a sort code
  for UK rails, a CLABE for SPEI. Render what comes back rather than assuming a
  shape, and show the reference exactly as returned - a transfer without it has to
  be attributed by hand.
</ResponseField>

<ResponseField name="applicationFeeBps" type="number">
  Your fee on this account, in basis points (100 bps = 1%), taken from money
  arriving on it.
</ResponseField>

<Warning>
  **Store what you get back.** Reading an account back after creation is not
  available yet: the get, list and update endpoints answer `501 not_implemented`
  until the banking partner integration can serve them. Keep the details and the
  reference from this response rather than planning to fetch them later.
</Warning>

<Note>
  Some currencies provision asynchronously (USD, AED, COP): the details arrive
  moments after the account is created rather than with it. Until read-back exists,
  retry creation for the same user rather than polling - it is idempotent per user
  and wallet.
</Note>

<RequestExample>
  ```bash cURL theme={null}
  curl -X POST "$RHEON_API/v1/virtual-accounts" \
    -H "Authorization: Bearer $RHEON_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "accountId": "acct_8f2c91d0a4",
      "walletId": "wlt_5b71e0c3"
    }'
  ```
</RequestExample>

<ResponseExample>
  ```json 200 theme={null}
  {
    "id": "va_8f2c91d0a4",
    "details": {
      "iban": "IE25XXXX99035504017602",
      "bic": "XXXXIE2D",
      "beneficiary": "Jane Doe",
      "reference": "RHN-84921"
    },
    "applicationFeeBps": 25
  }
  ```
</ResponseExample>

## Errors

| HTTP | `code`              | When                                                                        |
| ---- | ------------------- | --------------------------------------------------------------------------- |
| 400  | `invalid_request`   | A field is missing or malformed, or the rail does not support the currency. |
| 401  | `unauthorized`      | Missing, malformed, or unknown API key.                                     |
| 403  | `permission_denied` | Your key does not carry the virtual-accounts permission.                    |
| 403  | `chain_not_allowed` | Your key is not enabled for `chain` as a destination.                       |
| 429  | `rate_limited`      | Over your key's rate limit.                                                 |
| 502  | `upstream_error`    | The banking partner is unavailable.                                         |
| 500  | `internal`          | Unexpected server error.                                                    |
