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

# Virtual Accounts Overview

> Create and manage tenant-scoped virtual accounts

Virtual accounts let you allocate bank-transfer receiving accounts for your customers through the Zentra control plane.

## What They Do

A virtual account gives a customer a dedicated account number that maps back to your tenant. When inbound payments are processed, Zentra records the credit and your integration can react through downstream workflows and webhooks.

### Typical Use Cases

<CardGroup cols={2}>
  <Card title="Customer Deposits" icon="building-columns">
    Let customers fund their balances through bank transfers.
  </Card>

  <Card title="Collections" icon="money-bill-wave">
    Reconcile transfer-based collections against a dedicated account record.
  </Card>

  <Card title="Merchant Settlement Flows" icon="shield">
    Allocate receiving accounts per merchant, business, or counterparty.
  </Card>

  <Card title="Operational Routing" icon="repeat">
    Route account creation through provider-aware internal policies instead of hard-coding a single bank.
  </Card>
</CardGroup>

## How It Works

1. **Create Account**: Call `POST /api/v1/virtual-accounts` with `customer_id` and `account_name`.
2. **Provider Selection**: Zentra routes the request internally and allocates the account with the selected provider.
3. **Share Details**: Present the returned `account_number`, `bank_name`, and `account_name` to your customer.
4. **Track Inbound Value**: Use `total_received_minor` and `transaction_count` for reporting.
5. **Manage Lifecycle**: Retrieve, list, freeze, unfreeze, reserve-assign, or close through the internal service contract; the reviewed public API surface currently exposes create, get, list, and close.

```mermaid theme={null}
graph TB
    A["Your App"] -->|"Create Virtual Account"| B["Zentra API"]
    B -->|"Provider-Routed Allocation"| C["Virtual Account Service"]
    C -->|"Account Details"| A
    D["Payer"] -->|"Bank Transfer"| E["Allocated Account Number"]
    E -->|"Credit Recorded"| C

    classDef app fill:#14161A,stroke:#2A2E35,stroke-width:1px,color:#F5F4F0
    classDef zentra fill:#2563FF,stroke:#AFC8FF,stroke-width:1px,color:#F5F4F0
    classDef rail fill:#2A2E35,stroke:#5770A0,stroke-width:1px,color:#F5F4F0
    class A,D app
    class B zentra
    class C,E rail
```

## Input Model

The current reviewed create endpoint supports:

* required:
  * `customer_id`
  * `account_name`
* optional:
  * `provider`
  * `account_type`
  * `metadata`
  * `bvn`
  * `country`
  * `currency`
  * `request_id`
  * `preferred_bank`

`bank_code` is not a create input on the reviewed endpoint. It is returned after provider allocation.

## Account States

| Status    | Meaning                         |
| --------- | ------------------------------- |
| `active`  | Account can receive payments    |
| `frozen`  | Account is temporarily blocked  |
| `closed`  | Account has been closed         |
| `expired` | Provider allocation has expired |

## Available Operations

<CardGroup cols={2}>
  <Card title="Create Account" icon="plus" href="/api-reference/virtual-accounts/create">
    Generate a new virtual account
  </Card>

  <Card title="Get Account" icon="eye" href="/api-reference/virtual-accounts/get">
    Retrieve account details
  </Card>

  <Card title="List Accounts" icon="list" href="/api-reference/virtual-accounts/list">
    List all virtual accounts
  </Card>

  <Card title="Close Account" icon="xmark" href="/api-reference/virtual-accounts/close">
    Close an account
  </Card>
</CardGroup>

## Quick Example

<CodeGroup>
  ```javascript JavaScript theme={null}
  const account = await client.virtualAccounts.create({
    customerId: 'cus_123',
    accountName: 'John Doe Collections'
  });

  console.log(`Account Number: ${account.accountNumber}`);
  console.log(`Bank: ${account.bankName}`);
  ```

  ```python Python theme={null}
  account = client.virtual_accounts.create(
      customer_id='cus_123',
      account_name='John Doe Collections'
  )

  print(f"Account Number: {account.account_number}")
  print(f"Bank: {account.bank_name}")
  ```

  ```php PHP theme={null}
  $account = $client->virtualAccounts->create([
      'customer_id' => 'cus_123',
      'account_name' => 'John Doe Collections'
  ]);

  echo "Account Number: {$account->account_number}\n";
  echo "Bank: {$account->bank_name}";
  ```
</CodeGroup>

## Integration Notes

<AccordionGroup>
  <Accordion title="Provider Choice Is Internal">
    If you omit `provider`, the gateway defaults it to `auto` and the internal routing layer chooses the provider.
  </Accordion>

  <Accordion title="Bank Preference Is Only A Hint">
    Use `preferred_bank` only when your provider path supports it. The final `bank_code` and `bank_name` come from the provider response.
  </Accordion>

  <Accordion title="Money Fields Use Minor Units">
    `total_received_minor` is the running inbound amount. Do not expect decimal money fields in the API response.
  </Accordion>

  <Accordion title="Metadata Round-Trips">
    Structured metadata is preserved on create, get, list, and close responses.
  </Accordion>
</AccordionGroup>

## Next Steps

<CardGroup cols={2}>
  <Card title="Create Virtual Account" icon="plus" href="/api-reference/virtual-accounts/create">
    Learn how to create accounts
  </Card>

  <Card title="Webhooks" icon="webhook" href="/api-reference/webhooks/overview">
    Handle account events
  </Card>

  <Card title="Customers" icon="users" href="/api-reference/customers/overview">
    Manage customer records
  </Card>
</CardGroup>
