Create a non-expiring virtual account
A non-expiring virtual account is an ordinary bank-issued virtual account with no time-to-live: the same lifecycle, the same settlement rules and the same notification as a number from Create a virtual account, except that it never reaches EXPIRED on its own and accepts any number of payments. Use it for a standing collection number per customer of yours: a school fee account per pupil, a savings number per member. The name a payer sees at name enquiry is the payer’s own, built from firstName and lastName.
Request
Section titled “Request”| 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. Note the field names: the three payer fields are camelCase, the settlement field is snake_case.
| Field | Type | Required | Description |
|---|---|---|---|
firstName |
string | No | Payer’s first name. Stored upper-cased. Max 100 characters. |
lastName |
string | No | Payer’s last name. Stored upper-cased. Max 100 characters. |
phoneNumber |
string | No | Payer’s phone, for example 08012345678. Normalised on save. Max 20 characters. |
beneficiary_account |
string | No | 10-digit account the payments settle to. Must exist at the bank and be able to receive credits. Same precedence as the dynamic call. |
firstName and lastName, joined with a space, form the name a payer sees at name enquiry. If both are omitted the number has no name.
curl -X POST https://api.bankcore.ng/api/legacy/agent/createFVA \ -H "Authorization: Bearer $TOKEN" \ -H "X-Agent-Account: 6020012345" \ -H "Content-Type: application/json" \ -d '{ "firstName": "Adaeze", "lastName": "Okafor", "phoneNumber": "08012345678", "beneficiary_account": "6020023456" }'{ "firstName": "Adaeze", "lastName": "Okafor", "phoneNumber": "08012345678", "beneficiary_account": "6020023456"}Response
Section titled “Response”{ "code": "0000", "desc": "4000001050"}| 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 the number against the payer.
Errors
Section titled “Errors”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 you may not read. |
0096 |
X-Agent-Account header is required |
Header missing. |
0096 |
FVA 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 belongs to an individual customer. |
0096 |
FVA creation failed: No allocatable LOCAL virtual account range found for customer: ... |
No bank-issued band for the owner of the header account, or the band is closed to new numbers. |
0096 |
FVA creation failed: All virtual account ranges exhausted ... or Virtual account range ... exhausted |
Every band is full. Ask the bank for more space. |
0096 |
FVA creation failed: Beneficiary account not found: ... |
beneficiary_account does not exist. |
0096 |
FVA creation failed: Beneficiary account ... is not active ... |
beneficiary_account cannot receive credits. |
Most failures share the code 0096; the text is the discriminator.
Same number space. The number is drawn from the same bands as expiring numbers, in the same order (bands reserved to your client first, then the owner’s shared bands, lowest start first), and consumes band capacity like any other.
Same settlement precedence. beneficiary_account wins; then an account the bank linked to the band; then the header account; then the oldest account of the band’s owner. The same caution as the dynamic call applies: beneficiary_account is checked for existence and creditability, not ownership. Only ever name your own accounts or a sub-agent’s.
No reference, no amount rule. The call takes no external_ref and no amount. There is no duplicate check: calling twice with the same payer creates two numbers. If you need a reference or an exact-amount rule on a permanent number, use create with no ttl and "multi": true.
Lifecycle. The number stays live for as long as the band is active. It never becomes USED, because every payment is accepted, and it never expires on its own. Once the current-build caution above is lifted, expire ends it like any other number; until then only the bank can switch it off.
In the portal
Section titled “In the portal”The Virtual accounts page lists bank-issued numbers with their status, settlement account and payer name; in the current build, numbers from this call are not listed there. Payments to them appear on Inflows for the band.