const session = await afriex.checkout.createSession({
amount: 500000,
currency: "NGN",
merchantReference: "order-2026-05-12-001",
redirectUrl: "https://yourapp.com/checkout/return",
customer: {
name: "John Doe",
email: "john@example.com",
phone: "+2348192837465",
countryCode: "NG",
},
// Send the same list everywhere; unsupported ones are dropped
channels: ["VIRTUAL_BANK_ACCOUNT", "MOBILE_MONEY", "CARD"],
metadata: { orderId: "order-456", cartId: "cart-123" },
});
// Redirect customer to session.checkoutUrl
console.log(session.checkoutUrl);
// What the payer will be shown, e.g. ["VIRTUAL_BANK_ACCOUNT", "CARD"]
console.log(session.channels);
curl --request POST \
--url https://sandbox.api.afriex.com/api/v1/checkout-session \
--header 'Content-Type: application/json' \
--header 'x-api-key: <api-key>' \
--data '
{
"amount": 500000,
"currency": "NGN",
"merchantReference": "order-2026-05-12-001",
"redirectUrl": "https://merchant.example.com/checkout/return",
"customer": {
"name": "John Doe",
"email": "john.doe@example.com",
"phone": "+2348192837465",
"countryCode": "NG"
},
"channels": [
"VIRTUAL_BANK_ACCOUNT",
"MOBILE_MONEY",
"CARD"
]
}
'import requests
url = "https://sandbox.api.afriex.com/api/v1/checkout-session"
payload = {
"amount": 500000,
"currency": "NGN",
"merchantReference": "order-2026-05-12-001",
"redirectUrl": "https://merchant.example.com/checkout/return",
"customer": {
"name": "John Doe",
"email": "john.doe@example.com",
"phone": "+2348192837465",
"countryCode": "NG"
},
"channels": ["VIRTUAL_BANK_ACCOUNT", "MOBILE_MONEY", "CARD"]
}
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({
amount: 500000,
currency: 'NGN',
merchantReference: 'order-2026-05-12-001',
redirectUrl: 'https://merchant.example.com/checkout/return',
customer: {
name: 'John Doe',
email: 'john.doe@example.com',
phone: '+2348192837465',
countryCode: 'NG'
},
channels: ['VIRTUAL_BANK_ACCOUNT', 'MOBILE_MONEY', 'CARD']
})
};
fetch('https://sandbox.api.afriex.com/api/v1/checkout-session', 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/checkout-session",
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([
'amount' => 500000,
'currency' => 'NGN',
'merchantReference' => 'order-2026-05-12-001',
'redirectUrl' => 'https://merchant.example.com/checkout/return',
'customer' => [
'name' => 'John Doe',
'email' => 'john.doe@example.com',
'phone' => '+2348192837465',
'countryCode' => 'NG'
],
'channels' => [
'VIRTUAL_BANK_ACCOUNT',
'MOBILE_MONEY',
'CARD'
]
]),
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/checkout-session"
payload := strings.NewReader("{\n \"amount\": 500000,\n \"currency\": \"NGN\",\n \"merchantReference\": \"order-2026-05-12-001\",\n \"redirectUrl\": \"https://merchant.example.com/checkout/return\",\n \"customer\": {\n \"name\": \"John Doe\",\n \"email\": \"john.doe@example.com\",\n \"phone\": \"+2348192837465\",\n \"countryCode\": \"NG\"\n },\n \"channels\": [\n \"VIRTUAL_BANK_ACCOUNT\",\n \"MOBILE_MONEY\",\n \"CARD\"\n ]\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/checkout-session")
.header("x-api-key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"amount\": 500000,\n \"currency\": \"NGN\",\n \"merchantReference\": \"order-2026-05-12-001\",\n \"redirectUrl\": \"https://merchant.example.com/checkout/return\",\n \"customer\": {\n \"name\": \"John Doe\",\n \"email\": \"john.doe@example.com\",\n \"phone\": \"+2348192837465\",\n \"countryCode\": \"NG\"\n },\n \"channels\": [\n \"VIRTUAL_BANK_ACCOUNT\",\n \"MOBILE_MONEY\",\n \"CARD\"\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://sandbox.api.afriex.com/api/v1/checkout-session")
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 \"amount\": 500000,\n \"currency\": \"NGN\",\n \"merchantReference\": \"order-2026-05-12-001\",\n \"redirectUrl\": \"https://merchant.example.com/checkout/return\",\n \"customer\": {\n \"name\": \"John Doe\",\n \"email\": \"john.doe@example.com\",\n \"phone\": \"+2348192837465\",\n \"countryCode\": \"NG\"\n },\n \"channels\": [\n \"VIRTUAL_BANK_ACCOUNT\",\n \"MOBILE_MONEY\",\n \"CARD\"\n ]\n}"
response = http.request(request)
puts response.read_body{
"data": {
"checkoutUrl": "https://pay.afriex.com/pay/eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9",
"channels": [
"VIRTUAL_BANK_ACCOUNT",
"CARD"
]
}
}{
"code": "<string>",
"error": "<string>",
"details": {
"errorMessage": "<string>",
"friendlyMessage": "<string>",
"data": {
"customerId": "<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>"
}
}
}{
"code": "<string>",
"error": "<string>",
"details": {
"errorMessage": "<string>",
"friendlyMessage": "<string>",
"data": {
"customerId": "<string>"
}
}
}Create Checkout Session
Creates a hosted checkout session for a customer and returns a checkoutUrl that the customer should be redirected to in order to complete payment. The session captures the merchant intent (amount, currency, merchant reference, customer details, and allowed payment channels) and is identified end-to-end by the merchant-supplied merchantReference.
const session = await afriex.checkout.createSession({
amount: 500000,
currency: "NGN",
merchantReference: "order-2026-05-12-001",
redirectUrl: "https://yourapp.com/checkout/return",
customer: {
name: "John Doe",
email: "john@example.com",
phone: "+2348192837465",
countryCode: "NG",
},
// Send the same list everywhere; unsupported ones are dropped
channels: ["VIRTUAL_BANK_ACCOUNT", "MOBILE_MONEY", "CARD"],
metadata: { orderId: "order-456", cartId: "cart-123" },
});
// Redirect customer to session.checkoutUrl
console.log(session.checkoutUrl);
// What the payer will be shown, e.g. ["VIRTUAL_BANK_ACCOUNT", "CARD"]
console.log(session.channels);
curl --request POST \
--url https://sandbox.api.afriex.com/api/v1/checkout-session \
--header 'Content-Type: application/json' \
--header 'x-api-key: <api-key>' \
--data '
{
"amount": 500000,
"currency": "NGN",
"merchantReference": "order-2026-05-12-001",
"redirectUrl": "https://merchant.example.com/checkout/return",
"customer": {
"name": "John Doe",
"email": "john.doe@example.com",
"phone": "+2348192837465",
"countryCode": "NG"
},
"channels": [
"VIRTUAL_BANK_ACCOUNT",
"MOBILE_MONEY",
"CARD"
]
}
'import requests
url = "https://sandbox.api.afriex.com/api/v1/checkout-session"
payload = {
"amount": 500000,
"currency": "NGN",
"merchantReference": "order-2026-05-12-001",
"redirectUrl": "https://merchant.example.com/checkout/return",
"customer": {
"name": "John Doe",
"email": "john.doe@example.com",
"phone": "+2348192837465",
"countryCode": "NG"
},
"channels": ["VIRTUAL_BANK_ACCOUNT", "MOBILE_MONEY", "CARD"]
}
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({
amount: 500000,
currency: 'NGN',
merchantReference: 'order-2026-05-12-001',
redirectUrl: 'https://merchant.example.com/checkout/return',
customer: {
name: 'John Doe',
email: 'john.doe@example.com',
phone: '+2348192837465',
countryCode: 'NG'
},
channels: ['VIRTUAL_BANK_ACCOUNT', 'MOBILE_MONEY', 'CARD']
})
};
fetch('https://sandbox.api.afriex.com/api/v1/checkout-session', 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/checkout-session",
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([
'amount' => 500000,
'currency' => 'NGN',
'merchantReference' => 'order-2026-05-12-001',
'redirectUrl' => 'https://merchant.example.com/checkout/return',
'customer' => [
'name' => 'John Doe',
'email' => 'john.doe@example.com',
'phone' => '+2348192837465',
'countryCode' => 'NG'
],
'channels' => [
'VIRTUAL_BANK_ACCOUNT',
'MOBILE_MONEY',
'CARD'
]
]),
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/checkout-session"
payload := strings.NewReader("{\n \"amount\": 500000,\n \"currency\": \"NGN\",\n \"merchantReference\": \"order-2026-05-12-001\",\n \"redirectUrl\": \"https://merchant.example.com/checkout/return\",\n \"customer\": {\n \"name\": \"John Doe\",\n \"email\": \"john.doe@example.com\",\n \"phone\": \"+2348192837465\",\n \"countryCode\": \"NG\"\n },\n \"channels\": [\n \"VIRTUAL_BANK_ACCOUNT\",\n \"MOBILE_MONEY\",\n \"CARD\"\n ]\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/checkout-session")
.header("x-api-key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"amount\": 500000,\n \"currency\": \"NGN\",\n \"merchantReference\": \"order-2026-05-12-001\",\n \"redirectUrl\": \"https://merchant.example.com/checkout/return\",\n \"customer\": {\n \"name\": \"John Doe\",\n \"email\": \"john.doe@example.com\",\n \"phone\": \"+2348192837465\",\n \"countryCode\": \"NG\"\n },\n \"channels\": [\n \"VIRTUAL_BANK_ACCOUNT\",\n \"MOBILE_MONEY\",\n \"CARD\"\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://sandbox.api.afriex.com/api/v1/checkout-session")
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 \"amount\": 500000,\n \"currency\": \"NGN\",\n \"merchantReference\": \"order-2026-05-12-001\",\n \"redirectUrl\": \"https://merchant.example.com/checkout/return\",\n \"customer\": {\n \"name\": \"John Doe\",\n \"email\": \"john.doe@example.com\",\n \"phone\": \"+2348192837465\",\n \"countryCode\": \"NG\"\n },\n \"channels\": [\n \"VIRTUAL_BANK_ACCOUNT\",\n \"MOBILE_MONEY\",\n \"CARD\"\n ]\n}"
response = http.request(request)
puts response.read_body{
"data": {
"checkoutUrl": "https://pay.afriex.com/pay/eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9",
"channels": [
"VIRTUAL_BANK_ACCOUNT",
"CARD"
]
}
}{
"code": "<string>",
"error": "<string>",
"details": {
"errorMessage": "<string>",
"friendlyMessage": "<string>",
"data": {
"customerId": "<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>"
}
}
}{
"code": "<string>",
"error": "<string>",
"details": {
"errorMessage": "<string>",
"friendlyMessage": "<string>",
"data": {
"customerId": "<string>"
}
}
}checkoutUrl that you redirect the customer to so they can complete payment on Afriex’s hosted page.
merchantReference: include fail for a FAILED result, or add SIMULATE_INSTANT to settle in about 30 seconds instead of waiting. For mobile money, SIMULATE_OTP / SIMULATE_NO_OTP control whether the payment requires the OTP step shown on the hosted page. See Testing transaction outcomes in sandbox.How it works
- Call this endpoint with the amount you want to collect, the customer’s details, your
merchantReference, and aredirectUrl. - Afriex returns a
checkoutUrl. - Redirect the customer to that URL.
- After payment, Afriex redirects the customer back to your
redirectUrland fires aCHECKOUT_SESSION.CREATEDwebhook to your configured callback URL.
Identifying the session
ThemerchantReference you supply is the end-to-end identifier. Use it to look up the session, match webhook deliveries, and reconcile any resulting transaction in your system. It must be unique per session.
Amounts are in minor units
amount is denominated in the smallest unit of the currency. For example, kobo for NGN or cents for USD. To charge ₦5,000.00, pass 500000. Minimum value is 100 (one major unit).
Choosing payment channels
channels is required and lists the deposit rails you are willing to offer the customer. Supported values are VIRTUAL_BANK_ACCOUNT, MOBILE_MONEY, and CARD; pass at least one.
Treat it as a cap, not an exact list. Channels the session’s currency cannot collect on are dropped silently, so you can send the same list on every corridor and let Afriex offer the right subset. For example, ["VIRTUAL_BANK_ACCOUNT", "MOBILE_MONEY", "CARD"] becomes mobile money for a KES session and cards for a USD session, all from one integration.
The response echoes what the payer will actually be shown as channels, in the order you sent them.
channels are supported for the currency (or the currency has no deposit channel at all), the request is rejected with 422 Unprocessable Entity.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. Requests made with a key that does not include the permission required by the target endpoint will be rejected with a 403 Forbidden response; an unrecognised, malformed or revoked key returns 401 Unauthorized. Manage your keys and their permissions under Developer → API keys in the dashboard.
Headers
API version in ISO 8601 format (e.g. 2025-12-28). Defaults to latest stable.
Body
The transaction amount in minor currency units (e.g. kobo for NGN, cents for USD). Minimum 100 (equivalent to 1 major currency unit).
x >= 100500000
Uppercase 3-letter ISO 4217 currency code (e.g. NGN, GHS). Must be a currency enabled for checkout sessions on the business.
"NGN"
Unique merchant-supplied reference for this session. Used end-to-end to look up the session and any resulting transaction.
1"order-2026-05-12-001"
HTTPS URL the customer is redirected to after the hosted checkout flow completes.
"https://merchant.example.com/checkout/return"
Show child attributes
Show child attributes
The payment channels you are willing to offer the customer, at least one. This is a cap, not an exact list: you do not need to vary it per country. Channels the currency does not support are dropped and the session is created with the rest, so the same list works for every corridor (send ["VIRTUAL_BANK_ACCOUNT", "MOBILE_MONEY", "CARD"] and a KES session offers mobile money while a USD one offers cards). The channels the customer will actually be shown come back as channels on the response. The request is rejected (422) only when none of the requested channels are supported for the currency, or when the currency supports no deposit channel at all.
1VIRTUAL_BANK_ACCOUNT, MOBILE_MONEY, CARD Optional flat key/value metadata to attach to the session. Both keys and values must be strings. At most 50 entries; keys up to 128 characters, values up to 1024 characters.
Show child attributes
Show child attributes
Response
Checkout session created successfully.
Show child attributes
Show child attributes
