Partner API · v1
Sell data, airtime and bills from your own platform
Connect your website, app or bot to EazyPay. Every purchase is one HTTPS request with a JSON body, paid from your EazyPay wallet at your reseller price, and you get the result instantly or by webhook.
Content-Type: application/json) and JSON responsesQuick start
- Log in and open Developer API. Generate a live key (and a sandbox key for testing).
- Call GET /catalog to get plan IDs and your prices.
- Buy with e.g. POST /data, sending your key, the plan ID, the phone number and your transaction PIN.
- 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 EazyPay as a supplier in your own admin panel, exactly like any other supplier — our API speaks the two most common VTU script formats.
YOUR_API_KEY:YOUR_PIN (key, colon, transaction PIN).| Service | Vicom-type URL | MSORG-type URL |
|---|---|---|
| Balance | GET /api/user | GET /api/user/ |
| Airtime | POST /api/airtime | POST /api/topup/ |
| Data | POST /api/data | POST /api/data/ |
| Cable TV | POST /api/cable verify: /api/cable/cable-validation | POST /api/cablesub/ verify: /api/validateiuc |
| Electricity | POST /api/bill verify: /api/bill/bill-validation | POST /api/billpayment/ verify: /api/validatemeter |
| Exam PINs | POST /api/exam | POST /api/epin/ |
| Recharge / data cards | POST /api/recharge_card POST /api/data_card | same |
| Bulk SMS | POST /api/bulk-sms | same |
| Order status | GET /api/transaction/<request-id> | same |
| Plan lists | GET /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:
1MTN,2AIRTEL,3GLO,49MOBILE. MSORG-type:1MTN,2GLO,3AIRTEL,49MOBILE. Network names ("MTN") work too. - Common field spellings are all accepted (
phoneormobile_number,planordata_plan,iucorsmart_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
eaz_live_…and spend real money. Sandbox keys start withsandbox_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:
{
"status": "success",
"message": "Data purchase successful",
"data": {
"reference": "EAZE213826EA8181791581826",
"balance_after": 44770
}
}
Delivered. Keep the reference.
{
"status": "pending",
"success": true,
"pending": true,
"message": "Your order is processing.",
"data": {
"reference": "EAZE213826EA8181791581826"
}
}
Accepted and charged; the provider hasn't confirmed yet. Wait for the webhook or poll /receipt. Do not retry.
{
"status": "error",
"success": false,
"message": "Transaction failed. Your wallet has been refunded.",
"refunded": true,
"reference": "EAZE213826EA8181791581826"
}
The provider declined it and your wallet was refunded. Safe to retry.
{
"status": "error",
"message": "Invalid transaction PIN"
}
Nothing was charged. Fix the request and try again.
| HTTP | Meaning |
|---|---|
| 200 | Success or pending (check status). |
| 400 | Missing/invalid field, wrong PIN, insufficient balance ("Insufficient balance. Please top up your wallet."), or declined and refunded. |
| 401 | Missing, 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. |
| 404 | Unknown transaction reference (/receipt). |
| 405 | Wrong method (e.g. GET on a POST endpoint). |
| 429 | Too many requests — slow down (limits). |
| 500 | Our 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_idwith 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.
curl "https://eazypay.ng/api/v1/balance" \
-H "Authorization: Bearer YOUR_API_KEY"
<?php
$ch = curl_init("https://eazypay.ng/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://eazypay.ng/api/v1/balance", {
headers: {
"Authorization": "Bearer YOUR_API_KEY"
}
});
const data = await res.json();
console.log(data);
import requests
res = requests.get(
"https://eazypay.ng/api/v1/balance",
headers={"Authorization": "Bearer YOUR_API_KEY"},
timeout=60,
)
print(res.json())
{
"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.
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://eazypay.ng/api/v1/catalog" \
-H "Authorization: Bearer YOUR_API_KEY"
<?php
$ch = curl_init("https://eazypay.ng/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://eazypay.ng/api/v1/catalog", {
headers: {
"Authorization": "Bearer YOUR_API_KEY"
}
});
const data = await res.json();
console.log(data);
import requests
res = requests.get(
"https://eazypay.ng/api/v1/catalog",
headers={"Authorization": "Bearer YOUR_API_KEY"},
timeout=60,
)
print(res.json())
{
"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.
| Body field | Type | Required | Description |
|---|---|---|---|
| plan_id | integer | Yes | The plan's id from GET /catalog or the data plan table. |
| phone | string | Yes | 11-digit Nigerian number, e.g. 08031234567. |
| pin | string | Yes | The 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_id | string | No | Your 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. |
| network | string | No | Ignored — the plan decides the network. Accepted for older integrations. |
| ported | boolean | No | Send true for a number ported to another network, to skip the number-prefix check. |
curl -X POST "https://eazypay.ng/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://eazypay.ng/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://eazypay.ng/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://eazypay.ng/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())
{
"status": "success",
"message": "Data purchase successful",
"data": {
"reference": "EAZE213826EA8181791581826",
"cashback_earned": 0,
"balance_before": 45250,
"balance_after": 44770
}
}
{
"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.
| Body field | Type | Required | Description |
|---|---|---|---|
| network | string | Yes | MTN, GLO, AIRTEL or 9MOBILE. |
| phone | string | Yes | 11-digit Nigerian number. |
| amount | number | Yes | Face value in naira. Default limits ₦50 – ₦10,000 per purchase. |
| pin | string | Yes | The 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). |
| ported | boolean | No | Send true for a number ported to another network, to skip the number-prefix check. |
| request_id | string | No | Your 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://eazypay.ng/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://eazypay.ng/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://eazypay.ng/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://eazypay.ng/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())
{
"status": "success",
"message": "Airtime purchase successful",
"data": {
"reference": "EAZE213826EA8181791581826",
"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.
| Body field | Type | Required | Description |
|---|---|---|---|
| cable_id | integer | Yes | The provider: cable_plans[].cable_id from the catalog (see the cable table). |
| smartcard | string | Yes | Smartcard / IUC number. |
curl -X POST "https://eazypay.ng/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://eazypay.ng/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://eazypay.ng/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://eazypay.ng/api/v1/validate-cable",
headers={"Authorization": "Bearer YOUR_API_KEY"},
json={"cable_id":1,"smartcard":"7023456789"},
timeout=60,
)
print(res.json())
{
"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.
| Body field | Type | Required | Description |
|---|---|---|---|
| plan_id | integer | Yes | The package's id from cable_plans (catalog or cable table). The package decides the provider. |
| smartcard | string | Yes | Smartcard / IUC number. Verify it first with /validate-cable. |
| pin | string | Yes | The 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_id | string | No | Your 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. |
| phone | string | No | Customer's phone number, passed to the provider. |
curl -X POST "https://eazypay.ng/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://eazypay.ng/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://eazypay.ng/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://eazypay.ng/api/v1/cabletv",
headers={"Authorization": "Bearer YOUR_API_KEY"},
json={"plan_id":12,"smartcard":"7023456789","pin":"12345"},
timeout=60,
)
print(res.json())
{
"status": "success",
"message": "Subscription successful",
"data": {
"reference": "EAZE213826EA8181791581826",
"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.
| Body field | Type | Required | Description |
|---|---|---|---|
| disco_id | integer | Yes | The electricity company's disco_id (catalog or disco table). |
| meter_number | string | Yes | Meter number. |
| meter_type | string | Yes | prepaid or postpaid. |
curl -X POST "https://eazypay.ng/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://eazypay.ng/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://eazypay.ng/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://eazypay.ng/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())
{
"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.
| Body field | Type | Required | Description |
|---|---|---|---|
| disco_id | integer | Yes | The electricity company's disco_id. |
| meter_number | string | Yes | Meter number. Verify it first with /validate-meter. |
| meter_type | string | Yes | prepaid or postpaid. |
| amount | number | Yes | Amount in naira. Default limits ₦1,000 – ₦50,000. A company may add a service charge (see discos[].charge). |
| pin | string | Yes | The 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_id | string | No | Your 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. |
| phone | string | No | Customer'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://eazypay.ng/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://eazypay.ng/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://eazypay.ng/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://eazypay.ng/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())
{
"status": "success",
"success": true,
"message": "Electricity purchase successful",
"pending": false,
"data": {
"reference": "EAZE213826EA8181791581826",
"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.
| Body field | Type | Required | Description |
|---|---|---|---|
| exam_name | string | Yes | Exam code, e.g. WAEC, NECO, NABTEB (see the exam table). |
| quantity | integer | Yes | 1 – 5 PINs. |
| pin | string | Yes | The 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_id | string | No | Your 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://eazypay.ng/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://eazypay.ng/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://eazypay.ng/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://eazypay.ng/api/v1/exam_pin",
headers={"Authorization": "Bearer YOUR_API_KEY"},
json={"exam_name":"WAEC","quantity":1,"pin":"12345"},
timeout=60,
)
print(res.json())
{
"status": "success",
"message": "Exam PIN purchase successful",
"data": {
"reference": "EAZE213826EA8181791581826",
"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.
| Body field | Type | Required | Description |
|---|---|---|---|
| network_id | integer | Yes | 1 MTN, 2 GLO, 3 AIRTEL, 4 9MOBILE. |
| denomination | integer | Yes | Card value, e.g. 100, 200, 500 — must be one returned by GET /recharge-card. |
| quantity | integer | No | 1 – 50 cards (default 1). |
| pin | string | Yes | The 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_id | string | No | Your 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_card | string | No | Business name printed on the cards (max 30 characters). |
curl -X POST "https://eazypay.ng/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://eazypay.ng/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://eazypay.ng/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://eazypay.ng/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())
{
"status": "success",
"message": "2 card(s) ready",
"data": {
"reference": "EAZE213826EA8181791581826",
"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.
| Body field | Type | Required | Description |
|---|---|---|---|
| plan_id | integer | Yes | Data plan id (same IDs as /data). |
| quantity | integer | No | 1 – 5 cards (default 1). |
| pin | string | Yes | The 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_id | string | No | Your 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://eazypay.ng/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://eazypay.ng/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://eazypay.ng/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://eazypay.ng/api/v1/data-card",
headers={"Authorization": "Bearer YOUR_API_KEY"},
json={"plan_id":209,"quantity":1,"pin":"12345"},
timeout=60,
)
print(res.json())
{
"status": "success",
"message": "1 card(s) ready",
"data": {
"reference": "EAZE213826EA8181791581826",
"pins": [
{
"pin": "1234567890",
"serial": "DC0001"
}
]
}
}
Send bulk SMS
Sends one message to many numbers. Limited to 20 requests per hour.
| Body field | Type | Required | Description |
|---|---|---|---|
| sender_id | string | Yes | Sender name shown on phones, max 11 characters. |
| message | string | Yes | The message. Long messages are charged per page (see bulk_sms_pricing in the catalog). |
| recipients | array or string | Yes | Phone numbers as a JSON array, or one string separated by commas or new lines. |
| pin | string | Yes | The 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_id | string | No | Your 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://eazypay.ng/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://eazypay.ng/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://eazypay.ng/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://eazypay.ng/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())
{
"status": "success",
"message": "SMS sent to 2 recipient(s)",
"data": {
"reference": "EAZE213826EA8181791581826"
}
}
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.
| Query parameter | Type | Required | Description |
|---|---|---|---|
| reference | string | Yes | The 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://eazypay.ng/api/v1/receipt?reference=EAZE213826EA8181791581826" \
-H "Authorization: Bearer YOUR_API_KEY"
<?php
$ch = curl_init("https://eazypay.ng/api/v1/receipt?reference=EAZE213826EA8181791581826");
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://eazypay.ng/api/v1/receipt?reference=EAZE213826EA8181791581826", {
headers: {
"Authorization": "Bearer YOUR_API_KEY"
}
});
const data = await res.json();
console.log(data);
import requests
res = requests.get(
"https://eazypay.ng/api/v1/receipt",
headers={"Authorization": "Bearer YOUR_API_KEY"},
params={"reference":"EAZE213826EA8181791581826"},
timeout=60,
)
print(res.json())
{
"status": "success",
"success": true,
"data": {
"id": 95,
"reference": "EAZE213826EA8181791581826",
"transaction_ref": "EAZE213826EA8181791581826",
"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
}
}
{
"status": "error",
"success": false,
"message": "Transaction not found."
}
Transaction history
Your transactions, newest first.
| Query parameter | Type | Required | Description |
|---|---|---|---|
| page | integer | No | Page number (default 1). |
| per_page | integer | No | 10 – 50 (default 20). |
| filter | string | No | Only one service, e.g. data, airtime, cabletv, electricity. |
curl "https://eazypay.ng/api/v1/transactions?page=1&per_page=20&filter=data" \
-H "Authorization: Bearer YOUR_API_KEY"
<?php
$ch = curl_init("https://eazypay.ng/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://eazypay.ng/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://eazypay.ng/api/v1/transactions",
headers={"Authorization": "Bearer YOUR_API_KEY"},
params={"page":1,"per_page":20,"filter":"data"},
timeout=60,
)
print(res.json())
{
"status": "success",
"data": {
"transactions": [
{
"id": 95,
"transaction_ref": "EAZE213826EA8181791581826",
"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.
| Header | Value |
|---|---|
| X-Webhook-Event | transaction.success or transaction.failed |
| X-Webhook-Signature | HMAC-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-Type | application/json |
{
"event": "transaction.success",
"reference": "EAZE213826EA8181791581826",
"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
referenceto ignore repeats. - Failed orders include a
message; electricity includes thetoken. 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.
ALPHA (8 plans)
| ID | Plan | Type | Validity |
|---|---|---|---|
| 240 | Alpha N600 - ₦600 (30days ) | alpha | 30DAY |
| 241 | Alpha N1100 - ₦1,100 (30 days) | alpha | 30DAY |
| 242 | Alpha N1600 - ₦1,600 (30 days) | alpha | 30DAY |
| 243 | Alpha N2100 - ₦2,100 (30 days) | alpha | 30DAY |
| 244 | Alpha N2600 - ₦2,600 (30 days) | alpha | 30DAY |
| 245 | Alpha N3120 - ₦3,120 (30 days) | alpha | 30DAY |
| 246 | Alpha N3620 - ₦3,620 (30 days) | alpha | 30DAY |
| 247 | Alpha N4150 - ₦4,150 (30 days) | alpha | 30DAY |
(6 plans)
| ID | Plan | Type | Validity |
|---|---|---|---|
| 212 | 500mb🤝 | CG | 30days |
| 209 | 1GB 30Days plan | CG | |
| 210 | 2GB 30Days plan | CG | 30 Days |
| 211 | 3GB | CG | 30Days |
| 213 | 5GB 30 Days plan | CG | 30 Days |
| 234 | 1.5GB [900] | COOPERATE GIFTING | 30 Days |
KIRANI (15 plans)
| ID | Plan | Type | Validity |
|---|---|---|---|
| 283 | 30 Minutes | kirani | 30DAY |
| 284 | 50 Minutes - ₦800 (30days) | kirani | 30DAY |
| 285 | 70 Minutes - ₦1,090 (30 days) | kirani | 30DAY |
| 286 | 100 Minutes - ₦1,580 (30 days) | kirani | 30DAY |
| 287 | 150 Minutes - ₦2,350 (30 days) | kirani | 30DAY |
| 288 | 200 Minutes - ₦3,100 (30 days) | kirani | 30DAY |
| 289 | 250 Minutes - ₦3,900 (30 days) | kirani | 30DAY |
| 290 | 300 Minutes - ₦4,600 (30 days) | kirani | 30DAY |
| 291 | 350 Minutes - ₦5,350 (30days) | kirani | 30DAY |
| 292 | 400 Minutes - ₦6,100 (30 days) | kirani | 30DAY |
| 293 | 500 Minutes - ₦7,600 (30 days) | kirani | 30DAY |
| 294 | 600 Minutes - ₦9,250 (30 days) | kirani | 30DAY |
| 295 | 700 Minutes - ₦10,800 (30 days) | kirani | 30DAY |
| 296 | 800 Minutes - ₦12,300 (30 days) | kirani | 30DAY |
| 297 | 900 Minutes - ₦13,850 (30 days) | kirani | 30DAY |
SMILE (35 plans)
| ID | Plan | Type | Validity |
|---|---|---|---|
| 253 | 1GB flexidaily - ₦450 (1 days) | smile | 1DAY |
| 254 | 2.5GB FlexiDaily - ₦750 (2 days) | smile | 2DAY |
| 255 | 1GB flexiweekly - ₦750 (30 days) | smile | 30DAY |
| 248 | SmileVoice ONLY 65 - ₦900 (30 days) | smile | 30DAY |
| 279 | 2GB midnight - ₦1,100 (7days ) | smile | 7DAY |
| 258 | 2GB FlexiWeekly - ₦1,550 (7days) | smile | 7DAY |
| 259 | 1.5GB Bigga - ₦1,550 (30days) | smile | 30DAY |
| 280 | 3GB midnight - ₦1,650 (7days ) | smile | 7DAY |
| 281 | 3GB weekend only - ₦1,650 (1 weekend) | smile | 1WEEK |
| 249 | SmileVoice ONLY 135 - ₦1,850 (30 days) | smile | 30DAY |
| 261 | 3GB Bigga - ₦2,300 (30days) | smile | 30DAY |
| 256 | SmileVoice ONLY 150 - ₦2,700 (60days) | smile | 60DAY |
| 262 | 5GB Bigga - ₦3,100 (30days) | smile | 30DAY |
| 257 | SmileVoice ONLY 175 - ₦3,600 (90days) | smile | 90DAY |
| 263 | 6.5GB Bigga - ₦3,800 (30 days) | smile | 30DAY |
| 264 | 10GB Bigga - ₦4,600 (30days) | smile | 30DAY |
| 250 | SmileVoice ONLY 430 - ₦5,700 (30 days) | smile | 30DAY |
| 251 | SmileVoice ONLY 450 - ₦7,200 (60 days) | smile | 60DAY |
| 271 | 20GB Bigger - ₦8,000 (30 days) | smile | 30DAY |
| 252 | SmileVoice ONLY 500 - ₦9,000 (90days) | smile | 90DAY |
| 272 | 25GB Bigger - ₦9,500 (30 days) | smile | 30DAY |
| 273 | 30GB Bigger - ₦12,500 (30 days) | smile | 30DAY |
| 265 | 15GB 365 - ₦14,000 (360 days) | smile | 360DAY |
| 277 | Smile Maxi Lite - ₦15,000 (30 days) | smile | 30DAY |
| 274 | 40 Bigger - ₦15,500 (30 days) | smile | 30DAY |
| 260 | 2GB Bigga - ₦18,000 (30days) | smile | 30DAY |
| 275 | 60 Bigger - ₦21,000 (30 days) | smile | 30DAY |
| 276 | 75 Bigger - ₦23,000 (30 days) | smile | 30DAY |
| 278 | Smile MAXI Essentials - ₦27,700 (30 days) | smile | 30DAY |
| 267 | 35GB 365 - ₦29,000 (360 days) | smile | 360DAY |
| 268 | 90GB Jumbo - ₦31,000 (60days) | smile | 60DAY |
| 282 | Smile Maxi Home - ₦38,500 (30 days) | smile | 30DAY |
| 270 | Smile Maxi Office - ₦45,000 (30 days) | smile | 30DAY |
| 269 | 160GB Jumbo - ₦53,000 (90days ) | smile | 90DAY |
| 266 | Smile MAXI Data Flux - ₦61,500 (30 days) | smile | 30DAY |
MTN (69 plans)
| ID | Plan | Type | Validity |
|---|---|---|---|
| 7 | 75MB Daily [75] | GIFTING | 1 Day |
| 9 | 110MB Daily [100] | GIFTING | 1 Day |
| 11 | 230MB Daily [230] | GIFTING | 1 Day |
| 62 | 470MB Social Weekly [250] | GIFTING | 7 Days |
| 12 | 500MB Daily [350] | GIFTING | 1 Day |
| 14 | 750MB + 1HR(YT/IG/TT) [450] | GIFTING | 2 Days |
| 64 | 1.2GB Social bundle [500] | GIFTING | 30 Days |
| 24 | 500MB Weekly [500] | GIFTING | 7 Days |
| 17 | 1.5GB 2-Days [600] | GIFTING | 2 Days |
| 18 | 2GB 2-Days [750] | GIFTING | 2 Days |
| 25 | 1.2GB + 1HR(YT/IG/TT) [750] | GIFTING | 7 Days |
| 26 | 1GB Weekly [800] | GIFTING | 7 Days |
| 15 | 2.5GB Daily [800] | GIFTING | 1 Day |
| 19 | 2.5GB 2-Days [900] | GIFTING | 2 Days |
| 20 | 3.2GB 2-Days [1000] | GIFTING | 2 Days |
| 16 | 3.5GB Daily [1050] | GIFTING | 1 Day |
| 27 | 1.5GB Weekly [1100] | GIFTING | 7 Days |
| 21 | 4GB 2-Days [1200] | GIFTING | 2 Days |
| 37 | 2GB + 2MINS Monthly [1500] | GIFTING | 30 Days |
| 22 | 6.5GB 2-Days [1600] | GIFTING | 2 Days |
| 28 | 3.5GB Weekly [1600] | GIFTING | 7 Days |
| 23 | 8GB 2-Days [1900] | GIFTING | 2 Days |
| 38 | 2.7GB + 2MINS Monthly [2000] | GIFTING | 30 Days |
| 39 | 3.5GB + 5MINS Monthly [2500] | GIFTING | 30 Days |
| 29 | 7.2GB Weekly [2700] | GIFTING | 7 Days |
| 40 | 6.75GB Value Data [3100] | GIFTING | 30 Days |
| 41 | 7GB Monthly [3500] | GIFTING | 30 Days |
| 30 | 11GB Weekly [3600] | GIFTING | 7 Days |
| 31 | 15GB Weekly [4500] | GIFTING | 7 Days |
| 33 | 12.5GB 2-Weeks Plan [4500] | GIFTING | 14 Days |
| 42 | 10GB + 10MINS Monthly [4500] | GIFTING | 30 Days |
| 32 | 20GB Weekly [5500] | GIFTING | 7 Days |
| 44 | 12.5GB Monthly [5500] | GIFTING | 30 Days |
| 45 | 16.5GB + 10MINS Monthly [6500] | GIFTING | 30 Days |
| 49 | 20GB Monthly [7500] | GIFTING | |
| 50 | 25GB Monthly [9000] | GIFTING | 30 Days |
| 203 | 34GB Monthly [10500] | GIFTING | 30 Days |
| 52 | 36GB Monthly [11500] | GIFTING | 30 Days |
| 53 | 65GB Monthly [16000] | GIFTING | 30 Days |
| 54 | 75GB Monthly [18000] | GIFTING | 30 Days |
| 57 | 90GB 2-Month Plan [25000] | GIFTING | 60 Days |
| 55 | 165GB Monthly [35000] | GIFTING | 30 Days |
| 58 | 150GB 2-Month [40000] | GIFTING | 60 Days |
| 56 | 250GB Monthly [55000] | GIFTING | 30 Days |
| 59 | 480GB 3-Month [90000] | GIFTING | 90 Days |
| 60 | 800GB Yearly [125000] | GIFTING | 365 Days |
| 69 | 30GB Monthly Mifi [9000] | MIFI | 30 Days |
| 70 | 60GB Monthly Mifi [14500] | MIFI | 30 Days |
| 71 | 120GB Monthly Mifi [25000] | MIFI | 30 Days |
| 72 | Silver (150GB FUP Monthly Mifi [30000] | MIFI | 30 Days |
| 73 | Silver (260GB FUP Monthly Mifi [45000] | MIFI | |
| 214 | 500MB | MTN CG | 30 Days |
| 215 | 1GB | MTN CG | 30Days |
| 216 | 2GB | MTN CG | 30 Days |
| 217 | 3GB | MTN CG | 30 Days |
| 218 | 5GB | MTN CG | 30 Days |
| 223 | 1GB MONTHLY | PROMO | 30 Days |
| 224 | 5GB Bundle: | PROMO | 30 Days |
| 43 | 15GB Value Data [5500] | PROMO | 30 Days |
| 1 | 500MB | SME | 30days |
| 2 | 1GB DT | SME | 30 Days |
| 220 | 2GB | SME | 7 Days |
| 3 | 2GB DT | SME | 30 days |
| 221 | 3GB | SME | 7 Days |
| 4 | 3GB | SME | 30 Days |
| 222 | 5GB | SME | 7 Days |
| 5 | 5GB DT | SME | 30 days |
| 6 | 10GB | SME | 30 Days |
| 306 | 15GB | SME | 30 Days |
Mtn (1 plans)
| ID | Plan | Type | Validity |
|---|---|---|---|
| 219 | 1GB 7 Days | SME | 7 Days |
GLO (40 plans)
| ID | Plan | Type | Validity |
|---|---|---|---|
| 125 | 750MB Daily Awoof | AWOOF | 1 Day |
| 126 | 1.5B Daily Awoof | AWOOF | 1 Day |
| 127 | 2.5B 2-day Awoof | AWOOF | 2 Days |
| 128 | 10GB Weekly Awoof | AWOOF | 7 Days |
| 302 | 200MB | Corporate Gifting | 30 Days |
| 119 | 500MB CG | Corporate Gifting | 30 Days |
| 120 | 1GB CG | Corporate Gifting | 30 Days |
| 121 | 2GB CG | Corporate Gifting | 30 Days |
| 123 | 5GB CG | Corporate Gifting | 30 Days |
| 124 | 10GB CG | Corporate Gifting | 30 Days |
| 156 | 45MB Daily [60] | GIFTING | 1 Day |
| 161 | 3.7GB Weekly [1000] | GIFTING | 7 Days |
| 165 | 2.6GB Monthly [1000] | GIFTING | 30 Days |
| 166 | 5.2GB Monthly [1500] | GIFTING | 30 Days |
| 163 | 9GB Weekly [2000] | GIFTING | 7 Days |
| 167 | 6.25GB Monthly [2000] | GIFTING | 30 Days |
| 168 | 7.25GB Monthly [2500] | GIFTING | 30 Days |
| 169 | 10.5GB Monthly [3500] | GIFTING | 30 Days |
| 170 | 12.5GB Monthly [4500] | GIFTING | 30 Days |
| 164 | 24.5GB Weekly [5000] | GIFTING | 7 Days |
| 171 | 16.5GB Monthly [5000] | GIFTING | 30 Days |
| 172 | 20.5GB Monthly [6000] | GIFTING | 30 Days |
| 173 | 28GB Monthly [8000] | GIFTING | 30 Days |
| 174 | 42GB Monthly [10000] | GIFTING | 30 Days |
| 175 | 64GB Monthly [15000] | GIFTING | 30 Days |
| 176 | 107GB Monthly [20000] | GIFTING | 30 Days |
| 204 | 135GB Monthly [25000 | GIFTING | 30 Days |
| 177 | 165GB Monthly [30000] | GIFTING | 30 Days |
| 205 | 220GB Monthly [40000] | GIFTING | 30 Days |
| 206 | 310GB 2-month [50000] | GIFTING | 60 Days |
| 178 | 380GB 3-Month [60000] | GIFTING | 90 Days |
| 207 | 475GB 3-month [75000] | GIFTING | 90 Days |
| 179 | 1000GB Yearly [150000] | GIFTING | 365 Days |
| 145 | 300MB Daily for Social Media [100] | MY-G | 1 Day |
| 146 | 1GB 3-day for Social Media [300] | MY-G | 3 Days |
| 147 | 1.5GB Weekly for Social Media [500] | MY-G | 7 Days |
| 148 | 3.5GB 3-day for Social Media [1000] | MY-G | 30 Days |
| 153 | 1GB Daily [350] | SPECIAL | 1 Days |
| 154 | 2GB Daily [500] | SPECIAL | 1 Day |
| 155 | 5.9GB Weekly [1500] | SPECIAL | 7 Days |
Glo (4 plans)
| ID | Plan | Type | Validity |
|---|---|---|---|
| 303 | 1GB | Corporate Gifting | 7 Days |
| 304 | 3GB | Corporate Gifting | 7 Days |
| 298 | 3GB CG | Corporate Gifting | 30 Days |
| 305 | 5GB | Corporate Gifting | 7 Days |
AIRTEL (43 plans)
| ID | Plan | Type | Validity |
|---|---|---|---|
| 74 | 150MB Daily Plan | AWOOF | 1 Day |
| 75 | 300MB 2-Days Plan | AWOOF | 2 Days |
| 76 | 600MB 2-Days Plan | AWOOF | 2 Days |
| 77 | 1.5GB 1-Day Plan | AWOOF | 1 Day |
| 78 | 2GB 2-Days Plan | AWOOF | 2 Days |
| 79 | 3GB 2-Days Plan | AWOOF | 2 Days |
| 80 | 10GB Monthly Plan | AWOOF | 30 Days |
| 225 | 500MB | COOPERATE GIFTING | 7 Days |
| 226 | 1GB | COOPERATE GIFTING | 7 Days |
| 227 | 2GB | COOPERATE GIFTING | 30 Days |
| 81 | 75MB Daily [75] | GIFTING | 1 Day |
| 82 | 110MB Daily [100] | GIFTING | 1 Day |
| 83 | 230MB 2-Day [250] | GIFTING | Days |
| 84 | 300MB 2-Day [300] | GIFTING | 2 Days |
| 94 | 500MB Weekly [500] | GIFTING | 7 Days |
| 95 | 1GB Weekly [800] | GIFTING | 7 Days |
| 96 | 1.5GB Weekly [1000] | GIFTING | 7 Days |
| 97 | 4GB Weekly [500] | GIFTING | 7 Days |
| 102 | 2GB Monthly [1500] | GIFTING | 30 Days |
| 98 | 6GB Weekly [2000] | GIFTING | 7 Days |
| 103 | 3GB Monthly [2000] | GIFTING | 30 Days |
| 104 | 4GB Monthly [2500] | GIFTING | 30 Days |
| 99 | 8GB Weekly [2600] | GIFTING | 7 Days |
| 100 | 10GB Weekly | GIFTING | 7 Days |
| 105 | 8GB Monthly [3000] | GIFTING | 30 Days |
| 106 | 10GB Monthly [4000] | GIFTING | 30 Days |
| 107 | 13GB Monthly [5000] | GIFTING | 30 Days |
| 101 | 20GB Weekly [5000] | GIFTING | 7 Days |
| 108 | 18GB Monthly [6000] | GIFTING | 30 Days |
| 109 | 25GB Monthly [8000] | GIFTING | 30 Days |
| 110 | 35GB Monthly [10000] | GIFTING | 30 Days |
| 112 | 60GB Monthly [15000] | GIFTING | 30 Days |
| 113 | 100GB Monthly [20000] | GIFTING | 30 Days |
| 86 | 200MB 2-Days Social | SOCIAL | 2 Days |
| 87 | 1GB 3-Days Social plan | SOCIAL | 3 Days |
| 85 | 500MB 2-Day [350] | SOCIAL | 2 Days |
| 88 | 1.5GB Weekly Social plan | SOCIAL | 7 Days |
| 181 | UNLIMITED 50MBPS [25000] | UNLIMITED | 30 Days |
| 182 | UNLIMITED 20MBPS [30000] | UNLIMITED | 30 Days |
| 183 | UNLIMITED 40MBPS [35000] | UNLIMITED | 30 Days |
| 184 | UNLIMITED 100MBPS [45000] | UNLIMITED | 30 Days |
| 185 | UNLIMITED 60MBPS [50000] | UNLIMITED | 30 Days |
| 186 | UNLIMITED 20MBPS [80000] | UNLIMITED | 90 Days |
Airtel (7 plans)
| ID | Plan | Type | Validity |
|---|---|---|---|
| 228 | 3.5GB | COOPERATE GIFTING | 7 Days |
| 230 | 5GB [2000] | COOPERATE GIFTING | 7 Days |
| 229 | 4GB | COOPERATE GIFTING | 30 Days |
| 299 | 10GB | COOPERATE GIFTING | 7 Days |
| 231 | 8GB | COOPERATE GIFTING | 30 Days |
| 300 | 10GB | COOPERATE GIFTING | 30 Days |
| 301 | 25GB | COOPERATE GIFTING | 30 Days |
9MOBILE (7 plans)
| ID | Plan | Type | Validity |
|---|---|---|---|
| 232 | 500MB | COOPERATE GIFTING | 7 Days |
| 233 | 1GB [600] | COOPERATE GIFTING | 30 Days |
| 235 | 2GB [1200] | COOPERATE GIFTING | 7 Days |
| 236 | 3GB [1800] | COOPERATE GIFTING | 30 Days |
| 237 | 4GB | COOPERATE GIFTING | 30 Days |
| 238 | 5GB [3000] | COOPERATE GIFTING | 30 Days |
| 239 | 10GB [6000] | COOPERATE GIFTING | 30 Days |
Cable plan IDs
Send the package ID as plan_id to /cabletv, and the provider's cable_id to /validate-cable.
Provider IDs: 0 STARTIMES 2 DSTV 1 GOTV 3 STARTIMES 107 STARTIMES
| ID | Package | Provider | cable_id |
|---|---|---|---|
| 53 | DStv Compact Plus Movie Bundle Add-on E36 - | DSTV | 0 |
| 56 | DStv Movie Bundle Add-on | DSTV | 0 |
| 54 | DStv Showmax Premier League Add-on | DSTV | 0 |
| 70 | DStv Great Wall Standalone Bouquet | DSTV | 0 |
| 2 | DSTV Padi | DSTV | 2 |
| 6 | DSTV Yanga | DSTV | 0 |
| 69 | DStv French Touch Add-on | DSTV | 0 |
| 66 | DStv Great Wall Standalone Bouquet + Showmax | DSTV | 0 |
| 67 | DStv Yanga + Showmax | DSTV | 0 |
| 62 | DStv Padi + Showmax | DSTV | 0 |
| 5 | DSTV Padi+Extraview | DSTV | 0 |
| 68 | DStv French 11 | DSTV | 0 |
| 7 | DSTV Confam | DSTV | 0 |
| 4 | DSTV Yanga+Extraview | DSTV | 0 |
| 64 | Dstv Confam + Showmax | DSTV | 0 |
| 57 | DStv India Add-on | DSTV | 0 |
| 58 | DStv Indian | DSTV | 0 |
| 3 | DSTV comfam+Extraview | DSTV | 0 |
| 51 | DStv Compact | DSTV | 0 |
| 61 | DStv Asia + Showmax | DSTV | 0 |
| 63 | DStv Compact + Showmax | DSTV | 0 |
| 71 | DStv French Plus Add-on | DSTV | 0 |
| 78 | DStv Compact + Extra View | DSTV | 0 |
| 77 | DStv Compact + French Touch | DSTV | 0 |
| 81 | DStv Compact Plus | DSTV | 0 |
| 65 | DStv Compact Plus + Showmax | DSTV | 0 |
| 75 | DStv Compact + French Touch + ExtraView | DSTV | 0 |
| 82 | DStv Premium | DSTV | 0 |
| 73 | DStv Compact + French Plus | DSTV | 0 |
| 59 | DStv Premium + Showmax | DSTV | 0 |
| 76 | DStv Premium + Extra View | DSTV | 0 |
| 79 | DStv Premium-Asia | DSTV | 0 |
| 55 | DStv Premium W/Afr + Showmax | DSTV | 0 |
| 74 | DStv Compact Plus + French Plus | DSTV | 0 |
| 60 | DStv Premium + French + Showmax | DSTV | 0 |
| 80 | DStv Premium-French | DSTV | 0 |
| 72 | DStv Premium + French + Extra View | DSTV | 0 |
| 11 | GOtv Smallie -monthly | GOTV | 1 |
| 12 | GOtv jinja | GOTV | 1 |
| 83 | GOtv Smallie - quarterly | GOTV | 0 |
| 13 | GOtv Jolli | GOTV | 0 |
| 14 | GOtv Max | GOTV | 1 |
| 84 | GOtv Supa - monthly | GOTV | 0 |
| 85 | GOtv Smallie - yearly | GOTV | 0 |
| 15 | GOtv Supa Plus-monthly | GOTV | 0 |
| 23 | Nova (Antenna) - 1 Week | STARTIMES | 0 |
| 24 | Basic (Antenna)- 1 Week | STARTIMES | 0 |
| 25 | Basic (Dish) - 1 Week | STARTIMES | 0 |
| 16 | Nova- 1 Month | STARTIMES | 3 |
| 26 | Classic (Antenna) - 1 Week | STARTIMES | 3 |
| 27 | Classic (Antenna) - 1 Week | STARTIMES | 3 |
| 30 | Classic (Dish) - 1 Week | STARTIMES | 0 |
| 34 | Classic (Dish) - 1 Week | STARTIMES | 0 |
| 37 | Startimes SHS - Weekly | STARTIMES | 0 |
| 32 | Super (Antenna) - 1 Week | STARTIMES | 0 |
| 28 | Super (Dish)- 1 Week | STARTIMES | 0 |
| 18 | Basic (Antenna) -1 month | STARTIMES | 107 |
| 38 | Startimes SHS -Weekly | STARTIMES | 0 |
| 19 | Basic (Dish) -1 month | STARTIMES | 3 |
| 17 | Classic (Antenna) -1 month | STARTIMES | 3 |
| 36 | Global (Dish) - 1Week | STARTIMES | 0 |
| 31 | Classic (Dish) - 1 Month | STARTIMES | 0 |
| 39 | Startimes SHS - Weekly | STARTIMES | 0 |
| 33 | Super (Antenna) - 1 Month | STARTIMES | 0 |
| 22 | Super (Dish) 1Month | STARTIMES | 3 |
| 40 | Startimes SHS - Monthly | STARTIMES | 0 |
| 41 | Startimes SHS - Monthly | STARTIMES | 0 |
| 35 | Global (Dish) - 1 Month | STARTIMES | 0 |
| 29 | Chinese (Dish) - 1 month | STARTIMES | 0 |
| 42 | Startimes SHS - Monthly | STARTIMES | 0 |
| 43 | Startimes SHS -Monthly | STARTIMES | 0 |
Electricity company IDs
Send as disco_id to /validate-meter and /electricity.
| disco_id | Company |
|---|---|
| 11 | Aba Electricity |
| 8 | Abuja Electricity |
| 9 | Benin |
| 2 | Eko Electricity |
| 10 | Enugu Electricity |
| 6 | Ibadan Electricity |
| 1 | Ikeja Electricity |
| 5 | Jos Electricity |
| 7 | Kaduna Electricity |
| 3 | Kano Electricity |
| 4 | Post Harcourt Electricity |
| 12 | Yola Electricity |
Exam types
Send the code as exam_name to /exam_pin.
No exam types are active right now.
