INSTANT DELIVERY Fast Bills & Electricity Payment — Guaranteed 24/7 Service
API Documentation Sandbox Environment
Documentation Airtime Service

POST Purchase VTU Airtime

Programmatically dispatch Virtual Top-Up (VTU) airtime across MTN, Glo, Airtel, and 9mobile. Cashback commissions are credited instantly to your API wallet.

Endpoint Details

HTTP Method
POST
Route Path
/api/v2/vtu-airtime
Base URL
https://app.9jabillz.com.ng
Authentication
HMAC SHA256
Alternative Alias Route
You can also call /api/reseller/airtime interchangeably.

Request Body Parameters

Send request parameters formatted as a raw JSON payload:

Parameter Type Required Description
network String Yes Telecom operator. Supported values: MTN, GLO, AIRTEL, 9MOBILE
phone String Yes 11-digit recipient phone number (e.g. 08031234567)
amount Float/Int Yes Airtime value in Naira (NGN). Minimum: 50, Maximum: 50,000
request_ref String Yes Unique merchant request reference string for idempotency prevention

Sample Request JSON Payload

Request Body
{
  "network": "MTN",
  "phone": "08031234567",
  "amount": 100,
  "request_ref": "AIR-TEST-1005"
}

HMAC SHA256 Signature Formula

For POST requests, concatenate parameters using newline (\n) separators and include the SHA256 hex hash of the raw JSON request body:

Signature Payload Formula
CanonicalData = METHOD + "\n" + REQUEST_PATH + "\n" + TIMESTAMP + "\n" + NONCE + "\n" + SHA256(RawJsonBody)
Example       = "POST\n/api/v2/vtu-airtime\n1792008086\na1b2c3d4e5\n" + SHA256(RawJsonBody)
Signature     = LOWERCASE_HEX( HMAC_SHA256(CanonicalData, YOUR_SECRET_KEY) )

Integration Code Examples

Select your programming language below to view production-ready implementation snippets:

<?php
$apiKey    = "YOUR_LIVE_API_KEY";
$secretKey = "YOUR_LIVE_SECRET_KEY";

$path      = "/api/v2/vtu-airtime";
$url       = "https://app.9jabillz.com.ng" . $path;
$method    = "POST";
$timestamp = (string) time();$nonce     = bin2hex(random_bytes(8));

$payloadArray = [
    "network"     => "MTN",
    "phone"       => "08031234567",
    "amount"      => 100,
    "request_ref" => "AIR-" . uniqid()
];

$rawBody   = json_encode($payloadArray);
$bodyHash  = hash('sha256',$rawBody);

// Construct Canonical String Joined by Newline
$canonicalData = implode("\n", [
    strtoupper($method),
    $path,$timestamp,
    $nonce,$bodyHash
]);

$signature = hash_hmac('sha256', $canonicalData,$secretKey);

$headers = [
    "Content-Type: application/json",
    "Accept: application/json",
    "X-API-KEY: " . $apiKey,
    "X-API-SIGNATURE: " . $signature,
    "X-API-TIMESTAMP: " . $timestamp,
    "X-API-NONCE: " . $nonce
];

$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS,$rawBody);
curl_setopt($ch, CURLOPT_HTTPHEADER,$headers);

$response = curl_exec($ch);
curl_close($ch);

echo $response;
const axios = require('axios');
const crypto = require('crypto');

const apiKey    = 'YOUR_LIVE_API_KEY';
const secretKey = 'YOUR_LIVE_SECRET_KEY';

const path      = '/api/v2/vtu-airtime';
const url       = `https://app.9jabillz.com.ng${path}`;
const method    = 'POST';
const timestamp = Math.floor(Date.now() / 1000).toString();
const nonce     = crypto.randomBytes(8).toString('hex');

const requestBody = JSON.stringify({
    network: "MTN",
    phone: "08031234567",
    amount: 100,
    request_ref: "AIR-" + Date.now()
});

const bodyHash = crypto.createHash('sha256').update(requestBody).digest('hex');

const canonicalData = [
    method.toUpperCase(),
    path,
    timestamp,
    nonce,
    bodyHash
].join('\n');

const signature = crypto.createHmac('sha256', secretKey)
                        .update(canonicalData)
                        .digest('hex');

axios.post(url, requestBody, {
    headers: {
        'Content-Type': 'application/json',
        'Accept': 'application/json',
        'X-API-KEY': apiKey,
        'X-API-SIGNATURE': signature,
        'X-API-TIMESTAMP': timestamp,
        'X-API-NONCE': nonce
    }
})
.then(response => console.log(response.data))
.catch(error => console.error(error.response ? error.response.data : error.message));
import time
import secrets
import hmac
import hashlib
import json
import requests

api_key    = "YOUR_LIVE_API_KEY"
secret_key = "YOUR_LIVE_SECRET_KEY"

path      = "/api/v2/vtu-airtime"
url       = f"https://app.9jabillz.com.ng{path}"
method    = "POST"
timestamp = str(int(time.time()))
nonce     = secrets.token_hex(8)

payload_data = {
    "network": "MTN",
    "phone": "08031234567",
    "amount": 100,
    "request_ref": f"AIR-{int(time.time())}"
}

raw_body  = json.dumps(payload_data, separators=(',', ':'))
body_hash = hashlib.sha256(raw_body.encode('utf-8')).hexdigest()

canonical_data = f"{method.upper()}\n{path}\n{timestamp}\n{nonce}\n{body_hash}"
signature = hmac.new(secret_key.encode('utf-8'), canonical_data.encode('utf-8'), hashlib.sha256).hexdigest()

headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
    "X-API-KEY": api_key,
    "X-API-SIGNATURE": signature,
    "X-API-TIMESTAMP": timestamp,
    "X-API-NONCE": nonce
}

response = requests.post(url, data=raw_body, headers=headers)
print(response.json())
// Postman Pre-request Script Tab:
const secretKey = "YOUR_LIVE_SECRET_KEY";

const timestamp = Math.floor(Date.now() / 1000).toString();
const nonce = Math.random().toString(36).substring(2, 15);
const method = pm.request.method.toUpperCase();
const path = pm.request.url.getPath();
const body = pm.request.body && pm.request.body.raw ? pm.request.body.raw : "";

const bodyHash = CryptoJS.SHA256(body).toString(CryptoJS.enc.Hex);

const canonicalData = [method, path, timestamp, nonce, bodyHash].join("\n");
const signature = CryptoJS.HmacSHA256(canonicalData, secretKey).toString(CryptoJS.enc.Hex);

pm.variables.set("X-API-TIMESTAMP", timestamp);
pm.variables.set("X-API-NONCE", nonce);
pm.variables.set("X-API-SIGNATURE", signature);

Response Schema

Successful Response (200 OK)

JSON Response Payload
{
    "status": true,
    "message": "Airtime request processed successfully.",
    "data": {
        "status": "successful",
        "request_ref": "AIR-TEST-1005",
        "reference": "APIAIR-20261014224305-5340DB1A",
        "amount": 50,
        "cashback_earned": 1.25,
        "recipient": "08031234567",
        "provider": "MTN"
    }
}

Field Definitions

Property Type Description
status Boolean true when request processing completes successfully.
message String Executive outcome description.
data.status String Order status (successful or pending).
data.request_ref String Your unique merchant request reference string.
data.reference String System transaction reference generated by 9jaBillz.
data.amount Float Face value amount charged to your wallet in Naira (NGN).
data.cashback_earned Float Cashback commission credited instantly to your wallet.
data.recipient String Recipient phone number that received the top-up.
data.provider String Telecommunication provider name (MTN, GLO, AIRTEL, 9MOBILE).

Error Handling

HTTP Code Error Reason Example Response Payload
400 Bad Request Validation Error / Missing Fields {"status": false, "message": "Required fields missing or invalid: phone_number (11 digits), provider, amount, request_ref."}
400 Bad Request Insufficient Balance {"status": false, "message": "Insufficient API wallet balance."}
401 Unauthorized Invalid HMAC Signature {"status": false, "message": "Invalid API request signature."}
409 Conflict Replayed request_ref {"status": false, "message": "Duplicate request_ref detected. Transaction already processed."}
502 Bad Gateway Vendor Dispatch Failure {"status": false, "message": "Airtime vendor dispatch failed."}