Purchase airtime
Purchase airtime. Request fields, response examples and integration guidance.
/purchases/airtime
Example request
curl --request POST \
--url "https://api.strongmb.ng/v1/purchases/airtime" \
--header "Authorization: Bearer $STRONGMB_API_KEY" \
--header "Accept: application/json" \
--header "Content-Type: application/json" \
--data '{
"phone": "0123456789",
"product_code": "smb_mtn_vtu",
"amount": "100",
"reference": "SMB202609160001"
}'
// Server-side Node.js 22+; never expose your key in a browser.
async function main() {
const response = await fetch("https://api.strongmb.ng/v1/purchases/airtime", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.STRONGMB_API_KEY}`,
Accept: "application/json",
"Content-Type": "application/json"
},
body: JSON.stringify({
"phone": "0123456789",
"product_code": "smb_mtn_vtu",
"amount": "100",
"reference": "SMB202609160001"
}),
signal: AbortSignal.timeout(30000)
});
const result = await response.json();
console.log(response.status, result);
// For purchases, inspect data.status before showing a receipt.
}
main().catch(console.error);
<?php
// Requires the PHP cURL extension.
$client = curl_init('https://api.strongmb.ng/v1/purchases/airtime');
curl_setopt_array($client, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('STRONGMB_API_KEY'),
'Accept: application/json',
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => '{
"phone": "0123456789",
"product_code": "smb_mtn_vtu",
"amount": "100",
"reference": "SMB202609160001"
}',
]);
$raw = curl_exec($client);
if ($raw === false) {
throw new RuntimeException(curl_error($client));
}
$status = curl_getinfo($client, CURLINFO_HTTP_CODE);
curl_close($client);
$result = json_decode($raw, true, 512, JSON_THROW_ON_ERROR);
print_r(['http_status' => $status, 'response' => $result]);
// For purchases, inspect data.status before showing a receipt.
require 'net/http'
require 'json'
uri = URI('https://api.strongmb.ng/v1/purchases/airtime')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = uri.scheme == 'https'
http.open_timeout = 10
http.read_timeout = 30
request = Net::HTTP::Post.new(uri)
request['Authorization'] = 'Bearer ' + ENV.fetch('STRONGMB_API_KEY')
request['Accept'] = 'application/json'
request['Content-Type'] = 'application/json'
request.body = '{
"phone": "0123456789",
"product_code": "smb_mtn_vtu",
"amount": "100",
"reference": "SMB202609160001"
}'
begin
response = http.request(request)
result = JSON.parse(response.body)
puts({ http_status: response.code, response: result }.to_json)
rescue StandardError => error
warn error.message
end
# Reconcile an uncertain purchase before retrying.
import json
import os
from urllib.request import Request, urlopen
from urllib.error import HTTPError, URLError
headers = {
"Authorization": "Bearer " + os.environ["STRONGMB_API_KEY"],
"Accept": "application/json",
"Content-Type": "application/json",
}
payload = {'phone': '0123456789',
'product_code': 'smb_mtn_vtu',
'amount': '100',
'reference': 'SMB202609160001'}
body = json.dumps(payload).encode("utf-8")
request = Request(
"https://api.strongmb.ng/v1/purchases/airtime",
data=body, headers=headers, method="POST"
)
try:
with urlopen(request, timeout=30) as response:
result = json.load(response)
print(response.status, result)
except HTTPError as error:
print(error.code, error.read().decode("utf-8"))
except URLError as error:
print("Network error:", error.reason)
# Reconcile an uncertain purchase before retrying.
Top up airtime for any Nigerian network. Amount is deducted from the user's wallet balance.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| phone | string | Required | Recipient phone number (e.g. 0123456789) |
| product_code | string | Required | From /products/airtime (e.g. smb_mtn_vtu) |
| amount | string | Required | Airtime face value in Naira as string (e.g. "100") |
| reference | string | Required | Your unique reference. a-zA-Z0-9 only. |
Request Example
{
"phone": "0123456789",
"product_code": "smb_mtn_vtu",
"amount": "100",
"reference": "SMBD260aa1352a53aaa7sFAC9"
}
{
"status": true,
"message": "Airtime purchase is being processed.",
"data": {
"status": "processing",
"type": "airtime",
"provider": "mtn",
"recipient": "0123456789",
"airtime_amount": 100,
"reference": "SMBD260aa1352a53aaa7sFAC9",
"currency": "NGN",
"balance_before": "44114.00",
"balance_after": "44015.00",
"amount": 99
},
"metadata": { "code": "ERR_TRANSACTION_PROCESSING", "timestamp": 1773797068, "trace_id": "96640DE2C7" }
}
{
"status": true,
"message": "Airtime purchased successfully.",
"data": {
"status": "successful",
"type": "airtime",
"provider": "mtn",
"recipient": "0123456789",
"airtime_amount": 100,
"reference": "SMBD260aa1352a53aaa7sFAC9",
"currency": "NGN",
"balance_before": "44114.00",
"balance_after": "44015.00",
"amount": 99
},
"metadata": { "code": "TRANSACTION_SUCCESSFUL", "timestamp": 1773797069, "trace_id": "C2D3E4F5A6" }
}
{
"status": false,
"message": "Your transaction has failed, amount has been refunded to your wallet.",
"data": {
"transaction_status": "failed",
"type": "airtime",
"provider": "mtn",
"title": "₦100 mtn airtime",
"recipient": "0123456789",
"discount": 1,
"status": "failed",
"airtime_type": "vtu",
"description": null,
"reference": "SMBD260aaa53afsaa7fsFAC9",
"airtime_amount": "100.00",
"date": "2026-09-25 00:07:54",
"currency": "NGN"
},
"metadata": {
"code": "ERR_TRANSACTION_FAILED",
"timestamp": 1790291274,
"trace_id": "8F13C46C98"
}
}
{
"status": false,
"message": "Insufficient wallet balance.",
"data": null,
"metadata": { "code": "ERR_INSUFFICIENT_BALANCE", "timestamp": 1773797069, "trace_id": "97641EF3D8" }
}
{
"status": false,
"message": "Product code is invalid or currently inactive.",
"data": null,
"metadata": { "code": "ERR_INVALID_PRODUCT_CODE_OR_INACTIVE", "timestamp": 1773797072, "trace_id": "AA644H26GB" }
}
{
"status": false,
"message": "Invalid mobile number.",
"data": null,
"metadata": { "code": "ERR_INVALID_MOBILE_NUMBER", "timestamp": 1773797071, "trace_id": "99643G15FA" }
}
{
"status": false,
"message": "Daily limit exceeded. Contact support to increase.",
"data": null,
"metadata": { "code": "ERR_DAILY_LIMIT_EXCEEDED", "timestamp": 1773797073, "trace_id": "BB645I37HC" }
}
{
"status": false,
"message": "Service provider temporarily unavailable.",
"data": null,
"metadata": { "code": "ERR_PRODUCT_GATEWAY_UNAVAILABLE", "timestamp": 1773797070, "trace_id": "98642F04E9" }
}
Understand the request fields
| Field | Integration guidance |
|---|---|
phone
|
Recipient phone number. Preserve the leading zero. Confirm the network: prefixes do not account for ported numbers. |
product_code
|
An exact identifier from the matching product list, not a provider name or an identifier from a different API. |
amount
|
Amount in Nigerian naira, not kobo. Check the current product price and minimum before submitting. |
reference
|
Your saved identifier for this intended purchase. Use 10–255 letters or digits. Duplicate references are rejected. |
Handle the purchase result
Show a receipt only for a successful outcome. Keep processing transactions pending. Reconcile failed or timed-out purchases before another attempt.
Response fields and types
Expand an object to explore its fields. [] indicates an array item. Error responses may return
data: null.
| Field path | JSON type | Meaning and handling |
|---|---|---|
status |
boolean | Request-level success flag. Check the HTTP status and metadata code as well; a successful API request is not by itself proof of purchase fulfillment. |
message |
string | Human-readable description of the result. Use metadata.code for programmatic error handling instead of parsing this text. |
data |
null | object | A failed purchase can return transaction details even when the top-level status is false. Check that data is an object before reading data.status; other errors may return null or validation information. |
data.status |
string | Purchase outcome: successful, processing or failed. Use this field rather than the top-level status flag to decide whether a purchase completed. |
data.type |
string | Service or transaction type, for example data, airtime, electricity or cable TV. |
data.provider |
string | Provider identifier associated with the purchased service. |
data.recipient |
string | Phone number, meter or customer identifier for the purchase. Compare it with the intended recipient. |
data.airtime_amount |
number | string | Face value of the airtime. |
data.reference |
string | Reference supplied when creating the purchase. Save it and use the same value for transaction verification. |
data.currency |
string | Currency code, such as NGN for Nigerian naira. |
data.balance_before |
string | Wallet balance before this transaction, as reported by the API. |
data.balance_after |
string | Wallet balance after this transaction, as reported by the API. |
data.amount |
number | Amount debited for this transaction, in the indicated currency. |
metadata |
object | Diagnostic information about the response. |
metadata.code |
string | Machine-readable result code. Use it to distinguish validation, authentication and service errors. |
metadata.timestamp |
integer | Unix timestamp in seconds associated with the response. |
metadata.trace_id |
string | Correlation identifier for troubleshooting. Retain it with a redacted request when contacting support. |
data.transaction_status |
string | Deprecated legacy outcome field. Use data.status in new integrations. |
data.title |
string | Display title for the airtime transaction. |
data.discount |
number | Discount value returned for this transaction. Consult the product pricing model when interpreting the value. |
data.airtime_type |
string | Airtime product classification, such as vtu. |
data.description |
string | null | Optional transaction description; this failed example returns null. |
data.date |
string | Transaction date and time as returned by the API. |
Always check metadata.code; do not rely on HTTP status alone. See response codes and recommended
handling.
Test your integration Use the sandbox test values and examples.
Questions? Let’s work through them.
Having an issue or need help with your integration? Join the Strongmb Slack community to ask questions and get assistance from our team and other developers.
Keep API keys and customer details private when sharing examples.
Experiencing a service issue? Check Strongmb’s service status for incident updates.
Did this page help you?
Up to 100 characters. Please leave out personal details, account information and API keys.