Skip to main content

Installation

Install the EasyOTP Python SDK using pip:
pip install easyotp

Quick Start

from easyotp import EasyOTP

client = EasyOTP(api_key='YOUR_API_KEY')

result = client.send(
    channel='sms',
    recipient='+1234567890',
    message='Your verification code is: {code}'
)

print('Verification ID:', result['verification_id'])

Initialization

Create a new EasyOTP client instance with your API key:
from easyotp import EasyOTP

client = EasyOTP(
    api_key='YOUR_API_KEY',
    base_url='https://app.easyotp.dev/api/v1'
)

Configuration Options

api_key
string
required
Your EasyOTP API key. Get it from your dashboard.
base_url
string
Base URL for the API. Defaults to https://app.easyotp.dev/api/v1.
Never expose your API key in client-side code. Always use the SDK from your backend server.

Methods

send()

Send a verification code via SMS, Email, or Voice.
result = client.send(
    channel='sms',
    recipient='+1234567890',
    message='Your verification code is: {code}',
    expires_in=300
)

Parameters

channel
string
required
Communication channel. Must be one of: sms, email, or voice
recipient
string
required
Recipient address:
  • For SMS/Voice: E.164 formatted phone number (e.g., +1234567890)
  • For Email: Valid email address (e.g., [email protected])
message
string
Custom message template. Use {code} as a placeholder for the verification code.Default: "Your verification code is: {code}"
subject
string
Email subject line (only used when channel is email)Default: "Your Verification Code"
expires_in
int
Code expiration time in seconds. Must be between 60 and 3600.Default: 300 (5 minutes)
code
string
Custom verification code. Must be a numeric string between 4-10 digits.If not provided, a code will be automatically generated.

Returns

success
bool
Always True for successful requests
verification_id
str
Unique identifier for this verification. Use this when calling verify().
expires_at
str
ISO 8601 timestamp when the code expires
request_id
str
Unique request identifier for debugging

verify()

Verify a code that was previously sent.
result = client.verify(
    verification_id='11f951d5-32d1-4b49-bdda-7da248e2615c',
    code='123456'
)

Parameters

verification_id
string
required
The verification ID returned from the send() method
code
string
required
The verification code to check. Must be a numeric string between 4-10 digits.

Returns

success
bool
Always True for successful requests (even if the code is invalid)
verified
bool
True if the code was correct and not expired, False otherwise
message
str
Human-readable result message. Possible values:
  • "Code verified successfully"
  • "Invalid code"
  • "Code expired"
  • "Code already used"
request_id
str
Unique request identifier for debugging

Examples

Complete Verification Flow

from easyotp import EasyOTP
import os

client = EasyOTP(api_key=os.environ.get('EASYOTP_API_KEY'))

def verify_phone_number(phone_number):
    try:
        result = client.send(
            channel='sms',
            recipient=phone_number,
            message='Your verification code is: {code}',
            expires_in=300
        )
        
        print('Code sent! Verification ID:', result['verification_id'])
        return result['verification_id']
    except Exception as e:
        print(f'Failed to send code: {e}')
        raise

def check_verification_code(verification_id, code):
    try:
        result = client.verify(
            verification_id=verification_id,
            code=code
        )
        
        if result['verified']:
            print('Code verified successfully!')
            return True
        else:
            print('Verification failed:', result['message'])
            return False
    except Exception as e:
        print(f'Failed to verify code: {e}')
        raise

verification_id = verify_phone_number('+1234567890')
is_valid = check_verification_code(verification_id, '123456')

Sending via Different Channels

result = client.send(
    channel='sms',
    recipient='+1234567890',
    message='Your Acme Corp verification code is: {code}',
    expires_in=300
)

Error Handling

The SDK raises exceptions for failed requests. Always wrap API calls in try-except blocks:
from easyotp import EasyOTP
from easyotp.exceptions import EasyOTPError, AuthenticationError, InsufficientCreditsError, RateLimitError

client = EasyOTP(api_key=os.environ.get('EASYOTP_API_KEY'))

try:
    result = client.send(
        channel='sms',
        recipient='+1234567890',
        message='Your verification code is: {code}'
    )
    
    print('Success:', result['verification_id'])
except AuthenticationError:
    print('Invalid API key')
except InsufficientCreditsError:
    print('Insufficient credits')
except RateLimitError as e:
    print(f'Rate limit exceeded. Retry after {e.retry_after} seconds')
except EasyOTPError as e:
    print(f'Error: {e.message}')

Flask Integration Example

from flask import Flask, request, jsonify
from easyotp import EasyOTP
import os

app = Flask(__name__)
client = EasyOTP(api_key=os.environ.get('EASYOTP_API_KEY'))

sessions = {}

@app.route('/api/send-code', methods=['POST'])
def send_code():
    try:
        data = request.json
        phone_number = data.get('phoneNumber')
        
        result = client.send(
            channel='sms',
            recipient=phone_number,
            message='Your verification code is: {code}',
            expires_in=300
        )
        
        import uuid
        session_id = str(uuid.uuid4())
        sessions[session_id] = {
            'phone_number': phone_number,
            'verification_id': result['verification_id']
        }
        
        return jsonify({'sessionId': session_id})
    except Exception as e:
        return jsonify({'error': str(e)}), 500

@app.route('/api/verify-code', methods=['POST'])
def verify_code():
    try:
        data = request.json
        session_id = data.get('sessionId')
        code = data.get('code')
        
        session = sessions.get(session_id)
        if not session:
            return jsonify({'error': 'Invalid session'}), 400
        
        result = client.verify(
            verification_id=session['verification_id'],
            code=code
        )
        
        if result['verified']:
            del sessions[session_id]
            return jsonify({'success': True})
        else:
            return jsonify({'success': False, 'message': result['message']})
    except Exception as e:
        return jsonify({'error': str(e)}), 500

if __name__ == '__main__':
    app.run()

Django Integration Example

from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.http import require_http_methods
from easyotp import EasyOTP
import os
import json

client = EasyOTP(api_key=os.environ.get('EASYOTP_API_KEY'))

@csrf_exempt
@require_http_methods(["POST"])
def send_code(request):
    try:
        data = json.loads(request.body)
        phone_number = data.get('phoneNumber')
        
        result = client.send(
            channel='sms',
            recipient=phone_number,
            message='Your verification code is: {code}',
            expires_in=300
        )
        
        import uuid
        session_id = str(uuid.uuid4())
        request.session[session_id] = {
            'phone_number': phone_number,
            'verification_id': result['verification_id']
        }
        
        return JsonResponse({'sessionId': session_id})
    except Exception as e:
        return JsonResponse({'error': str(e)}, status=500)

@csrf_exempt
@require_http_methods(["POST"])
def verify_code(request):
    try:
        data = json.loads(request.body)
        session_id = data.get('sessionId')
        code = data.get('code')
        
        session = request.session.get(session_id)
        if not session:
            return JsonResponse({'error': 'Invalid session'}, status=400)
        
        result = client.verify(
            verification_id=session['verification_id'],
            code=code
        )
        
        if result['verified']:
            del request.session[session_id]
            return JsonResponse({'success': True})
        else:
            return JsonResponse({'success': False, 'message': result['message']})
    except Exception as e:
        return JsonResponse({'error': str(e)}, status=500)

Error Handling

The SDK raises custom exceptions for different error types:

Exception Classes

  • EasyOTPError: Base exception for all SDK errors
  • AuthenticationError: Raised for 401 errors (invalid API key)
  • InsufficientCreditsError: Raised for 402 errors (insufficient credits)
  • ForbiddenError: Raised for 403 errors (API key disabled)
  • NotFoundError: Raised for 404 errors (verification not found)
  • RateLimitError: Raised for 429 errors (rate limit exceeded)
  • ServerError: Raised for 500 errors (internal server error)

Error Object Properties

All exceptions include:
  • message: Human-readable error message
  • status_code: HTTP status code
  • request_id: Unique request identifier for debugging
  • retry_after: Seconds to wait before retrying (for rate limit errors)

Common Error Codes

Status CodeExceptionSolution
400EasyOTPErrorCheck your request parameters
401AuthenticationErrorVerify your API key is correct
402InsufficientCreditsErrorAdd credits to your account
403ForbiddenErrorAPI key is disabled
404NotFoundErrorVerification ID doesn’t exist
429RateLimitErrorWait for retry_after seconds
500ServerErrorContact support with request_id

Type Hints

The SDK includes type hints for better IDE support:
from easyotp import EasyOTP
from typing import Dict, Any

client = EasyOTP(api_key='YOUR_API_KEY')

def send_otp(phone_number: str) -> Dict[str, Any]:
    return client.send(
        channel='sms',
        recipient=phone_number,
        message='Your code is: {code}'
    )

def verify_otp(verification_id: str, code: str) -> Dict[str, Any]:
    return client.verify(
        verification_id=verification_id,
        code=code
    )

Best Practices

Store API keys securely: Use environment variables and never commit them to version control.
Handle errors gracefully: Always wrap SDK calls in try-except blocks and provide meaningful error messages to users.
Use appropriate expiration times:
  • SMS/Voice: 2-5 minutes
  • Email: 10-15 minutes
Keep verification IDs server-side: Never expose verification IDs in URLs or client-side code. Store them server-side associated with user sessions.
Rate limiting: The SDK automatically handles rate limit responses. Check for retry_after in exception objects to inform users when they can retry.
Use environment variables: Store your API key in environment variables for better security:
import os
client = EasyOTP(api_key=os.environ.get('EASYOTP_API_KEY'))

Additional Resources