Virtual Accounts

Create single or multi use virtual accounts via the Atlas API.

Atlas supports two types of virtual accounts, single use and multi-use. The single use virtual accounts expire once a payment is completed on it or the assigned expiry reaches (whichever comes first). A multi-use virtual account can be re-used for multiple transactions and does not expire. There is also another category of virtual accounts under multi-use virtual accounts that are tied to customers, known as DVAs (dedicated virtual accounts). DVAs are assigned to customers automatically when you create them on Atlas.

DVAs and has_wallet

A customer only gets a DVA automatically if you set has_wallet to true when you create them. See Creating a customer in the Customers guide for details, or attach one to an existing customer who doesn't have one yet.

Creating a virtual account

To create a virtual account for your business, make a request to the Create Virtual Account endpoint. Every account is provisioned in NGN and settles into your business collection wallet.

The request body depends on the account_type you're creating:

  • account_name (required): the name shown to payers on transfer, between 3 and 250 characters.
  • source_reference (required): your own unique reference for the source of this virtual account, between 3 and 250 characters. Use it to look the account up later with Get Virtual Account.
  • amount (optional): a fixed amount expected on the account. Omit it to accept any amount.
  • expires_at (required for single_use, omit for multi_use): formatted as ISO 8601 (YYYY-MM-DD HH:MM:SS), for example 2026-07-20 18:30:00. Must be in the future and within 24 hours.
{
  "account_type": "single_use",
  "account_name": "Acme Store",
  "source_reference": "src_1234567890",
  "amount": 5000,
  "expires_at": "2026-07-20 18:30:00"
}

The examples below show how to send this request for a single_use account:

curl -X POST "https://atlas.tryduplo.com/api/v1/virtual-account" \
  -H "Authorization: Bearer your_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
    "account_type": "single_use",
    "account_name": "Acme Store",
    "source_reference": "src_1234567890",
    "amount": 5000,
    "expires_at": "2026-07-20 18:30:00"
  }'

On a successful request, you'll get a response similar to the one below:

JSON
{
  "requestId": "abcd1234-5678-90ef-ghij-1234567890kl",
  "requestTimestamp": "2026-07-20 09:15:00",
  "message": "Virtual account created successfully.",
  "statusCode": 201,
  "data": {
    "id": "019a1639-ce25-70b7-ab20-16fcb2bac023",
    "businessId": "019a1639-ce25-70b7-ab20-16fcb2bac024",
    "businessState": "TEST",
    "amount": {
      "value": 5000,
      "currency": "NGN",
      "formatted": "NGN5000"
    },
    "reference": "VA_A1B2C3D4E5F6",
    "walletId": "019a1639-ce25-70b7-ab20-16fcb2bac025",
    "sourceReference": "src_1234567890",
    "accountNumber": "1234567890",
    "accountName": "Acme Store",
    "providerName": "globus",
    "accountType": "single_use",
    "status": "active",
    "currency": "NGN",
    "expiresAt": "2026-07-20 18:30:00",
    "createdAt": "2026-07-20 09:15:00"
  }
}

Listing virtual accounts

To retrieve virtual accounts belonging to your business, make a GET request to the List Virtual Accounts endpoint.

The supported query parameters are:

ParameterDescription
referenceFilter by the Atlas-generated account reference.
accountNumberFilter by the account number.
accountTypeFilter by single_use or multi_use.
statusFilter by derived status, active, inactive, or expired. An account past its expiry is always expired, even if this filter is set to active.
currencyFilter by currency, for example NGN.
searchPartial match on reference, account number, or account name.
startDate / endDateFilter by creation date range.
sortSort direction on createdAt, ASC or DESC. Defaults to DESC.
limitResults per page, defaults to 1000.
pagePage number, defaults to 1.
curl -X GET "https://atlas.tryduplo.com/api/v1/virtual-account?accountType=single_use&status=active&limit=10&page=1" \
  -H "Authorization: Bearer your_API_KEY" \
  -H "Accept: application/json"

On a successful request, you'll get a response similar to the one below:

JSON
{
  "requestId": "abcd1234-5678-90ef-ghij-1234567890kl",
  "requestTimestamp": "2026-07-20 09:15:00",
  "message": "Virtual accounts retrieved successfully.",
  "statusCode": 200,
  "data": [
    {
      "id": "019a1639-ce25-70b7-ab20-16fcb2bac023",
      "businessId": "019a1639-ce25-70b7-ab20-16fcb2bac024",
      "businessState": "TEST",
      "amount": {
        "value": 5000,
        "currency": "NGN",
        "formatted": "NGN5000"
      },
      "reference": "VA_A1B2C3D4E5F6",
      "walletId": "019a1639-ce25-70b7-ab20-16fcb2bac025",
      "sourceReference": "src_1234567890",
      "accountNumber": "1234567890",
      "accountName": "Acme Store",
      "providerName": "globus",
      "accountType": "single_use",
      "status": "active",
      "currency": "NGN",
      "expiresAt": "2026-07-20 18:30:00",
      "createdAt": "2026-07-20 09:15:00"
    }
  ],
  "meta": {
    "current_page": 1,
    "from": 1,
    "last_page": 3,
    "per_page": 50,
    "to": 50,
    "total": 128
  }
}

Retrieving a virtual account

You can retrieve a single virtual account by its Atlas-generated reference, or by your own source_reference, using the Get Virtual Account endpoint. Pass exactly one of reference or sourceReference as a query parameter, the only difference is the query string:

curl -X GET "https://atlas.tryduplo.com/api/v1/virtual-account/find?reference=VA_A1B2C3D4E5F6" \
  -H "Authorization: Bearer your_API_KEY" \
  -H "Accept: application/json"

The examples below use the reference lookup, swap the query parameter for the source reference variant above to look up by source_reference instead:

curl -X GET "https://atlas.tryduplo.com/api/v1/virtual-account/find?reference=VA_A1B2C3D4E5F6" \
  -H "Authorization: Bearer your_API_KEY" \
  -H "Accept: application/json"

If neither reference nor sourceReference is provided, or if both are provided, the request returns a 422. If no virtual account with that reference (or source reference) belongs to your business, the request returns a 404.

Handling virtual account deposits

When a payer deposits money into a virtual account, the amount is settled into your business wallet and Atlas sends an IN_FLOW_SUCCESS_EVENT webhook to your configured endpoint.

The recipient object on the webhook payload's data identifies the account that received the inflow:

recipient
{
  "accountName": "Acme Store",
  "accountNumber": "1234567890"
}

Match recipient.accountNumber against the accountNumber of your virtual accounts, available from the list or retrieve endpoints, to determine which account was credited. If the account is single_use, treat it as fulfilled once you receive this event.

To review credits after the fact rather than as they arrive, use the Listing transactions endpoint in the Balances and Transactions guide.

Always verify the webhook to ensure it came from Atlas.

How is this guide?

Last updated on

On this page