Create Virtual Account - Afriex Business API

Afriex SDK

TypeScript

const account = await afriex.paymentMethods.createVirtualAccount({
  currency: "USD",
  label: "SALES",
  customerId: "optional-customer-id",
});
curl --request POST \
  --url https://sandbox.api.afriex.com/api/v1/payment-method/virtual-account \
  --header 'Content-Type: application/json' \
  --header 'x-api-key: <api-key>' \
  --data '
{
  "currency": "NGN",
  "customerId": "68e6717848e1f632e9686460",
  "label": "SALES"
}
'
import requests

url = "https://sandbox.api.afriex.com/api/v1/payment-method/virtual-account"

payload = {
    "currency": "NGN",
    "customerId": "68e6717848e1f632e9686460",
    "label": "SALES"
}
headers = {
    "x-api-key": "<api-key>",
    "Content-Type": "application/json"
}

response = requests.post(url, json=payload, headers=headers)

print(response.text)
const options = {
  method: 'POST',
  headers: {'x-api-key': '<api-key>', 'Content-Type': 'application/json'},
  body: JSON.stringify({currency: 'NGN', customerId: '68e6717848e1f632e9686460', label: 'SALES'})
};

fetch('https://sandbox.api.afriex.com/api/v1/payment-method/virtual-account', options)
  .then(res => res.json())
  .then(res => console.log(res))
  .catch(err => console.error(err));
<?php

$curl = curl_init();

curl_setopt_array($curl, [
  CURLOPT_URL => "https://sandbox.api.afriex.com/api/v1/payment-method/virtual-account",
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_ENCODING => "",
  CURLOPT_MAXREDIRS => 10,
  CURLOPT_TIMEOUT => 30,
  CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
  CURLOPT_CUSTOMREQUEST => "POST",
  CURLOPT_POSTFIELDS => json_encode([
    'currency' => 'NGN',
    'customerId' => '68e6717848e1f632e9686460',
    'label' => 'SALES'
  ]),
  CURLOPT_HTTPHEADER => [
    "Content-Type: application/json",
    "x-api-key: <api-key>"
  ],
]);

$response = curl_exec($curl);
$err = curl_error($curl);

curl_close($curl);

if ($err) {
  echo "cURL Error #:" . $err;
} else {
  echo $response;
}
?>
package main

import (
    "fmt"
    "strings"
    "net/http"
    "io"
)

func main() {

url := "https://sandbox.api.afriex.com/api/v1/payment-method/virtual-account"

payload := strings.NewReader(`{
  "currency": "NGN",
  "customerId": "68e6717848e1f632e9686460",
  "label": "SALES"
}`)

req, _ := http.NewRequest("POST", url, payload)

req.Header.Add("x-api-key", "<api-key>")
    req.Header.Add("Content-Type", "application/json")

res, _ := http.DefaultClient.Do(req)

defer res.Body.Close()
    body, _ := io.ReadAll(res.Body)

fmt.Println(string(body))

}
HttpResponse<String> response = Unirest.post("https://sandbox.api.afriex.com/api/v1/payment-method/virtual-account")
  .header("x-api-key", "<api-key>")
  .header("Content-Type", "application/json")
  .body("{\n  \"currency\": \"NGN\",\n  \"customerId\": \"68e6717848e1f632e9686460\",\n  \"label\": \"SALES\"\n}")
  .asString();
require 'uri'
require 'net/http'

url = URI("https://sandbox.api.afriex.com/api/v1/payment-method/virtual-account")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["x-api-key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n  \"currency\": \"NGN\",\n  \"customerId\": \"68e6717848e1f632e9686460\",\n  \"label\": \"SALES\"\n}"

response = http.request(request)
puts response.read_body

Response Example

{
  "data": {
    "paymentMethodId": "690cc5bbe2a1143ff6070119",
    "channel": "VIRTUAL_BANK_ACCOUNT",
    "customerId": "68e6717848e1f632e9686460",
    "institution": {
      "institutionName": "FIDELITY BANK"
    },
    "accountName": "Lily New",
    "accountNumber": "3820404958",
    "countryCode": "NG"
  }
}

Creates a new virtual account for the resolved customer-or-owner and currency. Pass customerId to mint the virtual account for a specific end-user, or omit it to mint one for the business owner. Important: Virtual accounts are only active in production and do not work on staging/dev.

Static vs dynamic virtual accounts

You choose between two flavours of virtual account by what you pass alongside currency and customerId.

Static (label)

Pass a label to group static virtual accounts by purpose. Static accounts are permanently assigned to the customer and never expire. The same account number remains valid for repeated funding. Allowed labels: SALES, OPERATIONS, PAYROLL, COLLECTIONS, VENDOR_PAYMENTS, TAX, REFUNDS, MARKETING, TREASURY, GENERAL. Use static accounts when you want stable, long-lived account numbers a customer can top up over time, organised by purpose.

Dynamic (amount)

Pass an amount to mint a dynamic (ephemeral) virtual account tied to that specific amount. Dynamic accounts expire after a short window. Use dynamic accounts when you need to collect a specific, known amount within a defined window, like a one-time payment for a particular order.

label and amount are mutually exclusive. Supplying both is rejected at validation.

BVN requirement for NGN static virtual accounts

For NGN static virtual accounts (label-based, Nigeria), the customer must have a Bank Verification Number (BVN) on file. This is a regulatory requirement for permanently assigned accounts in Nigeria. If the BVN is missing, the API returns an error. You can supply a BVN when creating a new customer or add it to an existing customer at any time using the Update Customer KYC endpoint.

NGN static virtual accounts will fail if the customer has not provided their BVN. This requirement does not apply to dynamic virtual accounts or to virtual accounts in other currencies.

Limits

Creation is subject to a per-(business, customer, currency) cap. Requests that would exceed the cap return VIRTUAL_ACCOUNT_LIMIT_REACHED with 400. Call List Virtual Accounts first to check what already exists for the customer.