> For the complete documentation index, see [llms.txt](https://developers.klasha.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://developers.klasha.com/~/revisions/LgPYv1wt83TA5LzyGVuI/bank-account-collection/virtual-account-creation.md).

# Virtual Account Creation

## Summary

Create Virtual Accounts on demand, receive funds from customers via these accounts and get notification on its usage.

Dedicated Virtual Accounts (DVAs) is a service that lets you create nigerian virtual accounts for your customers. These accounts allow your customers to receive payment from their customers.

When you create a Dedicated Virtual Account (DVA) for a customer, all bank transfers to that account will automatically be recorded as transactions from that customer.

### Coverage

| Country | currency |
| ------- | -------- |
| Nigeria | NGN      |

#### Integration steps

You can generate a VA and start receiving money in 3 easy steps:

1. Prepare and encrypt the payload (fields include: first name, last name, currency and email)
2. Initiate VA creation
3. Get instant response

***

{% hint style="info" %}

### Before you begin!

* [Link](https://api.postman.com/collections/8963555-100bce95-af05-4af3-8ff6-797f50c99492?access_key=PMAT-01H5J5C8851FV7P97X9BYC19ZE) to the Postman collection
* Find your keys on the Klasha Dashboard → Settings → Generate API Keys ([here](https://dashboard.klasha.com/settings/keys))
* Klasha Dashboard, Generate API Keys page

<img src="https://257545343-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FNw4nU37LIEg41plxXG5u%2Fuploads%2FvBXI8QATrncq17zlRm1P%2Fdashboad-klasha-settings.png?alt=media&amp;token=1ebaf2b3-7e99-4490-9ede-a660c8d0035c" alt="" data-size="original">

{% endhint %}

{% content-ref url="/pages/p15ikIRu4qZuG2xRX2op" %}
[Token Generation](/~/revisions/LgPYv1wt83TA5LzyGVuI/overview/token-generation.md)
{% endcontent-ref %}

## Create a virtual account

> <mark style="color:yellow;">**POST**</mark>  {{env\_url}}/wallet/virtual/v3/business/create/account

Encrypt the plain request body using the encryption algorithm specified [here](https://developers.klasha.com/accepting-payments/payments-api#java). Set the encrypted data to the message as shown below. You are required to set the x-auth-token and Authorization in the headers.

#### Headers

| Key           | Value                    |
| ------------- | ------------------------ |
| x-auth-token  | Your merchant public key |
| Authorization | Bearer \<token here>     |

#### Request Body to be encrypted (plain)

{% tabs %}
{% tab title="NGN (Individual)" %}

```json
{
   "firstName": "John",
   "lastName": "Doe",
   "currency": "NGN",
   "email": "test@klasha.com"
}
```

{% endtab %}

{% tab title="NGN (Business)" %}

```json
{
   "currency": "NGN"
   "email": "test@klasha.com"
}
```

{% endtab %}
{% endtabs %}

| Name                                        | Type   | Description                                             |
| ------------------------------------------- | ------ | ------------------------------------------------------- |
| firstName<mark style="color:red;">\*</mark> | String | account first name                                      |
| lastName<mark style="color:red;">\*</mark>  | String | account last name                                       |
| currency<mark style="color:red;">\*</mark>  | String | Must be one of the supported currencies in the Coverage |
| email<mark style="color:red;">\*</mark>     | String | email to be linked to the VA                            |

#### **Final Request Body (encrypted)**

```json
{
   "message": "encrypted-message"
}
```

**NB**: The encrypted payload must be used with the create virtual account endpoint as seen above.

#### Response

When you create a Virtual Account (VA), please allow a few seconds for processing. The accountName will be the first and last name for a personal account, or the business name for a corporate account. Below are some sample responses you can expect.

{% tabs %}
{% tab title="200: OK (NGN) " %}

```json
{
    "id": 645,
    "walletId": null,
    "accountNumber": "8571529225",
    "bankName": "WEMA BANK",
    "orderRef": "7uIyXachQYC9hcTpgWOZ",
    "txRef": "klasha-virtual-account-banktransfer-Business owner-133",
    "flwRef": "URF_vK8el9541NEy0j66imFD",
    "currency": "NGN",
    "userId": null,
    "businessId": 133,
    "bankCode": null,
    "enabled": true,
    "accountName": "Business owner",
    "email": "test@klasha.com",
    "profileHash": null,
    "blockReason": null,
    "createdAt": "2025-09-29 13:32:59",
    "updatedAt": "2025-09-29 13:32:59"
}
```

{% endtab %}

{% tab title="400: Bad Request " %}

```json
{
    "message": "There is no identity available for this bvn.",
    "error": "Operation not allowed"
}
```

{% endtab %}

{% tab title="400: Bad Request " %}

```json
{
    "message": "Bvn name mismatch.",
    "error": "Operation not allowed"
}
```

{% endtab %}
{% endtabs %}

## Requery VA

> <mark style="color:green;">**GET**</mark> <mark style="color:red;">`{{env_url}}`</mark>`/wallet/virtual/v2/account/`<mark style="color:red;">`{{email}}`</mark>

In case of network downtime or failures during VA creation, the virtual account can be re-queried with the user’s email. This can be fetched using the email specified during the initial VA creation.

#### Headers

| Key           | Value                |
| ------------- | -------------------- |
| Authorization | Bearer \<token here> |

{% tabs %}
{% tab title="200: OK " %}

```json
[
    {
        "accountNumber": "8573777620",
        "bankName": "WEMA BANK",
        "orderRef": "HsKRPDlemp7XBKvgO1HE",
        "txRef": "klasha-fund-wallet-banktransfer-steph-AJDcN6app",
        "flwRef": "URF_1Qw8TF2ZN1KkIdsqyHYI",
        "businessId": 5,
        "enabled": true,
        "accountName": "Forrest Green",
        "email": "test@klasha.com",
        "createdAt": "2023-07-04 17:02:59",
        "updatedAt": "2023-07-04 17:02:59"
    }
]
```

{% endtab %}
{% endtabs %}

<details>

<summary>Transaction Webhook</summary>

When payments are received from your users, we would send a webhook with the details of the transaction to your callback URL.

```json
{
  "data": {
    "createdAt": "2023-07-14T19:28:18.585",
    "narration": "Bank Transfer",
    "destinationCurrency": "NGN",
    "sourceAmount": 2000,
    "sourceCurrency": "NGN",
    "virtualAccount":"0987654321",
    "tnxRef": "reference_322123243",
    "status": "successful",
    "destinationAmount": 2000,
    "originatorAccountName":"Stephen Oj",
    "bankName": "Access Bank",
    "originatorAccountNumber":"1234456211",
    "customer": {
      "id": 53603,
      "name": "Last Name",
      "email": "test@steph.com",
      "phone": null,
      "createdAt": "2023-07-04 20:11:05",
      "updatedAt": "2023-07-04 20:11:05"
    }
  },
  "event": "charge.completed"
}
```

</details>

## Polling transaction status

> <mark style="color:yellow;">**POST**</mark> `{{env_url}}/nucleus/tnx/collection/status`

To know the status of a transaction, you can fetch the transaction using the Transaction Status API on the Postman collection. Make use of the session id received from the bank. See an example below:

#### Request Body

| Name                                      | Type   | Description                                                      |
| ----------------------------------------- | ------ | ---------------------------------------------------------------- |
| gateRef<mark style="color:red;">\*</mark> | String | session id received from the bank (e.g. 10043509483902847574822) |

{% tabs %}
{% tab title="200: OK " %}

```json
{
    "destinationCurrency": "NGN",
    "sourceAmount": 2500.000000,
    "sourceCurrency": "NGN",
    "status": "successful",
    "destinationAmount": 2500.000000,
    "customer": {
        "id": 53603,
        "name": "Last Name",
        "email": "test@steph.com",
        "phone": null,
        "createdAt": "2023-07-04 20:11:05",
        "updatedAt": "2023-07-04 20:11:05"
    }
}
```

{% endtab %}
{% endtabs %}
