Skip to main content

Django SDK for SignalBridge SMS Gateway

Project description

SignalBridge Django SDK

Official Django SDK for SignalBridge SMS Gateway - Send SMS through multiple vendors with a unified API.

Python Version Django Version License Version Downloads

Features

  • 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

Installation

pip install signalbridge-django

Add 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-here

Quick Start

Basic SMS Sending

from 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"

In Django Views

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)

Real-World Use Cases

1. OTP Verification System

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)

2. Batch Student Notifications

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")
        raise

3. Appointment Reminders with Balance Check

from 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 result

4. Cost Estimator Before Sending

from 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")

5. Transaction History and Reporting

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
    }

Management Commands

The SDK includes Django management commands for CLI operations:

Send SMS from Command Line

python manage.py signalbridge_send_sms 256700000000 "Your message"

Check Balance

python manage.py signalbridge_check_balance --currency=UGX

Output:

Balance Summary

  Currency: UGX
  Balance: 50000.0
  Credit Limit: 0.0
  Segment Price: 50.0

View Transaction History

python manage.py signalbridge_transactions --page=1 --per-page=20 --type=debit

API Reference

Client Methods

send_sms(recipient, message, metadata=None, is_test=False, scheduled_at=None)

Send 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 message
  • is_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_batch(messages, is_test=False)

Send multiple SMS messages in one request.

Parameters:

  • messages (list): List of message dicts with recipient, message, optional metadata
  • is_test (bool): Mark all as test messages

Returns: Dict with total, successful, failed counts

get_balance(currency='UGX')

Get current balance for a currency.

Returns: Dict with balance, credit_limit, segment_price

get_balance_summary()

Get comprehensive balance summary with recent activity.

get_transactions(per_page=15, page=1, transaction_type=None, start_date=None, end_date=None)

Retrieve transaction history.

Parameters:

  • per_page (int): Results per page (1-100)
  • page (int): Page number
  • transaction_type (str): Filter by 'credit' or 'debit'
  • start_date (str): Start date (YYYY-MM-DD)
  • end_date (str): End date (YYYY-MM-DD)

calculate_segments(message)

Calculate number of SMS segments for a message.

Returns: int - Number of segments

estimate_cost(message, segment_price)

Estimate cost for sending a message.

Returns: float - Estimated cost

Exception Handling

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}")

Configuration

Django Settings

# settings.py

# Required
SIGNALBRIDGE_TOKEN = 'your-api-token-here'


# Logging
LOGGING = {
    'loggers': {
        'signalbridge': {
            'level': 'INFO',
            'handlers': ['console'],
        },
    },
}

Environment Variables

SIGNALBRIDGE_TOKEN=your-api-token-here

Testing

from 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'])

Requirements

  • Python 3.8+
  • Django 3.2+
  • requests >= 2.25.0

Support

For issues and questions:

License

MIT License - see LICENSE file for details.

Related SDKs

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

signalbridge_django_sdk-1.0.1.tar.gz (19.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

signalbridge_django_sdk-1.0.1-py3-none-any.whl (12.7 kB view details)

Uploaded Python 3

File details

Details for the file signalbridge_django_sdk-1.0.1.tar.gz.

File metadata

  • Download URL: signalbridge_django_sdk-1.0.1.tar.gz
  • Upload date:
  • Size: 19.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for signalbridge_django_sdk-1.0.1.tar.gz
Algorithm Hash digest
SHA256 d394c4cb58852721dfb899a389e4cf15cd93517adae0ab8ae384fae7a02eb72d
MD5 6d52ea9baad8dd8e4d44ca864b022aa4
BLAKE2b-256 cb5f0a9c5739542b2b51710b5029b8597891dba955898176667cf8e55815a0bd

See more details on using hashes here.

File details

Details for the file signalbridge_django_sdk-1.0.1-py3-none-any.whl.

File metadata

File hashes

Hashes for signalbridge_django_sdk-1.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 d3664d88af249dba08cac3ac65a304d77969b90427b54b0720aa92dcc36d1873
MD5 c9c5f43f6c0cd7cf10b7e236c0c189b4
BLAKE2b-256 53caf4a83978662df219807247d5638d78965be34584063ef318ef92925131ac

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page