Partner API · v1

Sell data, airtime and bills from your own platform

Connect your website, app or bot to HananSub. Every purchase is one HTTPS request with a JSON body, paid from your HananSub wallet at your reseller price, and you get the result instantly or by webhook.

Base URLhttps://www.hanansub.com/api/v1
FormatJSON request bodies (Content-Type: application/json) and JSON responses
Who can use itVendor (API) accounts. Contact us to upgrade your account.

Quick start

  1. Log in and open Developer API. Generate a live key (and a sandbox key for testing).
  2. Call GET /catalog to get plan IDs and your prices.
  3. Buy with e.g. POST /data, sending your key, the plan ID, the phone number and your transaction PIN.
  4. Set a webhook URL so you're told when pending orders finish.

Connect without coding

Already run a VTU website? You don't need to write any code to sell our services. Add HananSub as a supplier in your own admin panel, exactly like any other supplier — our API speaks the two most common VTU script formats.

API URLhttps://www.hanansub.com/api/
API / auth typeVicom or Token (Larabills / VTUPlug-type scripts), or MSORG — choose whichever your script offers.
API key / tokenYour live API key. If you haven't locked it to your server's IP addresses, enter it as YOUR_API_KEY:YOUR_PIN (key, colon, transaction PIN).
Plan / package IDsOur IDs from the tables below. Many scripts can import them automatically from the list URLs.
ServiceVicom-type URLMSORG-type URL
BalanceGET /api/userGET /api/user/
AirtimePOST /api/airtimePOST /api/topup/
DataPOST /api/dataPOST /api/data/
Cable TVPOST /api/cable
verify: /api/cable/cable-validation
POST /api/cablesub/
verify: /api/validateiuc
ElectricityPOST /api/bill
verify: /api/bill/bill-validation
POST /api/billpayment/
verify: /api/validatemeter
Exam PINsPOST /api/examPOST /api/epin/
Recharge / data cardsPOST /api/recharge_card
POST /api/data_card
same
Bulk SMSPOST /api/bulk-smssame
Order statusGET /api/transaction/<request-id>same
Plan listsGET /api/data_plans · /api/get-cable · /api/get-cable-plan?cable=ID · /api/get-bill · /api/get-exam · /api/get-networks
  • Network numbers follow your script's format. Vicom-type: 1 MTN, 2 AIRTEL, 3 GLO, 4 9MOBILE. MSORG-type: 1 MTN, 2 GLO, 3 AIRTEL, 4 9MOBILE. Network names ("MTN") work too.
  • Common field spellings are all accepted (phone or mobile_number, plan or data_plan, iuc or smart_card_number, …), and replies include both formats' fields (status, Status, api_response, msg, request-id, new_balance…).
  • Send your request-id (most scripts do) and retries are safe: the same ID returns the original order. Your script's automatic status check (/api/transaction/<request-id>) works too.
  • Building something new? Use the v1 API below — it is cleaner and fully documented here.

Authentication

Send your API key as a Bearer token on every request:

Authorization: Bearer YOUR_API_KEY
  • Live keys look like han_live_… and spend real money. Sandbox keys start with sandbox_ and are fully simulated (details). Same URL — the key decides.
  • Purchases need your transaction PIN in the body ("pin") — unless your key is locked to your server's IP addresses. Three wrong PINs lock purchases for 10 minutes.
  • IP allowlist (recommended): on the Developer API page, list your server's IP addresses. Requests from any other IP are refused, and purchases from your listed IPs no longer need the PIN — the simplest and safest setup for a server-to-server integration.
  • Keys don't expire. If one leaks, regenerate it on the Developer API page — the old key stops working at once.

Responses & errors

Every response has a status field. A purchase ends in one of four ways — handle all four:

Success (HTTP 200)
{
    "status": "success",
    "message": "Data purchase successful",
    "data": {
        "reference": "HANE213826EA8181791581826",
        "balance_after": 44770
    }
}

Delivered. Keep the reference.

Pending (HTTP 200)
{
    "status": "pending",
    "success": true,
    "pending": true,
    "message": "Your order is processing.",
    "data": {
        "reference": "HANE213826EA8181791581826"
    }
}

Accepted and charged; the provider hasn't confirmed yet. Wait for the webhook or poll /receipt. Do not retry.

Declined & refunded (HTTP 400)
{
    "status": "error",
    "success": false,
    "message": "Transaction failed. Your wallet has been refunded.",
    "refunded": true,
    "reference": "HANE213826EA8181791581826"
}

The provider declined it and your wallet was refunded. Safe to retry.

Rejected (HTTP 4xx)
{
    "status": "error",
    "message": "Invalid transaction PIN"
}

Nothing was charged. Fix the request and try again.

HTTPMeaning
200Success or pending (check status).
400Missing/invalid field, wrong PIN, insufficient balance ("Insufficient balance. Please top up your wallet."), or declined and refunded.
401Missing, wrong or revoked API key, or suspended account.
403"API access requires a vendor account.", API access disabled for the account, request from an IP not on your allowlist, or the service is switched off.
404Unknown transaction reference (/receipt).
405Wrong method (e.g. GET on a POST endpoint).
429Too many requests — slow down (limits).
500Our error. Check /receipt before retrying a purchase.

Limits & safety

  • Purchases: 30 per minute per account. Smartcard/meter lookups: 20 per 5 minutes. Bulk SMS: 20 requests per hour.
  • Duplicate protection: an identical purchase (same service, number and amount/plan) within 5 seconds is refused with "Duplicate request detected" and not charged.
  • Retrying safely: send your own request_id with each purchase. If a request times out, send it again with the same ID — you get the original order back ("duplicate": true) instead of buying twice. Without a request_id, check /transactions before retrying.
  • Your account's daily spending limits and per-purchase limits also apply.

Sandbox testing

  • Use your sandbox_… key against the same base URL. Nothing real is bought and your live wallet is untouched.
  • Your sandbox wallet starts with ₦1,000,000 (reset it any time on the Developer API page).
  • Purchases succeed instantly — unless the phone, meter or smartcard number ends in 0000, which simulates a decline and refund so you can test that path.
  • Sandbox purchases also send webhooks, marked "sandbox": true.

Wallet balance

Your wallet and cashback balance. With a sandbox key it returns the simulated sandbox balance.

GET /api/v1/balance
curl "https://www.hanansub.com/api/v1/balance" \
  -H "Authorization: Bearer YOUR_API_KEY"
<?php
$ch = curl_init("https://www.hanansub.com/api/v1/balance");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer YOUR_API_KEY',
    ],
]);
$response = json_decode(curl_exec($ch), true);
curl_close($ch);

print_r($response);
const res = await fetch("https://www.hanansub.com/api/v1/balance", {
  headers: {
    "Authorization": "Bearer YOUR_API_KEY"
  }
});
const data = await res.json();
console.log(data);
import requests

res = requests.get(
    "https://www.hanansub.com/api/v1/balance",
    headers={"Authorization": "Bearer YOUR_API_KEY"},
    timeout=60,
)
print(res.json())
Response · 200
{
    "status": "success",
    "data": {
        "wallet_balance": 45250,
        "cashback_balance": 120.5,
        "currency": "NGN",
        "sandbox": false
    }
}

Catalog & your prices

Every active data plan, cable plan, electricity company and exam type, priced for your account tier. Call it to build your own price list, and cache it — prices change rarely.

GET /api/v1/catalog

Use data_plans[].id as plan_id when buying data, cable_plans[].id as plan_id for cable TV, cable_plans[].cable_id when validating a smartcard, and discos[].disco_id for electricity. The plan_id field inside a catalog row is our internal supplier code — don't send it.

curl "https://www.hanansub.com/api/v1/catalog" \
  -H "Authorization: Bearer YOUR_API_KEY"
<?php
$ch = curl_init("https://www.hanansub.com/api/v1/catalog");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer YOUR_API_KEY',
    ],
]);
$response = json_decode(curl_exec($ch), true);
curl_close($ch);

print_r($response);
const res = await fetch("https://www.hanansub.com/api/v1/catalog", {
  headers: {
    "Authorization": "Bearer YOUR_API_KEY"
  }
});
const data = await res.json();
console.log(data);
import requests

res = requests.get(
    "https://www.hanansub.com/api/v1/catalog",
    headers={"Authorization": "Bearer YOUR_API_KEY"},
    timeout=60,
)
print(res.json())
Response · 200
{
    "status": "success",
    "data": {
        "data_plans": [
            {
                "id": 209,
                "network": "GLO",
                "plan_id": "0",
                "plan_name": "1 GB",
                "display_name": "1GB",
                "data_type": "SME",
                "data_size": "1GB",
                "validity": "14 Days",
                "selling_price": "480.00",
                "network_id": 2,
                "cashback_type": null,
                "cashback_value": null
            }
        ],
        "cable_plans": [
            {
                "id": 12,
                "provider": "GOTV",
                "cable_id": "1",
                "plan_id": "gotv-max",
                "plan_name": "GOtv Max",
                "display_name": "GOtv Max",
                "selling_price": "8500.00"
            }
        ],
        "discos": [
            {
                "disco_id": 1,
                "disco_name": "Ikeja Electric",
                "charge": "0.00"
            }
        ],
        "exam_prices": {
            "WAEC": 3500,
            "NECO": 1200
        },
        "recharge_card_prices": {
            "MTN": {
                "100": 98
            }
        },
        "bulk_sms_pricing": {
            "price_per_page": 3,
            "discount_percent": 0,
            "cost_price": 2.5
        },
        "cashback": {
            "airtime": null
        }
    }
}

Buy data

Sends a data bundle to a phone number.

POST /api/v1/data
Body fieldTypeRequiredDescription
plan_idintegerYesThe plan's id from GET /catalog or the data plan table.
phonestringYes11-digit Nigerian number, e.g. 08031234567.
pinstringYesThe account's 4–6 digit transaction PIN (the one set on the website or app). Three wrong PINs lock purchases for 10 minutes. Not needed if your key is locked to your server IPs (details).
request_idstringNoYour own unique order ID (max 64 characters). Send the same ID again — e.g. after a timeout — and you get the original order back (with "duplicate": true) instead of a second purchase.
networkstringNoIgnored — the plan decides the network. Accepted for older integrations.
portedbooleanNoSend true for a number ported to another network, to skip the number-prefix check.
curl -X POST "https://www.hanansub.com/api/v1/data" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"plan_id":209,"phone":"08157038870","pin":"12345","request_id":"order-1002"}'
<?php
$ch = curl_init("https://www.hanansub.com/api/v1/data");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST => true,
    CURLOPT_POSTFIELDS => json_encode([
      'plan_id' => 209,
      'phone' => '08157038870',
      'pin' => '12345',
      'request_id' => 'order-1002',
    ]),
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer YOUR_API_KEY',
        'Content-Type: application/json',
    ],
]);
$response = json_decode(curl_exec($ch), true);
curl_close($ch);

print_r($response);
const res = await fetch("https://www.hanansub.com/api/v1/data", {
  method: "POST",
  headers: {
    "Authorization": "Bearer YOUR_API_KEY",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
      "plan_id": 209,
      "phone": "08157038870",
      "pin": "12345",
      "request_id": "order-1002"
  })
});
const data = await res.json();
console.log(data);
import requests

res = requests.post(
    "https://www.hanansub.com/api/v1/data",
    headers={"Authorization": "Bearer YOUR_API_KEY"},
    json={"plan_id":209,"phone":"08157038870","pin":"12345","request_id":"order-1002"},
    timeout=60,
)
print(res.json())
Response · 200
{
    "status": "success",
    "message": "Data purchase successful",
    "data": {
        "reference": "HANE213826EA8181791581826",
        "cashback_earned": 0,
        "balance_before": 45250,
        "balance_after": 44770
    }
}
Number on a different network
{
    "status": "error",
    "message": "This number looks like an MTN line, not GLO. If it was ported, set ported to true."
}

Buy airtime

Tops up a phone number. Your discount is applied automatically, so you are charged less than the face value.

POST /api/v1/airtime
Body fieldTypeRequiredDescription
networkstringYesMTN, GLO, AIRTEL or 9MOBILE.
phonestringYes11-digit Nigerian number.
amountnumberYesFace value in naira. Default limits ₦50 – ₦10,000 per purchase.
pinstringYesThe account's 4–6 digit transaction PIN (the one set on the website or app). Three wrong PINs lock purchases for 10 minutes. Not needed if your key is locked to your server IPs (details).
portedbooleanNoSend true for a number ported to another network, to skip the number-prefix check.
request_idstringNoYour own unique order ID (max 64 characters). Send the same ID again — e.g. after a timeout — and you get the original order back (with "duplicate": true) instead of a second purchase.
curl -X POST "https://www.hanansub.com/api/v1/airtime" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"network":"MTN","phone":"08031234567","amount":100,"pin":"12345","request_id":"order-1001"}'
<?php
$ch = curl_init("https://www.hanansub.com/api/v1/airtime");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST => true,
    CURLOPT_POSTFIELDS => json_encode([
      'network' => 'MTN',
      'phone' => '08031234567',
      'amount' => 100,
      'pin' => '12345',
      'request_id' => 'order-1001',
    ]),
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer YOUR_API_KEY',
        'Content-Type: application/json',
    ],
]);
$response = json_decode(curl_exec($ch), true);
curl_close($ch);

print_r($response);
const res = await fetch("https://www.hanansub.com/api/v1/airtime", {
  method: "POST",
  headers: {
    "Authorization": "Bearer YOUR_API_KEY",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
      "network": "MTN",
      "phone": "08031234567",
      "amount": 100,
      "pin": "12345",
      "request_id": "order-1001"
  })
});
const data = await res.json();
console.log(data);
import requests

res = requests.post(
    "https://www.hanansub.com/api/v1/airtime",
    headers={"Authorization": "Bearer YOUR_API_KEY"},
    json={"network":"MTN","phone":"08031234567","amount":100,"pin":"12345","request_id":"order-1001"},
    timeout=60,
)
print(res.json())
Response · 200
{
    "status": "success",
    "message": "Airtime purchase successful",
    "data": {
        "reference": "HANE213826EA8181791581826",
        "cashback_earned": 0,
        "balance_before": 45250,
        "balance_after": 45151
    }
}

Verify a smartcard / IUC

Looks up the customer name on a DStv, GOtv or Startimes card before you charge them. Free, but limited to 20 lookups per 5 minutes.

POST /api/v1/validate-cable
Body fieldTypeRequiredDescription
cable_idintegerYesThe provider: cable_plans[].cable_id from the catalog (see the cable table).
smartcardstringYesSmartcard / IUC number.
curl -X POST "https://www.hanansub.com/api/v1/validate-cable" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"cable_id":1,"smartcard":"7023456789"}'
<?php
$ch = curl_init("https://www.hanansub.com/api/v1/validate-cable");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST => true,
    CURLOPT_POSTFIELDS => json_encode([
      'cable_id' => 1,
      'smartcard' => '7023456789',
    ]),
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer YOUR_API_KEY',
        'Content-Type: application/json',
    ],
]);
$response = json_decode(curl_exec($ch), true);
curl_close($ch);

print_r($response);
const res = await fetch("https://www.hanansub.com/api/v1/validate-cable", {
  method: "POST",
  headers: {
    "Authorization": "Bearer YOUR_API_KEY",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
      "cable_id": 1,
      "smartcard": "7023456789"
  })
});
const data = await res.json();
console.log(data);
import requests

res = requests.post(
    "https://www.hanansub.com/api/v1/validate-cable",
    headers={"Authorization": "Bearer YOUR_API_KEY"},
    json={"cable_id":1,"smartcard":"7023456789"},
    timeout=60,
)
print(res.json())
Response · 200
{
    "status": "success",
    "success": true,
    "message": "SmartCard verified successfully.",
    "data": {
        "name": "IBRAHIM MUSA",
        "customer_name": "IBRAHIM MUSA",
        "smartcard": "7023456789"
    }
}

Pay for cable TV

Renews or changes a DStv, GOtv or Startimes subscription.

POST /api/v1/cabletv
Body fieldTypeRequiredDescription
plan_idintegerYesThe package's id from cable_plans (catalog or cable table). The package decides the provider.
smartcardstringYesSmartcard / IUC number. Verify it first with /validate-cable.
pinstringYesThe account's 4–6 digit transaction PIN (the one set on the website or app). Three wrong PINs lock purchases for 10 minutes. Not needed if your key is locked to your server IPs (details).
request_idstringNoYour own unique order ID (max 64 characters). Send the same ID again — e.g. after a timeout — and you get the original order back (with "duplicate": true) instead of a second purchase.
phonestringNoCustomer's phone number, passed to the provider.
curl -X POST "https://www.hanansub.com/api/v1/cabletv" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"plan_id":12,"smartcard":"7023456789","pin":"12345"}'
<?php
$ch = curl_init("https://www.hanansub.com/api/v1/cabletv");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST => true,
    CURLOPT_POSTFIELDS => json_encode([
      'plan_id' => 12,
      'smartcard' => '7023456789',
      'pin' => '12345',
    ]),
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer YOUR_API_KEY',
        'Content-Type: application/json',
    ],
]);
$response = json_decode(curl_exec($ch), true);
curl_close($ch);

print_r($response);
const res = await fetch("https://www.hanansub.com/api/v1/cabletv", {
  method: "POST",
  headers: {
    "Authorization": "Bearer YOUR_API_KEY",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
      "plan_id": 12,
      "smartcard": "7023456789",
      "pin": "12345"
  })
});
const data = await res.json();
console.log(data);
import requests

res = requests.post(
    "https://www.hanansub.com/api/v1/cabletv",
    headers={"Authorization": "Bearer YOUR_API_KEY"},
    json={"plan_id":12,"smartcard":"7023456789","pin":"12345"},
    timeout=60,
)
print(res.json())
Response · 200
{
    "status": "success",
    "message": "Subscription successful",
    "data": {
        "reference": "HANE213826EA8181791581826",
        "cashback_earned": 0,
        "balance_before": 45250,
        "balance_after": 36750
    }
}

Verify a meter

Looks up the customer name and address on a meter. Free, 20 lookups per 5 minutes.

POST /api/v1/validate-meter
Body fieldTypeRequiredDescription
disco_idintegerYesThe electricity company's disco_id (catalog or disco table).
meter_numberstringYesMeter number.
meter_typestringYesprepaid or postpaid.
curl -X POST "https://www.hanansub.com/api/v1/validate-meter" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"disco_id":1,"meter_number":"45031234567","meter_type":"prepaid"}'
<?php
$ch = curl_init("https://www.hanansub.com/api/v1/validate-meter");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST => true,
    CURLOPT_POSTFIELDS => json_encode([
      'disco_id' => 1,
      'meter_number' => '45031234567',
      'meter_type' => 'prepaid',
    ]),
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer YOUR_API_KEY',
        'Content-Type: application/json',
    ],
]);
$response = json_decode(curl_exec($ch), true);
curl_close($ch);

print_r($response);
const res = await fetch("https://www.hanansub.com/api/v1/validate-meter", {
  method: "POST",
  headers: {
    "Authorization": "Bearer YOUR_API_KEY",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
      "disco_id": 1,
      "meter_number": "45031234567",
      "meter_type": "prepaid"
  })
});
const data = await res.json();
console.log(data);
import requests

res = requests.post(
    "https://www.hanansub.com/api/v1/validate-meter",
    headers={"Authorization": "Bearer YOUR_API_KEY"},
    json={"disco_id":1,"meter_number":"45031234567","meter_type":"prepaid"},
    timeout=60,
)
print(res.json())
Response · 200
{
    "status": "success",
    "data": {
        "name": "ADEBAYO OLU",
        "address": "12 Allen Avenue, Ikeja"
    }
}

Pay an electricity bill

Buys prepaid units (returns the token) or pays a postpaid bill.

POST /api/v1/electricity
Body fieldTypeRequiredDescription
disco_idintegerYesThe electricity company's disco_id.
meter_numberstringYesMeter number. Verify it first with /validate-meter.
meter_typestringYesprepaid or postpaid.
amountnumberYesAmount in naira. Default limits ₦1,000 – ₦50,000. A company may add a service charge (see discos[].charge).
pinstringYesThe account's 4–6 digit transaction PIN (the one set on the website or app). Three wrong PINs lock purchases for 10 minutes. Not needed if your key is locked to your server IPs (details).
request_idstringNoYour own unique order ID (max 64 characters). Send the same ID again — e.g. after a timeout — and you get the original order back (with "duplicate": true) instead of a second purchase.
phonestringNoCustomer's phone number.

If the provider is slow, the response has "status": "pending" and "token": null; the token arrives in your webhook and in /receipt.

curl -X POST "https://www.hanansub.com/api/v1/electricity" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"disco_id":1,"meter_number":"45031234567","meter_type":"prepaid","amount":2000,"pin":"12345"}'
<?php
$ch = curl_init("https://www.hanansub.com/api/v1/electricity");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST => true,
    CURLOPT_POSTFIELDS => json_encode([
      'disco_id' => 1,
      'meter_number' => '45031234567',
      'meter_type' => 'prepaid',
      'amount' => 2000,
      'pin' => '12345',
    ]),
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer YOUR_API_KEY',
        'Content-Type: application/json',
    ],
]);
$response = json_decode(curl_exec($ch), true);
curl_close($ch);

print_r($response);
const res = await fetch("https://www.hanansub.com/api/v1/electricity", {
  method: "POST",
  headers: {
    "Authorization": "Bearer YOUR_API_KEY",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
      "disco_id": 1,
      "meter_number": "45031234567",
      "meter_type": "prepaid",
      "amount": 2000,
      "pin": "12345"
  })
});
const data = await res.json();
console.log(data);
import requests

res = requests.post(
    "https://www.hanansub.com/api/v1/electricity",
    headers={"Authorization": "Bearer YOUR_API_KEY"},
    json={"disco_id":1,"meter_number":"45031234567","meter_type":"prepaid","amount":2000,"pin":"12345"},
    timeout=60,
)
print(res.json())
Response · 200
{
    "status": "success",
    "success": true,
    "message": "Electricity purchase successful",
    "pending": false,
    "data": {
        "reference": "HANE213826EA8181791581826",
        "token": "1234-5678-9012-3456-7890",
        "cashback_earned": 0,
        "pending": false,
        "balance_before": 45250,
        "balance_after": 43250
    }
}

Buy exam PINs

WAEC, NECO, NABTEB and other result-checker PINs.

POST /api/v1/exam_pin
Body fieldTypeRequiredDescription
exam_namestringYesExam code, e.g. WAEC, NECO, NABTEB (see the exam table).
quantityintegerYes1 – 5 PINs.
pinstringYesThe account's 4–6 digit transaction PIN (the one set on the website or app). Three wrong PINs lock purchases for 10 minutes. Not needed if your key is locked to your server IPs (details).
request_idstringNoYour own unique order ID (max 64 characters). Send the same ID again — e.g. after a timeout — and you get the original order back (with "duplicate": true) instead of a second purchase.
curl -X POST "https://www.hanansub.com/api/v1/exam_pin" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"exam_name":"WAEC","quantity":1,"pin":"12345"}'
<?php
$ch = curl_init("https://www.hanansub.com/api/v1/exam_pin");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST => true,
    CURLOPT_POSTFIELDS => json_encode([
      'exam_name' => 'WAEC',
      'quantity' => 1,
      'pin' => '12345',
    ]),
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer YOUR_API_KEY',
        'Content-Type: application/json',
    ],
]);
$response = json_decode(curl_exec($ch), true);
curl_close($ch);

print_r($response);
const res = await fetch("https://www.hanansub.com/api/v1/exam_pin", {
  method: "POST",
  headers: {
    "Authorization": "Bearer YOUR_API_KEY",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
      "exam_name": "WAEC",
      "quantity": 1,
      "pin": "12345"
  })
});
const data = await res.json();
console.log(data);
import requests

res = requests.post(
    "https://www.hanansub.com/api/v1/exam_pin",
    headers={"Authorization": "Bearer YOUR_API_KEY"},
    json={"exam_name":"WAEC","quantity":1,"pin":"12345"},
    timeout=60,
)
print(res.json())
Response · 200
{
    "status": "success",
    "message": "Exam PIN purchase successful",
    "data": {
        "reference": "HANE213826EA8181791581826",
        "pins": [
            {
                "pin": "123456789012",
                "serial": "WRN123456789"
            }
        ],
        "balance_before": 45250,
        "balance_after": 41750
    }
}

Print recharge cards

Generates airtime PINs to print or resell. GET /recharge-card returns the networks and the denominations currently available.

POST /api/v1/recharge-card
Body fieldTypeRequiredDescription
network_idintegerYes1 MTN, 2 GLO, 3 AIRTEL, 4 9MOBILE.
denominationintegerYesCard value, e.g. 100, 200, 500 — must be one returned by GET /recharge-card.
quantityintegerNo1 – 50 cards (default 1).
pinstringYesThe account's 4–6 digit transaction PIN (the one set on the website or app). Three wrong PINs lock purchases for 10 minutes. Not needed if your key is locked to your server IPs (details).
request_idstringNoYour own unique order ID (max 64 characters). Send the same ID again — e.g. after a timeout — and you get the original order back (with "duplicate": true) instead of a second purchase.
name_on_cardstringNoBusiness name printed on the cards (max 30 characters).
curl -X POST "https://www.hanansub.com/api/v1/recharge-card" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"network_id":1,"denomination":100,"quantity":2,"pin":"12345","name_on_card":"My Shop"}'
<?php
$ch = curl_init("https://www.hanansub.com/api/v1/recharge-card");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST => true,
    CURLOPT_POSTFIELDS => json_encode([
      'network_id' => 1,
      'denomination' => 100,
      'quantity' => 2,
      'pin' => '12345',
      'name_on_card' => 'My Shop',
    ]),
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer YOUR_API_KEY',
        'Content-Type: application/json',
    ],
]);
$response = json_decode(curl_exec($ch), true);
curl_close($ch);

print_r($response);
const res = await fetch("https://www.hanansub.com/api/v1/recharge-card", {
  method: "POST",
  headers: {
    "Authorization": "Bearer YOUR_API_KEY",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
      "network_id": 1,
      "denomination": 100,
      "quantity": 2,
      "pin": "12345",
      "name_on_card": "My Shop"
  })
});
const data = await res.json();
console.log(data);
import requests

res = requests.post(
    "https://www.hanansub.com/api/v1/recharge-card",
    headers={"Authorization": "Bearer YOUR_API_KEY"},
    json={"network_id":1,"denomination":100,"quantity":2,"pin":"12345","name_on_card":"My Shop"},
    timeout=60,
)
print(res.json())
Response · 200
{
    "status": "success",
    "message": "2 card(s) ready",
    "data": {
        "reference": "HANE213826EA8181791581826",
        "pins": [
            {
                "pin": "1234567890123456",
                "serial": "SN0001"
            },
            {
                "pin": "6543210987654321",
                "serial": "SN0002"
            }
        ]
    }
}

Print data cards

Generates data PINs. GET /data-card?net=MTN lists the plans for a network.

POST /api/v1/data-card
Body fieldTypeRequiredDescription
plan_idintegerYesData plan id (same IDs as /data).
quantityintegerNo1 – 5 cards (default 1).
pinstringYesThe account's 4–6 digit transaction PIN (the one set on the website or app). Three wrong PINs lock purchases for 10 minutes. Not needed if your key is locked to your server IPs (details).
request_idstringNoYour own unique order ID (max 64 characters). Send the same ID again — e.g. after a timeout — and you get the original order back (with "duplicate": true) instead of a second purchase.
curl -X POST "https://www.hanansub.com/api/v1/data-card" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"plan_id":209,"quantity":1,"pin":"12345"}'
<?php
$ch = curl_init("https://www.hanansub.com/api/v1/data-card");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST => true,
    CURLOPT_POSTFIELDS => json_encode([
      'plan_id' => 209,
      'quantity' => 1,
      'pin' => '12345',
    ]),
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer YOUR_API_KEY',
        'Content-Type: application/json',
    ],
]);
$response = json_decode(curl_exec($ch), true);
curl_close($ch);

print_r($response);
const res = await fetch("https://www.hanansub.com/api/v1/data-card", {
  method: "POST",
  headers: {
    "Authorization": "Bearer YOUR_API_KEY",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
      "plan_id": 209,
      "quantity": 1,
      "pin": "12345"
  })
});
const data = await res.json();
console.log(data);
import requests

res = requests.post(
    "https://www.hanansub.com/api/v1/data-card",
    headers={"Authorization": "Bearer YOUR_API_KEY"},
    json={"plan_id":209,"quantity":1,"pin":"12345"},
    timeout=60,
)
print(res.json())
Response · 200
{
    "status": "success",
    "message": "1 card(s) ready",
    "data": {
        "reference": "HANE213826EA8181791581826",
        "pins": [
            {
                "pin": "1234567890",
                "serial": "DC0001"
            }
        ]
    }
}

Send bulk SMS

Sends one message to many numbers. Limited to 20 requests per hour.

POST /api/v1/bulk_sms
Body fieldTypeRequiredDescription
sender_idstringYesSender name shown on phones, max 11 characters.
messagestringYesThe message. Long messages are charged per page (see bulk_sms_pricing in the catalog).
recipientsarray or stringYesPhone numbers as a JSON array, or one string separated by commas or new lines.
pinstringYesThe account's 4–6 digit transaction PIN (the one set on the website or app). Three wrong PINs lock purchases for 10 minutes. Not needed if your key is locked to your server IPs (details).
request_idstringNoYour own unique order ID (max 64 characters). Send the same ID again — e.g. after a timeout — and you get the original order back (with "duplicate": true) instead of a second purchase.
curl -X POST "https://www.hanansub.com/api/v1/bulk_sms" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"sender_id":"MyShop","message":"Your order is ready.","recipients":["08031234567","08051234567"],"pin":"12345"}'
<?php
$ch = curl_init("https://www.hanansub.com/api/v1/bulk_sms");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST => true,
    CURLOPT_POSTFIELDS => json_encode([
      'sender_id' => 'MyShop',
      'message' => 'Your order is ready.',
      'recipients' => [
        '08031234567',
        '08051234567',
      ],
      'pin' => '12345',
    ]),
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer YOUR_API_KEY',
        'Content-Type: application/json',
    ],
]);
$response = json_decode(curl_exec($ch), true);
curl_close($ch);

print_r($response);
const res = await fetch("https://www.hanansub.com/api/v1/bulk_sms", {
  method: "POST",
  headers: {
    "Authorization": "Bearer YOUR_API_KEY",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
      "sender_id": "MyShop",
      "message": "Your order is ready.",
      "recipients": [
          "08031234567",
          "08051234567"
      ],
      "pin": "12345"
  })
});
const data = await res.json();
console.log(data);
import requests

res = requests.post(
    "https://www.hanansub.com/api/v1/bulk_sms",
    headers={"Authorization": "Bearer YOUR_API_KEY"},
    json={"sender_id":"MyShop","message":"Your order is ready.","recipients":["08031234567","08051234567"],"pin":"12345"},
    timeout=60,
)
print(res.json())
Response · 200
{
    "status": "success",
    "message": "SMS sent to 2 recipient(s)",
    "data": {
        "reference": "HANE213826EA8181791581826"
    }
}

Transaction status

Gets one transaction by its reference — use it to check a pending order. If an order has been pending for over 2 minutes, this call also re-checks it with the provider before answering.

GET /api/v1/receipt
Query parameterTypeRequiredDescription
referencestringYesThe reference you got when buying (query string).

data.status is success, pending, processing or failed. A failed order is refunded to your wallet automatically.

curl "https://www.hanansub.com/api/v1/receipt?reference=HANE213826EA8181791581826" \
  -H "Authorization: Bearer YOUR_API_KEY"
<?php
$ch = curl_init("https://www.hanansub.com/api/v1/receipt?reference=HANE213826EA8181791581826");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer YOUR_API_KEY',
    ],
]);
$response = json_decode(curl_exec($ch), true);
curl_close($ch);

print_r($response);
const res = await fetch("https://www.hanansub.com/api/v1/receipt?reference=HANE213826EA8181791581826", {
  headers: {
    "Authorization": "Bearer YOUR_API_KEY"
  }
});
const data = await res.json();
console.log(data);
import requests

res = requests.get(
    "https://www.hanansub.com/api/v1/receipt",
    headers={"Authorization": "Bearer YOUR_API_KEY"},
    params={"reference":"HANE213826EA8181791581826"},
    timeout=60,
)
print(res.json())
Response · 200
{
    "status": "success",
    "success": true,
    "data": {
        "id": 95,
        "reference": "HANE213826EA8181791581826",
        "transaction_ref": "HANE213826EA8181791581826",
        "category": "data",
        "type": "debit",
        "amount": 480,
        "status": "success",
        "description": "GLO 1 GB for 08157038870",
        "phone": "08157038870",
        "balance_before": 45250,
        "balance_after": 44770,
        "charge": 0,
        "provider_ref": null,
        "created_at": "2026-10-09 22:37:06",
        "pins": [],
        "token": null,
        "meta": {},
        "recharge_card": null
    }
}
Unknown reference (404)
{
    "status": "error",
    "success": false,
    "message": "Transaction not found."
}

Transaction history

Your transactions, newest first.

GET /api/v1/transactions
Query parameterTypeRequiredDescription
pageintegerNoPage number (default 1).
per_pageintegerNo10 – 50 (default 20).
filterstringNoOnly one service, e.g. data, airtime, cabletv, electricity.
curl "https://www.hanansub.com/api/v1/transactions?page=1&per_page=20&filter=data" \
  -H "Authorization: Bearer YOUR_API_KEY"
<?php
$ch = curl_init("https://www.hanansub.com/api/v1/transactions?page=1&per_page=20&filter=data");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer YOUR_API_KEY',
    ],
]);
$response = json_decode(curl_exec($ch), true);
curl_close($ch);

print_r($response);
const res = await fetch("https://www.hanansub.com/api/v1/transactions?page=1&per_page=20&filter=data", {
  headers: {
    "Authorization": "Bearer YOUR_API_KEY"
  }
});
const data = await res.json();
console.log(data);
import requests

res = requests.get(
    "https://www.hanansub.com/api/v1/transactions",
    headers={"Authorization": "Bearer YOUR_API_KEY"},
    params={"page":1,"per_page":20,"filter":"data"},
    timeout=60,
)
print(res.json())
Response · 200
{
    "status": "success",
    "data": {
        "transactions": [
            {
                "id": 95,
                "transaction_ref": "HANE213826EA8181791581826",
                "category": "data",
                "amount": "480.00",
                "status": "success",
                "description": "GLO 1 GB for 08157038870",
                "created_at": "2026-10-09 22:37:06"
            }
        ],
        "total": 1,
        "page": 1,
        "per_page": 20,
        "total_pages": 1
    }
}

Webhooks

Set an HTTPS URL on the Developer API page. When any of your purchases reaches a final result — success, or failed (refunded) — we POST it to you. This is how you learn the outcome of a pending order without polling.

HeaderValue
X-Webhook-Eventtransaction.success or transaction.failed
X-Webhook-SignatureHMAC-SHA256 of the raw request body, using your live API key as the secret (your sandbox key if you have no live key), in hex. Check it before trusting the body.
Content-Typeapplication/json
{
    "event": "transaction.success",
    "reference": "HANE213826EA8181791581826",
    "status": "success",
    "service": "electricity",
    "amount": 2000,
    "description": "Ikeja Electric prepaid ₦2,000 for 45031234567",
    "phone": "08031234567",
    "network": null,
    "refunded": false,
    "balance_after": 43250,
    "sandbox": false,
    "created_at": "2026-10-09T22:37:06+01:00",
    "timestamp": "2026-10-09T22:37:40+01:00",
    "token": "1234-5678-9012-3456-7890"
}
  • Reply with any 2xx status within 10 seconds. Otherwise we retry after 1, 5, 15, 60 and 240 minutes, then stop.
  • You may receive the same event more than once — use reference to ignore repeats.
  • Failed orders include a message; electricity includes the token. If you regenerate your live key, signatures use the new key.

Verifying the signature

<?php
$body = file_get_contents('php://input');
$expected = hash_hmac('sha256', $body, 'YOUR_LIVE_API_KEY');
if (!hash_equals($expected, $_SERVER['HTTP_X_WEBHOOK_SIGNATURE'] ?? '')) {
    http_response_code(401);
    exit;
}
$event = json_decode($body, true);
// Look up your order by $event['reference'] and mark it success / failed.
http_response_code(200);
const crypto = require("crypto");
const express = require("express");
const app = express();

app.post("/webhook", express.raw({ type: "application/json" }), (req, res) => {
  const expected = crypto.createHmac("sha256", process.env.LIVE_API_KEY)
    .update(req.body).digest("hex");
  const got = req.get("X-Webhook-Signature") || "";
  if (got.length !== expected.length ||
      !crypto.timingSafeEqual(Buffer.from(got), Buffer.from(expected))) {
    return res.sendStatus(401);
  }
  const event = JSON.parse(req.body);
  // Look up your order by event.reference and mark it success / failed.
  res.sendStatus(200);
});
import hashlib, hmac, json
from flask import Flask, request, abort

app = Flask(__name__)

@app.post("/webhook")
def webhook():
    body = request.get_data()
    expected = hmac.new(b"YOUR_LIVE_API_KEY", body, hashlib.sha256).hexdigest()
    if not hmac.compare_digest(expected, request.headers.get("X-Webhook-Signature", "")):
        abort(401)
    event = json.loads(body)
    # Look up your order by event["reference"] and mark it success / failed.
    return "", 200

Data plan IDs

Live list of active plans. Send the ID as plan_id. Your prices are in GET /catalog.

Data share (1 plans)
IDPlanTypeValidity
209
(3 plans)
IDPlanTypeValidity
214
215
216
SME PLAN (1 plans)
IDPlanTypeValidity
217500MBSME7-Days
MTN (75 plans)
IDPlanTypeValidity
4618.6GB Always On [5500]ALWAYS ON30 Days
4745GB Always On [9000]ALWAYS ON30 Days
2021GB Daily BundleAWOOF1 Day
43GB DTDATA TRANSFER30 Days
55GB DTDATA TRANSFER30 Days
1500MB DTDATA TRANSFER30 Days
21GB DTDATA TRANSFER30 Days
32GB DTDATA TRANSFER30 Days
20334GB Monthly [10000]GIFTING30 Days
775MB Daily [75]GIFTING1 Day
9110MB Daily [100]GIFTING1 Day
11230MB Daily [200]GIFTING1 Day
12500MB Daily [350]GIFTING1 Day
14750MB + 1HR(YT/IG/TT) [450]GIFTING2 Days
131GB + 1.5MINS Daily [500]GIFTING1 Day
24500MB Weekly [500]GIFTING7 Days
171.5GB 2-Days [600]GIFTING2 Days
182GB 2-Days [750]GIFTING2 Days
152.5GB Daily [750]GIFTING1 Day
251.2GB + 1HR(YT/IG/TT) [750]GIFTING7 Days
261GB Weekly [800]GIFTING7 Days
192.5GB 2-Days [900]GIFTING2 Days
163.5GB Daily [1000]GIFTING1 Day
203.2GB 2-Days [1000]GIFTING2 Days
271.5GB Weekly [1000]GIFTING7 Days
214GB 2-Days [1200]GIFTING2 Days
225.5GB 2-Days [1500]GIFTING2 Days
283.5GB Weekly [1500]GIFTING7 Days
372GB + 2MINS Monthly [1500]GIFTING30 Days
237GB 2-Days [1800]GIFTING2 Days
382.7GB + 2MINS Monthly [2000]GIFTING30 Days
296GB Weekly [2500]GIFTING7 Days
393.5GB + 5MINS Monthly [2500]GIFTING30 Days
3011GB Weekly [3500]GIFTING7 Days
417GB Monthly [3500]GIFTING30 Days
3115GB Weekly [4000]GIFTING7 Days
3312.5GB 2-Weeks Plan [4500]GIFTING14 Days
4210GB + 10MINS Monthly [4500]GIFTING30 Days
3220GB Weekly [5000]GIFTING7 Days
4412.5GB Monthly [5500]GIFTING30 Days
3418GB 2-Weeks Plan [6000]GIFTING14 Days
4516.5GB + 10MINS Monthly [6500]GIFTING30 Days
4920GB Monthly [7500]GIFTING
3528GB 2-Weeks Plan [8000]GIFTING14 Days
5025GB Monthly [9000]GIFTING30 Days
3640GB 2-Weeks Plan [10000]GIFTING14 Days
5236GB Monthly [11000]GIFTING30 Days
5365GB Monthly [16000]GIFTING30 Days
5475GB Monthly [18000]GIFTING30 Days
5790GB 2-Month Plan [25000]GIFTING60 Days
55165GB Monthly [35000]GIFTING30 Days
58150GB 2-Month [40000]GIFTING60 Days
56250GB Monthly [55000]GIFTING30 Days
59480GB 3-Month [90000]GIFTING90 Days
60800GB Yearly [125000]GIFTING365 Days
6930GB Monthly Mifi [9000]MIFI30 Days
7060GB Monthly Mifi [14500]MIFI30 Days
71120GB Monthly Mifi [25000]MIFI30 Days
72Silver (150GB FUP Monthly Mifi [30000]MIFI30 Days
73Silver (260GB FUP Monthly Mifi [45000]MIFI
4825GB Postpaid Monthly [7000]POSTPAID30 Days
18040GB Postpaid 3-month [9000]POSTPAID90 Days
221500MBSME7-Days
2181GBSME30-Days
2222GBSME7-Days
2233GBSME7-Days
61200MB Social Daily [100]SOCIAL1 Day
62470MB Social Weekly [200]SOCIAL7 Days
641.2GB Social Daily [450]SOCIAL30 Days
65ThryveTalk Bundles 1500(110 MINS, 300MB, 105 SMS UNITS)THRYVE30 Days
67ThryveData 1500(35 MINS, 1.8GB, 150 SMS UNITS)THRYVE30 Days
66ThryveTalk Bundles 3000(250 MINS, 1GB, 75 SMS UNITS)THRYVE30 Days
406.75GB Value Data [3000]VALUE DATA30 Days
4314.5GB Value Data [5000]VALUE DATA30 Days
5120GB Value Data [10000]VALUE DATA30 Days
GLO (70 plans)
IDPlanTypeValidity
1356.1GB 15 Days [2000]ALWAYS ON15 Days
13615GB 30 Days [3500]ALWAYS ON
13730GB 30 Days [5000]ALWAYS ON30 Days
13845GB 30 Days [7000]ALWAYS ON30 Days
125750MB Daily AwoofAWOOF1 Day
1261.5B Daily AwoofAWOOF1 Day
1272.5B 2-day AwoofAWOOF2 Days
12810GB Weekly AwoofAWOOF7 Days
237200MB CGCorporate Gifting30 Days
119500MB CGCorporate Gifting30 Days
2381GB CGCorporate Gifting3 Days
2391GB CGCorporate Gifting7 Days
1201GB CGCorporate Gifting30 Days
1212GB CGCorporate Gifting30 Days
2403GB CGCorporate Gifting3 Days
2413GB CGCorporate Gifting7-Days
2423GB CGCorporate Gifting30-Days
2435GB CGCorporate Gifting3-Days
2445GB CGCorporate Gifting7-Days
2455GB CGCorporate Gifting30-Days
24610GB CGCorporate Gifting30-Days
15645MB Daily [50]GIFTING1 Day
157125MB Daily [100]GIFTING1 Day
158275MB 2-day [200]GIFTING2 Days
1591.55GB Weekly [500]GIFTING7 Days
1601.1GB 2-Week [750]GIFTING14 Days
1613.7GB Weekly [1000]GIFTING7 Days
1652.6GB Monthly [1000]GIFTING30 Days
1626GB Weekly [1500]GIFTING7 Days
1665.2GB Monthly [1500]GIFTING30 Days
1639GB Weekly [2000]GIFTING7 Days
1676.25GB Monthly [2000]GIFTING30 Days
1687.25GB Monthly [2500]GIFTING30 Days
16910.5GB Monthly [3000]GIFTING30 Days
17012.5GB Monthly [4000]GIFTING30 Days
16424.5GB Weekly [5000]GIFTING7 Days
17116.5GB Monthly [5000]GIFTING30 Days
17220.5GB Monthly [6000]GIFTING30 Days
17328GB Monthly [8000]GIFTING30 Days
17442GB Monthly [10000]GIFTING30 Days
17564GB Monthly [15000]GIFTING30 Days
176107GB Monthly [20000]GIFTING30 Days
204135GB Monthly [25000GIFTING30 Days
177165GB Monthly [30000]GIFTING30 Days
205220GB Monthly [40000]GIFTING30 Days
206310GB 2-month [50000]GIFTING60 Days
178335GB 3-Month [60000]GIFTING90 Days
207475GB 3-month [75000]GIFTING90 Days
1791000GB Yearly [150000]GIFTING365 Days
131500MB 1HR [200]HOURLY1 Day
1321GB 2HRS [300]HOURLY1 Day
145300MB Daily for Social Media [100]MY-G1 Day
1461GB 3-day for Social Media [300]MY-G3 Days
1471.5GB Weekly for Social Media [500]MY-G7 Days
1483.5GB 3-day for Social Media [1000]MY-G30 Days
2081GB 1 Night [100]NIGHT1 Day
129350MB 1 Night [60]NIGHT1 Day
130750MB 1 Night [120]NIGHT
1531GB Daily [350]SPECIAL1 Day
1542GB Daily [500]SPECIAL1 Day
1555.9GB Weekly [1500]SPECIAL7 Days
193Talk More - 5MINS 1DAYTALK MORE1 Day
194Talk More - 10MINS 3DAYSTALK MORE3 Days
195Talk More - 21MINS 7DAYSTALK MORE7 Days
196Talk More - 31MINS 7DAYSTALK MORE7 Days
197Talk More - 52MINS 15DAYSTALK MORE15 Days
198Talk More - 105MINS 15DAYSTALK MORE15 Days
199Talk More - 160MINS 30DAYSTALK MORE30 Days
200Talk More - 215MINS 30DAYSTALK MORE30 Days
201Talk More - 270MINS 30DAYSTALK MORE30 Days
AIRTEL (57 plans)
IDPlanTypeValidity
74150MB Daily PlanAWOOF1 Day
75300MB 2-Days PlanAWOOF2 Days
76600MB 2-Days PlanAWOOF2 Days
771.5GB 1-Day PlanAWOOF1 Day
782GB 2-Days PlanAWOOF2 Days
793GB 2-Days PlanAWOOF2 Days
8010GB Monthly PlanAWOOF30 Days
891GB Daily BingeBINGE1 Day
902GB 2-Day BingeBINGE2 Days
913GB 2-Day BingeBINGE2 Days
924GB 2-Day BingeBINGE2 Days
936GB 2-Day BingeBINGE2 Days
63250MB Daily [50]GIFTING1 Day
8175MB Daily [75]GIFTING1 Day
82110MB Daily [100]GIFTING1 Day
83230MB 2-Day [200]GIFTING1 Day
84300MB 2-Day [300]GIFTING2 Days
94500MB Weekly [500]GIFTING7 Days
951GB Weekly [800]GIFTING7 Days
961.5GB Weekly [1000]GIFTING7 Days
974GB Weekly [500]GIFTING7 Days
1022GB Monthly [1500]GIFTING30 Days
986GB Weekly [2000]GIFTING7 Days
1033GB Monthly [2000]GIFTING30 Days
998GB Weekly [2500]GIFTING7 Days
1044GB Monthly [2500]GIFTING30 Days
10010GB Weekly [3000]GIFTING7 Days
1058GB Monthly [3000]GIFTING30 Days
10610GB Monthly [4000]GIFTING30 Days
10120GB Weekly [5000]GIFTING7 Days
10713GB Monthly [5000]GIFTING30 Days
10818GB Monthly [6000]GIFTING30 Days
10925GB Monthly [8000]GIFTING30 Days
11035GB Monthly [10000]GIFTING30 Days
11260GB Monthly [15000]GIFTING30 Days
113100GB Monthly [20000]GIFTING30 Days
114160GB Monthly [30000]GIFTING30 Days
115210GB Monthly [40000]GIFTING60 Days
116300GB 3-Month [50000]GIFTING90 Days
117350GB 4-Month [60000]GIFTING120 Days
118685GB Yearly [100000]GIFTING365 Days
86200MB 2-Days SocialSOCIAL2 Days
871GB 3-Days SocialSOCIAL3 Days
85500MB 2-Day [350]SOCIAL2 Days
881.5GB Weekly SocialSOCIAL7 Days
187Talk More N100 - 10 MinutesTALK MORE3 Days
188Talk More N200 - 20 MinutesTALK MORE7 Days
189Talk More N300 - 30 MinutesTALK MORE7 Days
190Talk More N500 - 50 MinutesTALK MORE14 Days
191Talk More N1000 - 100 MinutesTALK MORE14 Days
192Talk More N1500 - 150 MinutesTALK MORE30 Days
181UNLIMITED 50MBPS [25000]UNLIMITED30 Days
182UNLIMITED 20MBPS [30000]UNLIMITED30 Days
183UNLIMITED 40MBPS [35000]UNLIMITED30 Days
184UNLIMITED 100MBPS [45000]UNLIMITED30 Days
185UNLIMITED 60MBPS [50000]UNLIMITED30 Days
186UNLIMITED 20MBPS [80000]UNLIMITED90 Days
9mobile (8 plans)
IDPlanTypeValidity
228500MBCORPORATE30-Day
2301GBCORPORATE30-Days
2311.5GBCORPORATE30 Days
2322GBCORPORATE30 Days
2333GBCORPORATE30 Days
2344GBCORPORATE30 Days
2355GBCORPORATE30 Days
23610GBCORPORATE30 Days

Cable plan IDs

Send the package ID as plan_id to /cabletv, and the provider's cable_id to /validate-cable.

Provider IDs: 2 DSTV  

IDPackageProvidercable_id
1DStv Padi - 1 MonthDSTV2

Electricity company IDs

Send as disco_id to /validate-meter and /electricity.

disco_idCompany
13Aba Electricity(APLE)
6Abuja Electricity(AEDC)
2Benin Electricity(BEDC)
1Eko Electricity(EKEDC)
17Enugu Electricity(EEDC)
11Ibadan Electricity(IBEDC)
4Ikeja Electricity(IKEDC)
3Jos Electricity(JED)
21Kaduna Electricity(KAEDCO)
7Kano Electricity Distribution(KEDC)
10Portharcourt Electricity(PHED)
23Yola Electricity(YED)

Exam types

Send the code as exam_name to /exam_pin.

CodeExam
WAECWest African Examinations Council
NECONational Examinations Council
NABTEBNational Business and Technical Examinations Board