Skip to content

Create a virtual account

Allocates the next free number from a LOCAL band and records the rules a payment to it must satisfy. The number is live immediately; a payer at any bank can name-enquire and pay it as soon as you have the response. You need a LOCAL band assigned to the customer who owns the account in X-Agent-Account; ask your relationship manager if the call returns “No allocatable LOCAL virtual account range”.

POST/api/legacy/agent/virtual_account/createscope: accounts:create
Header Required Description
X-Agent-Account Yes A 10-digit account you may read: your own, or a sub-agent’s transaction account. Decides whose band is used and the fallback settlement account.

The body is JSON. Every field is optional; an empty object is a valid request and yields a single-use number with no expiry, no amount rule, the name VIRTUAL ACCOUNT and a generated reference.

Field Type Required Description
account_name string No The name a payer sees at name enquiry. Stored upper-cased. Default Virtual Account. Max 255 characters.
external_ref string No Your reference for this number (order id, invoice number). Must be unique across all numbers your bank has ever issued to the tenant. A random UUID is generated if omitted. Max 255 characters.
amount decimal No The amount you expect. Sent as a JSON number or a numeric string.
exact_amount boolean No When true (the default) and amount is set, a transfer for any other value is refused. false keeps amount as a note only. Ignored when amount is absent.
multi boolean No true accepts any number of payments. Default false: the number becomes USED after the first accepted payment.
ttl integer No Minutes until the number expires. 0 or omitted means no expiry.
beneficiary_account string No 10-digit account the payments settle to. Must exist at the bank and be able to receive credits.
Terminal window
curl -X POST https://api.bankcore.ng/api/legacy/agent/virtual_account/create \
-H "Authorization: Bearer $TOKEN" \
-H "X-Agent-Account: 6020012345" \
-H "Content-Type: application/json" \
-d '{
"account_name": "ACME STORES ORDER 1042",
"external_ref": "ORD-1042",
"amount": 50000.00,
"exact_amount": true,
"ttl": 1440
}'
{
"code": "0000",
"desc": "4000001042"
}
Field Description
code 0000 on success.
desc The 10-digit virtual account number. On failure, the reason in words.

Nothing else is returned. Keep your own record of external_ref against the number; the portal and the native lookup GET /api/virtual-accounts/by-account/{accountNumber} can return the full record later.

HTTP 200 always. Read code, then desc.

Code desc begins with When
0012 Account ... is not linked to this API client X-Agent-Account names an account the ownership guard does not let you read.
0096 X-Agent-Account header is required Header missing or blank.
0096 VA creation failed: Agent account not found: ... The header account does not exist in your tenant.
0096 Account does not belong to an agent The header account’s owner is an individual customer, not a corporate or agent.
0096 VA creation failed: Duplicate external reference: ... external_ref was used before. Nothing was created.
0096 VA creation failed: No allocatable LOCAL virtual account range found for customer: ... The owner of the header account has no LOCAL band, or the band is closed to new numbers.
0096 VA creation failed: All virtual account ranges exhausted ... or Virtual account range ... exhausted Every band is full. Ask the bank for more space.
0096 VA creation failed: Beneficiary account not found: ... beneficiary_account does not exist at the bank.
0096 VA creation failed: Beneficiary account ... is not active (status: ...) beneficiary_account is closed, frozen, dormant or restricted.
0096 VA creation failed: Settlement account ... No beneficiary_account, no band-linked account, and the header account cannot receive credits.

Most failures share the code 0096; the text is the discriminator. Do not retry a Duplicate external reference with the same reference.

Settlement account precedence. beneficiary_account wins. Without it, an account the bank linked to the band wins over your header account, so on a band the bank has pointed at one collection account, payments go there whatever X-Agent-Account says. Without either, the header account is used; without that, the oldest account of the band’s owner.

Reference uniqueness is tenant-wide and permanent. An external_ref from an expired or used number cannot be reused. Make references globally unique on your side (prefix with your system name).

Expiry is judged at arrival. A payment that reached the bank while the number was live is credited even if the number lapses while NIBSS confirms it. A payment that arrives after expiry is refused before the money moves.

Bands reserved to your client are drained first; after that the shared bands of the same customer, lowest start first. Numbers may be sequential or permuted across the band depending on how the bank configured it, so do not infer anything from the order you receive them in.

Idempotency. The call is not idempotent on its own. Use external_ref as your idempotency key: a retry after a timeout returns 0096 Duplicate external reference if the first call succeeded, and the portal or native lookup will give you the number.

The Virtual accounts page lists the number the moment it is created, with status, expiry, the amount rule, your external_ref under “client reference”, and the settlement account.