Ready-to-use code samples in PHP, Python, JavaScript, Node.js, and more. Start sending SMS in minutes with our comprehensive examples.
Follow these steps to start sending SMS via our API
Copy and paste ready-to-use code examples in your preferred programming language
Laravel integration using HTTP Client
<?php
namespace App\Services;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
class BulkSMSService
{
protected $baseUrl;
protected $apiToken;
protected $senderId;
public function __construct()
{
$this->baseUrl = config('services.bulksms.base_url');
$this->apiToken = config('services.bulksms.api_token');
$this->senderId = config('services.bulksms.sender_id');
}
/**
* Send SMS to a single recipient
*/
public function sendSMS(string $to, string $message, ?string $senderId = null): array
{
$response = Http::withHeaders([
'Authorization' => 'Bearer ' . $this->apiToken,
'Accept' => 'application/json',
])
->timeout(30)
->post($this->baseUrl . '/v2/sms', [
'from' => $senderId ?? $this->senderId,
'to' => $to,
'body' => $message,
]);
if ($response->successful()) {
$data = $response->json();
Log::info('SMS sent successfully', [
'message_id' => $data['data']['id'] ?? null,
'cost' => $data['data']['cost'] ?? null,
]);
return $data;
}
// Handle error
Log::error('SMS sending failed', [
'status' => $response->status(),
'error' => $response->json(),
]);
throw new \Exception('Failed to send SMS: ' . $response->json('message', 'Unknown error'));
}
/**
* Send SMS to multiple recipients
*/
public function sendBulkSMS(array $recipients, string $message, ?string $senderId = null): array
{
$results = [
'total' => count($recipients),
'successful' => 0,
'failed' => 0,
'results' => [],
];
foreach ($recipients as $recipient) {
try {
$result = $this->sendSMS($recipient, $message, $senderId);
$results['successful']++;
$results['results'][] = [
'recipient' => $recipient,
'status' => 'success',
'data' => $result,
];
} catch (\Exception $e) {
$results['failed']++;
$results['results'][] = [
'recipient' => $recipient,
'status' => 'failed',
'error' => $e->getMessage(),
];
}
}
return $results;
}
}
// Configuration in config/services.php
// 'bulksms' => [
// 'base_url' => env('BULK_SMS_BASE_URL', 'https://www.bulksmsnigeria.com/api'),
// 'api_token' => env('BULK_SMS_API_TOKEN'),
// 'sender_id' => env('BULK_SMS_SENDER_ID'),
// ],
// Usage Example
use App\Services\BulkSMSService;
$smsService = new BulkSMSService();
// Send single SMS
$result = $smsService->sendSMS(
to: '+2348012345678',
message: 'Hello from Laravel!'
);
// Send bulk SMS
$results = $smsService->sendBulkSMS(
recipients: ['+2348012345678', '+2348087654321'],
message: 'Bulk message from Laravel'
);
echo "Sent {$results['successful']} of {$results['total']} messages";
Plain PHP using cURL
<?php
function sendBulkSMS($to, $message, $apiToken, $senderId) {
$url = 'https://www.bulksmsnigeria.com/api/v2/sms';
$data = [
'from' => $senderId,
'to' => $to,
'body' => $message
];
$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'
]);
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$error = curl_error($ch);
curl_close($ch);
if ($error) {
throw new Exception("cURL Error: " . $error);
}
$result = json_decode($response, true);
if ($httpCode !== 200 || $result['status'] !== 'success') {
$errorMsg = $result['message'] ?? 'Unknown error';
throw new Exception("API Error: " . $errorMsg);
}
return $result;
}
// Usage
try {
$result = sendBulkSMS(
to: '+2348012345678',
message: 'Hello from PHP!',
apiToken: 'your-api-token-here',
senderId: 'YourSenderID'
);
echo "Success! Message ID: " . $result['data']['id'] . "\n";
echo "Cost: โฆ" . $result['data']['cost'] . "\n";
} catch (Exception $e) {
echo "Error: " . $e->getMessage() . "\n";
}
Python with requests library
"""
BulkSMS Nigeria API Integration for Django
==========================================
Complete Python implementation for sending SMS via BulkSMS Nigeria API v2.
Requirements:
- Django framework
- requests library (pip install requests)
Configuration (settings.py):
BULK_SMS_BASE_URL = 'https://www.bulksmsnigeria.com/api'
BULK_SMS_API_TOKEN = 'your-api-token-here'
BULK_SMS_SENDER_ID = 'YourSenderID' # Must be registered at /sender-ids
Usage:
from .bulk_sms_api import BulkSMSAPI
sms_api = BulkSMSAPI()
result = sms_api.send_sms(
to_number="+2348012345678",
message="Hello from Django!"
)
Author: David Jay
Date: November 27, 2025
"""
from django.conf import settings
import requests
import logging
logger = logging.getLogger(__name__)
# ============================================================================
# ERROR CODE MAPPING
# ============================================================================
# Based on app/Constants/ApiErrorCode.php from the Laravel application
BSNG_ERROR_MAP = {
# Authentication Errors (1000-1099)
"BSNG-1000": {
"http": 401,
"message": "Authentication failed. Invalid or missing API token."
},
"BSNG-1001": {
"http": 401,
"message": "API token expired. Please generate a new token."
},
"BSNG-1002": {
"http": 403,
"message": "Account suspended. Please contact support."
},
"BSNG-1003": {
"http": 403,
"message": "Account not verified. Please complete KYC verification."
},
# Validation Errors (2000-2099)
"BSNG-2000": {
"http": 422,
"message": "Validation error. Check your request parameters."
},
"BSNG-2001": {
"http": 422,
"message": "Invalid phone number format."
},
"BSNG-2002": {
"http": 422,
"message": "Message body is required."
},
"BSNG-2003": {
"http": 422,
"message": "Sender ID is required."
},
"BSNG-2004": {
"http": 422,
"message": "Invalid sender ID format. Must be 3-11 alphanumeric characters."
},
"BSNG-2005": {
"http": 422,
"message": "Message body exceeds maximum length."
},
"BSNG-2006": {
"http": 422,
"message": "No valid recipients found."
},
"BSNG-2011": {
"http": 403,
"message": "Sender ID not registered or not approved. Please register at /sender-ids"
},
# Wallet & Balance Errors (3000-3099)
"BSNG-3000": {
"http": 402,
"message": "Insufficient wallet balance. Please fund your account."
},
"BSNG-3001": {
"http": 403,
"message": "Transaction limit exceeded."
},
"BSNG-3002": {
"http": 402,
"message": "Minimum balance requirement not met."
},
# SMS Processing Errors (4000-4099)
"BSNG-4000": {
"http": 500,
"message": "SMS processing failed. Please try again."
},
"BSNG-4001": {
"http": 503,
"message": "SMS gateway unavailable. Please try again later."
},
"BSNG-4002": {
"http": 400,
"message": "Invalid gateway specified."
},
"BSNG-4003": {
"http": 429,
"message": "Rate limit exceeded. Please slow down your requests."
},
# General Errors (5000+)
"BSNG-5000": {
"http": 500,
"message": "Internal server error. Please contact support."
},
"BSNG-5001": {
"http": 503,
"message": "Service temporarily unavailable. Please try again later."
},
}
# ============================================================================
# BULK SMS API CLASS
# ============================================================================
class BulkSMSAPI:
"""
Main class for BulkSMS Nigeria API integration.
Handles SMS sending with proper error handling, logging, and response parsing.
"""
def __init__(self, base_url=None, api_token=None, sender_id=None):
"""
Initialize the BulkSMS API client.
Args:
base_url (str, optional): API base URL. Defaults to settings.BULK_SMS_BASE_URL
api_token (str, optional): API token. Defaults to settings.BULK_SMS_API_TOKEN
sender_id (str, optional): Default sender ID. Defaults to settings.BULK_SMS_SENDER_ID
"""
self.base_url = base_url or getattr(settings, 'BULK_SMS_BASE_URL', None)
self.api_token = api_token or getattr(settings, 'BULK_SMS_API_TOKEN', None)
self.sender_id = sender_id or getattr(settings, 'BULK_SMS_SENDER_ID', None)
# Validate required settings
if not self.base_url:
raise ValueError("BULK_SMS_BASE_URL not configured in Django settings")
if not self.api_token:
raise ValueError("BULK_SMS_API_TOKEN not configured in Django settings")
if not self.sender_id:
logger.warning("BULK_SMS_SENDER_ID not configured - sender_id must be provided in send_sms()")
def _headers(self):
"""
Generate headers for API requests.
Returns:
dict: HTTP headers for the request
"""
return {
"Authorization": f"Bearer {self.api_token}",
"Content-Type": "application/json",
"Accept": "application/json"
}
def send_sms(self, to_number, message, sender_id=None, gateway=None):
"""
Send SMS to a given number with the specified message.
Args:
to_number (str): Recipient phone number (e.g., "+2348012345678" or "08012345678")
message (str): SMS message body
sender_id (str, optional): Sender ID to use. Defaults to class sender_id.
NOTE: Sender ID must be registered at /sender-ids
gateway (str, optional): Specific gateway to use (e.g., "mtn", "airtel", "glo", "9mobile")
Returns:
dict: Success response with message details
{
"success": True,
"message_id": "MSG123456",
"cost": 2.50,
"units_used": 1,
"recipients": 1,
"response": {...} # Full API response
}
Raises:
ValueError: If required parameters are missing
Exception: If API request fails or returns an error
Example:
>>> sms_api = BulkSMSAPI()
>>> result = sms_api.send_sms(
... to_number="+2348012345678",
... message="Hello from Django!",
... sender_id="MySenderID"
... )
>>> print(f"Message sent! ID: {result['message_id']}")
"""
# Validate required parameters
if not to_number:
raise ValueError("to_number is required")
if not message:
raise ValueError("message is required")
# Use provided sender_id or fall back to class default
sender = sender_id or self.sender_id
if not sender:
raise ValueError("sender_id is required (either in __init__ or send_sms)")
# Build API endpoint
url_endpoint = f"{self.base_url}/v2/sms"
# Build the payload
payload = {
"from": sender,
"to": to_number,
"body": message
}
# Include gateway in payload if provided
if gateway:
payload["gateway"] = gateway
logger.info(f"Sending SMS to {to_number} from {sender} via {url_endpoint}")
logger.debug(f"Payload: {payload}")
try:
# Send POST request with JSON payload
# CRITICAL: Use json= parameter, not data= parameter
response = requests.post(
url_endpoint,
json=payload, # Sends as JSON with correct Content-Type
headers=self._headers(),
timeout=30 # 30 second timeout to prevent hanging
)
# Log response for debugging
logger.debug(f"Response Status: {response.status_code}")
logger.debug(f"Response Body: {response.text}")
# Parse JSON response
try:
result = response.json()
except ValueError as e:
logger.error(f"Non-JSON response from API: {response.text}")
raise Exception(f"Invalid API response (non-JSON): {response.text}")
# Handle error responses
if result.get("status") == "error":
error_code = result.get("code", "UNKNOWN")
error_info = BSNG_ERROR_MAP.get(
error_code,
{"http": 500, "message": "Unknown error"}
)
# Build detailed error message
error_message = f"Bulk SMS API Error [{error_code}]: {error_info['message']}"
# Include additional error details from API if available
if result.get("message"):
error_message += f" - API says: {result.get('message')}"
logger.error(error_message)
logger.error(f"Full error response: {result}")
raise Exception(error_message)
# Handle success responses
elif result.get("status") == "success":
data = result.get("data", {})
logger.info(f"SMS sent successfully to {to_number}")
logger.info(f"Message ID: {data.get('id')}, Cost: {data.get('cost')}")
return {
"success": True,
"message_id": data.get("id"),
"cost": data.get("cost"),
"units_used": data.get("units"),
"recipients": data.get("recipients", 1),
"response": result # Include full response for advanced usage
}
# Handle unexpected status
else:
unexpected_status = result.get("status", "NONE")
logger.warning(f"Unexpected API response status: {unexpected_status}")
logger.warning(f"Full response: {result}")
raise Exception(f"Unexpected API response status: {unexpected_status}")
# Handle network timeouts
except requests.exceptions.Timeout:
logger.error(f"API request timeout for {to_number}")
raise Exception("SMS API request timed out after 30 seconds. Please try again.")
# Handle connection errors
except requests.exceptions.ConnectionError as e:
logger.error(f"Connection error to SMS API: {str(e)}")
raise Exception(f"Unable to connect to SMS API. Please check your network connection.")
# Handle other request errors
except requests.exceptions.RequestException as e:
logger.error(f"Request error: {str(e)}")
raise Exception(f"SMS API request failed: {str(e)}")
def send_bulk_sms(self, recipients, message, sender_id=None, gateway=None):
"""
Send SMS to multiple recipients.
Args:
recipients (list): List of phone numbers
message (str): SMS message body
sender_id (str, optional): Sender ID to use
gateway (str, optional): Specific gateway to use
Returns:
dict: Results summary
{
"total": 10,
"successful": 8,
"failed": 2,
"results": [...] # Individual results for each recipient
}
Example:
>>> results = sms_api.send_bulk_sms(
... recipients=["+2348012345678", "+2348087654321"],
... message="Bulk message"
... )
>>> print(f"{results['successful']}/{results['total']} sent successfully")
"""
if not isinstance(recipients, list):
raise ValueError("recipients must be a list of phone numbers")
results = {
"total": len(recipients),
"successful": 0,
"failed": 0,
"results": []
}
for recipient in recipients:
try:
result = self.send_sms(
to_number=recipient,
message=message,
sender_id=sender_id,
gateway=gateway
)
results["successful"] += 1
results["results"].append({
"recipient": recipient,
"status": "success",
"data": result
})
except Exception as e:
results["failed"] += 1
results["results"].append({
"recipient": recipient,
"status": "failed",
"error": str(e)
})
logger.error(f"Failed to send SMS to {recipient}: {str(e)}")
logger.info(f"Bulk SMS completed: {results['successful']}/{results['total']} successful")
return results
def get_balance(self):
"""
Get current wallet balance (if endpoint exists).
Note: Implement this method based on your API's balance endpoint.
Returns:
dict: Balance information
"""
# TODO: Implement balance check endpoint
raise NotImplementedError("Balance check endpoint not implemented yet")
def check_sender_id_status(self, sender_id):
"""
Check if a sender ID is registered and approved (if endpoint exists).
Note: Implement this method based on your API's sender ID status endpoint.
Args:
sender_id (str): Sender ID to check
Returns:
dict: Status information
"""
# TODO: Implement sender ID status check endpoint
raise NotImplementedError("Sender ID status check endpoint not implemented yet")
# ============================================================================
# UTILITY FUNCTIONS
# ============================================================================
def format_phone_number(phone_number, country_code="234"):
"""
Format phone number to international format.
Args:
phone_number (str): Phone number in any format
country_code (str): Default country code (default: "234" for Nigeria)
Returns:
str: Formatted phone number with country code
Examples:
>>> format_phone_number("08012345678")
"+2348012345678"
>>> format_phone_number("2348012345678")
"+2348012345678"
>>> format_phone_number("+2348012345678")
"+2348012345678"
"""
# Remove all non-numeric characters
cleaned = ''.join(filter(str.isdigit, phone_number))
# Remove leading zeros
cleaned = cleaned.lstrip('0')
# Add country code if not present
if not cleaned.startswith(country_code):
cleaned = country_code + cleaned
return f"+{cleaned}"
# ============================================================================
# USAGE EXAMPLES
# ============================================================================
if __name__ == "__main__":
"""
Example usage and testing.
To test this module directly:
python python-api-implementation.py
Make sure to configure your Django settings first!
"""
print("BulkSMS Nigeria API - Python Implementation")
print("=" * 50)
# Example 1: Initialize and send single SMS
print("\n[Example 1] Single SMS")
print("-" * 50)
try:
sms_api = BulkSMSAPI()
result = sms_api.send_sms(
to_number="2348012345678",
message="Hello from BulkSMS Nigeria! This is a test message.",
sender_id="TestSender"
)
print(f"โ Success!")
print(f" Message ID: {result['message_id']}")
print(f" Cost: โฆ{result['cost']}")
print(f" Units: {result['units_used']}")
except Exception as e:
print(f"โ Error: {str(e)}")
# Example 2: Send bulk SMS
print("\n[Example 2] Bulk SMS")
print("-" * 50)
try:
sms_api = BulkSMSAPI()
recipients = [
"2348012345678",
"2348087654321",
"2347012345678"
]
results = sms_api.send_bulk_sms(
recipients=recipients,
message="Bulk message test",
sender_id="BulkTest"
)
print(f"โ Bulk send completed!")
print(f" Total: {results['total']}")
print(f" Successful: {results['successful']}")
print(f" Failed: {results['failed']}")
except Exception as e:
print(f"โ Error: {str(e)}")
# Example 3: Using phone number formatter
print("\n[Example 3] Phone Number Formatting")
print("-" * 50)
test_numbers = [
"08012345678",
"2348012345678",
"+2348012345678",
"0701 234 5678"
]
for number in test_numbers:
formatted = format_phone_number(number)
print(f" {number:20} โ {formatted}")
print("\n" + "=" * 50)
print("For Django integration, add to your settings.py:")
print("""
BULK_SMS_BASE_URL = 'https://yourdomain.com/api'
BULK_SMS_API_TOKEN = 'your-api-token-here'
BULK_SMS_SENDER_ID = 'YourSenderID'
""")
print("\nIMPORTANT: Register your sender ID at /sender-ids before using!")
This is a production-ready Django integration with error handling, logging, and bulk SMS support. Install with: pip install requests
Browser JavaScript using Fetch API
class BulkSMSAPI {
constructor(apiToken, senderId) {
this.baseUrl = 'https://www.bulksmsnigeria.com/api';
this.apiToken = apiToken;
this.senderId = senderId;
}
async sendSMS(to, message, senderId = null) {
try {
const response = await fetch(`${this.baseUrl}/v2/sms`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${this.apiToken}`,
'Content-Type': 'application/json',
'Accept': 'application/json'
},
body: JSON.stringify({
from: senderId || this.senderId,
to: to,
body: message
})
});
const result = await response.json();
if (!response.ok || result.status !== 'success') {
throw new Error(result.message || 'Failed to send SMS');
}
return result;
} catch (error) {
console.error('SMS sending failed:', error);
throw error;
}
}
async sendBulkSMS(recipients, message, senderId = null) {
const results = {
total: recipients.length,
successful: 0,
failed: 0,
results: []
};
for (const recipient of recipients) {
try {
const result = await this.sendSMS(recipient, message, senderId);
results.successful++;
results.results.push({
recipient,
status: 'success',
data: result
});
} catch (error) {
results.failed++;
results.results.push({
recipient,
status: 'failed',
error: error.message
});
}
}
return results;
}
}
// Usage Example
const smsAPI = new BulkSMSAPI('your-api-token', 'YourSenderID');
// Send single SMS
smsAPI.sendSMS('+2348012345678', 'Hello from JavaScript!')
.then(result => {
console.log('Success!', result.data);
console.log('Message ID:', result.data.id);
console.log('Cost: โฆ' + result.data.cost);
})
.catch(error => {
console.error('Error:', error.message);
});
// Send bulk SMS
const recipients = ['+2348012345678', '+2348087654321'];
smsAPI.sendBulkSMS(recipients, 'Bulk message from JS')
.then(results => {
console.log(`Sent ${results.successful} of ${results.total} messages`);
});
Node.js with Axios
// Install: npm install axios
const axios = require('axios');
class BulkSMSService {
constructor(apiToken, senderId) {
this.baseUrl = 'https://www.bulksmsnigeria.com/api';
this.apiToken = apiToken;
this.senderId = senderId;
// Create axios instance with defaults
this.client = axios.create({
baseURL: this.baseUrl,
timeout: 30000,
headers: {
'Authorization': `Bearer ${this.apiToken}`,
'Content-Type': 'application/json',
'Accept': 'application/json'
}
});
}
async sendSMS(to, message, senderId = null) {
try {
const response = await this.client.post('/v2/sms', {
from: senderId || this.senderId,
to: to,
body: message
});
if (response.data.status !== 'success') {
throw new Error(response.data.message || 'Failed to send SMS');
}
console.log('SMS sent successfully:', {
messageId: response.data.data.id,
cost: response.data.data.cost
});
return response.data;
} catch (error) {
if (error.response) {
// API returned error response
const apiError = error.response.data;
console.error('API Error:', apiError.code, apiError.message);
throw new Error(`API Error [${apiError.code}]: ${apiError.message}`);
} else if (error.request) {
// Request made but no response
console.error('Network Error: No response from server');
throw new Error('Network error: Unable to reach SMS API');
} else {
// Other errors
console.error('Error:', error.message);
throw error;
}
}
}
async sendBulkSMS(recipients, message, senderId = null) {
const results = {
total: recipients.length,
successful: 0,
failed: 0,
results: []
};
// Send in parallel for better performance
const promises = recipients.map(async (recipient) => {
try {
const result = await this.sendSMS(recipient, message, senderId);
results.successful++;
results.results.push({
recipient,
status: 'success',
data: result
});
} catch (error) {
results.failed++;
results.results.push({
recipient,
status: 'failed',
error: error.message
});
}
});
await Promise.all(promises);
return results;
}
}
// Usage Example
async function main() {
const smsService = new BulkSMSService(
process.env.BULK_SMS_API_TOKEN,
process.env.BULK_SMS_SENDER_ID
);
try {
// Send single SMS
const result = await smsService.sendSMS(
'+2348012345678',
'Hello from Node.js!'
);
console.log('Message sent:', result.data.id);
// Send bulk SMS
const recipients = ['+2348012345678', '+2348087654321'];
const bulkResults = await smsService.sendBulkSMS(
recipients,
'Bulk message from Node.js'
);
console.log(`Sent ${bulkResults.successful}/${bulkResults.total} messages`);
} catch (error) {
console.error('Error:', error.message);
process.exit(1);
}
}
main();
Run: npm install axios
Command line cURL examples
# Send Single SMS
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": "YourSenderID",
"to": "+2348012345678",
"body": "Hello from cURL!"
}'
# Send SMS with Gateway Specification
curl -X POST https://www.bulksmsnigeria.com/api/v2/sms \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"from": "YourSenderID",
"to": "08012345678",
"body": "Message with specific gateway",
"gateway": "mtn"
}'
# Schedule SMS for Future Delivery
curl -X POST https://www.bulksmsnigeria.com/api/v2/sms \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"from": "YourSenderID",
"to": "+2348012345678",
"body": "Scheduled message",
"schedule_time": "2025-12-25 09:00:00"
}'
# Success Response (200 OK)
{
"status": "success",
"message": "SMS sent successfully",
"data": {
"id": "MSG123456",
"cost": 2.50,
"units": 1,
"recipients": 1
}
}
# Error Response (403 Forbidden - Sender ID Not Registered)
{
"status": "error",
"code": "BSNG-2011",
"message": "Sender ID not registered or not approved",
"errors": {
"from": ["Please register your sender ID at /sender-ids"]
}
}
# Error Response (402 Payment Required - Insufficient Balance)
{
"status": "error",
"code": "BSNG-3000",
"message": "Insufficient wallet balance",
"errors": {
"balance": ["Please fund your account to send SMS"]
}
}
Download pre-configured Postman collections to test our API instantly
Complete Postman collection for production API endpoints
Test API endpoints in sandbox mode (no charges)
Our developer support team is here to help you get started quickly