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

# Open a virtual account

> Step-by-step guide to opening a Trace Finance-issued BRL virtual account.

## Overview

A virtual account is a fiat account issued directly by Trace Finance. It suits customers who run their own treasury, intercompany flows, or proprietary commerce on Trace Finance. Use `VIRTUAL` as the account type. Every account is multi-currency, so crypto support is always included alongside the fiat assets you enable.

Verification for a virtual account follows Trace Finance's compliance baseline only, which is a lighter document set than a named account. Additional documents apply only when the owner is itself a regulated payment entity, such as a payment service provider, a banking-as-a-service provider, or a virtual-asset service provider. The exact set for your account is always returned in `requirements.currentlyDue` when you create it. See [BRL virtual accounts](/guides/compliance/brl-virtual-accounts) for the full checklist.

## Prerequisites

* Valid [authentication credentials](/guides/authentication).
* Account owner details: legal name (or first and last name for an individual), tax ID, industry, expected monthly volume, and address.
* The baseline document checklist. See [BRL virtual accounts](/guides/compliance/brl-virtual-accounts). The documents that apply to your account appear in `requirements.currentlyDue` after creation.

## Steps

<Steps>
  <Step title="Create the account">
    Submit a request with the fiat assets to enable and the account owner's details. Set each fiat asset's `accountType` to `VIRTUAL`. Crypto support is always included, so you don't declare it or set its `accountType`.

    ```bash theme={"theme":"tokyo-night"}
    curl --request POST \
      --url https://api.sandbox.tracefinance.com/v1/accounts \
      --header 'Authorization: Bearer <token>' \
      --header 'X-Idempotency-Key: <unique-key>' \
      --header 'Content-Type: application/json' \
      --data '{
        "assets": [
          { "code": "BRL", "accountType": "VIRTUAL" }
        ],
        "owner": {
          "type": "COMPANY",
          "legalName": "Acme Ltda",
          "taxId": {
            "value": "11222333000181",
            "type": "CNPJ"
          },
          "industry": "SOFTWARE_DEVELOPMENT",
          "expectedMonthlyVolume": "FROM_0_TO_50000",
          "incorporateDate": "2018-05-12",
          "isStartup": false,
          "address": {
            "addressLine1": "Rua das Flores, 100",
            "addressLine2": "Suite 456",
            "city": "São Paulo",
            "state": "SP",
            "country": "BR",
            "postalCode": "01234-567"
          }
        }
      }'
    ```

    The response returns the account in `ACTION_REQUIRED` status, with the document types required for onboarding listed under `requirements.currentlyDue`. For an individual owner, set `owner.type` to `INDIVIDUAL` and provide `firstName` and `lastName` instead of `legalName`. To fix a rejected field after creation, use [`PATCH /v1/accounts/{accountId}`](/api-reference/fx-account/accounts/update-account) to replace the owner profile before submitting for review.

    <Note>
      A virtual account's document set is the compliance baseline. You only provide additional documents when the owner handles third-party funds as a regulated payment entity. Whatever applies is listed in `requirements.currentlyDue`. See [BRL virtual accounts](/guides/compliance/brl-virtual-accounts) for details.
    </Note>
  </Step>

  <Step title="Upload required documents">
    The creation response includes a `requirements.currentlyDue` array listing every document you need to provide. Each item carries a `type` discriminator. `ACCOUNT_DOCUMENT` and `UBO_DOCUMENT` name a specific `documentType`, while `IDENTITY_VERIFICATION` and `INCORPORATION_DOCUMENT` are grouped requirements whose `options` array lists the acceptable document types together with the `subTypes` and `requiredMetadata` each option needs. Upload documents against the `/v1/accounts/{accountId}/documents` endpoint, setting `holder.type` to `ACCOUNT` and `holder.referenceId` to the account ID:

    ```bash theme={"theme":"tokyo-night"}
    curl --request POST \
      --url https://api.sandbox.tracefinance.com/v1/accounts/<account-id>/documents \
      --header 'Authorization: Bearer <token>' \
      --header 'X-Idempotency-Key: <unique-key>' \
      --form 'body={"documentType":"ARTICLES_OF_ASSOCIATION","holder":{"type":"ACCOUNT","referenceId":"<account-id>"}};type=application/json' \
      --form 'file=@/path/to/articles-of-association.pdf'
    ```

    Returns `204 No Content`. Upload one document per request, repeating for every requirement listed in `currentlyDue`.
  </Step>

  <Step title="Add beneficial owners (company accounts)">
    Company-owned accounts require at least one beneficial owner (UBO). Register each UBO with their identity, contact, and address details. `phone` and `email` are required so we can reach the UBO for follow-up during compliance review.

    ```bash theme={"theme":"tokyo-night"}
    curl --request POST \
      --url https://api.sandbox.tracefinance.com/v1/accounts/<account-id>/ubos \
      --header 'Authorization: Bearer <token>' \
      --header 'X-Idempotency-Key: <unique-key>' \
      --header 'Content-Type: application/json' \
      --data '{
        "name": "João Silva",
        "taxId": {
          "value": "12345678909",
          "type": "CPF"
        },
        "address": {
          "addressLine1": "Rua das Flores, 100",
          "city": "São Paulo",
          "state": "SP",
          "country": "BR",
          "postalCode": "01234-567"
        },
        "phone": "5511999999999",
        "email": "joao.silva@example.com",
        "ownershipPercentage": 50.0,
        "isLegalRepresentative": false
      }'
    ```

    The response includes the UBO's `id`, which you'll need for uploading their documents. Individual accounts have no UBOs, so skip this step and the next one.
  </Step>

  <Step title="Upload UBO documents">
    Each UBO needs identity documents. Use the same `/v1/accounts/{accountId}/documents` endpoint, this time setting `holder.type` to `UBO` and `holder.referenceId` to the UBO's `id`. Identity documents typically require a `documentSubType` (for example `FRONT_SIDE` or `BACK_SIDE`) and a `metadata.country`:

    ```bash theme={"theme":"tokyo-night"}
    curl --request POST \
      --url https://api.sandbox.tracefinance.com/v1/accounts/<account-id>/documents \
      --header 'Authorization: Bearer <token>' \
      --header 'X-Idempotency-Key: <unique-key>' \
      --form 'body={"documentType":"ID_CARD","documentSubType":"FRONT_SIDE","holder":{"type":"UBO","referenceId":"<ubo-id>"},"metadata":{"country":"BR"}};type=application/json' \
      --form 'file=@/path/to/ubo-id-front.pdf'
    ```

    Returns `204 No Content`. Repeat for every side and every UBO registered on the account.
  </Step>

  <Step title="Submit for review">
    Once all required documents are uploaded, submit the account for compliance review. This endpoint has no request body:

    ```bash theme={"theme":"tokyo-night"}
    curl --request POST \
      --url https://api.sandbox.tracefinance.com/v1/accounts/<account-id>/review \
      --header 'Authorization: Bearer <token>' \
      --header 'X-Idempotency-Key: <unique-key>'
    ```

    Returns `202 Accepted`. The account transitions from `ACTION_REQUIRED` to `REVIEWING`. If any documents are still missing or rejected, the API returns `422` with a `MISSING_DOCUMENTS_FOR_REVIEW` error listing the outstanding `documentType` names.
  </Step>

  <Step title="Wait for activation">
    After review is approved, each asset activates on its own pipeline. The crypto wallet always activates first, since it has no manual steps, but the crypto wallet activating does not move the account to `ACTIVE`. The account moves through `OPENING` and becomes `ACTIVE` only once a fiat asset finishes onboarding. Subscribe to the [`ACCOUNT_ASSET_ACTIVATED`](/api-reference/fx-webhook/events/account/account-asset-activated) and [`ACCOUNT_ASSET_FAILED`](/api-reference/fx-webhook/events/account/account-asset-failed) webhooks to react as each asset finishes, or poll [`GET /v1/accounts/{accountId}`](/api-reference/fx-account/accounts/get-account). Each entry in the response's `assets` array carries its own provider-account `status` (`ONBOARDING`, `ACTIVE`, `FAILED`, `FROZEN`, `DEACTIVATED`) so you can see which assets are ready.
  </Step>

  <Step title="Retrieve funding instructions">
    Once the account is active, retrieve the incoming transfer details for each active asset:

    ```bash theme={"theme":"tokyo-night"}
    curl --request GET \
      --url https://api.sandbox.tracefinance.com/v1/accounts/<account-id>/fundingInstructions \
      --header 'Authorization: Bearer <token>'
    ```

    ```json Response theme={"theme":"tokyo-night"}
    [
      {
        "asset": "BRL",
        "type": "PIX_KEY",
        "rail": "PIX_KEY",
        "keyType": "RANDOM",
        "key": "b3f1c2a4-9d8e-4f2a-8c1b-2e5f7a9c0d13",
        "accountIdentifier": "VA-000123"
      }
    ]
    ```

    For a virtual account, the Pix key is issued by Trace Finance rather than the account owner. Trace may share one key across virtual accounts, so route inbound funds using the `accountIdentifier` returned alongside the key. Filter the catalog with the optional `asset` and `rail` query parameters when you only need one rail for an asset.
  </Step>
</Steps>

## What happens next

* [Make a deposit](/journeys/deposit) — fund the account with BRL or crypto.
* [Execute a swap](/journeys/swap) — convert between the account's assets.
