API for resellers
Sell airtime, data, cable TV, electricity, exam pins and recharge cards on your own website or app. Each order is paid from your SmartTech Hub & Harvests wallet at your Agent or Dealer price, exactly as if you had pressed Buy on our site.
Getting started
- Open an account and become an Agent (Account, then Become an Agent). The API is for Agents and Dealers.
- Go to App, API and make a key. It is shown once: copy it then.
- Fund your wallet. Every order is paid from it.
- Send requests from your server with the key in the Authorization header.
| Address | https://smartek.com.ng/api/v1 |
| Key | Authorization: Bearer stk_live_YOUR_KEY_HERE (or the header x-api-key) |
| Format | JSON in, JSON out. Send Content-Type: application/json with a body. |
| Money | Naira, as numbers: 1500 is ₦1,500. |
| Limits | 240 requests a minute, of which 60 orders a minute. |
Keep the key on your server. Whoever has it can spend your wallet, so never put it in a web page or a phone app people can download. You can lock a key to your server's address, and switch a key off at any time, on the API page.
Orders and references
Every order you send carries a reference: your own name for it, 4 to 60 letters, digits, _, -, . or :. Use a new reference for each order, such as your own order number.
The same reference is always the same order. If your connection drops or times out and you do not know whether an order went through, send it again with the same reference. You get back the first order as it stands, with "repeated": true, and are never charged twice.
An order is in one of three states:
| delivered | Done. Tokens, pins and card details are in the answer. |
| processing | The supplier has not confirmed yet. Ask again with GET /orders/{reference} after 30 seconds or so. Most finish within a minute. |
| refunded | It could not be delivered. The full amount is back in your wallet, and "message" says why. |
Endpoints
All addresses below follow https://smartek.com.ng/api/v1. The figures in the examples are made up; your own come from /services and /plans.
GET/balance
Your wallet balance.
{ "balance": 25000, "currency": "NGN" }GET/services
Everything you can buy right now, with the code to send. Airtime shows your discount, electricity your service charge and its smallest amount, exam pins your price, and the rest point to their plans.
{
"services": [
{ "code": "mtn-airtime", "category": "airtime", "name": "MTN Airtime",
"discount_percent": 1.5, "min_amount": 50, "max_amount": 50000 },
{ "code": "mtn-sme-data", "category": "data", "name": "MTN SME Data",
"plans": "/api/v1/plans?service=mtn-sme-data" },
{ "code": "ibadan-electric", "category": "electricity", "name": "Ibadan Electricity",
"service_charge": 50, "min_amount": 1000, "max_amount": null,
"meter_types": ["prepaid", "postpaid"] },
{ "code": "waec", "category": "exam_pin", "name": "WAEC Result Checker", "price": 1234 }
]
}GET/plans?service=CODE
Data plans, TV packages or recharge card values for one service, at your price. Send the plan's code when buying.
{
"service": "mtn-sme-data",
"plans": [
{ "code": "mtn-sme-1gb-30", "name": "1GB, 30 days", "price": 999 }
]
}POST/verify
Whose smartcard or meter a number is, before you buy. Free.
| service | A cable TV or electricity code |
| number | The smartcard or meter number |
| meter_type | Electricity only: prepaid or postpaid |
{ "name": "ADEBAYO OLUWASEUN", "details": { "Address": "12 Taiwo Road, Ilorin" } }POST/buy
Places one order and pays for it from your wallet. Every order needs reference and service, then:
| airtime | phone, amount (one phone number per order) |
| data | phone, plan |
| cable | smartcard, plan, phone (the customer's, for the supplier's notice) |
| electricity | meter, meter_type (prepaid or postpaid), amount, phone |
| exam_pin | quantity (1 to 50; 1 if left out) |
| recharge_pin | plan (the card value's code), quantity, name_on_card (2 to 30 letters, printed on the cards) |
A new order answers 201 with the order. The same reference again answers 200 with the first order and "repeated": true.
{
"order": {
"id": "6f1c2a9e-3b7d-4c55-9a51-2f0e8d1b7c40",
"reference": "ORDER-10045",
"status": "delivered",
"service": "ibadan-electric",
"category": "electricity",
"description": "Ibadan Electricity (prepaid)",
"recipient": "45031234567",
"quantity": 1,
"amount": 2050,
"token": "1234-5678-9012-3456-7890",
"units": "28.4 kWh",
"created_at": "2026-10-12T09:15:02.118Z",
"completed_at": "2026-10-12T09:15:05.940Z"
}
}Exam pins come back as "pins": [{ "pin": "…", "serial": "…" }]. Recharge cards come back as "card" (network, value, name, load_code) and "pins".
GET/orders/{reference}
One order, by your reference (or by our order id). A processing order is checked with the supplier before answering.
Errors
Every error has the same shape, with a short code to act on and a message you can show your customer:
{ "error": { "code": "INSUFFICIENT_FUNDS", "message": "Your wallet balance is not enough for this order. Fund your wallet, then try again." } }| 400 | Something in the request needs fixing: BAD_JSON, BAD_REFERENCE, UNKNOWN_SERVICE, INVALID, BAD_QUANTITY, BELOW_MINIMUM, ABOVE_MAXIMUM. Nothing was charged. |
| 401 UNAUTHORISED | No key, a wrong key, or a key that has been switched off. |
| 402 INSUFFICIENT_FUNDS | Your wallet does not hold enough. Nothing was charged. |
| 403 | NOT_ALLOWED (the account is no longer an Agent or Dealer) or IP_NOT_ALLOWED (the key is locked to other addresses). |
| 404 NOT_FOUND | No order with that reference, or no smartcard or meter with that number. |
| 409 SAME_ORDER_JUST_PLACED | The same service, number and amount was ordered under another reference less than 90 seconds ago. Nothing was charged. |
| 429 RATE_LIMITED | Too many requests. Wait a minute. |
| 500, 503 | A problem on our side or a supplier's, or the service is paused. For an order, ask for it by its reference before sending it again. |
Examples
curl
curl https://smartek.com.ng/api/v1/balance \
-H "Authorization: Bearer stk_live_YOUR_KEY_HERE"
curl https://smartek.com.ng/api/v1/buy \
-H "Authorization: Bearer stk_live_YOUR_KEY_HERE" \
-H "Content-Type: application/json" \
-d '{"reference":"ORDER-10044","service":"mtn-airtime","phone":"08031234567","amount":500}'
curl https://smartek.com.ng/api/v1/orders/ORDER-10044 \
-H "Authorization: Bearer stk_live_YOUR_KEY_HERE"PHP
<?php
function smartek($method, $path, $body = null) {
$ch = curl_init('https://smartek.com.ng/api/v1' . $path);
$headers = ['Authorization: Bearer ' . getenv('SMARTEK_API_KEY')];
if ($body !== null) {
$headers[] = 'Content-Type: application/json';
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($body));
}
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => $method,
CURLOPT_HTTPHEADER => $headers,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 60,
]);
$answer = json_decode(curl_exec($ch), true);
curl_close($ch);
return $answer;
}
// Data for a customer. Use your own order number as the reference,
// and send the same one again if you are not sure it went through.
$result = smartek('POST', '/buy', [
'reference' => 'ORDER-10045',
'service' => 'mtn-sme-data',
'plan' => 'mtn-sme-1gb-30',
'phone' => '08031234567',
]);
if (isset($result['error'])) {
echo $result['error']['message'];
} elseif ($result['order']['status'] === 'processing') {
// Ask again in 30 seconds: smartek('GET', '/orders/ORDER-10045')
}JavaScript (Node.js)
const res = await fetch('https://smartek.com.ng/api/v1/buy', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.SMARTEK_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
reference: 'ORDER-10046',
service: 'dstv',
plan: 'dstv-compact',
smartcard: '7023456789',
phone: '08031234567',
}),
});
const answer = await res.json();
if (!res.ok) throw new Error(answer.error.message);
console.log(answer.order.status);Codes, plans and figures in these examples are made up: ask /services and /plans for the real ones. Questions? Call or WhatsApp 0813 077 3569, or email smarttechhub.harvest@gmail.com.
