SBB API
Get your API key →
Viewing as
Getting Started/Introduction
SBB Data API

Sell VTU from your own platform

Buy airtime, data, electricity and cable TV from your own website, app or bot, paid for from your SBB Data wallet at your own account's prices.

There are three ways in, and one API key works on all of them. Use the switch at the top of the page to see each endpoint in the API you're using.

APIUse it whenSellsBase URL
NativeYou're building a new integration, or you already use the SBB Data API.Data, airtimehttps://www.sbbdata.com.ng/api/v1
MSORGYour system already uses an MSORG-style API.Data, airtime, electricity, cable TVhttps://www.sbbdata.com.ng/compat/msorg
ADEXYour system already uses an ADEX-style API.Data, airtime, electricity, cable TVhttps://www.sbbdata.com.ng/compat/adex

Fund your wallet the usual way, by bank transfer to your dedicated account in the dashboard. The API spends that same balance. There's no test mode, so every successful purchase is real.


Playground

Sandbox

Send a request to the live API from your browser. Requests marked [real money] debit your wallet and deliver for real.

GET

What you type here goes only to the SBB Data API, and is never logged by this page. It's kept in this browser tab until you close it.


Authentication

Generate your API key in the dashboard at www.sbbdata.com.ng, under Profile → Account → API Integration. The same key works on all three APIs. Only the header changes:

APIHeader
Nativex-api-key: YOUR_API_KEY
MSORGAuthorization: Token YOUR_API_KEY
ADEXAuthorization: Token YOUR_API_KEY
Your API key can spend your wallet

No transaction PIN is needed on API purchases, so anyone holding your key can spend your balance. Keep it on your server, never in website or app code. If it leaks, generate a new one in the dashboard straight away. That cancels the old key on all three APIs, so update your integrations at the same time.


Responses and errors

Every response is JSON. Check the HTTP status first, then the body.

Native

status is a boolean, and message explains what happened.

{
  "status": false,
  "message": "Invalid planId or network"
}

MSORG and ADEX

Errors have the same shape on both. Branch on code, because message can change. When a purchase has been refunded, newbal gives your balance.

{
  "status": "error",
  "message": "mobile_number and plan are required.",
  "code": "VALIDATION_ERROR"
}
HTTPcode (MSORG, ADEX)Meaning
400VALIDATION_ERROR, REQUEST_FAILEDMissing or wrong fields, low balance, a duplicate request, or a number that doesn't match the network. Nothing was charged, or any charge was refunded.
400PROVIDER_REJECTEDThe provider rejected a meter or smart card check. Nothing was charged.
400PROVIDER_DECLINEDThe provider declined an electricity or cable purchase. Your wallet has been refunded.
401UNAUTHORIZEDMissing or wrong key, token or password.
403FORBIDDENThe account is frozen or temporarily locked.
404NOT_FOUNDThe endpoint or transaction doesn't exist on your account.
429RATE_LIMITEDThe airtime limit or a request limit was reached. Wait, then try again.
500INTERNAL_ERRORSomething failed on our side. Look up the purchase before retrying.
502PROVIDER_UNAVAILABLEA provider check or listing failed. Nothing was charged. Try again shortly.

When a purchase is still processing

Sometimes a provider doesn't give a clear answer straight away. The purchase is then marked processing and your wallet stays debited, because it may still be delivered. Don't retry it, or you could deliver twice. Look it up with the lookup endpoints until it settles. If it stays stuck, our team reviews it.


Limits and safeguards

RuleDetail
Airtime limit₦5,000 per account in any 20-minute window, on all three APIs. Reaching it returns 429 and pauses airtime for up to an hour. It can't be raised through the API, so spread out large batches.
Duplicate guardThe same purchase to the same number within 30 seconds is rejected with a 400, even if the first attempt failed. Wait before retrying.
Network checkA number whose prefix belongs to a different network is rejected before you're charged. For ported numbers, send bypassNetworkCheck (Native), Ported_number (MSORG) or bypass (ADEX).
Request limitMSORG and ADEX allow 300 requests a minute. The ADEX token endpoint allows 20 a minute.
Password attemptsFive wrong passwords on the ADEX token endpoint lock the account for 5 minutes.

Compatibility APIs

MSORG and ADEX let you move an existing integration to SBB Data by changing its base URL and token, with no other code changes. Choose MSORG or ADEX at the top of the page to read that API's setup. They cover data, airtime, electricity and cable TV. Exam pins, bulk SMS and printable recharge cards aren't offered.

Compatibility API

MSORG

If your system already talks to an MSORG-style VTU API, point it at the base URL below and use your SBB Data API key as the token.

Base URL

https://www.sbbdata.com.ng/compat/msorg

Authorization: Token YOUR_API_KEY

Network numbers

NumberNetwork
1MTN
2Airtel
3Glo
49mobile

The network names work too. Meter types are prepaid or 1, and postpaid or 2.

Use SBB Data's own ids

plan, disco_name, cablename and cableplan must come from List data plans, List discos and List providers on this site. Ids from your previous provider won't work. The network numbers above and the meter types are the only values that carry over.

Test before you switch

The routes and request fields follow the MSORG convention, but the response bodies are SBB Data's own design. If your code reads specific response fields, try a small purchase and compare it with the samples here before moving live traffic.

status is true on account, listing and validation responses, and a string on purchases: "success" or "processing". Errors always have "status": "error". Check the HTTP code first, then the status documented for that endpoint.

Compatibility API

ADEX

If your system already talks to an ADEX-style VTU API, point it at the base URL below. The two-step login works as you'd expect: exchange your email and password for a token, then send that token on every other call.

Base URL

https://www.sbbdata.com.ng/compat/adex

  1. Get your token with POST /api/user and HTTP Basic auth, using your account email and password.
  2. Send it on every other call: Authorization: Token <AccessToken>.

The AccessToken is your SBB Data API key. If you already have one it stays the same, so getting a token never breaks another integration on your account. You can also skip step 1 and use the key from your dashboard directly.

Network numbers

NumberNetwork
1MTN
2Airtel
3Glo
49mobile

The network names work too. meter_type is prepaid or 1, and postpaid or 2.

Use SBB Data's own ids

data_plan, disco, cablename and cableplan must come from List data plans, List discos and List providers on this site. Ids from your previous provider won't work. The network numbers above and the meter types are the only values that carry over.

Test before you switch

Field names such as oldbal, newbal and wallet_vending follow the ADEX convention, but this is SBB Data's own implementation. If your code reads specific response fields, try a small purchase first.

Successful ADEX responses use the string "success" or "processing" in status. Errors have "status": "error".


Account

Check your account and wallet balance.

GET/compat/msorg/api/user/POST/compat/adex/api/userMSORGADEX

Account and token

Returns your wallet balance. On ADEX this is also how you get your token.

The native API has no account endpoint. Your balance comes back as newBalance on every purchase, and your dashboard always shows it.
Auth: Authorization: Token YOUR_API_KEY
curl "https://www.sbbdata.com.ng/compat/msorg/api/user/" \
  -H "Authorization: Token YOUR_API_KEY"
const res = await fetch("https://www.sbbdata.com.ng/compat/msorg/api/user/", {
  headers: {
    Authorization: "Token YOUR_API_KEY"
  }
});
const data = await res.json();

Response

{
  "status": true,
  "user": {
    "id": "69070f2ea1b94c0012d4e8a1",
    "username": "you@example.com",
    "email": "you@example.com",
    "full_name": "Your Name",
    "wallet_balance": "15230.00"
  }
}
Auth: HTTP Basic, your account email and password

Send your account email and password with HTTP Basic auth. Calling this again returns the same token, so it's safe to call from every server or worker you run, and to read your balance.

curl -X POST "https://www.sbbdata.com.ng/compat/adex/api/user" \
  -u "you@example.com:your_account_password"
const credentials = btoa("you@example.com:your_account_password");
const res = await fetch("https://www.sbbdata.com.ng/compat/adex/api/user", {
  method: "POST",
  headers: { Authorization: `Basic ${credentials}` }
});
const data = await res.json();

Response

{
  "status": "success",
  "AccessToken": "vtu_3f9a1b2c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e",
  "balance": "15230.00",
  "username": "you@example.com"
}

Five wrong passwords lock the account for 5 minutes, the same as logging in on the website. If you store the token, you don't need to send your password on every run.


Data

List the plans you can buy, at your own prices, then buy one.

GET/api/v1/data-plansGET/compat/msorg/api/data-plans/GET/compat/adex/api/data-plansNativeMSORGADEX

List data plans

Returns every active plan, grouped by network, with your account's pricing already applied. Prices can change, so refresh this list regularly instead of hardcoding it.

Auth: x-api-key: YOUR_API_KEY
curl "https://www.sbbdata.com.ng/api/v1/data-plans" \
  -H "x-api-key: YOUR_API_KEY"
const res = await fetch("https://www.sbbdata.com.ng/api/v1/data-plans", {
  headers: {
    "x-api-key": "YOUR_API_KEY"
  }
});
const data = await res.json();

Response

{
  "status": true,
  "data": {
    "MTN": [
      {
        "planId": "159",
        "name": "1GB - 30 Days",
        "price": "300"
      },
      {
        "planId": "160",
        "name": "2GB - 30 Days",
        "price": "550"
      }
    ],
    "AIRTEL": [
      {
        "planId": "10",
        "name": "1GB - 30 Days",
        "price": "300"
      }
    ]
  }
}
Auth: Authorization: Token YOUR_API_KEY
curl "https://www.sbbdata.com.ng/compat/msorg/api/data-plans/" \
  -H "Authorization: Token YOUR_API_KEY"
const res = await fetch("https://www.sbbdata.com.ng/compat/msorg/api/data-plans/", {
  headers: {
    Authorization: "Token YOUR_API_KEY"
  }
});
const data = await res.json();

Response

{
  "status": true,
  "plans": {
    "MTN": [
      {
        "planId": "159",
        "name": "1GB - 30 Days",
        "price": "300"
      }
    ],
    "AIRTEL": [
      {
        "planId": "10",
        "name": "1GB - 30 Days",
        "price": "300"
      }
    ]
  }
}
Auth: Authorization: Token YOUR_API_KEY
curl "https://www.sbbdata.com.ng/compat/adex/api/data-plans" \
  -H "Authorization: Token YOUR_API_KEY"
const res = await fetch("https://www.sbbdata.com.ng/compat/adex/api/data-plans", {
  headers: {
    Authorization: "Token YOUR_API_KEY"
  }
});
const data = await res.json();

Response

{
  "status": "success",
  "plans": {
    "MTN": [
      {
        "planId": "159",
        "name": "1GB - 30 Days",
        "price": "300"
      }
    ],
    "AIRTEL": [
      {
        "planId": "10",
        "name": "1GB - 30 Days",
        "price": "300"
      }
    ]
  }
}

POST/api/v1/purchasePOST/compat/msorg/api/data/POST/compat/adex/api/dataNativeMSORGADEX

Buy data

Debits your wallet and sends the plan to the number. If the provider declines, your wallet is refunded before the response comes back.

Auth: x-api-key: YOUR_API_KEY

One endpoint handles both data and airtime. Sending planId makes it a data purchase.

FieldTypeDescription
networkstringrequiredNetwork name (MTN, AIRTEL, GLO, 9MOBILE) or its number, 1 to 4.
phonestringrequiredThe number to credit, e.g. 08031234567.
planIdstringrequiredFrom List data plans. plan_id also works.
bypassNetworkCheckbooleanoptionalSkips the check that the number belongs to the network. Use it for ported numbers.
curl -X POST "https://www.sbbdata.com.ng/api/v1/purchase" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"network":"MTN","phone":"08031234567","planId":"159"}'
const res = await fetch("https://www.sbbdata.com.ng/api/v1/purchase", {
  method: "POST",
  headers: {
    "x-api-key": "YOUR_API_KEY",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({"network":"MTN","phone":"08031234567","planId":"159"})
});
const data = await res.json();

Response

{
  "status": true,
  "message": "Data purchase successful",
  "data": {
    "reference": "API_DAT_9F2A1B4C0D3E",
    "network": "MTN",
    "phone": "08031234567",
    "planId": "159",
    "amount": 300,
    "status": "successful",
    "newBalance": 14930
  }
}
{
  "status": true,
  "message": "Your purchase is being processed. Check your transaction history for updates.",
  "data": {
    "reference": "API_DAT_9F2A1B4C0D3E",
    "status": "processing",
    "newBalance": 14930
  }
}
{
  "status": false,
  "message": "Transaction failed. Balance refunded.",
  "data": {
    "newBalance": 15230
  }
}

A 202 means the provider took the request but hasn't confirmed it yet. Your wallet stays debited, so don't retry. To check it from your own code, use the MSORG lookup with the reference and the same key.

Auth: Authorization: Token YOUR_API_KEY
FieldTypeDescription
networkstring or numberrequiredNetwork name (MTN, AIRTEL, GLO, 9MOBILE) or its number, 1 to 4.
mobile_numberstringrequiredThe number to credit, e.g. 08031234567.
planstringrequiredFrom List data plans.
Ported_numberbooleanoptionalSkips the check that the number belongs to the network.
curl -X POST "https://www.sbbdata.com.ng/compat/msorg/api/data/" \
  -H "Authorization: Token YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"network":1,"mobile_number":"08031234567","plan":"159"}'
const res = await fetch("https://www.sbbdata.com.ng/compat/msorg/api/data/", {
  method: "POST",
  headers: {
    Authorization: "Token YOUR_API_KEY",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({"network":1,"mobile_number":"08031234567","plan":"159"})
});
const data = await res.json();

Response

{
  "status": "success",
  "id": "69070f2ea1b94c0012d4e8a1",
  "reference": "API_DAT_9F2A1B4C0D3E",
  "network": "MTN",
  "mobile_number": "08031234567",
  "plan": "159",
  "amount": 300,
  "message": "Data plan delivered to 08031234567.",
  "oldbal": 15230,
  "newbal": 14930
}
{
  "status": "error",
  "message": "Transaction failed. Balance refunded.",
  "code": "REQUEST_FAILED",
  "newbal": 15230
}
Auth: Authorization: Token YOUR_API_KEY
FieldTypeDescription
networkstring or numberrequiredNetwork name (MTN, AIRTEL, GLO, 9MOBILE) or its number, 1 to 4.
phonestringrequiredThe number to credit, e.g. 08031234567.
data_planstringrequiredFrom List data plans.
request-idstringoptionalYour own reference. It's echoed back as sent.
bypassbooleanoptionalSkips the check that the number belongs to the network.
curl -X POST "https://www.sbbdata.com.ng/compat/adex/api/data" \
  -H "Authorization: Token YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"network":1,"phone":"08031234567","data_plan":"159","request-id":"order-1001"}'
const res = await fetch("https://www.sbbdata.com.ng/compat/adex/api/data", {
  method: "POST",
  headers: {
    Authorization: "Token YOUR_API_KEY",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({"network":1,"phone":"08031234567","data_plan":"159","request-id":"order-1001"})
});
const data = await res.json();

Response

{
  "network": "MTN",
  "request-id": "order-1001",
  "reference": "API_DAT_9F2A1B4C0D3E",
  "amount": "300",
  "dataplan": "159",
  "status": "success",
  "message": "Data delivered to 08031234567.",
  "response": "Data delivered to 08031234567.",
  "phone_number": "08031234567",
  "oldbal": "15230",
  "newbal": 14930,
  "system": "API",
  "plan_type": "GIFTING",
  "wallet_vending": "wallet"
}
{
  "status": "error",
  "message": "Transaction failed. Balance refunded.",
  "code": "REQUEST_FAILED",
  "newbal": 15230
}

oldbal is a string and newbal is a number, matching what ADEX-style clients expect.


Airtime

Send airtime to any Nigerian number.

POST/api/v1/purchasePOST/compat/msorg/api/topup/POST/compat/adex/api/topupNativeMSORGADEX

Buy airtime

Capped at ₦5,000 per account in any 20-minute window, on all three APIs. Any bonus balance on your account is spent before your wallet balance.

Auth: x-api-key: YOUR_API_KEY

One endpoint handles both data and airtime. Sending amount with no plan makes it an airtime purchase.

FieldTypeDescription
networkstringrequiredNetwork name (MTN, AIRTEL, GLO, 9MOBILE) or its number, 1 to 4.
phonestringrequiredThe number to credit, e.g. 08031234567.
amountnumberrequiredAmount in naira, greater than 0.
bypassNetworkCheckbooleanoptionalSkips the check that the number belongs to the network.
curl -X POST "https://www.sbbdata.com.ng/api/v1/purchase" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"network":"MTN","phone":"08031234567","amount":500}'
const res = await fetch("https://www.sbbdata.com.ng/api/v1/purchase", {
  method: "POST",
  headers: {
    "x-api-key": "YOUR_API_KEY",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({"network":"MTN","phone":"08031234567","amount":500})
});
const data = await res.json();

Response

{
  "status": true,
  "message": "Transaction processed successfully.",
  "data": {
    "reference": "API_AIR_3C0430D93336",
    "network": "MTN",
    "phone": "08031234567",
    "amount": 500,
    "status": "successful",
    "newBalance": 14730,
    "newBonusBalance": 0
  }
}
{
  "status": false,
  "message": "Transaction failed. Balance refunded.",
  "data": {
    "newBalance": 15230,
    "newBonusBalance": 0
  }
}
{
  "status": false,
  "message": "Transaction would exceed ₦5,000 airtime limit per 20 minutes. Please try again later."
}
Auth: Authorization: Token YOUR_API_KEY
FieldTypeDescription
networkstring or numberrequiredNetwork name (MTN, AIRTEL, GLO, 9MOBILE) or its number, 1 to 4.
mobile_numberstringrequiredThe number to credit, e.g. 08031234567.
amountnumberrequiredAmount in naira, greater than 0.
Ported_numberbooleanoptionalSkips the check that the number belongs to the network.
curl -X POST "https://www.sbbdata.com.ng/compat/msorg/api/topup/" \
  -H "Authorization: Token YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"network":1,"mobile_number":"08031234567","amount":500}'
const res = await fetch("https://www.sbbdata.com.ng/compat/msorg/api/topup/", {
  method: "POST",
  headers: {
    Authorization: "Token YOUR_API_KEY",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({"network":1,"mobile_number":"08031234567","amount":500})
});
const data = await res.json();

Response

{
  "status": "success",
  "id": "69070f2ea1b94c0012d4e8a1",
  "reference": "API_AIR_3C0430D93336",
  "network": "MTN",
  "mobile_number": "08031234567",
  "amount": 500,
  "message": "₦500 airtime sent to 08031234567.",
  "oldbal": 15230,
  "newbal": 14730
}
{
  "status": "error",
  "message": "Transaction would exceed ₦5,000 airtime limit per 20 minutes. Please try again later.",
  "code": "RATE_LIMITED"
}
Auth: Authorization: Token YOUR_API_KEY
FieldTypeDescription
networkstring or numberrequiredNetwork name (MTN, AIRTEL, GLO, 9MOBILE) or its number, 1 to 4.
phonestringrequiredThe number to credit, e.g. 08031234567.
amountnumberrequiredAmount in naira, greater than 0.
request-idstringoptionalYour own reference. It's echoed back as sent.
bypassbooleanoptionalSkips the check that the number belongs to the network.
plan_typestringoptionalEchoed back as sent. Defaults to VTU.
curl -X POST "https://www.sbbdata.com.ng/compat/adex/api/topup" \
  -H "Authorization: Token YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"network":1,"phone":"08031234567","amount":500,"request-id":"order-1002"}'
const res = await fetch("https://www.sbbdata.com.ng/compat/adex/api/topup", {
  method: "POST",
  headers: {
    Authorization: "Token YOUR_API_KEY",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({"network":1,"phone":"08031234567","amount":500,"request-id":"order-1002"})
});
const data = await res.json();

Response

{
  "network": "MTN",
  "request-id": "order-1002",
  "reference": "API_AIR_3C0430D93336",
  "amount": 500,
  "discount": 0,
  "status": "success",
  "message": "Successfully purchased MTN VTU ₦500 for 08031234567",
  "phone_number": "08031234567",
  "oldbal": "15230",
  "newbal": 14730,
  "system": "API",
  "plan_type": "VTU",
  "wallet_vending": "wallet"
}
{
  "status": "error",
  "message": "Transaction would exceed ₦5,000 airtime limit per 20 minutes. Please try again later.",
  "code": "RATE_LIMITED"
}

Electricity

Available on MSORG and ADEX.

GET/compat/msorg/api/discos/GET/compat/adex/api/discosMSORGADEX

List discos

Returns the electricity companies you can pay, with the id each purchase needs.

The native API sells airtime and data only, so electricity isn't available here. Switch to MSORG or ADEX at the top of this page. They use the same API key.
Auth: Authorization: Token YOUR_API_KEY
curl "https://www.sbbdata.com.ng/compat/msorg/api/discos/" \
  -H "Authorization: Token YOUR_API_KEY"
const res = await fetch("https://www.sbbdata.com.ng/compat/msorg/api/discos/", {
  headers: {
    Authorization: "Token YOUR_API_KEY"
  }
});
const data = await res.json();

Response

{
  "status": true,
  "discos": [
    {
      "discoId": "DISCO_ID",
      "name": "Ikeja Electric"
    }
  ]
}
Auth: Authorization: Token YOUR_API_KEY
curl "https://www.sbbdata.com.ng/compat/adex/api/discos" \
  -H "Authorization: Token YOUR_API_KEY"
const res = await fetch("https://www.sbbdata.com.ng/compat/adex/api/discos", {
  headers: {
    Authorization: "Token YOUR_API_KEY"
  }
});
const data = await res.json();

Response

{
  "status": "success",
  "discos": [
    {
      "discoId": "DISCO_ID",
      "name": "Ikeja Electric"
    }
  ]
}

GET/compat/msorg/api/validatemeterGET/compat/adex/api/bill/bill-validationMSORGADEX

Validate a meter

Returns the customer name on a meter so you can confirm it before paying.

The native API sells airtime and data only, so electricity isn't available here. Switch to MSORG or ADEX at the top of this page. They use the same API key.
Auth: Authorization: Token YOUR_API_KEY
FieldTypeDescription
meternumberstringrequiredThe meter number.
disconamestringrequiredA discoId from List discos.
mtypestring or numberrequiredprepaid or 1; postpaid or 2.
amountnumberoptionalThe amount you plan to pay. Defaults to 1000.
curl "https://www.sbbdata.com.ng/compat/msorg/api/validatemeter?meternumber=45031234567&disconame=DISCO_ID&mtype=prepaid&amount=2000" \
  -H "Authorization: Token YOUR_API_KEY"
const res = await fetch("https://www.sbbdata.com.ng/compat/msorg/api/validatemeter?meternumber=45031234567&disconame=DISCO_ID&mtype=prepaid&amount=2000", {
  headers: {
    Authorization: "Token YOUR_API_KEY"
  }
});
const data = await res.json();

Response

{
  "status": true,
  "customer_name": "ADA OBI",
  "address": "1 Allen Avenue, Ikeja"
}
Auth: Authorization: Token YOUR_API_KEY
FieldTypeDescription
meter_numberstringrequiredThe meter number.
discostringrequiredA discoId from List discos.
meter_typestring or numberrequiredprepaid or 1; postpaid or 2.
amountnumberoptionalThe amount you plan to pay. Defaults to 1000.
curl "https://www.sbbdata.com.ng/compat/adex/api/bill/bill-validation?meter_number=45031234567&disco=DISCO_ID&meter_type=prepaid&amount=2000" \
  -H "Authorization: Token YOUR_API_KEY"
const res = await fetch("https://www.sbbdata.com.ng/compat/adex/api/bill/bill-validation?meter_number=45031234567&disco=DISCO_ID&meter_type=prepaid&amount=2000", {
  headers: {
    Authorization: "Token YOUR_API_KEY"
  }
});
const data = await res.json();

Response

{
  "status": "success",
  "name": "ADA OBI"
}

POST/compat/msorg/api/billpayment/POST/compat/adex/api/billMSORGADEX

Buy electricity

Validates the meter, debits your wallet, and pays the disco. Prepaid purchases return the token to give your customer. If the disco declines, your wallet is refunded before the response comes back.

The native API sells airtime and data only, so electricity isn't available here. Switch to MSORG or ADEX at the top of this page. They use the same API key.
Auth: Authorization: Token YOUR_API_KEY
FieldTypeDescription
disco_namestringrequiredA discoId from List discos.
meter_numberstringrequiredThe meter number.
MeterTypestring or numberrequiredprepaid or 1; postpaid or 2.
amountnumberrequiredWhole naira. The disco may set its own minimum.
curl -X POST "https://www.sbbdata.com.ng/compat/msorg/api/billpayment/" \
  -H "Authorization: Token YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"disco_name":"DISCO_ID","meter_number":"45031234567","MeterType":"prepaid","amount":2000}'
const res = await fetch("https://www.sbbdata.com.ng/compat/msorg/api/billpayment/", {
  method: "POST",
  headers: {
    Authorization: "Token YOUR_API_KEY",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({"disco_name":"DISCO_ID","meter_number":"45031234567","MeterType":"prepaid","amount":2000})
});
const data = await res.json();

Response

{
  "status": "success",
  "id": "69070f2ea1b94c0012d4e8a1",
  "reference": "COMPAT_ELEC_5b1f0c9ad2e34f77",
  "disco_name": "DISCO_ID",
  "meter_number": "45031234567",
  "amount": 2000,
  "token": "1234-5678-9012-3456-7890",
  "units": "42.5",
  "message": "Electricity payment successful.",
  "oldbal": 15230,
  "newbal": 13230
}
{
  "status": "processing",
  "id": "69070f2ea1b94c0012d4e8a1",
  "reference": "COMPAT_ELEC_5b1f0c9ad2e34f77",
  "disco_name": "DISCO_ID",
  "meter_number": "45031234567",
  "amount": 2000,
  "message": "Electricity payment processing.",
  "oldbal": 15230,
  "newbal": 13230
}
{
  "status": "error",
  "message": "Transaction declined by the provider. Your wallet has been refunded.",
  "code": "PROVIDER_DECLINED",
  "newbal": 15230
}

Check status, not just the HTTP code. processing comes back with a 200: the provider hasn't given a clear answer, so your wallet stays debited while it's resolved. Don't retry; look it up instead.

Auth: Authorization: Token YOUR_API_KEY
FieldTypeDescription
discostringrequiredA discoId from List discos.
meter_numberstringrequiredThe meter number.
meter_typestring or numberrequiredprepaid or 1; postpaid or 2.
amountnumberrequiredWhole naira. The disco may set its own minimum.
request-idstringoptionalYour own reference. It's echoed back as sent.
curl -X POST "https://www.sbbdata.com.ng/compat/adex/api/bill" \
  -H "Authorization: Token YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"disco":"DISCO_ID","meter_number":"45031234567","meter_type":"prepaid","amount":2000,"request-id":"order-1003"}'
const res = await fetch("https://www.sbbdata.com.ng/compat/adex/api/bill", {
  method: "POST",
  headers: {
    Authorization: "Token YOUR_API_KEY",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({"disco":"DISCO_ID","meter_number":"45031234567","meter_type":"prepaid","amount":2000,"request-id":"order-1003"})
});
const data = await res.json();

Response

{
  "disco_name": "DISCO_ID",
  "request-id": "order-1003",
  "reference": "COMPAT_ELEC_5b1f0c9ad2e34f77",
  "amount": 2000,
  "charges": 0,
  "status": "success",
  "message": "Transaction successful DISCO_ID PREPAID ₦2000 to 45031234567",
  "meter_number": "45031234567",
  "meter_type": "PREPAID",
  "oldbal": "15230",
  "newbal": 13230,
  "system": "API",
  "token": "1234-5678-9012-3456-7890",
  "units": "42.5",
  "wallet_vending": "wallet"
}
{
  "status": "error",
  "message": "Transaction declined by the provider. Your wallet has been refunded.",
  "code": "PROVIDER_DECLINED",
  "newbal": 15230
}

Check status, not just the HTTP code. processing comes back with a 200 and your wallet stays debited while it's resolved. Don't retry.


Cable TV

Available on MSORG and ADEX. Prices are always set by SBB Data. Any amount you send is ignored.

GET/compat/msorg/api/cable-providers/GET/compat/adex/api/cable-providersMSORGADEX

List providers and plans

Returns each cable provider with its plans and current prices.

The native API sells airtime and data only, so cable TV isn't available here. Switch to MSORG or ADEX at the top of this page. They use the same API key.
Auth: Authorization: Token YOUR_API_KEY
curl "https://www.sbbdata.com.ng/compat/msorg/api/cable-providers/" \
  -H "Authorization: Token YOUR_API_KEY"
const res = await fetch("https://www.sbbdata.com.ng/compat/msorg/api/cable-providers/", {
  headers: {
    Authorization: "Token YOUR_API_KEY"
  }
});
const data = await res.json();

Response

{
  "status": true,
  "providers": [
    {
      "billerId": "BILLER_ID",
      "name": "DStv",
      "plans": [
        {
          "itemId": "ITEM_ID",
          "name": "Compact",
          "amount": 15700
        }
      ]
    }
  ]
}
Auth: Authorization: Token YOUR_API_KEY
curl "https://www.sbbdata.com.ng/compat/adex/api/cable-providers" \
  -H "Authorization: Token YOUR_API_KEY"
const res = await fetch("https://www.sbbdata.com.ng/compat/adex/api/cable-providers", {
  headers: {
    Authorization: "Token YOUR_API_KEY"
  }
});
const data = await res.json();

Response

{
  "status": "success",
  "providers": [
    {
      "billerId": "BILLER_ID",
      "name": "DStv",
      "plans": [
        {
          "itemId": "ITEM_ID",
          "name": "Compact",
          "amount": 15700
        }
      ]
    }
  ]
}

GET/compat/msorg/api/validateiucGET/compat/adex/api/cable/cable-validationMSORGADEX

Validate a smart card

Returns the customer name on a smart card or IUC number so you can confirm it before paying.

The native API sells airtime and data only, so cable TV isn't available here. Switch to MSORG or ADEX at the top of this page. They use the same API key.
Auth: Authorization: Token YOUR_API_KEY
FieldTypeDescription
smart_card_numberstringrequiredThe smart card or IUC number.
cablenamestringrequiredA billerId from List providers.
curl "https://www.sbbdata.com.ng/compat/msorg/api/validateiuc?smart_card_number=7012345678&cablename=BILLER_ID" \
  -H "Authorization: Token YOUR_API_KEY"
const res = await fetch("https://www.sbbdata.com.ng/compat/msorg/api/validateiuc?smart_card_number=7012345678&cablename=BILLER_ID", {
  headers: {
    Authorization: "Token YOUR_API_KEY"
  }
});
const data = await res.json();

Response

{
  "status": true,
  "customer_name": "BELLO MUSA",
  "renewal_amount": 15700
}

renewal_amount is what renewing the current bouquet costs right now, when the provider reports one.

Auth: Authorization: Token YOUR_API_KEY
FieldTypeDescription
iucstringrequiredThe smart card or IUC number.
cablestringrequiredA billerId from List providers.
curl "https://www.sbbdata.com.ng/compat/adex/api/cable/cable-validation?iuc=7012345678&cable=BILLER_ID" \
  -H "Authorization: Token YOUR_API_KEY"
const res = await fetch("https://www.sbbdata.com.ng/compat/adex/api/cable/cable-validation?iuc=7012345678&cable=BILLER_ID", {
  headers: {
    Authorization: "Token YOUR_API_KEY"
  }
});
const data = await res.json();

Response

{
  "status": "success",
  "name": "BELLO MUSA"
}

POST/compat/msorg/api/cablesub/POST/compat/adex/api/cableMSORGADEX

Buy a cable subscription

Send a plan to change the customer to that bouquet at its listed price. Leave the plan out to renew their current bouquet at the amount the provider quotes. If the provider declines, your wallet is refunded before the response comes back.

The native API sells airtime and data only, so cable TV isn't available here. Switch to MSORG or ADEX at the top of this page. They use the same API key.
Auth: Authorization: Token YOUR_API_KEY
FieldTypeDescription
cablenamestringrequiredA billerId from List providers.
smart_card_numberstringrequiredThe smart card or IUC number.
cableplanstringoptionalAn itemId to change to. Leave it out to renew.
curl -X POST "https://www.sbbdata.com.ng/compat/msorg/api/cablesub/" \
  -H "Authorization: Token YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"cablename":"BILLER_ID","cableplan":"ITEM_ID","smart_card_number":"7012345678"}'
const res = await fetch("https://www.sbbdata.com.ng/compat/msorg/api/cablesub/", {
  method: "POST",
  headers: {
    Authorization: "Token YOUR_API_KEY",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({"cablename":"BILLER_ID","cableplan":"ITEM_ID","smart_card_number":"7012345678"})
});
const data = await res.json();

Response

{
  "status": "success",
  "id": "69070f2ea1b94c0012d4e8a1",
  "reference": "COMPAT_CABLE_8e2a7d10c4b94f33",
  "cablename": "BILLER_ID",
  "cableplan": "ITEM_ID",
  "smart_card_number": "7012345678",
  "amount": 15700,
  "message": "Cable subscription successful.",
  "oldbal": 30930,
  "newbal": 15230
}
{
  "status": "error",
  "message": "Transaction declined by the provider. Your wallet has been refunded.",
  "code": "PROVIDER_DECLINED",
  "newbal": 30930
}

As with electricity, check status: processing comes back with a 200 and your wallet stays debited while it's resolved.

Auth: Authorization: Token YOUR_API_KEY
FieldTypeDescription
cablenamestringrequiredA billerId from List providers.
smart_card_numberstringrequiredThe smart card or IUC number.
cableplanstringoptionalAn itemId to change to. Leave it out to renew.
request-idstringoptionalYour own reference. It's echoed back as sent.
curl -X POST "https://www.sbbdata.com.ng/compat/adex/api/cable" \
  -H "Authorization: Token YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"cablename":"BILLER_ID","cableplan":"ITEM_ID","smart_card_number":"7012345678","request-id":"order-1004"}'
const res = await fetch("https://www.sbbdata.com.ng/compat/adex/api/cable", {
  method: "POST",
  headers: {
    Authorization: "Token YOUR_API_KEY",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({"cablename":"BILLER_ID","cableplan":"ITEM_ID","smart_card_number":"7012345678","request-id":"order-1004"})
});
const data = await res.json();

Response

{
  "cablename": "BILLER_ID",
  "cableplan": "ITEM_ID",
  "amount": 15700,
  "status": "success",
  "message": "Successfully subscribed BILLER_ID for Smart Card 7012345678",
  "smart_card_number": "7012345678",
  "request-id": "order-1004",
  "reference": "COMPAT_CABLE_8e2a7d10c4b94f33",
  "oldbal": 30930,
  "newbal": 15230,
  "system": "API"
}
{
  "status": "error",
  "message": "Transaction declined by the provider. Your wallet has been refunded.",
  "code": "PROVIDER_DECLINED",
  "newbal": 30930
}

As with electricity, check status: processing comes back with a 200 and your wallet stays debited while it's resolved.


Transactions

Check on purchases you've made. These live on MSORG, and your key works there whichever API you bought through.

GET/compat/msorg/api/data/MSORG

List data purchases

Returns your 100 most recent data purchases, newest first.

The native API has no history endpoint. Use the MSORG one with the same API key. It includes purchases made through the native API.
Auth: Authorization: Token YOUR_API_KEY
curl "https://www.sbbdata.com.ng/compat/msorg/api/data/" \
  -H "Authorization: Token YOUR_API_KEY"
const res = await fetch("https://www.sbbdata.com.ng/compat/msorg/api/data/", {
  headers: {
    Authorization: "Token YOUR_API_KEY"
  }
});
const data = await res.json();

Response

{
  "status": true,
  "results": [
    {
      "id": "69070f2ea1b94c0012d4e8a1",
      "reference": "API_DAT_9F2A1B4C0D3E",
      "network": "MTN",
      "mobile_number": "08031234567",
      "plan": "159",
      "amount": 300,
      "status": "success",
      "created_at": "2026-11-02T10:12:03.000Z"
    }
  ]
}

plan here is the id of the plan as it was sent to the provider, which can differ from the planId you bought with.

ADEX has no history endpoint. Your ADEX token also works on MSORG, so call the MSORG one with the same key.

GET/compat/msorg/api/data/{id}MSORG

Look up a data or airtime purchase

Takes the id or the reference of a purchase, so it also finds purchases made through the native API.

The native API has no lookup endpoint. Use the MSORG one with the same API key and the reference you got back.
Auth: Authorization: Token YOUR_API_KEY
curl "https://www.sbbdata.com.ng/compat/msorg/api/data/API_DAT_9F2A1B4C0D3E" \
  -H "Authorization: Token YOUR_API_KEY"
const res = await fetch("https://www.sbbdata.com.ng/compat/msorg/api/data/API_DAT_9F2A1B4C0D3E", {
  headers: {
    Authorization: "Token YOUR_API_KEY"
  }
});
const data = await res.json();

Response

{
  "id": "69070f2ea1b94c0012d4e8a1",
  "reference": "API_DAT_9F2A1B4C0D3E",
  "network": "MTN",
  "mobile_number": "08031234567",
  "plan": "159",
  "amount": 300,
  "status": "success",
  "created_at": "2026-11-02T10:12:03.000Z"
}

status is success, processing, pending or failed.

ADEX has no lookup endpoint. Your ADEX token also works on MSORG, so call the MSORG lookup with the same key to check a purchase.

GET/compat/msorg/api/billpayment/{id}MSORG

Look up an electricity purchase

Takes the id or reference of a purchase. Also how you get a prepaid token again.

The native API sells airtime and data only, so electricity isn't available here. Switch to MSORG or ADEX at the top of this page. They use the same API key.
Auth: Authorization: Token YOUR_API_KEY
curl "https://www.sbbdata.com.ng/compat/msorg/api/billpayment/COMPAT_ELEC_5b1f0c9ad2e34f77" \
  -H "Authorization: Token YOUR_API_KEY"
const res = await fetch("https://www.sbbdata.com.ng/compat/msorg/api/billpayment/COMPAT_ELEC_5b1f0c9ad2e34f77", {
  headers: {
    Authorization: "Token YOUR_API_KEY"
  }
});
const data = await res.json();

Response

{
  "status": true,
  "id": "69070f2ea1b94c0012d4e8a1",
  "reference": "COMPAT_ELEC_5b1f0c9ad2e34f77",
  "disco_name": "DISCO_ID",
  "meter_number": "45031234567",
  "amount": 2000,
  "token": "1234-5678-9012-3456-7890",
  "status_detail": "success"
}

Here status only says the lookup worked. The purchase's own state is in status_detail.

ADEX has no lookup endpoint. Your ADEX token also works on MSORG, so call the MSORG lookup with the same key to check a purchase.

GET/compat/msorg/api/cablesub/{id}MSORG

Look up a cable purchase

Takes the id or reference of a purchase.

The native API sells airtime and data only, so cable TV isn't available here. Switch to MSORG or ADEX at the top of this page. They use the same API key.
Auth: Authorization: Token YOUR_API_KEY
curl "https://www.sbbdata.com.ng/compat/msorg/api/cablesub/COMPAT_CABLE_8e2a7d10c4b94f33" \
  -H "Authorization: Token YOUR_API_KEY"
const res = await fetch("https://www.sbbdata.com.ng/compat/msorg/api/cablesub/COMPAT_CABLE_8e2a7d10c4b94f33", {
  headers: {
    Authorization: "Token YOUR_API_KEY"
  }
});
const data = await res.json();

Response

{
  "status": true,
  "id": "69070f2ea1b94c0012d4e8a1",
  "reference": "COMPAT_CABLE_8e2a7d10c4b94f33",
  "cablename": "BILLER_ID",
  "smart_card_number": "7012345678",
  "amount": 15700,
  "status_detail": "success"
}

Here status only says the lookup worked. The purchase's own state is in status_detail.

ADEX has no lookup endpoint. Your ADEX token also works on MSORG, so call the MSORG lookup with the same key to check a purchase.