NeratSubs API
Get your API key →
Getting Started/Introduction
NeratSubs API v1

Build on NeratSubs

The NeratSubs API lets you sell airtime, data, electricity, cable TV, and social-media packages directly from your own platform, using the same wallet, pricing, and provider connections that power the NeratSubs app. Every endpoint below is documented against the live, production API — not a simplified or hypothetical version of it.

Base URL

https://api.neratsub.com.ng/api

This API is account-based: you integrate as a NeratSubs user, using your own wallet balance to fund purchases you make on behalf of your customers. There is no separate "merchant" account type — any NeratSubs account can generate an API key and start integrating immediately.


Playground

Sandbox

Pick an endpoint, then send a real request straight from your browser to api.neratsub.com.ng. This isn't a mockup — it's a live call against the production API, using your own credentials. Purchase and voucher endpoints spend real wallet balance.

GET

Your personal API key, from Settings → API Access in the app.

Your key is used only for the request you send, never logged, and never sent anywhere but NeratSubs' own API — kept in this tab's session storage at most, cleared when you close it.


Authentication

Every request is authenticated with an API key, sent in the X-API-Key header.

Getting a key

API keys are generated from inside the NeratSubs app, not through this API — open the app, go to Settings → API Access, and tap Enable. The raw key is shown exactly once. If you lose it, generate a new one (this immediately invalidates the old one — there's no overlap period), or disable API access entirely from the same screen.

X-API-Key: your_api_key_here

NeratSubs stores only a one-way hash of your key — support cannot look up or recover a lost key for you, and neither can you retrieve it again from the app after the first time it's shown.

⚠ An API key has full account access

There is currently no way to scope a key to "purchases only." A key authenticates as your full NeratSubs account — the same as being logged into the app — and can move money from your wallet, change your account settings, and read your transaction history. Treat it like a password: never commit it to source control, never expose it to client-side/browser code, and rotate it immediately if it's ever leaked.


Requests & Responses

Every request body is JSON. Send Content-Type: application/json on any request with a body.

Response shape

Every response is plain JSON — the data directly, no wrapper envelope:

{ "user": { "...": "..." } }
// or { "transaction": "...", "balance": 12345 }, { "balance": 12345 }, etc.
// -- the exact shape is documented per endpoint below.

On failure, a flat error message with no typed error code:

{ "error": "Incorrect PIN" }

Check the HTTP status code to branch on the kind of failure — there is no separate code field to switch on.


Errors

HTTP status codes you'll actually see from this API:

StatusMeaning
400Request body failed validation, or a business rule rejected it (e.g. amount below minimum, insufficient balance).
401Missing or invalid X-API-Key, or an incorrect transaction PIN.
404The resource (transaction, voucher, route) doesn't exist, or doesn't belong to your account.
409The request conflicts with existing state — a duplicate value, a voucher already redeemed, a virtual account already generated.
429Rate limited — see Rate Limits.
502The upstream network/disco/cable/SMM provider declined or errored. Your wallet is automatically refunded before this is returned.
500Unexpected server error. Safe to retry.
A prompt decline is never a silent failure

If a purchase's upstream provider declines or errors, you get a non-2xx response back and your wallet debit is reversed before the response is sent — you never need to poll or guess whether a refund is coming.


Rate Limits

Two limits apply, tracked separately. Everything not listed below is unthrottled.

Auth routes — 20 / 15 minutes, per IP Purchases & vouchers — 60 / hour, per account

The auth limit covers every /auth/* route, including change-pin and change-password. The purchases & vouchers limit covers every method under /purchases and /vouchers — including the read-only listing endpoints, not just the ones that spend money. Services, wallet, transactions, account, and API-access endpoints have no endpoint-specific limit.

The 429 response is still normal JSON

Unlike some APIs, a rate-limit rejection here uses the same { error } shape as every other error — no special parsing needed. Standard rate-limit headers are included on every response:

RateLimit-Limit: 60
RateLimit-Policy: 60;w=3600
RateLimit-Remaining: 0
RateLimit-Reset: 1800

GET /services

The full list of service types, providers, and fixed-price packages — fetch this to know what providerId/packageId values are valid for a purchase. The whole catalog is a few dozen rows, returned in one shot — no pagination or filtering params.

curl https://api.neratsub.com.ng/api/services \
  -H "X-API-Key: your_api_key_here"
const res = await fetch("https://api.neratsub.com.ng/api/services", {
  headers: { "X-API-Key": process.env.NERATSUBS_API_KEY }
});
const { serviceTypes, providers, packages } = await res.json();

Response

{
  "serviceTypes": ["airtime", "data", "electricity", "cable", "social"],
  "providers": [
    { "id": "mtn", "serviceType": "airtime", "name": "MTN" },
    { "id": "mtn-data", "serviceType": "data", "name": "MTN" },
    { "id": "dstv", "serviceType": "cable", "name": "DStv" }
  ],
  "packages": [
    { "id": "mtn-data-1gb-30d", "providerId": "mtn-data", "label": "1GB — 30 Days", "amount": 450, "category": "monthly" },
    { "id": "mtn-data-2gb-30d", "providerId": "mtn-data", "label": "2GB — 30 Days", "amount": 800, "category": "monthly" }
  ]
}

packages only applies to data, cable, and social service types — airtime and electricity are free-amount (you choose the amount at purchase time, see Buy a service).


GET /auth/me

Returns your account — name, username, email, balance, virtual account, referral code, and more. There is no separate "check balance" endpoint — use this, or Get wallet.

curl https://api.neratsub.com.ng/api/auth/me \
  -H "X-API-Key: your_api_key_here"
const res = await fetch("https://api.neratsub.com.ng/api/auth/me", {
  headers: { "X-API-Key": process.env.NERATSUBS_API_KEY }
});
const { user } = await res.json();
console.log(user.balance);

Response

{
  "user": {
    "id": "68f1a2b3c4d5e6f7a8b9c0d1",
    "name": "Jane Developer",
    "username": "janedev",
    "email": "you@example.com",
    "balance": 15230,
    "profileComplete": true,
    "role": "user",
    "referralCode": "JANE4F2A",
    "virtualAccount": { "accountNumber": "8123456789", "bankName": "Providus Bank" },
    "createdAt": "2026-01-14T09:22:11.000Z"
  }
}
POST /auth/change-pin

Change your transaction PIN. Requires the current one.

FieldTypeNotes
currentPinstringrequiredYour current 4-digit PIN.
newPinstringrequired4 digits.
curl -X POST https://api.neratsub.com.ng/api/auth/change-pin \
  -H "X-API-Key: your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{"currentPin":"1234","newPin":"5678"}'
POST /auth/change-password

Change your login password. Requires the current one.

FieldTypeNotes
currentPasswordstringrequired
newPasswordstringrequiredAt least 6 characters.
curl -X POST https://api.neratsub.com.ng/api/auth/change-password \
  -H "X-API-Key: your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{"currentPassword":"old_password","newPassword":"new_password_123"}'
GET /account/upgrade-request

Check the status of your own upgrade request, if you have made one.

curl https://api.neratsub.com.ng/api/account/upgrade-request \
  -H "X-API-Key: your_api_key_here"
GET /account/referral-stats

Your referral code, how many people you have referred, and how much you have earned from it.

curl https://api.neratsub.com.ng/api/account/referral-stats \
  -H "X-API-Key: your_api_key_here"

POST /purchases Rate limited — 60/hour

Buy airtime, data, electricity, cable, or a social-media package. For a package-based service (data/cable/social), the price is always the catalog price — amount is ignored. For airtime/electricity, amount is required and must meet the service minimum (₦1,000 for electricity, no minimum for airtime).

FieldTypeNotes
serviceTypestringrequiredairtime | data | electricity | cable | social
providerIdstringrequiredFrom List services.
referencestringrequiredPhone number (airtime/data), meter number (electricity), smartcard number (cable), or profile link (social).
packageIdstringoptionalRequired for data/cable/social.
amountnumberoptionalRequired for airtime/electricity.
couponCodestringoptionalApplies a discount if valid.
pinstringrequiredYour 4-digit transaction PIN.
curl -X POST https://api.neratsub.com.ng/api/purchases \
  -H "X-API-Key: your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "serviceType": "data",
    "providerId": "mtn-data",
    "packageId": "mtn-data-1gb-30d",
    "reference": "08031234567",
    "pin": "1234"
  }'
const res = await fetch("https://api.neratsub.com.ng/api/purchases", {
  method: "POST",
  headers: {
    "X-API-Key": process.env.NERATSUBS_API_KEY,
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    serviceType: "data",
    providerId: "mtn-data",
    packageId: "mtn-data-1gb-30d",
    reference: "08031234567",
    pin: "1234"
  })
});
const { ok, transaction, balance } = await res.json();

Response

{
  "ok": true,
  "transaction": {
    "id": "68f9a1b2c3d4e5f6a7b8c9d1",
    "kind": "purchase",
    "serviceType": "data",
    "providerName": "MTN",
    "reference": "08031234567",
    "amount": 450,
    "status": "successful",
    "date": "2026-10-05T11:02:00.000Z"
  },
  "balance": 14780
}

GET /transactions

List your transactions, newest first.

Query paramTypeNotes
kindstringoptionalpurchase | funding | voucher
serviceTypestringoptionalairtime | data | electricity | cable
curl "https://api.neratsub.com.ng/api/transactions?kind=purchase" \
  -H "X-API-Key: your_api_key_here"
GET /transactions/:id

Get one transaction by id.

curl https://api.neratsub.com.ng/api/transactions/68f9a1b2c3d4e5f6a7b8c9d1 \
  -H "X-API-Key: your_api_key_here"

GET /wallet

Get your balance and dedicated funding account (if you have generated one).

curl https://api.neratsub.com.ng/api/wallet \
  -H "X-API-Key: your_api_key_here"

Response

{
  "balance": 14780,
  "virtualAccount": { "accountNumber": "8123456789", "bankName": "Providus Bank" }
}
POST /wallet/virtual-account

Generate a dedicated bank account number for funding your wallet by transfer — requires BVN or NIN verification. One per account; calling this again once generated is rejected with 409.

FieldTypeNotes
idTypestringrequiredBVN or NIN
idNumberstringrequired11 digits, must match the account holder's name.
curl -X POST https://api.neratsub.com.ng/api/wallet/virtual-account \
  -H "X-API-Key: your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{"idType":"BVN","idNumber":"12345678901"}'

Response

{ "virtualAccount": { "accountNumber": "8123456789", "bankName": "Providus Bank" } }
POST /wallet/verify-pin

Confirm your PIN with no side effect — does not move money.

curl -X POST https://api.neratsub.com.ng/api/wallet/verify-pin \
  -H "X-API-Key: your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{"pin":"1234"}'

Vouchers

Prepaid codes redeemable for wallet credit, airtime, data, electricity, or cable — create them to give away or resell, or redeem/use ones you have. Every voucher endpoint below is rate limited at 60/hour per account, same as purchases.

GET /vouchers Rate limited — 60/hour

List vouchers you created.

curl https://api.neratsub.com.ng/api/vouchers \
  -H "X-API-Key: your_api_key_here"
POST /vouchers Rate limited — 60/hour

Create a voucher. Debits amountPerRedemption × maxRedemptions from your wallet immediately.

FieldTypeNotes
typestringrequiredwallet | airtime | data | electricity | cable
providerId / packageIdstringoptionalRequired for non-wallet types, same rules as Buy a service.
amountnumberoptionalRequired for wallet/airtime/electricity types.
maxRedemptionsnumberrequired1 to 1000.
expiresAtstringrequiredISO date.
messagestringoptionalUp to 200 characters.
codestringoptionalCustom voucher code; auto-generated if omitted.
pinstringrequiredYour 4-digit transaction PIN.
curl -X POST https://api.neratsub.com.ng/api/vouchers \
  -H "X-API-Key: your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "wallet",
    "amount": 500,
    "maxRedemptions": 10,
    "expiresAt": "2026-12-31T23:59:59.000Z",
    "message": "Enjoy!",
    "pin": "1234"
  }'

Response

{
  "voucher": { "code": "ABC123", "type": "wallet", "amountPerRedemption": 500, "maxRedemptions": 10 },
  "transaction": { "id": "...", "kind": "voucher", "amount": 5000, "status": "successful" },
  "balance": 9780
}
GET /vouchers/lookup/:code Rate limited — 60/hour

Preview a voucher by code before redeeming it — never reveals who created it.

curl https://api.neratsub.com.ng/api/vouchers/lookup/ABC123 \
  -H "X-API-Key: your_api_key_here"
POST /vouchers/redeem Rate limited — 60/hour

Redeem a voucher. Omitting reference claims it now and defers delivery to Deliver a claimed voucher later. wallet-type is always credited instantly.

FieldTypeNotes
codestringrequired
referencestringoptionalPhone/meter/smartcard — omit to defer delivery.
pinstringrequiredYour 4-digit transaction PIN.
curl -X POST https://api.neratsub.com.ng/api/vouchers/redeem \
  -H "X-API-Key: your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{"code":"ABC123","reference":"08031234567","pin":"1234"}'
POST /vouchers/:code/use Rate limited — 60/hour

Deliver a previously deferred redemption. No PIN — the creator already paid at redemption time.

curl -X POST https://api.neratsub.com.ng/api/vouchers/ABC123/use \
  -H "X-API-Key: your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{"reference":"08031234567"}'
GET /vouchers/redeemed Rate limited — 60/hour

List vouchers you have redeemed as the claimant.

curl https://api.neratsub.com.ng/api/vouchers/redeemed \
  -H "X-API-Key: your_api_key_here"

API Access

Manage this personal API key from the API itself — the same actions available in Settings → API Access in the app.

GET /api-access

Check whether a key is enabled, and its prefix.

curl https://api.neratsub.com.ng/api/api-access \
  -H "X-API-Key: your_api_key_here"
POST /api-access/enable

Generate a key (or rotate the existing one). The raw key is only ever shown in this response — there's also POST /api-access/regenerate, identical except it 400s if no key exists yet.

Response

{ "apiKey": "ns_live_3f9a1b2c4d5e6f7a8b9c0d1e2f3a4b5c", "status": "enabled" }
POST /api-access/disable

Revoke your key immediately.

curl -X POST https://api.neratsub.com.ng/api/api-access/disable \
  -H "X-API-Key: your_api_key_here"

Ready to integrate?

Open the NeratSubs app → Settings → API Access to generate your key.

Get the app →