Bulk SMS API Nigeria

Powerful REST API for developers to integrate bulk SMS into their applications. Complete documentation with code examples in multiple languages.

Ready-to-Use Code Examples

Skip the setup! Get complete, production-ready code examples in PHP, Python, JavaScript, Node.js, and more. Plus download our Postman collections to test instantly.

🐘 PHP Laravel 🐍 Python 🟢 Node.js 🌐 JavaScript 🔧 cURL 📮 Postman

Quick Start Guide

1

Sign Up & Get API Token

Register for free and get your API token instantly. No credit card required.

2

Choose Your Language

Use our code examples in PHP, Python, JavaScript, or cURL

3

Start Sending SMS

Make your first request and start sending bulk SMS

Base URL

All API requests should be made to the following base URLs:

Production API

https://www.bulksmsnigeria.com/api/v2

Sandbox API (Testing)

https://www.bulksmsnigeria.com/api/sandbox/v2
SANDBOX

Test Environment

Use our sandbox environment to test your integration without sending real SMS messages or consuming your wallet balance.

No Real SMS Sent

Messages are simulated - no actual SMS delivered

Zero Cost

Your wallet balance is never deducted

Same API Structure

Identical request/response format

Available Sandbox Endpoints

Endpoint Method Description
/api/sandbox/v2/sms POST/GET Send test SMS (simulated)
/api/sandbox/v2/balance GET Check account balance
/api/sandbox/v2/delivery-reports GET List delivery reports
/api/sandbox/v2/sender-ids GET List registered sender IDs
/api/sandbox/v2/account GET Get account information
Note: Sandbox uses the same API token as production. Rate limit: 120 requests/minute.

Authentication

Our API accepts authentication tokens in multiple ways for maximum flexibility. The recommended method is using the Authorization header:

RECOMMENDED

Authorization Header

Authorization: Bearer YOUR_API_TOKEN

Custom Header

api_token: YOUR_API_TOKEN

Query Parameter

?api_token=YOUR_API_TOKEN

Request Body

{"api_token": "YOUR_API_TOKEN"}

POST Send Bulk SMS

Send bulk SMS messages to one or multiple recipients across all Nigerian networks

Endpoints

/api/v2/sms Recommended
/api/v1/sms/create Legacy

Request Parameters

Parameter Type Required Description
from string Required Sender ID (max 11 characters)
to string Required Comma-separated phone numbers (e.g., 2347012345678,2348012345678)
body string Required Message content (up to 1530 characters)
gateway string Optional Gateway: direct-refund, direct-corporate, otp, dual-backup
unicode boolean Optional Send as Unicode to keep emoji and non-Latin text (default: false). Unicode messages hold 70 characters per page instead of 160, so they cost more. When false, Unicode characters are replaced with standard equivalents (e.g. ’ becomes ') and emoji are removed.
callback_url string Optional URL for delivery status callbacks/webhooks

Unicode & billing

By default (unicode=false) your message is sent as standard SMS: 160 characters for one page, 153 per page after that. Curly quotes, dashes, accented letters and similar characters are converted to their plain equivalents and emoji are removed, so a stray character never pushes you onto Unicode pricing.

Set unicode=true (or 1) to send the text exactly as written. If it contains Unicode characters it is billed at 70 characters for one page and 67 per page after that. Emoji count as two characters.

Code Examples

curl -X POST https://www.bulksmsnigeria.com/api/v2/sms \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
    "from": "YourCompany",
    "to": "2347012345678,2348012345678",
    "body": "Hello from BulkSMS Nigeria API! Welcome to our service.",
    "gateway": "direct-refund"
  }'
<?php
$apiToken = 'YOUR_API_TOKEN';
$url = 'https://www.bulksmsnigeria.com/api/v2/sms';

$data = [
    'from' => 'YourCompany',
    'to' => '2347012345678,2348012345678',
    'body' => 'Hello from BulkSMS Nigeria API!',
    'gateway' => 'direct-refund'
];

$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Authorization: Bearer ' . $apiToken,
    'Content-Type: application/json',
    'Accept: application/json'
]);

$response = curl_exec($ch);
curl_close($ch);

$result = json_decode($response, true);
print_r($result);
?>
import requests
import json

api_token = 'YOUR_API_TOKEN'
url = 'https://www.bulksmsnigeria.com/api/v2/sms'

headers = {
    'Authorization': f'Bearer {api_token}',
    'Content-Type': 'application/json',
    'Accept': 'application/json'
}

data = {
    'from': 'YourCompany',
    'to': '2347012345678,2348012345678',
    'body': 'Hello from BulkSMS Nigeria API!',
    'gateway': 'direct-refund'
}

response = requests.post(url, headers=headers, json=data)
result = response.json()
print(result)
const apiToken = 'YOUR_API_TOKEN';
const url = 'https://www.bulksmsnigeria.com/api/v2/sms';

const data = {
    from: 'YourCompany',
    to: '2347012345678,2348012345678',
    body: 'Hello from BulkSMS Nigeria API!',
    gateway: 'direct-refund'
};

fetch(url, {
    method: 'POST',
    headers: {
        'Authorization': `Bearer ${apiToken}`,
        'Content-Type': 'application/json',
        'Accept': 'application/json'
    },
    body: JSON.stringify(data)
})
.then(response => response.json())
.then(result => console.log(result))
.catch(error => console.error('Error:', error));

Success Response

{
  "status": "success",
  "code": "BSNG-0000",
  "message": "Message sent successfully",
  "data": {
    "message_id": "a22f907b-c5aa-44e4-89e4-06fe253e9cbb",
    "cost": 5.00,
    "currency": "NGN",
    "recipients_count": 2,
    "gateway_used": "direct-refund",
    "unicode": false,
    "page_count": 1
  }
}

Error Responses

Errors use the same envelope with "status": "error", a BSNG-XXXX code and a matching HTTP status. None of the errors below send the message or charge your wallet, so fix the request rather than retrying it unchanged.

{
  "status": "error",
  "code": "BSNG-2012",
  "error": {
    "message": "Duplicate message. An identical message was sent to the same recipients within the last minute, so this one was not sent and you were not charged.",
    "code": "BSNG-2012",
    "description": "Duplicate message"
  }
}
Code HTTP Meaning
BSNG-2002 422 The body is missing, or it only contains emoji/Unicode characters, which are removed when unicode is false.
BSNG-2012 409 Duplicate message: the same text was sent to the same recipients within the last minute.
BSNG-2013 422 Message not permitted on this route: OTPs, verification codes and other transactional messages must use the corporate/OTP route, and international senders the international route. Not sent and not charged.

The full list of error codes is in the API documentation in your dashboard.

GET Check Account Balance

Check your current SMS credit balance

Endpoint

/api/v2/balance

Example Request

curl -X GET https://www.bulksmsnigeria.com/api/v2/balance \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Accept: application/json"

Success Response

{
  "data": {
    "status": "success",
    "message": "Balance Inquiry Successful"
  },
  "balance": {
    "total_balance": 9884.24,
    "universal_wallet": "9879.23",
    "sms_wallet": "5.01",
    "sms_bonus": "0.00"
  }
}

GET Fetch Delivery Reports

Get per-recipient delivery statuses for a sent message

Endpoint

/api/v2/delivery-reports

Parameters

Parameter Required Description
message_id Yes The message_id returned when the message was sent
page No Page number, defaults to 1
per_page No Results per page, defaults to 100 (max 1000)

Example Request

curl -X GET "https://www.bulksmsnigeria.com/api/v2/delivery-reports?message_id=YOUR_MESSAGE_ID" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Accept: application/json"

Success Response

{
  "status": "success",
  "code": "BSNG-0000",
  "message": "Delivery report retrieved",
  "data": {
    "message_id": "a22f907b-c5aa-44e4-89e4-06fe253e9cbb",
    "summary": {"total": 3, "delivered": 2, "pending": 1, "failed": 0},
    "reports": [
      {"recipient": "2347037770033", "delivery_status": "delivrd"},
      {"recipient": "2348012345678", "delivery_status": "delivrd"},
      {"recipient": "2349050030090", "delivery_status": "sent awaiting status"}
    ],
    "pagination": {"current_page": 1, "per_page": 100, "total": 3, "last_page": 1}
  }
}

POST Delivery Webhooks

Get each recipient's delivery outcome pushed to your server, instead of polling for delivery reports

How it works

  1. Pass a callback_url (and optionally your own customer_reference) when you send a message.
  2. When a recipient's final outcome is known (delivered or failed), we send a POST request with a JSON body to your callback_url.
  3. You receive one request per recipient. Messages still in progress (queued, sent awaiting status) do not trigger a webhook.

Example payload

POST https://yourapp.com/webhooks/sms
Content-Type: application/json

{
  "message_id": "a22f907b-c5aa-44e4-89e4-06fe253e9cbb",
  "recipient": "2348012345678",
  "delivery_status": "delivrd",
  "customer_reference": "order-42",
  "callback_url": "https://yourapp.com/webhooks/sms",
  "data": {
    "message_id": "a22f907b-c5aa-44e4-89e4-06fe253e9cbb",
    "recipient": "2348012345678",
    "delivery_status": "delivrd",
    "customer_reference": "order-42"
  }
}

Payload fields

Field Description
message_id The message_id returned when you sent the message
recipient The phone number this update is for, in international format
delivery_status The final outcome, in lowercase (see below)
customer_reference The reference you sent with the message, or null
callback_url The URL this request was sent to
data The same fields again, kept for older integrations. Read either; they always match

Reading delivery_status

Treat delivrd, delivered and success as delivered. Treat any other value as not delivered: these are the network's failure codes (for example undeliv, expired, rejectd, failed) or a status from us explaining what happened to the message.

New status values can appear over time, so match the three delivered values and treat everything else as not delivered rather than listing failure codes.

Responding and retries

  • Reply with any 2xx status within 30 seconds. Do slow work after you respond.
  • If your server doesn't reply with a 2xx, we try again, up to 3 attempts in total with increasing gaps between them.
  • Because of retries you can receive the same update more than once, so make your handler safe to run twice (for example, key on message_id + recipient).
  • Missed an update? GET /api/v2/delivery-reports?message_id=… always has the latest status for every recipient.

Securing your endpoint: webhook requests are not signed. Put a long random secret in your callback URL (for example https://yourapp.com/webhooks/sms?secret=…) and reject requests without it, and always use an HTTPS URL.

Example handler (PHP)

<?php
// https://yourapp.com/webhooks/sms?secret=YOUR_LONG_RANDOM_SECRET

if (!hash_equals('YOUR_LONG_RANDOM_SECRET', $_GET['secret'] ?? '')) {
    http_response_code(403);
    exit;
}

$update = json_decode(file_get_contents('php://input'), true);

$delivered = in_array($update['delivery_status'], ['delivrd', 'delivered', 'success'], true);

// Save idempotently: the same update can arrive more than once.
saveDeliveryStatus(
    $update['message_id'],
    $update['recipient'],
    $delivered ? 'delivered' : 'failed',
    $update['customer_reference']
);

http_response_code(200);

GET List Sender IDs

List your registered sender IDs and their approval status

Endpoint

/api/v2/sender-ids

Example Request

curl -X GET https://www.bulksmsnigeria.com/api/v2/sender-ids \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Accept: application/json"

Success Response

{
  "status": "success",
  "code": "BSNG-0000",
  "message": "Sender IDs retrieved",
  "data": {
    "sender_ids": [
      {"sender_id": "MyBrand", "status": "approved", "purpose": "Transactional alerts", "approved_at": "2026-01-15 09:30:00", "rejection_reason": null}
    ],
    "total": 1
  }
}

GET Get Account Information

Retrieve your account profile, verification level, and balance

Endpoint

/api/v2/account

Example Request

curl -X GET https://www.bulksmsnigeria.com/api/v2/account \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Accept: application/json"

Success Response

{
  "status": "success",
  "code": "BSNG-0000",
  "message": "Account information retrieved",
  "data": {
    "user_id": "0f8e2a64-1bbb-4f3e-9c0d-5a3a1c2d4e5f",
    "email": "dev@example.com",
    "name": "Ada Developer",
    "account_status": "active",
    "verification_level": "verified",
    "balance": 10250.50,
    "currency": "NGN",
    "created_at": "2025-11-02 08:14:33"
  }
}

Ready to Integrate Our SMS API?

Sign up now and get your API token instantly. Start sending bulk SMS in minutes with a ₦50 free SMS credit.

Why Choose Our Bulk SMS API?

Instant Delivery

Messages delivered in seconds with 99.9% uptime guarantee

All Networks

Deliver to MTN, GLO, Airtel, 9mobile including DND numbers

Affordable Rates

From ₦6.49 per SMS (excl. VAT) with volume discounts