Official Django SDK for SignalBridge SMS Gateway - Send SMS through multiple vendors with a unified API.
- Unified SMS API - Single interface for multiple SMS vendors (SpeedaMobile, Africa's Talking, etc)
- Batch Sending - Send bulk SMS efficiently with detailed results
- Balance Management - Real-time balance tracking and transaction history
- Segment Calculation - Automatic GSM 7-bit vs Unicode detection and cost estimation
- Django Integration - Native Django settings, logging, and session support
- Management Commands - CLI tools for common SMS operations
- Session Pooling - HTTP session reuse for optimal performance
- Typed Exceptions - Specific exceptions for different error scenarios
pip install signalbridge-djangoAdd to your Django INSTALLED_APPS:
# settings.py
INSTALLED_APPS = [
# ...
'signalbridge',
]
# SignalBridge Configuration
SIGNALBRIDGE_TOKEN = 'your-api-token-here'Or use environment variables:
# .env
SIGNALBRIDGE_TOKEN=your-api-token-herefrom signalbridge.client import get_client
client = get_client()
# Send single SMS
result = client.send_sms(
recipient='256700000000',
message='Hello from SignalBridge!'
)
print(result['message']) # "SMS queued successfully"from django.http import JsonResponse
from django.views import View
from signalbridge.client import get_client
from signalbridge.exceptions import SignalBridgeException
class SendSMSView(View):
def post(self, request):
try:
client = get_client()
result = client.send_sms(
recipient=request.POST.get('phone'),
message=request.POST.get('message')
)
return JsonResponse({
'success': True,
'message': result['message']
})
except SignalBridgeException as e:
return JsonResponse({
'success': False,
'message': str(e)
}, status=500)from django.views import View
from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt
from django.utils.decorators import method_decorator
import random
from signalbridge.client import get_client
class SendOTPView(View):
@method_decorator(csrf_exempt)
def post(self, request):
phone = request.POST.get('phone')
otp = random.randint(100000, 999999)
# Store in session
request.session['otp'] = str(otp)
request.session['otp_phone'] = phone
client = get_client()
result = client.send_sms(
recipient=phone,
message=f'Your verification code is {otp}. Valid for 5 minutes.',
metadata={'purpose': 'otp'}
)
return JsonResponse({
'success': True,
'message': 'OTP sent successfully'
})
class VerifyOTPView(View):
@method_decorator(csrf_exempt)
def post(self, request):
submitted = request.POST.get('otp')
stored = request.session.get('otp')
if submitted == stored:
del request.session['otp']
return JsonResponse({'success': True, 'message': 'Verified'})
else:
return JsonResponse({'success': False, 'message': 'Invalid OTP'}, status=400)from signalbridge.client import get_client
from signalbridge.exceptions import InsufficientBalanceException
def send_exam_results(students):
"""Send exam results to multiple students"""
messages = []
for student in students:
messages.append({
'recipient': student.phone,
'message': f"Dear {student.name}, your exam result: {student.marks}/100",
'metadata': {'student_id': student.id}
})
try:
client = get_client()
result = client.send_batch(messages)
print(f"Sent {result['data']['successful']} of {result['data']['total']} messages")
return result
except InsufficientBalanceException as e:
print(f"Need {e.get_required_balance()} UGX, have {e.get_current_balance()} UGX")
raisefrom signalbridge.client import get_client
def send_appointment_reminder(appointment):
client = get_client()
# Check balance first
balance = client.get_balance()
if balance['data']['balance'] < 100: # Minimum threshold
raise ValueError("Balance too low. Please top up.")
message = (
f"Reminder: Dear {appointment.patient_name}, "
f"you have an appointment with Dr. {appointment.doctor} "
f"on {appointment.date} at {appointment.time}."
)
result = client.send_sms(
recipient=appointment.phone,
message=message,
metadata={'appointment_id': appointment.id}
)
return resultfrom signalbridge.client import get_client
def estimate_campaign_cost(message, recipient_count):
"""Calculate cost before sending bulk SMS"""
client = get_client()
# Get current pricing
balance = client.get_balance()
segment_price = balance['data']['segment_price']
# Calculate segments
segments = client.calculate_segments(message)
cost_per_message = client.estimate_cost(message, segment_price)
total_cost = cost_per_message * recipient_count
return {
'segments': segments,
'cost_per_message': cost_per_message,
'recipient_count': recipient_count,
'total_cost': total_cost,
'current_balance': balance['data']['balance'],
'sufficient': balance['data']['balance'] >= total_cost
}
# Usage
estimate = estimate_campaign_cost("Your message here", recipient_count=500)
print(f"Campaign will cost {estimate['total_cost']} for {estimate['recipient_count']} recipients")from signalbridge.client import get_client
from datetime import datetime, timedelta
def generate_monthly_report():
"""Generate SMS usage report for the past month"""
client = get_client()
end_date = datetime.now().strftime('%Y-%m-%d')
start_date = (datetime.now() - timedelta(days=30)).strftime('%Y-%m-%d')
transactions = client.get_transactions(
per_page=100,
transaction_type='debit', # Only SMS sends
start_date=start_date,
end_date=end_date
)
total_spent = sum(t['amount'] for t in transactions['data']['data'])
total_messages = len(transactions['data']['data'])
return {
'period': f"{start_date} to {end_date}",
'total_messages': total_messages,
'total_spent': total_spent,
'average_cost': total_spent / total_messages if total_messages > 0 else 0
}The SDK includes Django management commands for CLI operations:
python manage.py signalbridge_send_sms 256700000000 "Your message"python manage.py signalbridge_check_balance --currency=UGXOutput:
Balance Summary
Currency: UGX
Balance: 50000.0
Credit Limit: 0.0
Segment Price: 50.0
python manage.py signalbridge_transactions --page=1 --per-page=20 --type=debitSend a single SMS message.
Parameters:
recipient(str): Phone number in international format (e.g., '256700000000')message(str): Message content (max 1000 characters)metadata(dict, optional): Custom data to store with messageis_test(bool): Flag as test message (won't be charged)scheduled_at(datetime, optional): Schedule for future sending
Returns: Dict with success, message, and data keys
Send multiple SMS messages in one request.
Parameters:
messages(list): List of message dicts withrecipient,message, optionalmetadatais_test(bool): Mark all as test messages
Returns: Dict with total, successful, failed counts
Get current balance for a currency.
Returns: Dict with balance, credit_limit, segment_price
Get comprehensive balance summary with recent activity.
Retrieve transaction history.
Parameters:
per_page(int): Results per page (1-100)page(int): Page numbertransaction_type(str): Filter by 'credit' or 'debit'start_date(str): Start date (YYYY-MM-DD)end_date(str): End date (YYYY-MM-DD)
Calculate number of SMS segments for a message.
Returns: int - Number of segments
Estimate cost for sending a message.
Returns: float - Estimated cost
The SDK provides specific exceptions for different scenarios:
from signalbridge.exceptions import (
InsufficientBalanceException,
ValidationException,
NoClientException,
ServiceUnavailableException,
SignalBridgeException
)
try:
client.send_sms(recipient='256700000000', message='Test')
except InsufficientBalanceException as e:
print(f"Balance: {e.get_current_balance()}")
print(f"Required: {e.get_required_balance()}")
print(f"Segments: {e.get_segments()}")
except ValidationException as e:
print(f"Errors: {e.get_errors()}")
print(f"First error: {e.get_first_error()}")
except NoClientException as e:
print("Client not found or unauthorized")
except ServiceUnavailableException as e:
print("Service temporarily unavailable")
except SignalBridgeException as e:
print(f"Error: {e.message}")
print(f"Status: {e.status_code}")# settings.py
# Required
SIGNALBRIDGE_TOKEN = 'your-api-token-here'
# Logging
LOGGING = {
'loggers': {
'signalbridge': {
'level': 'INFO',
'handlers': ['console'],
},
},
}SIGNALBRIDGE_TOKEN=your-api-token-herefrom django.test import TestCase
from unittest.mock import patch, MagicMock
from signalbridge.client import SignalBridgeClient
class SMSTestCase(TestCase):
@patch('signalbridge.client.requests.Session')
def test_send_sms(self, mock_session):
# Mock API response
mock_response = MagicMock()
mock_response.status_code = 200
mock_response.json.return_value = {
'success': True,
'message': 'SMS queued successfully'
}
mock_session.return_value.request.return_value = mock_response
client = SignalBridgeClient(token='test-token')
result = client.send_sms('256700000000', 'Test message')
self.assertTrue(result['success'])- Python 3.8+
- Django 3.2+
- requests >= 2.25.0
For issues and questions:
- Documentation: https://signal-bridge.nugsoftstagging.com/docs
MIT License - see LICENSE file for details.
- Laravel SDK: nugsoft/signalbridge-laravel-sdk
- PHP SDK: nugsoft/signalbridge-php-sdk