API Documentation

Sell data, airtime, electricity, cable TV and e-pins from your own app or website. Your wallet is charged for each order, minus your API commission.

https://jonet.com.ng/api_live/v1/ Postman collection

Overview

The JoNet API is a set of simple JSON endpoints. Every order is paid from your JoNet wallet, and your API commission is taken off at the moment you buy.

  1. Create a JoNet account, then apply for API access from Upgrade Account in your dashboard.
  2. Once approved, open API Keys in your dashboard and generate your key. Keep it secret -- it can spend your wallet.
  3. Fund your wallet, and set your Webhook URL so we can tell you when a pending order finishes.
  4. Call the catalog endpoints (plans, packages, discos), store them, and start selling.

Authentication

Send your API key in the Authorization header on every request. A Bearer prefix is also accepted.

Authorization: YOUR_API_KEY
  • Keys are valid for one year. We remind you before expiry; an expired key returns 106. Generating a new key stops the old one immediately.
  • Use https only -- plain http is refused (104).
  • Up to 50 requests a minute per key (429 after that).
  • You can restrict your key to your own server IP addresses on your dashboard. A request from any other IP is refused, and its responseCode is the IP we saw.

Making requests

  • Base URL: https://jonet.com.ng/api_live/v1/
  • POST endpoints take a JSON body with Content-Type: application/json (max 64 KB). GET endpoints take query parameters.
  • Always read responseCode in the JSON body. Don't decide on the HTTP status alone -- some refusals come back with HTTP 404 and a JSON body.
  • Store the catalogs (data plans, TV packages, add-ons, discos) and refresh them regularly rather than on every order.

Customer ID

Every purchase needs a customer_id: your own unique reference for the order. It must:

  • start with today's date and hour in Lagos time (WAT, GMT+1) as YYYYMMDDHH -- we recommend adding the minute too (YYYYMMDDHHmm);
  • be 10 to 20 characters, using only letters, digits and -;
  • be unique on your account. Reusing one returns JO105.
"customer_id": "2026100114305581234"   // 2026-10-01 14:30 + "5581234"
The customer_id is how you find an order again with Requery. Keep it with your order.

Handling responses

Every purchase reply ends up in one of three states. Use the Treat as column in the table below.

  • Success (200) -- delivered.
  • Pending (201, 202, 203, 2031, 2032, JO105) -- your wallet was charged and the order is still being completed. It will succeed or be refunded. We send your webhook when it finishes, or you can call Requery.
  • Failed -- not delivered. If you were charged, the reply says refunded (JO106, JO107, JO1061) and the money is back in your wallet.
Never resend a Pending order with a new customer_id -- you may deliver it twice. The same goes for a timeout or no reply at all: Requery the customer_id first. We only refund when the vendor clearly confirms a failure; anything unclear stays Pending until it is settled.

Response codes

Any code not listed here should be treated as Failed.

CodeMeaningTreat as
200Successful. On Requery, 200 only means the order was found -- read status for its state.Success
201, 202, 203Processing / status not final yet. The order is charged; it completes or is refunded shortly. Wait for the webhook or Requery.Pending
2031, 2032Electricity: duplicate at the vendor (2031) or unknown status (2032). Not refunded -- Requery.Pending
JO105This customer_id was already used on your account. Requery that customer_id -- do not resend with a new one.Pending
JO106, JO107, JO1061Failed. Your wallet has been refunded.Failed
002, 10114Your wallet could not be charged. Nothing was taken.Failed
101No Authorization header found.Failed
102Invalid API key (Get Wallet answers an invalid key with 103).Failed
103Wrong request method (e.g. GET on a POST endpoint), or invalid authorization: the token does not belong to this key's account, or the account is not an API account.Failed
104Insecure connection -- use https.Failed
105Unable to process: unknown plan / package / disco, or an invalid amount or quantity.Failed
106This API key has expired. Generate a new one on your dashboard.Failed
107This API key has been paused, or the account has been suspended.Failed
108, 109Account not found, no vendor set up for this service, or busy -- try again.Failed
110, 1014, 424Insufficient balance (424 is also used for "cannot be done right now", e.g. out of stock, Airtime to Cash errors).Failed
1005, 1050Unable to process request. If it persists, contact support.Failed
1015This account is not eligible to make purchases.Failed
JO101This service is temporarily switched off (or not supported for this provider).Failed
JO102Missing or invalid request fields.Failed
JO103Wrong phone number format (must start with 0).Failed
JO104Wrong customer_id format (see Customer ID below).Failed
JO1051Wrong network name (Airtime).Failed
JO109No webhook URL set on your account.Failed
JO110Transaction not found.Failed
JO119Transaction not completed yet (webhook can only be resent for a finished order).Failed
JO121Your wallet balance is negative. Fund your wallet first.Failed
JO123The meter or smartcard could not be verified with the vendor. You were not charged.Failed
409Another action on your wallet is in progress -- try again.Failed
429Too many requests (more than 50 a minute per key) -- slow down.Failed
500Temporary error -- try again.Failed
Your IP addressThis request came from an IP address not on your allowed list.Failed
INVALID_JSON, PAYLOAD_TOO_LARGEThe body is not valid JSON, or is larger than 64 KB.Failed
SERVICE_UNAVAILABLEThe same customer_id is already being processed (sent twice at the same time), or the service is briefly unavailable -- wait a moment, then requery that customer_id before retrying.Failed

Webhook

When an order that came back Pending reaches its final state, we POST this JSON to the webhook URL set on your dashboard (Settings › Webhook). Use an https URL.

  • To check it really came from us, compare the Authorization header with your API key.
  • type is Data, Airtime, E-Pin, Digital tv or ENERGY BILL; status is Successful or Failed (Failed = refunded).
  • Reply with HTTP 200. If you missed one, use Requery or Resend Webhook.
Successful
{
    "status": "Successful",
    "server_response": "Successful",
    "type": "Airtime",
    "data": {
        "receipent": "08031234567",
        "customer_id": "2026100114305581234",
        "vendor_id": "",
        "balance": "12856"
    }
}
Failed
{
    "status": "Failed",
    "server_response": "Receiver account not found.",
    "type": "Data",
    "data": {
        "receipent": "08031234567",
        "customer_id": "2026100114307719042",
        "vendor_id": "",
        "balance": "12808"
    }
}

Wallet

Your wallet balance and account details.

GET

Get Wallet

https://jonet.com.ng/api_live/v1/get_wallet.php

Your current wallet balance and the bank accounts you can fund it through.

Example request
curl -X GET 'https://jonet.com.ng/api_live/v1/get_wallet.php' \
  -H 'Authorization: YOUR_API_KEY'
Responses
Successful
{
    "responseCode": "200",
    "walletBalance": "19176",
    "user": {
        "email": "[email protected]",
        "usrtel": "08031234567",
        "AccountCreated": "2019-05-18 12:12:50",
        "LastModified": "2026-09-05 00:23:00",
        "Accounts": {
            "AccountDetails": {
                "bankName": "8594950150",
                "accountNumber": "Providus Bank"
            },
            "BackupAccountDetails": {
                "bankName": "7589497373",
                "accountNumber": "Sterling Bank"
            }
        },
        "referral_link": "https://jonet.com.ng/signup?referral_id=76099008c"
    }
}
Notes
  • Note the field names under Accounts: bankName holds the account number and accountNumber holds the bank name. This is long-standing behaviour that existing integrations rely on, so it is kept as is.

Data

Get the data plans, then buy one with its code.

GET

Get Data Bundles

https://jonet.com.ng/api_live/v1/get_data_bundles.php

All active data plans, grouped by provider and then by network. Store them on your side and refresh regularly.

Example request
curl -X GET 'https://jonet.com.ng/api_live/v1/get_data_bundles.php' \
  -H 'Authorization: YOUR_API_KEY'
Responses
Successful
{
    "MTN": {
        "MTN_CG": [
            {
                "name": "MTN CG",
                "size": "1GB",
                "code": "7",
                "Plan_ID": "7",
                "Price": "240"
            },
            {
                "name": "MTN CG",
                "size": "2GB",
                "code": "4",
                "Plan_ID": "4",
                "Price": "480"
            }
        ]
    }
}
Current catalog (first few items) LIVE
Notes
  • Use code as the code in Purchase Data.
  • Price is the plan price. Your API commission is taken off when you buy; Purchase Data returns what was actually charged in amountcharged.
POST

Purchase Data

https://jonet.com.ng/api_live/v1/purchase_data.php

Buy a data plan for a phone number.

Body (JSON)
FieldDescription
code stringRequiredThe plan code from Get Data Bundles.
phone stringRequiredBeneficiary number. Must start with 0 (07…, 08…, 09…).
customer_id stringRequiredYour unique reference -- see Customer ID.
Example request
curl -X POST 'https://jonet.com.ng/api_live/v1/purchase_data.php' \
  -H 'Authorization: YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{"code":"7","phone":"08031234567","customer_id":"2026100114305581234"}'
Responses
Successful (200)
{
    "responseCode": "200",
    "status": "Successful",
    "message": "1GB MTN_CG to 08031234567 Successful",
    "receipent": "08031234567",
    "email": "[email protected]",
    "amountcharged": "228",
    "commissionGiven": "12",
    "balance": "8600",
    "chargeMethod": "Wallet",
    "channel": "API",
    "customer_id": "2026100114305581234",
    "vendor_id": "13397889",
    "server_response": "Dear Customer, You have successfully shared 1GB Data to 2348031234567.",
    "createdOn": "2026-10-01 14:30:55"
}
Processing (203) -- wait for the webhook or Requery
{
    "responseCode": "203",
    "status": "Processing",
    "message": "",
    "receipent": "08031234567",
    "email": "[email protected]",
    "amountcharged": "228",
    "commissionGiven": "12",
    "balance": "8372",
    "chargeMethod": "Wallet",
    "channel": "API",
    "customer_id": "2026100114307719042",
    "server_response": "Processing, it will be successful or refunded within 1 minute",
    "createdOn": "2026-10-01 14:30:57"
}
Failed -- refunded (JO107)
{
    "responseCode": "JO107",
    "status": "Failed",
    "message": "",
    "receipent": "08031234567",
    "email": "[email protected]",
    "amountcharged": "228",
    "commissionGiven": "12",
    "balance": "8600",
    "chargeMethod": "Wallet",
    "channel": "API",
    "customer_id": "2026100114309920117",
    "server_response": "Invalid phone number for this network",
    "createdOn": "2026-10-01 14:31:02"
}
Request rejected (example)
{
    "message": "Wrong customer ID format. Please check the documentation for the right format",
    "responseCode": "JO104",
    "status": "Failed"
}
Common errors
CodeWhen
JO102Missing code, phone or customer_id
JO103Phone number does not start with 0
JO104customer_id format
JO105customer_id already used
SERVICE_UNAVAILABLESame customer_id sent twice at the same time (HTTP 503) -- requery it
105Unknown plan code
JO101Data switched off
110Insufficient balance
002Wallet could not be charged
1015 / 1050 / JO121Account checks (see response codes)

Airtime

Top up any MTN, Glo, Airtel or 9mobile number.

POST

Purchase Airtime

https://jonet.com.ng/api_live/v1/purchase_airtime.php

Send airtime to a phone number.

Body (JSON)
FieldDescription
amount numberRequiredAirtime amount in Naira, at least 50.
phone stringRequiredBeneficiary number. Must start with 0.
network stringRequiredExactly one of MTN, Glo, Airtel, 9mobile (case-sensitive).
customer_id stringRequiredYour unique reference -- see Customer ID.
Example request
curl -X POST 'https://jonet.com.ng/api_live/v1/purchase_airtime.php' \
  -H 'Authorization: YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{"amount":"100","phone":"08031234567","network":"MTN","customer_id":"2026100114325511870"}'
Responses
Successful (200)
{
    "responseCode": "200",
    "status": "Successful",
    "message": "100 MTN_Airtime VTU to 08031234567 Successful",
    "receipent": "08031234567",
    "email": "[email protected]",
    "amountcharged": "98",
    "commissionGiven": "2",
    "balance": "8502",
    "chargeMethod": "Wallet",
    "channel": "API",
    "customer_id": "2026100114325511870",
    "vendor_id": "230981",
    "server_response": "Transaction successful",
    "createdOn": "2026-10-01 14:32:55"
}
Processing (203)
{
    "responseCode": "203",
    "status": "Processing",
    "message": "VTU MTN_Airtime to 08031234567 Processing",
    "receipent": "08031234567",
    "email": "[email protected]",
    "amountcharged": "98",
    "commissionGiven": "2",
    "balance": "8404",
    "chargeMethod": "Wallet",
    "channel": "API",
    "customer_id": "2026100114326640021",
    "server_response": "Processing",
    "createdOn": "2026-10-01 14:32:58"
}
Failed -- refunded (JO107)
{
    "responseCode": "JO107",
    "status": "Failed",
    "message": "",
    "receipent": "08031234567",
    "email": "[email protected]",
    "amountcharged": "98",
    "commissionGiven": "2",
    "balance": "8502",
    "chargeMethod": "Wallet",
    "channel": "API",
    "customer_id": "2026100114328810455",
    "server_response": "Transaction failed",
    "createdOn": "2026-10-01 14:33:04"
}
Common errors
CodeWhen
JO102Missing field, or amount below 50
JO103Phone format
JO104customer_id format
JO105customer_id already used
JO1051Network name not one of MTN, Glo, Airtel, 9mobile
JO101Airtime switched off for this network
1014 / 424Insufficient balance
10114Wallet could not be charged
109Busy -- try again

Cable TV

DStv, GOtv and StarTimes. Get packages and add-ons, check a smartcard, then subscribe.

GET

Get TV Packages

https://jonet.com.ng/api_live/v1/get_tv_packages.php

All active TV packages, grouped by package name, one entry per number of months. Cheapest first.

Example request
curl -X GET 'https://jonet.com.ng/api_live/v1/get_tv_packages.php' \
  -H 'Authorization: YOUR_API_KEY'
Responses
Successful
{
    "DStv Yanga Bouquet E36": [
        {
            "title": "DStv Yanga Bouquet E36",
            "service_type": "dstv",
            "price": "4200",
            "code": "NNJ1E36",
            "Plan_ID": "34",
            "months": "1",
            "allowance": "1",
            "s/n": "12"
        },
        {
            "title": "DStv Yanga Bouquet E36",
            "service_type": "dstv",
            "price": "8400",
            "code": "NNJ1E36",
            "Plan_ID": "35",
            "months": "2",
            "allowance": null,
            "s/n": "13"
        }
    ]
}
Current catalog (first few items) LIVE
Notes
  • Use code and months as code and product_monthsPaidFor in Purchase Cable TV.
  • Plan_ID is the plan code for the MSORG-style cable endpoint (sent there as cableplan); empty when that package has no MSORG plan.
GET

Get Add-on Packages

https://jonet.com.ng/api_live/v1/get_tv_addon.php

DStv / GOtv add-ons, grouped by add-on name, one entry per number of months.

Example request
curl -X GET 'https://jonet.com.ng/api_live/v1/get_tv_addon.php' \
  -H 'Authorization: YOUR_API_KEY'
Responses
Successful
{
    "French 11 Bouquet E36": [
        {
            "addon_title": "French 11 Bouquet E36",
            "price": "5150",
            "addon_code": "FRN11E36",
            "months": "1",
            "allowance": null,
            "s/n": "1"
        }
    ]
}
Current catalog (first few items) LIVE
Notes
  • Send addon_code in Purchase Cable TV to add it. Add-ons are not available for StarTimes.
POST

Get SmartCard Info

https://jonet.com.ng/api_live/v1/get_smartcard_info.php

Check a smartcard / IUC number before paying -- the customer name, current bouquet and renewal amount. Free.

Body (JSON)
FieldDescription
SmartCard_no stringRequiredThe smartcard or IUC number.
service_type stringRequireddstv, gotv or startimes.
Example request
curl -X POST 'https://jonet.com.ng/api_live/v1/get_smartcard_info.php' \
  -H 'Authorization: YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{"SmartCard_no":"7040373739","service_type":"dstv"}'
Responses
DStv / GOtv
{
    "responseCode": "200",
    "status": "success",
    "message": "Successful",
    "data": {
        "user": {
            "customerName": "ADA OBI",
            "outstandingBalance": 0,
            "dueDate": "2026-10-23",
            "Renewal_Amount": 4200,
            "smartCardNumber": "7040373739",
            "Customer_Number": "6347783",
            "Status": "Open"
        },
        "hasDiscount": "true",
        "currentBouquet": "DStv Yanga Bouquet E36",
        "currentBouquetCode": "NNJ1E36"
    }
}
StarTimes
{
    "responseCode": "200",
    "status": "success",
    "message": "Successful",
    "data": {
        "user": {
            "customerName": "ADA OBI",
            "outstandingBalance": 0,
            "dueDate": "",
            "balance": "0",
            "smartCardNumber": "02134567890",
            "accountNumber": ""
        },
        "hasDiscount": "false",
        "currentBouquet": "Nova"
    }
}
Common errors
CodeWhen
JO102Missing field
JO101Lookup failed or service switched off
109No vendor set up for this service
Notes
  • A field a vendor does not provide comes back as an empty string.
POST

Purchase Cable TV

https://jonet.com.ng/api_live/v1/purchase_tv.php

Renew the current bouquet, or subscribe to a package (optionally with an add-on).

Body (JSON)
FieldDescription
SmartCard_no stringRequiredThe smartcard or IUC number.
service_type stringRequireddstv, gotv or startimes.
subscription_type stringRequiredrenew = renew / top up the current bouquet (uses any discount on the account). Anything else (e.g. change) = pay for the package in code.
code stringFor changePackage code from Get TV Packages. Ignored for renew (send 0).
product_monthsPaidFor stringFor changeNumber of months (from Get TV Packages). Ignored for renew.
amount numberFor renewFor renew: the amount to pay (e.g. Renewal_Amount from Get SmartCard Info). For change it is ignored -- the package price is always charged.
addon_code stringOptionalAn addon_code from Get Add-on Packages, or 0 for none. Not for StarTimes.
customer_id stringRequiredYour unique reference -- see Customer ID.
Example request
curl -X POST 'https://jonet.com.ng/api_live/v1/purchase_tv.php' \
  -H 'Authorization: YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{"SmartCard_no":"7040373739","subscription_type":"change","service_type":"dstv","code":"NNJ1E36","product_monthsPaidFor":"1","amount":"0","addon_code":"0","customer_id":"2026100114405590213"}'
Responses
Successful (200)
{
    "responseCode": "200",
    "status": "Successful",
    "message": "DStv Yanga Bouquet E36 dstv to 7040373739 Successful",
    "receipent": "08031234567",
    "email": "[email protected]",
    "amountcharged": "4137",
    "commissionGiven": "63",
    "balance": "35142",
    "chargeMethod": "Wallet",
    "channel": "API",
    "customer_id": "2026100114405590213",
    "vendor_id": "17592663",
    "server_response": "TRANSACTION SUCCESSFUL",
    "createdOn": "2026-10-01 14:40:59"
}
Processing (203)
{
    "responseCode": "203",
    "status": "Processing",
    "message": "DStv Yanga Bouquet E36 dstv to 7040373739 Processing",
    "receipent": "08031234567",
    "email": "[email protected]",
    "amountcharged": "4137",
    "commissionGiven": "63",
    "balance": "31005",
    "chargeMethod": "Wallet",
    "channel": "API",
    "customer_id": "2026100114406612390",
    "server_response": "",
    "createdOn": "2026-10-01 14:41:02"
}
Failed -- refunded (JO107; JO106 = network failure, adds server_response)
{
    "responseCode": "JO107",
    "status": "Failed",
    "message": "Invalid smartcard number",
    "phone": "08031234567",
    "email": "[email protected]",
    "commissionGiven": "63",
    "balance": "35142",
    "data": {
        "Service_type": "dstv",
        "SmartCard_no": "7040373739",
        "Package_type": "DStv Yanga Bouquet E36",
        "amountcharged": "4137",
        "months_paidfor": "1",
        "addon": "0"
    },
    "chargeMethod": "Wallet",
    "channel": "API",
    "customer_id": "2026100114409910877",
    "createdOn": "2026-10-01 14:41:08"
}
Common errors
CodeWhen
JO102Missing field
JO104customer_id format
JO105customer_id already used
105Unknown package code or months
110Insufficient balance, or renew amount is 0
JO101TV switched off, or renewal not supported for this provider
JO123Smartcard could not be verified -- not charged
002 / 1005 / 1015See response codes
Notes
  • The failed reply has a different shape from success/processing (package details under data) -- this is long-standing behaviour.

Electricity

Prepaid tokens and postpaid bill payments for every disco.

GET

Get Discos

https://jonet.com.ng/api_live/v1/get_disco.php

All discos, prepaid and postpaid.

Example request
curl -X GET 'https://jonet.com.ng/api_live/v1/get_disco.php' \
  -H 'Authorization: YOUR_API_KEY'
Responses
Successful
[
    {
        "title": "Ikeja Electric Prepaid",
        "service_type": "ikeja_electric_prepaid",
        "code": "ikeja",
        "MeterType": "Prepaid"
    },
    {
        "title": "Abuja Electric Postpaid",
        "service_type": "abuja_electric_postpaid",
        "code": "abuja",
        "MeterType": "Postpaid"
    }
]
Current catalog (first few items) LIVE
Notes
  • Use service_type as disco in Get Meter Info and Purchase Electricity.
POST

Get Meter Info

https://jonet.com.ng/api_live/v1/get_meter_info.php

Check a meter number before paying -- customer name, address and minimum amount. Free.

Body (JSON)
FieldDescription
meter_no stringRequiredThe meter number.
disco stringRequiredThe disco service_type from Get Discos (e.g. ikeja_electric_prepaid).
Example request
curl -X POST 'https://jonet.com.ng/api_live/v1/get_meter_info.php' \
  -H 'Authorization: YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{"meter_no":"45067891234","disco":"ikeja_electric_prepaid"}'
Responses
Successful
{
    "responseCode": "200",
    "status": "success",
    "message": "Successful",
    "data": {
        "minimumAmount": 500,
        "outstandingBalance": 0,
        "user": {
            "customerName": "ADA OBI",
            "address": "12 Allen Avenue, Ikeja",
            "district": "Ikeja",
            "meterNumber": "45067891234",
            "accountNumber": "",
            "paymentPlan": "Prepaid",
            "tariff": "R2",
            "rate": "",
            "Customer_Number": "",
            "Status": "Active"
        },
        "hasDiscount": false,
        "errorMessage": ""
    }
}
Common errors
CodeWhen
JO102Missing field
JO101Lookup failed or service switched off
109No vendor set up for this disco
Notes
  • A field a vendor does not provide comes back as an empty string.
POST

Purchase Electricity

https://jonet.com.ng/api_live/v1/purchase_power.php

Buy a prepaid token or pay a postpaid bill.

Body (JSON)
FieldDescription
meter_no stringRequiredThe meter number.
disco stringRequiredThe disco service_type from Get Discos (case-sensitive).
amount numberRequiredAmount in Naira, at least 500.
phone stringRequiredPhone number that receives the token by SMS.
customer_id stringRequiredYour unique reference -- see Customer ID.
Example request
curl -X POST 'https://jonet.com.ng/api_live/v1/purchase_power.php' \
  -H 'Authorization: YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{"meter_no":"45067891234","disco":"ikeja_electric_prepaid","amount":"1000","phone":"08031234567","customer_id":"2026100114505512390"}'
Responses
Successful (200)
{
    "responseCode": "200",
    "status": "Successful",
    "message": "",
    "receipent": "08031234567",
    "email": "[email protected]",
    "amountcharged": "988",
    "commissionGiven": "12",
    "balance": "34012",
    "chargeMethod": "Wallet",
    "channel": "API",
    "service_type": "ikeja_electric_prepaid",
    "user_details": "ADA OBI<br>12 Allen Avenue, Ikeja",
    "meter_token": "3515-3990-0297-6774-2452",
    "unit": "14.6",
    "customer_id": "2026100114505512390",
    "createdOn": "2026-10-01 14:50:59"
}
Processing (203) -- token empty until it completes
{
    "responseCode": "203",
    "status": "Processing",
    "message": "",
    "receipent": "08031234567",
    "email": "[email protected]",
    "amountcharged": "988",
    "commissionGiven": "12",
    "balance": "33024",
    "chargeMethod": "Wallet",
    "channel": "API",
    "service_type": "ikeja_electric_prepaid",
    "user_details": "ADA OBI<br>12 Allen Avenue, Ikeja",
    "meter_token": "",
    "unit": "",
    "customer_id": "2026100114506601234",
    "createdOn": "2026-10-01 14:51:03"
}
Failed -- refunded (JO1061; JO106 = network failure, adds server_response)
{
    "responseCode": "JO1061",
    "status": "Failed",
    "message": "",
    "receipent": "08031234567",
    "email": "[email protected]",
    "amountcharged": "988",
    "commissionGiven": "12",
    "balance": "34012",
    "chargeMethod": "Wallet",
    "channel": "API",
    "service_type": "ikeja_electric_prepaid",
    "user_details": "ADA OBI<br>12 Allen Avenue, Ikeja",
    "meter_token": "",
    "unit": "",
    "customer_id": "2026100114507789001",
    "createdOn": "2026-10-01 14:51:09"
}
Common errors
CodeWhen
JO102Missing field
JO104customer_id format
JO105customer_id already used
105Amount below 500, or unknown disco
110Insufficient balance
JO101Electricity switched off for this disco
JO123Meter could not be verified -- not charged
2031 / 2032Pending at the vendor -- Requery, not refunded
002 / 1015See response codes
Notes
  • user_details is the meter name and address separated by <br>.

E-Pins

Recharge-card pins (MTN, Glo, Airtel, 9mobile) and WAEC / NECO / JAMB exam pins.

GET

Get E-Pin Plans

https://jonet.com.ng/api_live/v1/get_epin_plans.php

E-Pin plans with their price and what you pay per pin.

Query parameters
FieldDescription
network stringOptionalOptional filter: MTN, Glo, Airtel, Etisalat, waec, neco, jamb.
Example request
curl -X GET 'https://jonet.com.ng/api_live/v1/get_epin_plans.php?network=MTN' \
  -H 'Authorization: YOUR_API_KEY'
Responses
Successful
{
    "responseCode": "200",
    "status": "Successful",
    "plans": [
        {
            "plan": "12",
            "network": "MTN",
            "name": "MTN 100",
            "price": 100,
            "amount_charged": 98,
            "available": true,
            "stock": null
        }
    ]
}
Notes
  • price = face value per pin; amount_charged = what you pay per pin; available: false = out of stock (stock is a count only for plans sold from JoNet's own stock).
POST

Purchase E-Pin

https://jonet.com.ng/api_live/v1/purchase_epin.php

Buy one or more pins. The pins and serials are in the reply.

Body (JSON)
FieldDescription
plan stringRequiredThe plan from Get E-Pin Plans.
quantity numberRequired1 to 20 (JAMB is always 1).
phone stringFor WAEC/JAMBRequired for WAEC and JAMB.
profile_id stringFor JAMBThe candidate's JAMB Profile ID. Required for JAMB.
customer_id stringRequiredYour unique reference -- see Customer ID.
Example request
curl -X POST 'https://jonet.com.ng/api_live/v1/purchase_epin.php' \
  -H 'Authorization: YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{"plan":"12","quantity":3,"phone":"08031234567","profile_id":"","customer_id":"2026100115005512345"}'
Responses
Successful (200)
{
    "responseCode": "200",
    "status": "Successful",
    "message": "Successful",
    "pins": [
        "1234-5678-9012",
        "2234-5678-9013",
        "3234-5678-9014"
    ],
    "serials": [
        "SN0001",
        "SN0002",
        "SN0003"
    ],
    "plan": "MTN 100",
    "network": "MTN",
    "quantity": 3,
    "amountcharged": 294,
    "commissionGiven": 6,
    "balance": 5000,
    "chargeMethod": "Wallet",
    "channel": "API",
    "customer_id": "2026100115005512345",
    "createdOn": "2026-10-01 15:00:59"
}
Processing (203) -- pins come later; Requery returns them
{
    "responseCode": "203",
    "status": "Processing",
    "message": "",
    "pins": [],
    "serials": [],
    "plan": "MTN 100",
    "network": "MTN",
    "quantity": 3,
    "amountcharged": 294,
    "commissionGiven": 6,
    "balance": 4706,
    "chargeMethod": "Wallet",
    "channel": "API",
    "customer_id": "2026100115006612345",
    "createdOn": "2026-10-01 15:01:03"
}
Common errors
CodeWhen
JO102Missing field
JO104customer_id format
JO105customer_id already used
105Unknown plan, quantity out of range, missing phone / profile_id, or plan unavailable
424Out of stock (or not enough for the quantity)
110Insufficient balance
JO107Vendor refused -- refunded
JO101E-Pins switched off
002 / 1015See response codes

Airtime to Cash

Your customer converts airtime on their own SIM; the payout goes to your wallet. Three steps, all within 15 minutes.

GET

Get Airtime to Cash Networks

https://jonet.com.ng/api_live/v1/get_a2c_networks.php

Networks and rates. Only networks with can_do_auto ON work with the steps below.

Example request
curl -X GET 'https://jonet.com.ng/api_live/v1/get_a2c_networks.php' \
  -H 'Authorization: YOUR_API_KEY'
Responses
Successful
[
    {
        "network": "MTN",
        "percentage": "80",
        "can_do_auto": "ON",
        "recipient": "08012345678"
    }
]
Notes
  • percentage is the rate paid on the converted amount.
POST

Start Airtime to Cash

https://jonet.com.ng/api_live/v1/a2c_start.php

Starts a conversion and sends an OTP to the SIM.

Body (JSON)
FieldDescription
phone stringRequiredThe SIM holding the airtime (11 digits).
amount numberRequiredAirtime to convert, up to 20,000.
network stringRequiredA network from Get Airtime to Cash Networks with can_do_auto ON.
share_pin stringRequiredThe SIM's airtime-share PIN. Used once, never stored.
Example request
curl -X POST 'https://jonet.com.ng/api_live/v1/a2c_start.php' \
  -H 'Authorization: YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{"phone":"08031234567","amount":2000,"network":"MTN","share_pin":"1234"}'
Responses
Successful
{
    "responseCode": "200",
    "status": "Successful",
    "reference": "2026100115104412345",
    "message": "OTP sent."
}
Common errors
CodeWhen
JO102Missing field
424Network not automatic, invalid phone/amount, or amount too small after fees
409Wallet busy
429More than 5 starts a minute from your IP
500Try again
POST

Complete Airtime to Cash

https://jonet.com.ng/api_live/v1/a2c_complete.php

Confirms the OTP; the payout is credited to your wallet.

Body (JSON)
FieldDescription
reference stringRequiredThe reference from Start.
otp stringRequiredThe OTP the SIM received.
share_pin stringRequiredThe SIM's airtime-share PIN again.
Example request
curl -X POST 'https://jonet.com.ng/api_live/v1/a2c_complete.php' \
  -H 'Authorization: YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{"reference":"2026100115104412345","otp":"123456","share_pin":"1234"}'
Responses
Successful
{
    "responseCode": "200",
    "status": "Successful",
    "reference": "2026100115104412345",
    "amount": 2000,
    "payout": 1550,
    "balance": 51550,
    "message": "Airtime converted successfully."
}
Common errors
CodeWhen
JO102Missing field
424Wrong OTP (try again or resend), not enough airtime, no longer pending, vendor refused, or "needs manual review" (airtime received -- support credits it)
409Wallet busy
Notes
  • Payout = converted amount × the rate, minus NGN 50 per NGN 5,000 shared.
POST

Resend Airtime to Cash OTP

https://jonet.com.ng/api_live/v1/a2c_resend.php

Sends the OTP again.

Body (JSON)
FieldDescription
reference stringRequiredThe reference from Start.
Example request
curl -X POST 'https://jonet.com.ng/api_live/v1/a2c_resend.php' \
  -H 'Authorization: YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{"reference":"2026100115104412345"}'
Responses
Successful
{
    "responseCode": "200",
    "status": "Successful",
    "message": "OTP resent."
}
Common errors
CodeWhen
JO102Missing field
424No longer pending
500Try again

Event Tickets

Sell tickets to events on JoNet, or list your own events. Ticket purchases are instant: tickets are issued (or nothing is charged) in the same call -- there is no Pending state.

GET

Get Events

https://jonet.com.ng/api_live/v1/get_events.php

Approved events that haven't ended, soonest first (up to 100), with their ticket categories.

Example request
curl -X GET 'https://jonet.com.ng/api_live/v1/get_events.php' \
  -H 'Authorization: YOUR_API_KEY'
Responses
Successful
{
    "responseCode": "200",
    "status": "Successful",
    "events": [
        {
            "id": "JENT1791065965412",
            "name": "Lagos Jazz Night",
            "venue": "Eko Hall, VI",
            "date": "2026-11-14 18:00:00",
            "edate": "2026-11-14 23:00:00",
            "description": "Live jazz.",
            "picture": "https://res.cloudinary.com/.../event.jpg",
            "organizer": "Ola Events",
            "tiers": [
                {
                    "id": "31",
                    "category": "Regular",
                    "price": "3000.00"
                },
                {
                    "id": "32",
                    "category": "VIP",
                    "price": "20000.00"
                }
            ]
        }
    ]
}
Notes
  • Use the event id and a tier id in Purchase Ticket.
POST

Purchase Ticket

https://jonet.com.ng/api_live/v1/purchase_ticket.php

Buy tickets for your customer from your wallet, at the full ticket price.

Body (JSON)
FieldDescription
event_id stringRequiredFrom Get Events.
tier_id numberRequiredA ticket category id of that event.
quantity numberRequired1 to 10.
customer_id stringRequiredYour unique reference -- see Customer ID. Sending the same one again returns the original tickets; nothing is bought twice. Reusing it for a DIFFERENT order (other event, tier, quantity or holder) is refused with 409.
holder_name stringRequiredYour customer's name -- printed on every ticket and seen by the organizer.
holder_phone stringRequiredYour customer's phone number.
holder_email stringRequiredYour customer's email.
attendees arrayOptionalOptional: [{name, phone, email}, ...] with exactly one entry per ticket, to put a different person on each ticket (then holder_* can be left out).
Example request
curl -X POST 'https://jonet.com.ng/api_live/v1/purchase_ticket.php' \
  -H 'Authorization: YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{"event_id":"JENT1791065965412","tier_id":31,"quantity":2,"customer_id":"2026100114305581234","holder_name":"Ada Obi","holder_phone":"08031234567","holder_email":"[email protected]"}'
Responses
Successful (200)
{
    "responseCode": "200",
    "status": "Successful",
    "message": "Ticket purchase successful.",
    "event_name": "Lagos Jazz Night",
    "quantity": 2,
    "amountcharged": 6000,
    "balance": "44000.00",
    "chargeMethod": "Wallet",
    "channel": "API",
    "customer_id": "2026100114305581234",
    "tickets": [
        {
            "ticket_code": "TKT9F2C41A7B0",
            "status": "valid",
            "category": "Regular",
            "price": "3000.00",
            "holder_name": "Ada Obi",
            "holder_phone": "08031234567",
            "holder_email": "[email protected]",
            "event_id": "JENT1791065965412",
            "event_name": "Lagos Jazz Night",
            "venue": "Eko Hall, VI",
            "date": "2026-11-14 18:00:00",
            "edate": "2026-11-14 23:00:00",
            "purchased_at": "2026-10-01 14:30:57",
            "barcode_url": "https://jonet.com.ng/barcode.php?codetype=code128&print=true&text=TKT9F2C41A7B0",
            "ticket_url": "https://jonet.com.ng/guest_ticket_reprint.php?code=TKT9F2C41A7B0"
        }
    ],
    "createdOn": "2026-10-01 14:30:57"
}
Rejected (example)
{
    "message": "Insufficient wallet balance for this purchase.",
    "responseCode": "110",
    "status": "Failed"
}
Common errors
CodeWhen
JO102Missing or invalid field (holder details, attendees count, quantity)
JO104customer_id format
105Event or ticket category not found
JO101Event not open for sales, or already ended
110Insufficient balance
JO121Negative wallet balance
1015Account not eligible, or it is your own event
409This customer_id is still processing -- check it with Get Ticket
Notes
  • Failures charge nothing. Your account is recorded as the buyer who paid; the holder is your customer.
  • Send your customer the ticket_url (or the code / barcode) -- it is checked at the gate.
GET

Get Ticket

https://jonet.com.ng/api_live/v1/get_ticket.php

Look up tickets by your customer_id, or by ticket code. Shows whether a ticket is valid, used or refunded.

Query parameters
FieldDescription
customer_id stringOptionalThe order's customer_id -- returns its tickets and the order status.
ticket_code stringOptionalOne code, or several separated by commas (max 50). Send this or customer_id.
Example request
curl -X GET 'https://jonet.com.ng/api_live/v1/get_ticket.php?customer_id=2026100114305581234&ticket_code=VALUE' \
  -H 'Authorization: YOUR_API_KEY'
Responses
By customer_id
{
    "responseCode": "200",
    "status": "Successful",
    "order": {
        "customer_id": "2026100114305581234",
        "status": "Successful",
        "message": "Ticket purchase successful."
    },
    "tickets": [
        {
            "ticket_code": "TKT9F2C41A7B0",
            "status": "valid",
            "category": "Regular",
            "price": "3000.00",
            "holder_name": "Ada Obi",
            "event_name": "Lagos Jazz Night"
        }
    ]
}
Not found
{
    "message": "Transaction not found",
    "responseCode": "JO110",
    "status": "Failed"
}
Common errors
CodeWhen
JO102Send customer_id or ticket_code
JO110Not found, or not yours
JO119The order is still processing
Notes
  • You can see tickets you bought, and every ticket of an event you organize. A Failed order charged nothing. Ticket entries carry the same fields as in Purchase Ticket.
GET

Get Event Fees

https://jonet.com.ng/api_live/v1/get_event_fees.php

JoNet's current fees for events you list.

Example request
curl -X GET 'https://jonet.com.ng/api_live/v1/get_event_fees.php' \
  -H 'Authorization: YOUR_API_KEY'
Responses
Successful
{
    "responseCode": "200",
    "status": "Successful",
    "paid_ticket_percent": 5,
    "free_event_fee": 500,
    "terms": "Paid tickets: JoNet keeps 5% of each ticket sold; you receive the rest. Free events (every ticket free): a one-off listing fee of NGN 500.00 is taken from your wallet when you submit the event, and refunded if the event is not approved. Attendees pay nothing."
}
Notes
  • Paid tickets: JoNet keeps paid_ticket_percent of each sale; you receive the rest (the buyer pays the ticket price).
  • Free events (every category free): one flat free_event_fee per event, taken from your wallet when you submit it and refunded if it isn't approved. Attendees pay nothing.
  • The rates in force when you submit an event stay with that event. 0 = no fee.
POST

Create Event

https://jonet.com.ng/api_live/v1/create_event.php

Submit your own event for sale. It starts pending and is sold once JoNet approves it.

Body (JSON)
FieldDescription
name, venue, description stringRequiredEvent details.
start_date, end_date stringRequiredYYYY-MM-DD.
start_time, end_time stringRequiredHH:MM (24-hour).
category[], price[] arrayRequiredOne pair per ticket category; a blank or 0 price = free.
picture fileRequiredJPEG, PNG, GIF or WEBP, up to 5 MB.
idempotency_key stringOptionalYour unique reference for this submission. Sending the same one again (e.g. after a lost reply) returns the first result -- no second event or listing fee. Reusing it for a different event is refused.
Example request
curl -X POST 'https://jonet.com.ng/api_live/v1/create_event.php' \
  -H 'Authorization: YOUR_API_KEY'
Responses
Successful
{
    "responseCode": "200",
    "status": "Successful",
    "message": "Event submitted for approval.",
    "event_id": "JENT1791065965412",
    "listing_fee": 0,
    "fee_percent": 5
}
Common errors
CodeWhen
JO102Missing or invalid field or picture
110Not enough balance for a free event's listing fee
1015Account not eligible
500Try again
Notes
  • Send as multipart/form-data (not JSON), up to 11 MB. 20 events per account per hour.
  • listing_fee = what was taken now (free events only); fee_percent = JoNet's share of each paid ticket for this event. See Get Event Fees.
GET

My Events

https://jonet.com.ng/api_live/v1/my_events.php

Events you organize with their status and tickets sold -- or, with event_id, the tickets sold for that event. Newest first, one page at a time.

Query parameters
FieldDescription
event_id stringOptionalOne of your events, to list its tickets.
page integerOptionalPage number, from 1 (default 1).
limit integerOptionalRows per page (default 100, max 500).
Example request
curl -X GET 'https://jonet.com.ng/api_live/v1/my_events.php?event_id=VALUE&page=VALUE&limit=VALUE' \
  -H 'Authorization: YOUR_API_KEY'
Responses
Your events
{
    "responseCode": "200",
    "status": "Successful",
    "events": [
        {
            "id": "JENT1791065965412",
            "name": "Lagos Jazz Night",
            "venue": "Eko Hall, VI",
            "date": "2026-11-14 18:00:00",
            "edate": "2026-11-14 23:00:00",
            "picture": "https://res.cloudinary.com/.../event.jpg",
            "status": "approved",
            "tickets_sold": "42",
            "fee_percent": "5.00",
            "listing_fee": "0.00"
        }
    ],
    "page": 1,
    "limit": 100,
    "has_more": false
}
One event's tickets
{
    "responseCode": "200",
    "status": "Successful",
    "event_id": "JENT1791065965412",
    "tickets": [
        {
            "ticket_code": "TKT9F2C41A7B0",
            "holder_name": "Ada Obi",
            "holder_phone": "08031234567",
            "holder_email": "[email protected]",
            "buyer_name": "Part Ner",
            "category": "Regular",
            "price": "3000.00",
            "status": "valid",
            "purchased_at": "2026-10-01 14:30:57"
        }
    ],
    "page": 1,
    "limit": 100,
    "has_more": false
}
Common errors
CodeWhen
JO110Not your event
Notes
  • status: pending (awaiting approval), approved (on sale), banned, closed.
  • has_more: true means there are more rows -- request the same URL with page + 1.

Requery & Webhook

Check an order's final status, or ask for its webhook again.

GET

Requery

https://jonet.com.ng/api_live/v1/requery.php

The current status of an order, by your customer_id. Use it after any Processing / unclear reply, or a timeout.

Query parameters
FieldDescription
customer_id stringRequiredThe customer_id you sent with the purchase.
Example request
curl -X GET 'https://jonet.com.ng/api_live/v1/requery.php?customer_id=2026100114305581234' \
  -H 'Authorization: YOUR_API_KEY'
Responses
Data / Airtime
{
    "responseCode": "200",
    "status": "Successful",
    "recharge_type": "Data",
    "receipent": "08031234567",
    "email": "[email protected]",
    "amountcharged": "228",
    "commissionGiven": "12",
    "balance": "8600",
    "chargeMothed": "Wallet",
    "channel": "API",
    "customer_id": "2026100114305581234",
    "vendor_id": "13397889",
    "server_response": "Dear Customer, You have successfully shared 1GB Data to 2348031234567.",
    "createdOn": "2026-10-01 14:30:55"
}
Electricity
{
    "responseCode": "200",
    "status": "Successful",
    "recharge_type": "ENERGY BILL",
    "receipent": "08031234567",
    "email": "[email protected]",
    "amountcharged": "988",
    "commissionGiven": "12",
    "balance": "34012",
    "chargeMethod": "Wallet",
    "channel": "API",
    "service_type": "ikeja_electric_prepaid",
    "user_details": "ADA OBI",
    "meter_token": "3515-3990-0297-6774-2452",
    "unit": "14.6",
    "customer_id": "2026100114505512390",
    "createdOn": "2026-10-01 14:50:59"
}
Cable TV
{
    "responseCode": "200",
    "status": "Successful",
    "recharge_type": "Digital tv",
    "phone": "08031234567",
    "email": "[email protected]",
    "commissionGiven": "63",
    "balance": "35142",
    "Service_type": "dstv",
    "SmartCard_no": "7040373739",
    "amountcharged": "4137",
    "months_paidfor": "1",
    "chargeMethod": "Wallet",
    "channel": "API",
    "customer_id": "2026100114405590213",
    "createdOn": "2026-10-01 14:40:59"
}
E-Pin -- pins filled once Successful
{
    "responseCode": "200",
    "status": "Successful",
    "recharge_type": "E-Pin",
    "plan": "MTN 100",
    "network": "MTN",
    "receipent": "08031234567",
    "email": "[email protected]",
    "pins": [
        "1234-5678-9012"
    ],
    "serials": [
        "SN0001"
    ],
    "amountcharged": "98",
    "commissionGiven": "2",
    "balance": "5000",
    "chargeMethod": "Wallet",
    "channel": "API",
    "customer_id": "2026100115005512345",
    "vendor_id": "",
    "createdOn": "2026-10-01 15:00:59"
}
Not found
{
    "message": "Transaction not found",
    "responseCode": "JO110",
    "status": "Failed"
}
Common errors
CodeWhen
JO102Missing customer_id
JO110No order with that customer_id on your account
Notes
  • responseCode is 200 whenever the order is found. The order's real state is in status (Successful, Failed, Pending, Processing).
  • The Data/Airtime reply spells the payment field chargeMothed (long-standing; the other services use chargeMethod).
POST

Resend Webhook

https://jonet.com.ng/api_live/v1/resend_webhook.php

Sends a finished Data or Airtime order's webhook to your URL again.

Body (JSON)
FieldDescription
customer_id stringRequiredThe customer_id of the order.
Example request
curl -X POST 'https://jonet.com.ng/api_live/v1/resend_webhook.php' \
  -H 'Authorization: YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{"customer_id":"2026100114305581234"}'
Responses
Successful
{
    "responseCode": "200",
    "status": "Successful",
    "message": "Webhook successfully resent"
}
Common errors
CodeWhen
JO102Missing customer_id
JO110Order not found
JO119Order not finished yet
JO109No webhook URL set
Questions or need test help? Email [email protected] or chat on WhatsApp.