API Reference#
This page provides a complete reference for the core APIs, services, and models in django-phone-verify.
Services#
PhoneVerificationService#
- class phone_verify.services.PhoneVerificationService(phone_number, backend=None)#
Main service class for sending and managing phone verification messages.
- Parameters:
phone_number (str) – The phone number to verify (E.164 format recommended)
backend (BaseBackend or None) – Optional backend instance. If None, uses the configured backend from settings
Methods:
- send_verification(number, security_code, context=None)#
Send a verification SMS to the specified phone number.
- Parameters:
number (str) – Recipient phone number
security_code (str) – The generated security code to send
context (dict) – Optional context for custom message formatting (e.g.,
{"username": "John"})
- Raises:
Backend-specific exception (e.g.,
TwilioRestException)
Example:
from phone_verify.services import PhoneVerificationService service = PhoneVerificationService(phone_number="+1234567890") service.send_verification( number="+1234567890", security_code="123456", context={"username": "Alice"} )
- phone_verify.services.send_security_code_and_generate_session_token(phone_number)#
High-level function that generates a security code, creates a session token, and sends the SMS.
- Parameters:
phone_number (str) – The phone number to send the code to
- Returns:
The generated session token (JWT)
- Return type:
str
Example:
from phone_verify.services import send_security_code_and_generate_session_token session_token = send_security_code_and_generate_session_token("+1234567890") # Returns: "eyJ0eXAiOiJKV1QiLCJhbGc..."
Backends#
BaseBackend#
- class phone_verify.backends.base.BaseBackend(**settings)#
Abstract base class for all SMS backends. Extend this to create custom backends.
Class Attributes:
SECURITY_CODE_VALID = 0- Code is valid and verifiedSECURITY_CODE_INVALID = 1- Code doesn’t exist or is incorrectSECURITY_CODE_EXPIRED = 2- Code has expiredSECURITY_CODE_VERIFIED = 3- Code already used (whenVERIFY_SECURITY_CODE_ONLY_ONCE=True)SESSION_TOKEN_INVALID = 4- Session token doesn’t match
Abstract Methods (must be implemented):
- abstractmethod send_sms(number, message)#
Send a single SMS message.
- Parameters:
number (str) – Recipient phone number
message (str) – Message content
- abstractmethod send_bulk_sms(numbers, message)#
Send an SMS to multiple recipients.
- Parameters:
numbers (list) – List of recipient phone numbers
message (str) – Message content
Concrete Methods:
- classmethod generate_security_code()#
Generate a random numeric security code based on
TOKEN_LENGTHsetting.- Returns:
Random numeric string (e.g., “123456”)
- Return type:
str
- classmethod generate_session_token(phone_number)#
Generate a unique JWT session token for the phone number.
- Parameters:
phone_number (str) – Phone number to encode
- Returns:
JWT token
- Return type:
str
- create_security_code_and_session_token(number)#
Create a security code and session token, storing them in the database.
- Parameters:
number (str) – Phone number
- Returns:
Tuple of (security_code, session_token)
- Return type:
tuple
- validate_security_code(security_code, phone_number, session_token)#
Validate a security code for a phone number.
- Parameters:
security_code (str) – The code to validate
phone_number (str) – Phone number to verify
session_token (str) – Session token from registration
- Returns:
Tuple of (SMSVerification object or None, status code)
- Return type:
tuple
- generate_message(security_code, context=None)#
Optional method to customize message generation. Return None to use default.
- Parameters:
security_code (str) – The generated code
context (dict) – Optional runtime context
- Returns:
Custom message string or None
- Return type:
str or None
Example:
def generate_message(self, security_code, context=None): username = context.get("username", "User") if context else "User" return f"Hi {username}, your OTP is {security_code}."
TwilioBackend#
- class phone_verify.backends.twilio.TwilioBackend(**options)#
Twilio SMS backend implementation.
Required OPTIONS:
SID: Twilio Account SIDSECRET: Twilio Auth TokenFROM: Twilio phone number (E.164 format)
Example Configuration:
PHONE_VERIFICATION = { "BACKEND": "phone_verify.backends.twilio.TwilioBackend", "OPTIONS": { "SID": "ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", "SECRET": "your_auth_token", "FROM": "+15551234567", }, ... }
NexmoBackend#
- class phone_verify.backends.nexmo.NexmoBackend(**options)#
Nexmo (Vonage) SMS backend implementation.
Required OPTIONS:
KEY: Nexmo API KeySECRET: Nexmo API SecretFROM: Sender ID or phone number
Example Configuration:
PHONE_VERIFICATION = { "BACKEND": "phone_verify.backends.nexmo.NexmoBackend", "OPTIONS": { "KEY": "your_api_key", "SECRET": "your_api_secret", "FROM": "YourApp", }, ... }
Models#
SMSVerification#
- class phone_verify.models.SMSVerification#
Database model for storing verification attempts.
Fields:
id(UUIDField): Primary keyphone_number(PhoneNumberField): Phone number being verifiedsecurity_code(CharField): The verification code sentsession_token(CharField): JWT token for this verification sessionis_verified(BooleanField): Whether the code has been successfully verifiedfailed_attempts(PositiveIntegerField): Number of failed verification attempts (default: 0)created_at(DateTimeField): When the verification was createdmodified_at(DateTimeField): Last modification time
Properties:
- is_expired#
Returns
Trueif the security code has expired based on theSECURITY_CODE_EXPIRATION_SECONDSsetting.- Returns:
Whether the code is expired
- Return type:
bool
Example:
verification = SMSVerification.objects.get(session_token=token) if verification.is_expired: print("Code has expired")
Constraints:
Unique together: (
security_code,phone_number,session_token)Ordered by:
-modified_at(newest first)
Example Query:
from phone_verify.models import SMSVerification # Find unverified codes for a phone number pending = SMSVerification.objects.filter( phone_number="+1234567890", is_verified=False ) # Check if a verification has expired verification = SMSVerification.objects.first() if verification and verification.is_expired: print("Verification has expired")
Serializers#
PhoneSerializer#
- class phone_verify.serializers.PhoneSerializer#
Simple serializer for phone number input.
Fields:
phone_number(PhoneNumberField): Required phone number field
Usage:
serializer = PhoneSerializer(data={"phone_number": "+1234567890"}) if serializer.is_valid(): phone = serializer.validated_data["phone_number"]
SMSVerificationSerializer#
- class phone_verify.serializers.SMSVerificationSerializer#
Serializer for verifying a security code.
Fields:
phone_number(PhoneNumberField): Phone number to verifysecurity_code(CharField): The code received via SMSsession_token(CharField): Session token from registration
Validation:
Automatically validates the security code against the backend and raises appropriate errors:
“Security code is not valid”
“Session Token mis-match”
“Security code has expired”
“Security code is already verified”
Usage:
serializer = SMSVerificationSerializer(data={ "phone_number": "+1234567890", "security_code": "123456", "session_token": "eyJ0eXAi..." }) serializer.is_valid(raise_exception=True)
ViewSets#
VerificationViewSet#
- class phone_verify.api.VerificationViewSet#
DRF ViewSet with two main actions for phone verification flow.
Actions:
- register(request)#
POST
/api/phone/registerSend a security code to a phone number.
Request Body:
{ "phone_number": "+1234567890" }
Response:
{ "session_token": "eyJ0eXAiOiJKV1QiLCJ..." }
- verify(request)#
POST
/api/phone/verifyVerify a security code.
Request Body:
{ "phone_number": "+1234567890", "security_code": "123456", "session_token": "eyJ0eXAiOiJKV1QiLCJ..." }
Response:
{ "message": "Security code is valid." }
Extending:
You can extend this ViewSet to add custom actions:
from phone_verify.api import VerificationViewSet class CustomVerificationViewSet(VerificationViewSet): @action(detail=False, methods=['POST']) def verify_and_login(self, request): # Custom logic here pass
Django Admin Interface#
SMSVerificationAdmin#
The Django admin interface provides an intuitive way to manage and monitor phone verifications.
Features:
List Display: Shows ID, security code, phone number, verification status, validity status, failed attempts, and creation date
Is Valid: Boolean indicator using Django’s standard icons - green checkmark when valid, red X when expired
Search: Search by phone number
Filters: Filter by verification status and creation date
Read-only Fields: All fields are read-only to prevent accidental modifications
Accessing the Admin:
Navigate to Django admin:
/admin/Click on “SMS Verifications” under the “Phone Verify” section
View all verification records with their validity status
Example View:
The admin list will show entries like:
ID: 550e8400-e29b-41d4-a716-446655440000
Security Code: 123456
Phone Number: +1234567890
Is Verified: ✓ (green checkmark)
Is Valid: ✓ (green checkmark - not expired) or ✗ (red X - expired)
Failed Attempts: 0
Created At: 2025-10-19 14:30:00
Management Commands#
cleanup_phone_verifications#
Django management command to clean up old SMS verification records from the database.
Usage:
# Delete records older than the default retention period (30 days or RECORD_RETENTION_DAYS setting)
python manage.py cleanup_phone_verifications
# Delete records older than a custom number of days
python manage.py cleanup_phone_verifications --days 7
# Dry-run mode: preview what would be deleted without actually deleting
python manage.py cleanup_phone_verifications --dry-run
# Combine options
python manage.py cleanup_phone_verifications --days 14 --dry-run
Options:
--days N: Number of days to retain records (overridesRECORD_RETENTION_DAYSsetting)--dry-run: Show what would be deleted without actually deleting anything
Configuration:
Add RECORD_RETENTION_DAYS to your PHONE_VERIFICATION settings to set the default retention period:
PHONE_VERIFICATION = {
...
'RECORD_RETENTION_DAYS': 30, # Keep records for 30 days (default)
}
Scheduling:
For production use, schedule this command to run periodically using cron, Celery Beat, or your preferred task scheduler:
# Example crontab entry (runs daily at 2 AM)
0 2 * * * /path/to/python /path/to/manage.py cleanup_phone_verifications
Example Output:
Successfully deleted 42 verification record(s) older than 30 days
Or for dry-run mode:
DRY RUN: Would delete 42 verification record(s) older than 30 days
Records that would be deleted:
- +1234567890 (created: 2025-09-15 10:23:45)
- +1234567891 (created: 2025-09-14 08:15:30)
... and 40 more