Developer
Bulk SMS API Integration Tutorial
Introduction
Integrating SMS functionality into your application unlocks powerful capabilities: send OTPs for authentication, notify customers of order updates, deliver marketing campaigns programmatically, and automate critical alerts. Our REST API makes it simple to send SMS from any application, whether you're building with PHP, Python, JavaScript, or any language that supports HTTP requests.
This comprehensive tutorial walks you through integrating the BulkSMS Nigeria API step-by-step, from authentication to sending your first message, handling responses, and implementing best practices. By the end, you'll have a fully functional SMS integration ready for production use.
What You'll Learn
- • How to authenticate with the API using your credentials
- • Sending single and bulk SMS messages
- • Checking account balance and delivery reports
- • Error handling and response codes
- • Code examples in PHP, Python, JavaScript, Node.js, and cURL
- • Best practices for production deployments
Prerequisites
What You Need Before Starting
- BulkSMS Nigeria Account: Sign up free to get your API credentials
- API Token: Found in your dashboard under Settings → API Configuration
- SMS Credits: Purchase credits or use free trial credits (50 SMS)
- Development Environment: PHP 7.4+, Python 3.7+, Node.js 14+, or any HTTP client
- Basic Programming Knowledge: Understanding of HTTP requests, JSON, and your chosen language
API Overview
API Specifications:
- Base URL:
https://www.bulksmsnigeria.com/api/v2 - Protocol: HTTPS (TLS 1.2+)
- Authentication: API token, sent as
Authorization: Bearer YOUR_API_TOKEN(anapi_tokenparameter also works) - Request Format: JSON or form data (GET query strings are also accepted)
- Response Format: JSON
- Rate Limits: 1,000 requests per minute for sending, 60 per minute for delivery reports
- Character Encoding: UTF-8
Step 1: Get Your API Credentials
Finding Your API Token
- Log in to your dashboard: https://www.bulksmsnigeria.com/login
- Open API Settings: Go to API Settings in your dashboard menu
- Copy your API Token: You'll see a long random string. That is your token
- Register your sender ID: Every API message must use a sender ID that is registered and approved on your account
- Keep it secure: Treat your API token like a password—never expose it in client-side code or public repositories
Security Warning
Your API token grants full access to your account. Store it in environment variables or secure configuration files, never hardcode it in your source code. Rotate tokens periodically and immediately if compromised.
Step 2: Send Your First SMS
Quick Start Example (cURL)
Let's send a test SMS using cURL to understand the basic request structure:
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": "YourBrand",
"to": "2348012345678",
"body": "Hello! This is a test message from BulkSMS Nigeria API."
}'
Replace YOUR_API_TOKEN with your actual token, YourBrand with your approved sender ID and 2348012345678 with a valid Nigerian phone number.
Request Parameters
| Parameter | Required | Description |
|---|---|---|
| from | Yes | Your approved sender ID (max 11 characters) |
| to | Yes | Recipient number(s): a comma-separated string or a JSON array |
| body | Yes | Message text. OTPs and other transactional messages must use the corporate/OTP route |
| gateway | No | Delivery route, e.g. direct-refund (default) or direct-corporate |
| unicode | No | true keeps emoji and non-Latin text (70 characters per page). Default false converts them to plain characters (160 per page) |
| append_sender | No | none, hosted (default) or all |
| callback_url | No | URL that receives delivery status updates (see Delivery Webhooks below) |
| customer_reference | No | Your own reference, returned in delivery reports and webhooks |
Expected Response
{
"status": "success",
"code": "BSNG-0000",
"message": "Message sent successfully",
"data": {
"message_id": "a22f907b-c5aa-44e4-89e4-06fe253e9cbb",
"cost": 6.49,
"currency": "NGN",
"recipients_count": 1,
"gateway_used": "direct-refund",
"unicode": false,
"page_count": 1
}
}
Save the message_id. You need it to fetch delivery reports.
Step 3: Integration by Language
Choose your programming language and follow the implementation guide:
PHP Integration
Using PHP cURL (Vanilla PHP)
<?php
class BulkSMSNigeria {
private $apiToken;
private $baseUrl = 'https://www.bulksmsnigeria.com/api/v2';
public function __construct($apiToken) {
$this->apiToken = $apiToken;
}
private function request($method, $path, $data = null) {
$ch = curl_init($this->baseUrl . $path);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Authorization: Bearer ' . $this->apiToken,
'Content-Type: application/json',
'Accept: application/json'
]);
if ($method === 'POST') {
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
}
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
$result = json_decode($response, true);
if ($httpCode >= 400) {
throw new Exception($result['error']['message'] ?? 'Request failed');
}
return $result;
}
public function sendSMS($from, $to, $body) {
return $this->request('POST', '/sms', [
'from' => $from,
'to' => $to, // "2348012345678" or ["2348012345678", "2348087654321"]
'body' => $body
]);
}
public function getBalance() {
return $this->request('GET', '/balance');
}
public function getDeliveryReport($messageId) {
return $this->request('GET', '/delivery-reports?message_id=' . urlencode($messageId));
}
}
// Usage Example
try {
$sms = new BulkSMSNigeria(getenv('BULKSMS_API_TOKEN'));
$result = $sms->sendSMS(
'YourBrand', // Sender ID
'2348012345678', // Recipient(s)
'Hello from PHP! Your order has been shipped.' // Message
);
echo "Message sent! ID: " . $result['data']['message_id'];
echo "\nCost: ₦" . $result['data']['cost'];
$balance = $sms->getBalance();
echo "\nBalance: ₦" . $balance['balance']['total_balance'];
} catch (Exception $e) {
echo "Error: " . $e->getMessage();
}
?>
Using PHP with Guzzle HTTP Client
<?php
require 'vendor/autoload.php';
use GuzzleHttp\Client;
use GuzzleHttp\Exception\RequestException;
class BulkSMSClient {
private $client;
public function __construct($apiToken) {
$this->client = new Client([
'base_uri' => 'https://www.bulksmsnigeria.com/api/v2/',
'headers' => [
'Authorization' => 'Bearer ' . $apiToken,
'Accept' => 'application/json'
],
'timeout' => 30
]);
}
public function sendSMS($from, $to, $body) {
try {
$response = $this->client->post('sms', [
'json' => [
'from' => $from,
'to' => $to,
'body' => $body
]
]);
return json_decode($response->getBody(), true);
} catch (RequestException $e) {
if ($e->hasResponse()) {
$error = json_decode($e->getResponse()->getBody(), true);
throw new Exception($error['error']['message'] ?? 'Request failed');
}
throw $e;
}
}
}
// Usage
$sms = new BulkSMSClient(getenv('BULKSMS_API_TOKEN'));
$result = $sms->sendSMS('YourBrand', '2348012345678', 'Hello from Guzzle! Your order has been shipped.');
print_r($result['data']);
?>
Python Integration
Using Python Requests Library
import os
import requests
class BulkSMSNigeria:
def __init__(self, api_token):
self.base_url = 'https://www.bulksmsnigeria.com/api/v2'
self.headers = {
'Authorization': f'Bearer {api_token}',
'Accept': 'application/json'
}
def send_sms(self, sender, recipients, body, **options):
"""
Send SMS to one or more recipients
Args:
sender (str): Approved sender ID (max 11 characters)
recipients (str or list): Phone number(s)
body (str): Message text
**options: Optional parameters, e.g. unicode=True,
callback_url='https://...', customer_reference='order-42'
Returns:
dict: API response containing message_id, cost, etc.
"""
payload = {'from': sender, 'to': recipients, 'body': body, **options}
try:
response = requests.post(
f'{self.base_url}/sms',
headers=self.headers,
json=payload,
timeout=30
)
response.raise_for_status()
return response.json()
except requests.exceptions.HTTPError as e:
error_data = e.response.json() if e.response is not None else {}
raise Exception(error_data.get('error', {}).get('message', 'SMS sending failed'))
except requests.exceptions.RequestException as e:
raise Exception(f'Network error: {str(e)}')
def get_balance(self):
"""Get current account balance in naira"""
response = requests.get(f'{self.base_url}/balance', headers=self.headers, timeout=10)
response.raise_for_status()
return response.json()['balance']['total_balance']
def get_delivery_report(self, message_id):
"""Get delivery report for a specific message"""
response = requests.get(
f'{self.base_url}/delivery-reports',
headers=self.headers,
params={'message_id': message_id},
timeout=10
)
response.raise_for_status()
return response.json()['data']
# Usage Example
if __name__ == '__main__':
sms = BulkSMSNigeria(os.environ['BULKSMS_API_TOKEN'])
try:
# Send single SMS
result = sms.send_sms(
sender='YourBrand',
recipients='2348012345678',
body='Hello from Python! This is a test message.'
)
print("✓ Message sent successfully!")
print(f" Message ID: {result['data']['message_id']}")
print(f" Cost: ₦{result['data']['cost']}")
# Send to multiple recipients
bulk_result = sms.send_sms(
sender='YourBrand',
recipients=['2348012345678', '2348087654321', '2349012345678'],
body='Flash sale! 30% off all items today only.'
)
print(f"\n✓ Bulk message sent to {bulk_result['data']['recipients_count']} recipients")
# Check balance
print(f"\nCurrent Balance: ₦{sms.get_balance()}")
except Exception as e:
print(f"✗ Error: {e}")
JavaScript (Node.js) Integration
Using Axios Library
const axios = require('axios');
class BulkSMSNigeria {
constructor(apiToken) {
this.client = axios.create({
baseURL: 'https://www.bulksmsnigeria.com/api/v2',
headers: {
'Authorization': `Bearer ${apiToken}`,
'Accept': 'application/json'
},
timeout: 30000
});
}
async sendSMS(from, to, body, options = {}) {
try {
// "to" can be a string or an array of numbers
const response = await this.client.post('/sms', { from, to, body, ...options });
return response.data;
} catch (error) {
if (error.response) {
// Server responded with an error
const { code, error: details } = error.response.data;
throw new Error(`${code}: ${details?.message || 'SMS sending failed'}`);
} else if (error.request) {
// Request made but no response
throw new Error('No response from server');
} else {
// Request setup error
throw new Error(error.message);
}
}
}
async getBalance() {
const response = await this.client.get('/balance');
return response.data.balance.total_balance;
}
async getDeliveryReport(messageId) {
const response = await this.client.get('/delivery-reports', {
params: { message_id: messageId }
});
return response.data.data;
}
}
// Usage Example
(async () => {
const sms = new BulkSMSNigeria(process.env.BULKSMS_API_TOKEN);
try {
// Send single SMS
const result = await sms.sendSMS(
'YourBrand',
'2348012345678',
'Hello from Node.js! This is a test message.'
);
console.log('✓ Message sent successfully!');
console.log(` Message ID: ${result.data.message_id}`);
console.log(` Cost: ₦${result.data.cost}`);
// Send to multiple recipients
const bulkResult = await sms.sendSMS(
'YourBrand',
['2348012345678', '2348087654321', '2349012345678'],
'Flash sale! 30% off all items today only.'
);
console.log(`\n✓ Bulk message sent to ${bulkResult.data.recipients_count} recipients`);
// Check balance
console.log(`\nCurrent Balance: ₦${await sms.getBalance()}`);
} catch (error) {
console.error('✗ Error:', error.message);
}
})();
JavaScript (Browser) Integration
⚠️ Security Warning
Never use your API token in client-side JavaScript! It would be exposed to anyone viewing your page source. Always make API calls from your backend server. If you need SMS functionality in a web app, create a backend endpoint that securely calls the BulkSMS API.
Secure Pattern: Backend Proxy Endpoint
// Frontend (JavaScript)
async function sendOTP(phoneNumber) {
try {
const response = await fetch('/api/send-otp', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
// Use your app's authentication (session, JWT, etc.)
'Authorization': `Bearer ${userAuthToken}`
},
body: JSON.stringify({ phone: phoneNumber })
});
const result = await response.json();
if (result.success) {
console.log('OTP sent successfully!');
} else {
console.error('Failed to send OTP:', result.message);
}
} catch (error) {
console.error('Error:', error);
}
}
// Backend (Node.js/Express) - This is where the API token is used
app.post('/api/send-otp', authenticateUser, async (req, res) => {
const { phone } = req.body;
// Verify user is authenticated
if (!req.user) {
return res.status(401).json({ success: false, message: 'Unauthorized' });
}
const otp = generateOTP(); // Generate 6-digit OTP
try {
// Call BulkSMS API from backend (secure)
const sms = new BulkSMSNigeria(process.env.BULKSMS_API_TOKEN);
await sms.sendSMS('YourApp', phone, `Your YourApp verification code is ${otp}. It expires in 10 minutes.`);
// Store OTP in session/database for verification
req.session.otp = otp;
res.json({ success: true, message: 'OTP sent' });
} catch (error) {
res.status(500).json({ success: false, message: 'Failed to send OTP' });
}
});
Step 4: Advanced Features
Sending Bulk SMS
Send to multiple recipients in a single API call:
// Recipients as comma-separated string
{
"from": "YourBrand",
"to": "2348012345678,2348087654321,2349012345678",
"body": "Flash sale! 30% off all items today only."
}
// Or as array (in JSON)
{
"from": "YourBrand",
"to": ["2348012345678", "2348087654321", "2349012345678"],
"body": "Flash sale! 30% off all items today only."
}
Unicode Messages (Emoji and Non-Latin Text)
By default, characters such as curly quotes (’), dashes (—) and accented letters are converted to plain equivalents and emoji are removed, so your message is billed at the standard 160 characters per page. To send emoji or non-Latin text exactly as written, set unicode to true. Unicode messages hold 70 characters per page, so they can cost 2–3 times more.
{
"from": "YourBrand",
"to": "2348012345678",
"body": "Ẹ kú àárọ̀! Your order is on its way 🚚",
"unicode": true
}
Personalized Messages
Send personalized messages by looping over your contacts:
// Python example
recipients_data = [
{"phone": "2348012345678", "name": "John", "amount": "5000"},
{"phone": "2348087654321", "name": "Sarah", "amount": "3200"},
]
for recipient in recipients_data:
body = f"Hi {recipient['name']}, your order of ₦{recipient['amount']} has been confirmed!"
sms.send_sms('ShopEase', recipient['phone'], body)
Getting Delivery Reports
// GET request to check delivery status
GET https://www.bulksmsnigeria.com/api/v2/delivery-reports?message_id={message_id}
// Optional: per_page (default 100, max 1000) and page for large sends
// Response
{
"status": "success",
"code": "BSNG-0000",
"message": "Delivery report retrieved",
"data": {
"message_id": "a22f907b-c5aa-44e4-89e4-06fe253e9cbb",
"customer_reference": "order-42",
"summary": {
"total": 3,
"delivered": 2,
"pending": 1,
"failed": 0
},
"reports": [
{ "recipient": "2348012345678", "delivery_status": "delivered" },
{ "recipient": "2348087654321", "delivery_status": "delivered" },
{ "recipient": "2349012345678", "delivery_status": "sent awaiting status" }
],
"pagination": { "current_page": 1, "per_page": 100, "total": 3, "last_page": 1 }
}
}
Delivery Webhooks
Instead of polling for delivery reports, pass a callback_url when sending. We POST a JSON update to that URL as each recipient's status changes:
// Send with a callback URL and your own reference
{
"from": "YourBrand",
"to": "2348012345678",
"body": "Your order has been shipped and arrives tomorrow.",
"callback_url": "https://yourapp.com/webhooks/sms",
"customer_reference": "order-42"
}
// What your callback URL receives
{
"message_id": "a22f907b-c5aa-44e4-89e4-06fe253e9cbb",
"recipient": "2348012345678",
"delivery_status": "delivered",
"customer_reference": "order-42",
"callback_url": "https://yourapp.com/webhooks/sms",
"data": {
"message_id": "a22f907b-c5aa-44e4-89e4-06fe253e9cbb",
"recipient": "2348012345678",
"delivery_status": "delivered",
"customer_reference": "order-42"
}
}
Checking Account Balance
// GET request
GET https://www.bulksmsnigeria.com/api/v2/balance
// Response (use balance.total_balance)
{
"data": {
"status": "success",
"message": "Balance Inquiry Successful"
},
"balance": {
"total_balance": 1250,
"universal_wallet": 1000,
"sms_wallet": 250,
"sms_bonus": 0,
"main_balance": 0,
"volume_bonus": 0,
"promo_bonus": 0
}
}
Step 5: Error Handling
Common HTTP Status Codes
| Status Code | Meaning | Action |
|---|---|---|
| 200 | Success | Request processed successfully |
| 400 | Bad Request | Check request format, missing/invalid parameters |
| 401 | Unauthorized | Invalid or missing API token |
| 402 | Payment Required | Insufficient wallet balance. Top up before resending |
| 403 | Forbidden | Sender ID not registered or API access restricted |
| 409 | Conflict | Duplicate message: the same text went to the same recipients within the last minute. Don't retry |
| 422 | Unprocessable | Validation error, e.g. a message that isn't permitted on the promotional route. Fix the message or use the right route before resending |
| 429 | Too Many Requests | Rate limit exceeded, wait and retry |
| 500 | Server Error | Retry with exponential backoff |
Error Response Format
{
"status": "error",
"code": "BSNG-3001",
"error": {
"message": "You have Insufficient Funds. You need a total of ₦60.00 to send this message.",
"code": "BSNG-3001",
"description": "Insufficient wallet balance"
}
}
Every error has the same shape: code is a stable BSNG-XXXX value to branch on, and error.message is a human-readable explanation. The full list of codes is in the API documentation in your dashboard.
Robust Error Handling Example (Python)
import requests
import time
def send_sms_with_retry(sms_client, sender, recipients, body, max_retries=3):
"""
Send SMS with automatic retry on transient failures
"""
for attempt in range(max_retries):
try:
# Call the API directly so HTTP status codes reach the handlers below
response = requests.post(
f'{sms_client.base_url}/sms',
headers=sms_client.headers,
json={'from': sender, 'to': recipients, 'body': body},
timeout=30
)
response.raise_for_status()
return response.json()
except requests.exceptions.HTTPError as e:
status_code = e.response.status_code
error_data = e.response.json()
error_message = error_data.get('error', {}).get('message', 'Unknown error')
if status_code == 400:
# Bad request - don't retry, fix the request
raise Exception(f"Invalid request: {error_message}")
elif status_code == 401:
# Unauthorized - API token invalid
raise Exception("Authentication failed. Check your API token.")
elif status_code == 402:
# Payment required - top up your wallet
raise Exception(f"Insufficient balance: {error_message}")
elif status_code == 403:
# Forbidden - unregistered sender ID or API access restricted
raise Exception(f"Access denied: {error_message}")
elif status_code in (409, 422):
# Duplicate or invalid message - retrying unchanged won't help
raise Exception(f"Message rejected ({error_data.get('code')}): {error_message}")
elif status_code == 429:
# Rate limit - wait and retry
wait_time = 2 ** attempt # Exponential backoff: 1s, 2s, 4s
print(f"Rate limited. Waiting {wait_time}s before retry...")
time.sleep(wait_time)
continue
elif status_code >= 500:
# Server error - retry with backoff
if attempt < max_retries - 1:
wait_time = 2 ** attempt
print(f"Server error. Retrying in {wait_time}s...")
time.sleep(wait_time)
continue
else:
raise Exception("Server error persists after retries")
else:
raise Exception(f"Unexpected error: {error_message}")
except requests.exceptions.Timeout:
if attempt < max_retries - 1:
print(f"Request timeout. Retrying...")
time.sleep(2)
continue
else:
raise Exception("Request timed out after multiple retries")
except requests.exceptions.ConnectionError:
if attempt < max_retries - 1:
print(f"Connection error. Retrying...")
time.sleep(2)
continue
else:
raise Exception("Could not connect to API server")
raise Exception("Failed after maximum retries")
# Usage
try:
result = send_sms_with_retry(sms, 'YourBrand', '2348012345678', 'Your order has been shipped and arrives tomorrow.')
print("✓ SMS sent successfully!")
except Exception as e:
print(f"✗ Failed to send SMS: {e}")
# Log error, send alert, etc.
Step 6: Best Practices
1. Secure API Token Storage
✓ DO:
- • Store API tokens in environment variables (
process.env.BULKSMS_API_TOKEN) - • Use configuration files outside web root (.env files)
- • Rotate tokens periodically (every 6-12 months)
- • Use different tokens for development and production
- • Implement token encryption in database if storing there
✗ DON'T:
- • Hardcode tokens in source code
- • Commit tokens to version control (Git)
- • Expose tokens in client-side JavaScript
- • Share tokens via email or insecure channels
- • Use production tokens for testing
2. Validate Phone Numbers
// PHP phone number validation
function validateNigerianPhone($phone) {
// Remove spaces, dashes, parentheses
$phone = preg_replace('/[^0-9]/', '', $phone);
// Check format: 234XXXXXXXXXX (13 digits starting with 234)
// or 0XXXXXXXXXX (11 digits starting with 0)
if (preg_match('/^234[789][01]\d{8}$/', $phone)) {
return $phone; // Already in international format
} elseif (preg_match('/^0[789][01]\d{8}$/', $phone)) {
return '234' . substr($phone, 1); // Convert to international
}
return false; // Invalid format
}
// Usage
$phone = validateNigerianPhone('08012345678');
if ($phone) {
// Send SMS to $phone (234801234567)
} else {
// Show error: invalid phone number
}
3. Implement Rate Limiting
Respect the API rate limit of 1,000 send requests per minute. Sending to many numbers in one request (up to a few hundred per call) is more efficient than one request per number:
// Python rate limiting example
import time
from collections import deque
class RateLimiter:
def __init__(self, max_calls=1000, time_window=60):
self.max_calls = max_calls
self.time_window = time_window
self.calls = deque()
def wait_if_needed(self):
now = time.time()
# Remove old calls outside time window
while self.calls and self.calls[0] < now - self.time_window:
self.calls.popleft()
# If at limit, wait until oldest call expires
if len(self.calls) >= self.max_calls:
sleep_time = self.calls[0] + self.time_window - now
time.sleep(sleep_time)
self.calls.popleft()
# Record this call
self.calls.append(now)
# Usage
limiter = RateLimiter(max_calls=1000, time_window=60)
for phone in large_recipient_list:
limiter.wait_if_needed()
sms.send_sms('YourBrand', phone, 'Your appointment is confirmed for tomorrow at 10am.')
4. Queue SMS for Background Processing
For large campaigns, use job queues instead of sending synchronously:
// Node.js with Bull Queue
const Queue = require('bull');
const smsQueue = new Queue('sms-sending');
// Producer: Add SMS jobs to queue
async function queueBulkSMS(recipients, body) {
for (const phone of recipients) {
await smsQueue.add({
from: 'YourBrand',
to: phone,
body: body
});
}
}
// Consumer: Process SMS jobs
smsQueue.process(async (job) => {
const { from, to, body } = job.data;
const sms = new BulkSMSNigeria(process.env.BULKSMS_API_TOKEN);
try {
await sms.sendSMS(from, to, body);
return { success: true };
} catch (error) {
// Will retry automatically based on queue settings
throw error;
}
});
5. Log All API Interactions
// Python logging example
import logging
logging.basicConfig(
filename='sms_api.log',
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s'
)
def send_sms_with_logging(sms_client, sender, recipients, body):
count = len(recipients) if isinstance(recipients, list) else len(recipients.split(','))
logging.info(f"Sending SMS to {count} recipients")
try:
result = sms_client.send_sms(sender, recipients, body)
logging.info(f"SMS sent successfully. Message ID: {result['data']['message_id']}")
logging.info(f"Cost: ₦{result['data']['cost']} for {result['data']['page_count']} page(s)")
return result
except Exception as e:
logging.error(f"SMS sending failed: {str(e)}")
raise
6. Monitor Account Balance
Check balance before sending to avoid failures:
// Check balance before campaign
const balance = await sms.getBalance(); // balance.total_balance in naira
const estimatedCost = recipientCount * 6.49; // your per-page rate × pages
if (balance < estimatedCost) {
throw new Error(
`Insufficient balance. Need ₦${estimatedCost} but have ₦${balance}`
);
}
// Proceed with sending
await sms.sendSMS('YourBrand', recipients, body);
Complete Integration Checklist
Before Going Live:
Common Integration Issues & Solutions
Issue 1: SSL Certificate Verification Errors
Error:
SSL: CERTIFICATE_VERIFY_FAILED
Solution:
Update your system's CA certificates or ensure your HTTP library is using updated certificates. Never disable SSL verification in production!
Issue 2: Timeout Errors on Large Campaigns
Solution:
- • Break large recipient lists into batches (100-500 per request)
- • Use background jobs/queues for bulk sending
- • Increase timeout setting to 30-60 seconds
- • Implement retry logic with exponential backoff
Issue 3: Messages Showing Random Numbers Instead of Sender ID
Causes:
- • Sender ID not registered/approved
- • Using unregistered sender ID in API call
- • Network operator rejection
Solution:
Register your sender ID through your dashboard and wait for approval (3-7 days) before using in campaigns.
Next Steps
Congratulations! You now have a fully functional SMS API integration. Here's what to do next:
- 1. Test thoroughly: Send test messages to all Nigerian networks (MTN, Glo, Airtel, 9mobile)
- 2. Implement monitoring: Set up alerts for API errors, low balance, and delivery failures
- 3. Optimize costs: Review message lengths, leave
unicodeoff unless you need emoji or non-Latin text, clean contact lists - 4. Scale gradually: Start with small campaigns, monitor performance, then scale up
- 5. Read full documentation: Explore advanced features like webhooks, templates, and analytics
Ready to Integrate SMS Into Your App?
Get your API credentials, a ₦50 free SMS credit, and start sending in minutes. Complete documentation, code examples, and 24/7 developer support included.
Ready to Put This Into Practice?
Start sending bulk SMS to your customers today with a ₦50 free SMS credit.