curl --request POST \
--url https://sandbox.api.afriex.com/api/v1/payment-method/virtual-account/simulate-transfer \
--header 'Content-Type: application/json' \
--header 'x-api-key: <api-key>' \
--data '
{
"accountNumber": "4821930275",
"amount": 5000,
"currency": "NGN"
}
'import requests
url = "https://sandbox.api.afriex.com/api/v1/payment-method/virtual-account/simulate-transfer"
payload = {
"accountNumber": "4821930275",
"amount": 5000,
"currency": "NGN"
}
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({accountNumber: '4821930275', amount: 5000, currency: 'NGN'})
};
fetch('https://sandbox.api.afriex.com/api/v1/payment-method/virtual-account/simulate-transfer', 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/simulate-transfer",
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([
'accountNumber' => '4821930275',
'amount' => 5000,
'currency' => 'NGN'
]),
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/simulate-transfer"
payload := strings.NewReader("{\n \"accountNumber\": \"4821930275\",\n \"amount\": 5000,\n \"currency\": \"NGN\"\n}")
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/simulate-transfer")
.header("x-api-key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"accountNumber\": \"4821930275\",\n \"amount\": 5000,\n \"currency\": \"NGN\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://sandbox.api.afriex.com/api/v1/payment-method/virtual-account/simulate-transfer")
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 \"accountNumber\": \"4821930275\",\n \"amount\": 5000,\n \"currency\": \"NGN\"\n}"
response = http.request(request)
puts response.read_body{
"data": {
"reference": "<string>"
}
}{
"code": "<string>",
"error": "<string>",
"details": {
"errorMessage": "<string>",
"friendlyMessage": "<string>",
"data": {
"customerId": "<string>"
}
}
}{
"code": "<string>",
"error": "<string>",
"details": {
"errorMessage": "<string>",
"friendlyMessage": "<string>",
"data": {
"customerId": "<string>"
}
}
}Simulate Virtual Account Transfer
Sandbox only; returns 403 in production. Credits a bank transfer into one of your sandbox virtual accounts, the way the account provider’s deposit notification would, so balances and your transaction webhook behave as in production. Pass the account number; for an account created with an amount (a one-time account), also pass the reference it was issued with. The deposit is reported by the transaction webhook.
curl --request POST \
--url https://sandbox.api.afriex.com/api/v1/payment-method/virtual-account/simulate-transfer \
--header 'Content-Type: application/json' \
--header 'x-api-key: <api-key>' \
--data '
{
"accountNumber": "4821930275",
"amount": 5000,
"currency": "NGN"
}
'import requests
url = "https://sandbox.api.afriex.com/api/v1/payment-method/virtual-account/simulate-transfer"
payload = {
"accountNumber": "4821930275",
"amount": 5000,
"currency": "NGN"
}
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({accountNumber: '4821930275', amount: 5000, currency: 'NGN'})
};
fetch('https://sandbox.api.afriex.com/api/v1/payment-method/virtual-account/simulate-transfer', 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/simulate-transfer",
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([
'accountNumber' => '4821930275',
'amount' => 5000,
'currency' => 'NGN'
]),
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/simulate-transfer"
payload := strings.NewReader("{\n \"accountNumber\": \"4821930275\",\n \"amount\": 5000,\n \"currency\": \"NGN\"\n}")
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/simulate-transfer")
.header("x-api-key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"accountNumber\": \"4821930275\",\n \"amount\": 5000,\n \"currency\": \"NGN\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://sandbox.api.afriex.com/api/v1/payment-method/virtual-account/simulate-transfer")
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 \"accountNumber\": \"4821930275\",\n \"amount\": 5000,\n \"currency\": \"NGN\"\n}"
response = http.request(request)
puts response.read_body{
"data": {
"reference": "<string>"
}
}{
"code": "<string>",
"error": "<string>",
"details": {
"errorMessage": "<string>",
"friendlyMessage": "<string>",
"data": {
"customerId": "<string>"
}
}
}{
"code": "<string>",
"error": "<string>",
"details": {
"errorMessage": "<string>",
"friendlyMessage": "<string>",
"data": {
"customerId": "<string>"
}
}
}403 in production.TRANSACTION.UPDATED webhook behave the same.
Sandbox virtual accounts receive no money on their own, so use this endpoint whenever you want to test what happens after a customer funds one.
Choosing the account
- Reusable virtual account (created without
amount): pass theaccountNumberandamountto credit. - One-time virtual account (created with
amount): pass the samereferencethe account was issued with, in addition toaccountNumberandamount.
Controlling the outcome
outcome defaults to success. Pass "outcome": "failed" to simulate a failed inflow.
The deposit lands as a transaction and is reported by webhook. See the Sandbox testing guide for how virtual accounts fit into the broader sandbox model.Authorizations
Static business API key issued from the dashboard. A business can provision multiple API keys, each scoped to a configurable set of permissions (e.g. read transactions, create deposits, etc). Permissions are chosen per key at creation time in the dashboard and may be revoked by deleting the key. Manage your keys and their permissions under Developer → API keys in the dashboard.
A request whose key does not carry the permission the target
endpoint requires is rejected with 401 Unauthorized, the same
response an unrecognised, malformed, revoked or disabled key
returns. The API does not distinguish the two cases on the wire.
See the Permissions reference for the permission each endpoint requires.
Headers
API version in ISO 8601 format. The only supported version is 2026-05-18, which is also the default when the header is omitted. Any other value is rejected with a 400 Bad Request.
Body
The virtual account number to pay into.
The amount transferred.
The account's currency.
The reference a one-time (amount-bound) account was issued with. Not needed for a reusable account.
Defaults to success.
success, failed Response
Accepted. The reference of the new deposit.
Show child attributes
Show child attributes
