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

# Collect Payments via Dedicated Virtual Bank Accounts

> Learn how to create dedicated virtual bank accounts for customers, look them up, and monitor incoming payments with Paylink Virtual Accounts.

A **virtual account** is a unique bank account number reserved exclusively for one customer. When a customer makes a transfer to their virtual account, Paylink captures the payment and notifies your server automatically. Virtual accounts are ideal for wallets, escrow flows, or any integration where customers pay on their own schedule via bank transfer.

## Create a Virtual Account

Send a `POST` request to `/virtual-accounts` to reserve a dedicated account number for a customer.

```json Request theme={null}
{
  "account_reference": "customer_123",
  "customer_name": "Ada Lovelace",
  "customer_email": "ada@example.com",
  "currency_code": "NGN",
  "bvn": "22222222222",
  "metadata": { "customer_id": "123" }
}
```

| Field               | Required | Description                                                  |
| ------------------- | -------- | ------------------------------------------------------------ |
| `account_reference` | ✅        | Your unique identifier for this customer or account          |
| `customer_name`     | ✅        | Full name of the account holder                              |
| `customer_email`    | ✅        | Customer's email address                                     |
| `currency_code`     | ✅        | Currency for this virtual account, e.g. `NGN`                |
| `bvn`               | ✅        | Customer's 11-digit Bank Verification Number                 |
| `metadata`          | Optional | Key-value pairs to link the account to your internal records |

A successful response returns the reserved bank account details:

```json Response theme={null}
{
  "status": "success",
  "account_number": "9012345678",
  "bank_name": "United Bank for Africa",
  "bank_code": "090XXX",
  "account_reference": "customer_123",
  "reservation_reference": "res_abc987xyz",
  "customer_name": "Ada Lovelace",
  "customer_email": "ada@example.com",
  "currency_code": "NGN",
  "metadata": { "customer_id": "123" }
}
```

<Tip>
  Store both `account_reference` and `reservation_reference` in your database. You will use `account_reference` for lookups and `reservation_reference` to uniquely identify this reservation internally.
</Tip>

## Look Up a Virtual Account

### By Account Reference

To fetch the details of an existing virtual account, call `GET /virtual-accounts/{account_reference}`:

```http Request theme={null}
GET /virtual-accounts/customer_123
```

This returns the same bank details and customer information as the creation response.

### By Customer Email

If you only have a customer's email address, use a `POST` request to `/virtual-accounts/email`:

```json Request theme={null}
{
  "email": "ada@example.com"
}
```

```json Response theme={null}
{
  "status": "success",
  "account_number": "9012345678",
  "bank_name": "United Bank for Africa",
  "account_reference": "customer_123",
  "customer_name": "Ada Lovelace",
  "customer_email": "ada@example.com"
}
```

<Note>
  If multiple virtual accounts share the same email address (for example, accounts created across different environments), the API returns the most recently created one.
</Note>

## Monitor Incoming Transactions

Retrieve a paginated list of all payments received into your virtual accounts at `GET /merchants/virtual-accounts/transactions`.

```http Example request theme={null}
GET /merchants/virtual-accounts/transactions?account_reference=customer_123&status=success&page=1&page_size=20
```

| Parameter           | Description                                                       |
| ------------------- | ----------------------------------------------------------------- |
| `account_reference` | Filter transactions for a specific virtual account                |
| `status`            | Filter by payment status (e.g. `success`, `processing`, `failed`) |
| `start_date`        | Earliest transaction date (ISO 8601)                              |
| `end_date`          | Latest transaction date (ISO 8601)                                |
| `page`              | Page number (default `1`)                                         |
| `page_size`         | Results per page (default `10`, max `100`)                        |

A typical entry in the transactions list looks like:

```json Single transaction (example) theme={null}
{
  "reference": "va_txn_56789",
  "account_reference": "customer_123",
  "amount": 5000.00,
  "currency": "NGN",
  "status": "success",
  "narration": "Transfer from John Doe",
  "created_at": "2026-01-15T10:30:00Z"
}
```

## Handle Webhook Events

When a customer completes a transfer to a virtual account, Paylink fires a `va_charge_success` webhook event to the URL you configured on your merchant dashboard.

```json Webhook payload (example) theme={null}
{
  "event_type": "va_charge_success",
  "status": "success",
  "message": "Virtual account payment received",
  "event_id": "evt_ghi789rst",
  "timestamp": "2026-01-15T10:30:00Z",
  "data": {
    "reference": "va_txn_56789",
    "account_reference": "customer_123",
    "amount": 5000.00,
    "currency": "NGN",
    "metadata": { "customer_id": "123" }
  }
}
```

Use the `account_reference` and any values you stored in `metadata` to identify which customer sent the payment and credit their account in your system.

A `va_charge_failure` event is fired when an incoming transfer to a virtual account cannot be processed. Listen for this event to alert your team or notify the customer to retry.

<Tip>
  Always include a `metadata` object containing your internal customer or account ID when creating a virtual account. This makes it straightforward to reconcile incoming `va_charge_success` events without an extra database lookup.
</Tip>

<Warning>
  Confirm the payment amount in the webhook payload before crediting the customer. Customers can send any amount to a virtual account, so do not assume the transferred amount matches a specific invoice.
</Warning>
