Python / Django Integration
Complete guide to integrate NestSMS into your Python and Django applications with practical examples for sending SMS, handling responses, and tracking delivery status.
Installation
Install the requests library:
pip install requests python-dotenvSetup
Create a .env file:
# .env
NESTSMS_API_KEY=nsms_live_your_api_key_herePython Examples
Send SMS
# send_sms.py
import os
import requests
from dotenv import load_dotenv
load_dotenv()
API_KEY = os.getenv('NESTSMS_API_KEY')
BASE_URL = 'https://api.nestsms.com/api/v1'
def send_sms(phone_number, message, sender_name='YourBrand'):
"""Send a single SMS"""
url = f'{BASE_URL}/sms/send'
headers = {
'X-API-Key': API_KEY,
'Content-Type': 'application/json'
}
payload = {
'to': phone_number,
'message': message,
'sender_id': sender_name,
'message_type': 'transactional'
}
try:
response = requests.post(url, json=payload, headers=headers)
response.raise_for_status()
data = response.json()
print('✓ SMS sent successfully!')
print(f'Job ID: {data["job_id"]}')
print(f'Cost: {data["cost"]}')
return data
except requests.exceptions.HTTPError as e:
error_data = e.response.json()
print(f'✗ Error: {error_data.get("error")}')
print(f'Code: {error_data.get("code")}')
raise
except requests.exceptions.RequestException as e:
print(f'✗ Request failed: {str(e)}')
raise
# Usage
if __name__ == '__main__':
send_sms('9840123456', 'Hello from NestSMS API!')Send Bulk SMS
# send_bulk_sms.py
def send_bulk_sms(recipients, message, sender_name='YourBrand'):
"""Send bulk SMS to multiple recipients"""
url = f'{BASE_URL}/sms/send'
if not isinstance(recipients, list) or len(recipients) > 1000:
raise ValueError('Recipients must be a list (max 1000)')
headers = {
'X-API-Key': API_KEY,
'Content-Type': 'application/json'
}
payload = {
'to': recipients,
'message': message,
'sender_id': sender_name,
'message_type': 'promotional'
}
try:
response = requests.post(url, json=payload, headers=headers)
response.raise_for_status()
data = response.json()
print(f'✓ Bulk SMS sent to {data["recipients_count"]} recipients')
print(f'Total cost: {data["cost"]}')
return data
except requests.exceptions.HTTPError as e:
error_data = e.response.json()
print(f'✗ Error: {error_data.get("error")}')
raise
# Usage
recipients = ['9840123456', '9851234567', '9861345678']
send_bulk_sms(recipients, 'Special offer! Get 50% off today.')Check SMS Status
# check_status.py
def check_sms_status(message_id):
"""Check delivery status of an SMS"""
url = f'{BASE_URL}/sms/status/{message_id}'
headers = {
'X-API-Key': API_KEY
}
try:
response = requests.get(url, headers=headers)
response.raise_for_status()
data = response.json()
print(f'Status: {data["status"]}')
print(f'Sent at: {data["sent_at"]}')
print(f'Delivered at: {data.get("delivered_at", "N/A")}')
return data
except requests.exceptions.HTTPError as e:
error_data = e.response.json()
print(f'✗ Error: {error_data.get("error")}')
raise
# Usage
check_sms_status('550e8400-e29b-41d4-a716-446655440000')Get Account Balance
# get_balance.py
def get_balance():
"""Get account balance and usage stats"""
url = f'{BASE_URL}/sms/balance'
headers = {
'X-API-Key': API_KEY
}
try:
response = requests.get(url, headers=headers)
response.raise_for_status()
data = response.json()
print(f'Balance: {data["balance"]} {data["currency"]}')
print(f'SMS sent today: {data["sms_sent_today"]}')
print(f'SMS sent this month: {data["sms_sent_this_month"]}')
return data
except requests.exceptions.HTTPError as e:
error_data = e.response.json()
print(f'✗ Error: {error_data.get("error")}')
raise
# Usage
get_balance()Complete Python Client
# nestsms_client.py
import requests
from typing import List, Dict, Optional
class NestSMSClient:
"""Complete NestSMS API client"""
def __init__(self, api_key: str, base_url: str = 'https://api.nestsms.com/api/v1'):
self.api_key = api_key
self.base_url = base_url
self.session = requests.Session()
self.session.headers.update({
'X-API-Key': api_key,
'Content-Type': 'application/json'
})
def send_sms(
self,
to: str,
message: str,
sender_id: str = 'YourBrand',
message_type: str = 'transactional',
encoding: str = 'text'
) -> Dict:
"""Send a single SMS"""
url = f'{self.base_url}/sms/send'
payload = {
'to': to,
'message': message,
'sender_id': sender_id,
'message_type': message_type,
'type': encoding
}
return self._make_request('POST', url, json=payload)
def send_bulk_sms(
self,
recipients: List[str],
message: str,
sender_id: str = 'YourBrand',
message_type: str = 'promotional'
) -> Dict:
"""Send bulk SMS to multiple recipients"""
if not isinstance(recipients, list) or len(recipients) > 1000:
raise ValueError('Recipients must be a list (max 1000)')
url = f'{self.base_url}/sms/send'
payload = {
'to': recipients,
'message': message,
'sender_id': sender_id,
'message_type': message_type
}
return self._make_request('POST', url, json=payload)
def check_status(self, message_id: str) -> Dict:
"""Check delivery status of an SMS"""
url = f'{self.base_url}/sms/status/{message_id}'
return self._make_request('GET', url)
def get_balance(self) -> Dict:
"""Get account balance and usage stats"""
url = f'{self.base_url}/sms/balance'
return self._make_request('GET', url)
def _make_request(self, method: str, url: str, **kwargs) -> Dict:
"""Internal method to make HTTP requests"""
try:
response = self.session.request(method, url, **kwargs)
response.raise_for_status()
return response.json()
except requests.exceptions.HTTPError as e:
error_data = e.response.json()
error_msg = f"API Error ({e.response.status_code}): {error_data.get('error')} [{error_data.get('code')}]"
raise Exception(error_msg)
except requests.exceptions.RequestException as e:
raise Exception(f'Network error: {str(e)}')
# Usage Example
if __name__ == '__main__':
client = NestSMSClient(os.getenv('NESTSMS_API_KEY'))
# Send SMS
result = client.send_sms('9840123456', 'Hello from NestSMS!')
print(result)
# Check balance
balance = client.get_balance()
print(balance)Django Integration
Django Settings
# settings.py
import os
from dotenv import load_dotenv
load_dotenv()
# NestSMS Configuration
NESTSMS_API_KEY = os.getenv('NESTSMS_API_KEY')
NESTSMS_BASE_URL = 'https://api.nestsms.com/api/v1'
NESTSMS_SENDER_ID = 'YourBrand'Django Service Class
# sms/services.py
from django.conf import settings
import requests
from typing import List, Dict
class SMSService:
"""Django SMS service for NestSMS"""
def __init__(self):
self.api_key = settings.NESTSMS_API_KEY
self.base_url = settings.NESTSMS_BASE_URL
self.sender_id = settings.NESTSMS_SENDER_ID
def send_sms(self, phone_number: str, message: str, message_type: str = 'transactional') -> Dict:
"""Send a single SMS"""
url = f'{self.base_url}/sms/send'
headers = {
'X-API-Key': self.api_key,
'Content-Type': 'application/json'
}
payload = {
'to': phone_number,
'message': message,
'sender_id': self.sender_id,
'message_type': message_type
}
try:
response = requests.post(url, json=payload, headers=headers)
response.raise_for_status()
return response.json()
except requests.exceptions.RequestException as e:
# Log error
raise Exception(f'Failed to send SMS: {str(e)}')
def send_bulk_sms(self, recipients: List[str], message: str) -> Dict:
"""Send bulk SMS"""
url = f'{self.base_url}/sms/send'
headers = {
'X-API-Key': self.api_key,
'Content-Type': 'application/json'
}
payload = {
'to': recipients,
'message': message,
'sender_id': self.sender_id,
'message_type': 'promotional'
}
try:
response = requests.post(url, json=payload, headers=headers)
response.raise_for_status()
return response.json()
except requests.exceptions.RequestException as e:
raise Exception(f'Failed to send bulk SMS: {str(e)}')
def check_status(self, message_id: str) -> Dict:
"""Check SMS delivery status"""
url = f'{self.base_url}/sms/status/{message_id}'
headers = {
'X-API-Key': self.api_key
}
try:
response = requests.get(url, headers=headers)
response.raise_for_status()
return response.json()
except requests.exceptions.RequestException as e:
raise Exception(f'Failed to check status: {str(e)}')Django Views
# sms/views.py
from django.http import JsonResponse
from django.views import View
from django.views.decorators.csrf import csrf_exempt
from django.utils.decorators import method_decorator
from .services import SMSService
import json
@method_decorator(csrf_exempt, name='dispatch')
class SendSMSView(View):
"""API endpoint to send SMS"""
def post(self, request):
try:
data = json.loads(request.body)
phone_number = data.get('to')
message = data.get('message')
if not phone_number or not message:
return JsonResponse({
'success': False,
'error': 'Missing required fields'
}, status=400)
sms_service = SMSService()
result = sms_service.send_sms(phone_number, message)
return JsonResponse({
'success': True,
'job_id': result['job_id'],
'cost': result['cost']
})
except Exception as e:
return JsonResponse({
'success': False,
'error': str(e)
}, status=500)
@method_decorator(csrf_exempt, name='dispatch')
class BulkSMSView(View):
"""API endpoint to send bulk SMS"""
def post(self, request):
try:
data = json.loads(request.body)
recipients = data.get('recipients', [])
message = data.get('message')
if not recipients or not message:
return JsonResponse({
'success': False,
'error': 'Missing required fields'
}, status=400)
sms_service = SMSService()
result = sms_service.send_bulk_sms(recipients, message)
return JsonResponse({
'success': True,
'job_id': result['job_id'],
'recipients_count': result['recipients_count'],
'cost': result['cost']
})
except Exception as e:
return JsonResponse({
'success': False,
'error': str(e)
}, status=500)
class SMSStatusView(View):
"""API endpoint to check SMS status"""
def get(self, request, message_id):
try:
sms_service = SMSService()
result = sms_service.check_status(message_id)
return JsonResponse({
'success': True,
'status': result['status'],
'sent_at': result['sent_at'],
'delivered_at': result.get('delivered_at')
})
except Exception as e:
return JsonResponse({
'success': False,
'error': str(e)
}, status=500)Django URLs
# sms/urls.py
from django.urls import path
from .views import SendSMSView, BulkSMSView, SMSStatusView
urlpatterns = [
path('send/', SendSMSView.as_view(), name='send_sms'),
path('bulk/', BulkSMSView.as_view(), name='bulk_sms'),
path('status/<str:message_id>/', SMSStatusView.as_view(), name='sms_status'),
]
# In main urls.py
# from django.urls import path, include
# urlpatterns = [
# path('api/sms/', include('sms.urls')),
# ]OTP Verification in Django
OTP Service
# sms/otp_service.py
import random
from django.core.cache import cache
from .services import SMSService
class OTPService:
"""OTP verification service"""
def __init__(self):
self.sms_service = SMSService()
self.otp_expiry = 300 # 5 minutes in seconds
def generate_otp(self) -> str:
"""Generate 6-digit OTP"""
return str(random.randint(100000, 999999))
def send_otp(self, phone_number: str) -> Dict:
"""Send OTP to phone number"""
otp = self.generate_otp()
# Store OTP in cache
cache_key = f'otp_{phone_number}'
cache.set(cache_key, otp, self.otp_expiry)
# Send SMS
message = f'Your verification code is {otp}. Valid for 5 minutes.'
result = self.sms_service.send_sms(
phone_number,
message,
message_type='otp'
)
return {
'success': True,
'job_id': result['job_id']
}
def verify_otp(self, phone_number: str, entered_otp: str) -> Dict:
"""Verify OTP"""
cache_key = f'otp_{phone_number}'
stored_otp = cache.get(cache_key)
if not stored_otp:
return {
'success': False,
'error': 'OTP expired or not found'
}
if stored_otp != entered_otp:
return {
'success': False,
'error': 'Invalid OTP'
}
# Clear OTP after successful verification
cache.delete(cache_key)
return {
'success': True,
'message': 'OTP verified successfully'
}OTP Views
# sms/views.py (add these views)
from .otp_service import OTPService
@method_decorator(csrf_exempt, name='dispatch')
class SendOTPView(View):
"""Send OTP to phone number"""
def post(self, request):
try:
data = json.loads(request.body)
phone_number = data.get('phone_number')
if not phone_number:
return JsonResponse({
'success': False,
'error': 'Phone number required'
}, status=400)
otp_service = OTPService()
result = otp_service.send_otp(phone_number)
return JsonResponse(result)
except Exception as e:
return JsonResponse({
'success': False,
'error': str(e)
}, status=500)
@method_decorator(csrf_exempt, name='dispatch')
class VerifyOTPView(View):
"""Verify OTP"""
def post(self, request):
try:
data = json.loads(request.body)
phone_number = data.get('phone_number')
otp = data.get('otp')
if not phone_number or not otp:
return JsonResponse({
'success': False,
'error': 'Phone number and OTP required'
}, status=400)
otp_service = OTPService()
result = otp_service.verify_otp(phone_number, otp)
return JsonResponse(result)
except Exception as e:
return JsonResponse({
'success': False,
'error': str(e)
}, status=500)Django Management Command
# sms/management/commands/send_sms.py
from django.core.management.base import BaseCommand
from sms.services import SMSService
class Command(BaseCommand):
help = 'Send SMS from command line'
def add_arguments(self, parser):
parser.add_argument('phone', type=str, help='Phone number')
parser.add_argument('message', type=str, help='Message to send')
def handle(self, *args, **options):
phone = options['phone']
message = options['message']
sms_service = SMSService()
try:
result = sms_service.send_sms(phone, message)
self.stdout.write(
self.style.SUCCESS(f'✓ SMS sent! Job ID: {result["job_id"]}')
)
except Exception as e:
self.stdout.write(
self.style.ERROR(f'✗ Error: {str(e)}')
)
# Usage:
# python manage.py send_sms 9840123456 "Hello from Django!"Response Examples
Successful Response
{
"success": true,
"job_id": "550e8400-e29b-41d4-a716-446655440000",
"message": "SMS queued successfully",
"recipients_count": 1,
"cost": 1.5
}Error Response
{
"success": false,
"error": "Insufficient balance",
"code": "INSUFFICIENT_BALANCE"
}Best Practices
- Use environment variables for API keys
- Implement proper error handling and logging
- Use Django cache for OTP storage (Redis recommended)
- Add rate limiting to prevent abuse
- Log all SMS activities for audit trails
- Use Celery for async SMS sending in production
- Implement retry logic with exponential backoff