InstantMobile VTU API
Sell data, airtime, cable TV and electricity from your own website, mobile app, POS or bot, using the same automated infrastructure that powers InstantMobile. This guide takes you from zero to your first live transaction, then explains every service in detail.
How it works
Your customers never talk to us directly. They pay you, your server sends the request to our API, we deliver the service and reply with the result. You decide your own selling prices and keep the difference.
01 Quick start
- Create an account. Register for free if you do not have one yet.
- Upgrade to an API plan. Go to Upgrade and choose the API / Developer package. API access is only available on that plan.
- Copy your API key. Open Profile > API. Your key is generated automatically. Keep it secret.
- Fund your wallet. Every API purchase is paid from your wallet balance, so add funds from Fund wallet.
- Make your first call. Check your balance to confirm everything works:
curl -X GET "https://instantmobile.com.ng/api/v1.php?action=balance" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Accept: application/json"
If you get "status": "success" with your balance, you are ready. If you get a 401 error, check that you copied the key correctly and that your account is on the API plan.
02 Base URL & request format
All requests go to one URL. You choose what to do with the action query parameter.
https://instantmobile.com.ng/api/v1.php- GET requests read information (balance, plan lists). They take no body.
- POST requests buy something. Send the parameters as a JSON body with
Content-Type: application/json. - Every response is JSON.
- Always call the API over HTTPS.
| Header | Value | When |
|---|---|---|
Authorization | Bearer YOUR_API_KEY | Every request |
Content-Type | application/json | POST requests |
Accept | application/json | Recommended |
03 Authentication
Every request must include your API key as a Bearer token in the Authorization header. The key identifies your account and the wallet that will be charged.
04 Responses & errors
Every response has a status field. Check it first.
Success
{
"status": "success",
"message": "Data delivered",
"reference": "DAT_51bd02e7"
}Error
{
"status": "error",
"message": "Insufficient balance"
}| HTTP code | Meaning | What to do |
|---|---|---|
200 | Success | Read the response and complete your order. |
400 | Bad request | A parameter is missing or wrong. Read the message and fix your request. |
401 | Unauthorized | Your key is missing, wrong, or your account is not on the API plan. |
402 | Insufficient balance | Fund your wallet, then try again. |
429 | Rate limited | You sent more than 60 requests in a minute. Wait and retry. |
500 | Server error | Something went wrong on our side. Do not retry purchases blindly, see the next section. |
05 References, retries & avoiding double charges
Purchases cost real money, so handle them carefully:
- Send your own unique
referencewith every purchase (for example your order ID). Never reuse a reference. - Save the order before calling the API, with status pending. Update it after you get the response.
- Store our reference from the response. Support will ask for it if anything goes wrong.
- On a timeout or network error, do not retry immediately. The purchase may have gone through. Check your transactions in the API portal or your transaction history first, then retry only if it is not there.
- Only charge your customer after you receive
"status": "success".
06 Rate limits
You can make up to 60 requests per minute per API key. That is plenty for normal use. If you need to send bulk purchases, space them out (one every second is safe) and cache plan lists instead of fetching them before every sale.
Check wallet balance
https://instantmobile.com.ng/api/v1.php?action=balanceReturns the current naira balance of the wallet linked to your API key. It is the simplest call, so use it to confirm your key works and to check you have enough funds before sending a purchase.
How to integrate
- Send a GET request to the balance action with your API key in the Authorization header.
- Read the balance field from the JSON response.
- Compare it with the cost of the purchase you are about to make. If it is too low, stop and alert your team or customer to fund the wallet.
Parameters
This endpoint takes no parameters. Just send your API key.
Example request
curl -X GET "https://instantmobile.com.ng/api/v1.php?action=balance" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Accept: application/json"
$ch = curl_init("https://instantmobile.com.ng/api/v1.php?action=balance");
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
"Authorization: Bearer YOUR_API_KEY",
"Content-Type: application/json",
],
]);
$res = json_decode(curl_exec($ch), true);
curl_close($ch);
if ($res["status"] === "success") {
// mark your order as complete
} else {
// show $res["message"] to your customer
}
// Run this on your server (Node.js), never in the browser
const res = await fetch("https://instantmobile.com.ng/api/v1.php?action=balance", {
method: "GET",
headers: {
"Authorization": "Bearer YOUR_API_KEY",
"Content-Type": "application/json"
}
});
const data = await res.json();
console.log(data);
Example response
{
"status": "success",
"balance": 5000
}
Good to know
- Call this before large batches so you do not run out mid-way.
- Cache the value for a few seconds instead of calling it before every single purchase.
List data plans
https://instantmobile.com.ng/api/v1.php?action=data-plansReturns every active data plan with its plan ID, network, type (SME, gifting, corporate and so on), name and your API price. Plan IDs can change when plans are updated, so always read them from this endpoint.
How to integrate
- Call data-plans once when your app starts, or on a schedule (for example every 30 minutes).
- Save the list in your own database or cache.
- Show the plans to your customers using your own selling price.
- When a customer buys, send the id of the chosen plan as plan_id to the Buy data endpoint.
Parameters
This endpoint takes no parameters. Just send your API key.
Example request
curl -X GET "https://instantmobile.com.ng/api/v1.php?action=data-plans" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Accept: application/json"
$ch = curl_init("https://instantmobile.com.ng/api/v1.php?action=data-plans");
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
"Authorization: Bearer YOUR_API_KEY",
"Content-Type: application/json",
],
]);
$res = json_decode(curl_exec($ch), true);
curl_close($ch);
if ($res["status"] === "success") {
// mark your order as complete
} else {
// show $res["message"] to your customer
}
// Run this on your server (Node.js), never in the browser
const res = await fetch("https://instantmobile.com.ng/api/v1.php?action=data-plans", {
method: "GET",
headers: {
"Authorization": "Bearer YOUR_API_KEY",
"Content-Type": "application/json"
}
});
const data = await res.json();
console.log(data);
Example response
{
"status": "success",
"data": [
{
"id": 1,
"network": "MTN",
"type": "SME",
"name": "MTN 1GB SME 30 Days",
"price": 430
}
]
}
Good to know
- Never hardcode plan IDs in your code.
- The price returned is what you pay. Add your own margin on top when selling.
- If a plan disappears from the list, hide it from your customers too.
Buy data
https://instantmobile.com.ng/api/v1.php?action=dataSends a data bundle to any Nigerian phone number on MTN, Glo, Airtel or 9mobile. The cost of the plan is deducted from your wallet and the bundle is delivered instantly in most cases.
How to integrate
- Get the plan_id from List data plans.
- Collect the customer phone number and confirm the network matches the plan.
- Generate your own unique reference and save the order in your database as pending.
- Send the POST request with network, phone, plan_id and reference.
- If status is success, mark your order as delivered. If it is an error, show the message and do not charge your customer.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
network | string | Required | Network slug: mtn, glo, airtel or 9mobile |
phone | string | Required | 11-digit Nigerian number, e.g. 08012345678 |
plan_id | integer | Required | The id of the plan from List data plans |
reference | string | Optional | Your own unique reference for this order (strongly recommended) |
Example request
curl -X POST "https://instantmobile.com.ng/api/v1.php?action=data" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{"network":"mtn","phone":"08012345678","plan_id":1,"reference":"ORDER_10045"}'
$ch = curl_init("https://instantmobile.com.ng/api/v1.php?action=data");
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
"Authorization: Bearer YOUR_API_KEY",
"Content-Type: application/json",
],
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => '{"network":"mtn","phone":"08012345678","plan_id":1,"reference":"ORDER_10045"}',
]);
$res = json_decode(curl_exec($ch), true);
curl_close($ch);
if ($res["status"] === "success") {
// mark your order as complete
} else {
// show $res["message"] to your customer
}
// Run this on your server (Node.js), never in the browser
const res = await fetch("https://instantmobile.com.ng/api/v1.php?action=data", {
method: "POST",
headers: {
"Authorization": "Bearer YOUR_API_KEY",
"Content-Type": "application/json"
},
body: JSON.stringify({"network":"mtn","phone":"08012345678","plan_id":1,"reference":"ORDER_10045"})
});
const data = await res.json();
console.log(data);
Example response
{
"status": "success",
"message": "Data delivered",
"reference": "DAT_51bd02e7"
}
Good to know
- The network must match the plan. Sending an MTN plan to a Glo number will fail.
- Ported numbers belong to the network they were ported to, not the prefix.
- Failed purchases are refunded to your wallet automatically.
Buy airtime
https://instantmobile.com.ng/api/v1.php?action=airtimeTops up airtime on any Nigerian number. Your plan discount is applied automatically, so you are charged slightly less than the face value.
How to integrate
- Collect the network, phone number and amount from your customer.
- Check the amount is at least the minimum (50 naira).
- Save the order with your own unique reference.
- Send the POST request.
- On success, mark the order complete. On error, show the message and do not charge your customer.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
network | string | Required | Network slug: mtn, glo, airtel or 9mobile |
phone | string | Required | 11-digit Nigerian number |
amount | number | Required | Amount in naira, minimum 50 |
reference | string | Optional | Your own unique reference (recommended) |
Example request
curl -X POST "https://instantmobile.com.ng/api/v1.php?action=airtime" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{"network":"mtn","phone":"08012345678","amount":100,"reference":"ORDER_10046"}'
$ch = curl_init("https://instantmobile.com.ng/api/v1.php?action=airtime");
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
"Authorization: Bearer YOUR_API_KEY",
"Content-Type: application/json",
],
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => '{"network":"mtn","phone":"08012345678","amount":100,"reference":"ORDER_10046"}',
]);
$res = json_decode(curl_exec($ch), true);
curl_close($ch);
if ($res["status"] === "success") {
// mark your order as complete
} else {
// show $res["message"] to your customer
}
// Run this on your server (Node.js), never in the browser
const res = await fetch("https://instantmobile.com.ng/api/v1.php?action=airtime", {
method: "POST",
headers: {
"Authorization": "Bearer YOUR_API_KEY",
"Content-Type": "application/json"
},
body: JSON.stringify({"network":"mtn","phone":"08012345678","amount":100,"reference":"ORDER_10046"})
});
const data = await res.json();
console.log(data);
Example response
{
"status": "success",
"message": "Airtime delivered",
"reference": "AIR_8f2a91c0"
}
Good to know
- Send whole naira amounts.
- The amount deducted from your wallet may be lower than the airtime value because of your discount.
List cable plans
https://instantmobile.com.ng/api/v1.php?action=cable-plansReturns all DStv, GOtv and StarTimes bouquets with their plan IDs and prices. Use it the same way as data plans.
How to integrate
- Call cable-plans and cache the result.
- Group the plans by provider in your interface.
- Send the selected id as plan_id to the Pay cable TV endpoint.
Parameters
This endpoint takes no parameters. Just send your API key.
Example request
curl -X GET "https://instantmobile.com.ng/api/v1.php?action=cable-plans" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Accept: application/json"
$ch = curl_init("https://instantmobile.com.ng/api/v1.php?action=cable-plans");
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
"Authorization: Bearer YOUR_API_KEY",
"Content-Type: application/json",
],
]);
$res = json_decode(curl_exec($ch), true);
curl_close($ch);
if ($res["status"] === "success") {
// mark your order as complete
} else {
// show $res["message"] to your customer
}
// Run this on your server (Node.js), never in the browser
const res = await fetch("https://instantmobile.com.ng/api/v1.php?action=cable-plans", {
method: "GET",
headers: {
"Authorization": "Bearer YOUR_API_KEY",
"Content-Type": "application/json"
}
});
const data = await res.json();
console.log(data);
Example response
{
"status": "success",
"data": [
{
"id": 12,
"provider": "dstv",
"name": "DStv Compact",
"price": 19000
}
]
}
Good to know
- Bouquet prices change when providers review them. Refresh your cache daily.
Pay cable TV
https://instantmobile.com.ng/api/v1.php?action=cableRenews or subscribes a DStv, GOtv or StarTimes decoder using its smartcard or IUC number.
How to integrate
- Get the plan_id from List cable plans.
- Collect the provider and the smartcard / IUC number from your customer and ask them to double-check it.
- Save the order with a unique reference.
- Send the POST request.
- On success, tell your customer the subscription is active. Decoders usually update within a few minutes.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
provider | string | Required | dstv, gotv or startimes |
iuc_number | string | Required | The decoder smartcard / IUC number |
plan_id | integer | Required | The id of the bouquet from List cable plans |
Example request
curl -X POST "https://instantmobile.com.ng/api/v1.php?action=cable" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{"provider":"dstv","iuc_number":"7012345678","plan_id":12}'
$ch = curl_init("https://instantmobile.com.ng/api/v1.php?action=cable");
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
"Authorization: Bearer YOUR_API_KEY",
"Content-Type: application/json",
],
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => '{"provider":"dstv","iuc_number":"7012345678","plan_id":12}',
]);
$res = json_decode(curl_exec($ch), true);
curl_close($ch);
if ($res["status"] === "success") {
// mark your order as complete
} else {
// show $res["message"] to your customer
}
// Run this on your server (Node.js), never in the browser
const res = await fetch("https://instantmobile.com.ng/api/v1.php?action=cable", {
method: "POST",
headers: {
"Authorization": "Bearer YOUR_API_KEY",
"Content-Type": "application/json"
},
body: JSON.stringify({"provider":"dstv","iuc_number":"7012345678","plan_id":12})
});
const data = await res.json();
console.log(data);
Example response
{
"status": "success",
"message": "Subscription successful",
"reference": "CAB_a8810b2e"
}
Good to know
- A wrong IUC number can credit someone else. Always show the number back to your customer before paying.
- If the decoder does not update, ask the customer to refresh it from the provider app or by SMS.
Pay electricity
https://instantmobile.com.ng/api/v1.php?action=electricityBuys a prepaid token or pays a postpaid bill for any supported electricity company (DISCO). For prepaid meters, the token is returned in the response.
How to integrate
- Collect the DISCO, meter number, meter type (prepaid or postpaid) and amount.
- Make sure the amount is at least the minimum (500 naira).
- Save the order with a unique reference.
- Send the POST request.
- For prepaid, show the token from the response to your customer and send it by SMS or email too.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
disco | string | Required | DISCO code, e.g. ikeja-electric, eko-electric, abuja-electric |
meter_number | string | Required | The customer meter number |
amount | number | Required | Amount in naira, minimum 500 |
meter_type | string | Optional | prepaid (default) or postpaid |
Example request
curl -X POST "https://instantmobile.com.ng/api/v1.php?action=electricity" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{"disco":"ikeja-electric","meter_number":"45012345678","amount":1000,"meter_type":"prepaid"}'
$ch = curl_init("https://instantmobile.com.ng/api/v1.php?action=electricity");
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
"Authorization: Bearer YOUR_API_KEY",
"Content-Type: application/json",
],
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => '{"disco":"ikeja-electric","meter_number":"45012345678","amount":1000,"meter_type":"prepaid"}',
]);
$res = json_decode(curl_exec($ch), true);
curl_close($ch);
if ($res["status"] === "success") {
// mark your order as complete
} else {
// show $res["message"] to your customer
}
// Run this on your server (Node.js), never in the browser
const res = await fetch("https://instantmobile.com.ng/api/v1.php?action=electricity", {
method: "POST",
headers: {
"Authorization": "Bearer YOUR_API_KEY",
"Content-Type": "application/json"
},
body: JSON.stringify({"disco":"ikeja-electric","meter_number":"45012345678","amount":1000,"meter_type":"prepaid"})
});
const data = await res.json();
console.log(data);
Example response
{
"status": "success",
"token": "1234-5678-9012-3456-7890",
"reference": "ELC_0c4e77aa"
}
Good to know
- Store the token in your database. Customers often ask for it again later.
- Postpaid payments do not return a token. The payment reflects on the customer account.
07 Recipe: build a data reselling website
Here is the typical flow most of our API users follow:
- Sync plans. Every 30 minutes, call
data-plansandcable-plans, save them in your database and apply your selling price. - Customer pays you. Your customer funds their wallet on your site or pays at checkout.
- Create the order. Save it as pending with a unique reference.
- Call the API. Send the purchase with that reference.
- Update the order. Mark it success and show a receipt, or mark it failed and refund your customer in your system.
- Watch your balance. Call
balanceevery few minutes and alert yourself when it drops below a safe level.
08 Go-live checklist
- Your API key is stored on the server only (environment variable or config file outside the web root).
- Every purchase sends a unique reference.
- Orders are saved before the API call and updated after.
- You never retry a purchase without checking if the first one went through.
- Plan lists are cached and refreshed, not hardcoded.
- You show our error message to customers instead of a blank failure.
- You have a low-balance alert.
- You tested each service with a small amount first.
09 Support
Track your API sales, transactions and health in the API portal. If something does not look right, contact our support team with the reference from the response and the time of the request.