addicta/otp

Multi-provider OTP package for Laravel

Installs: 1

Dependents: 0

Suggesters: 0

Security: 0

Stars: 0

Watchers: 0

Forks: 0

Open Issues: 0

pkg:composer/addicta/otp

0.4.0 2025-12-13 16:07 UTC

This package is not auto-updated.

Last update: 2025-12-13 19:23:01 UTC


README

A comprehensive Laravel package for sending and verifying One-Time Passwords (OTP) via SMS using multiple providers including Twilio and Unifonic.

Features

  • ๐Ÿ“ก Multi-Channel Support: Send OTPs via Phone (SMS) or Email
  • ๐Ÿ” Multi-Provider Support: Twilio (SMS & Verify API) and Unifonic providers
  • โœจ Twilio Verify Service: Full support for Twilio's Verify API with custom OTP codes
  • ๐Ÿ“ง Beautiful Email Templates: Professional, responsive HTML email templates
  • ๐Ÿ›ก๏ธ Security Features: Rate limiting, attempt tracking, and automatic blocking
  • โฐ Configurable Expiry: Customizable OTP expiration times
  • ๐Ÿ”„ Resend Protection: Prevents spam with configurable resend delays
  • ๐Ÿงช Fully Tested: Comprehensive test suite with 16 tests
  • ๐ŸŽฏ Laravel Integration: Service provider, facades, and auto-discovery
  • ๐Ÿ“ฑ Easy to Use: Simple API for generating and verifying OTPs
  • ๐ŸŒ Multi-Language: Built-in English and Arabic translations for both SMS and Email

Installation

Via Composer

composer require one-studio/otp

Laravel Auto-Discovery

The package will be automatically discovered by Laravel. If you're using Laravel 5.5+, no additional configuration is required.

Manual Registration (Laravel < 5.5)

Add the service provider to your config/app.php:

'providers' => [
    // ...
    Addicta\Otp\OtpServiceProvider::class,
],

Add the facade alias:

'aliases' => [
    // ...
    'Otp' => Addicta\Otp\Facades\Otp::class,
],

Configuration

Publishing Configuration and Translations

Publish the configuration file:

php artisan vendor:publish --provider="Addicta\Otp\OtpServiceProvider" --tag="otp-config"

Publish the translation files:

php artisan vendor:publish --provider="Addicta\Otp\OtpServiceProvider" --tag="otp-translations"

This will create:

  • config/otp.php - Configuration file
  • lang/vendor/otp/en/otp.php - English translations
  • lang/vendor/otp/ar/otp.php - Arabic translations

Environment Variables

Add the following environment variables to your .env file:

# Default Channel: 'phone' or 'email' (default: phone)
OTP_DEFAULT_CHANNEL=phone

# OTP Provider for phone channel (twilio or unifonic)
OTP_PROVIDER=twilio

# Twilio Configuration
TWILIO_ACCOUNT_SID=your_twilio_account_sid
TWILIO_AUTH_TOKEN=your_twilio_auth_token

# Twilio Service Type: 'sms' for direct SMS or 'verify' for Twilio Verify API
TWILIO_SERVICE_TYPE=sms

# Required for SMS service type
TWILIO_FROM=your_twilio_phone_number

# Required for Verify service type
TWILIO_VERIFICATION_SID=your_twilio_verification_sid

# Unifonic Configuration (if using Unifonic)
UNIFONIC_APP_SID=your_unifonic_app_sid
UNIFONIC_SENDER_ID=your_unifonic_sender_id

# Email Configuration
OTP_EMAIL_FROM_ADDRESS=noreply@yourapp.com
OTP_EMAIL_FROM_NAME="Your App Name"
OTP_EMAIL_SUBJECT="Your Verification Code"

# OTP Settings
OTP_LENGTH=4
OTP_EXPIRY=5
MAX_ATTEMPTS=3
RESEND_DELAY=60
BLOCK_DURATION=30

# Test Mode Settings
OTP_TEST_MODE=false
OTP_TEST_CODE=8888

Configuration File

The published configuration file (config/otp.php) contains:

return [
    // Default channel for OTP delivery: 'phone' or 'email'
    'default_channel' => env('OTP_DEFAULT_CHANNEL', 'phone'),

    // Default provider for phone OTPs
    'default' => env('OTP_PROVIDER', 'twilio'),

    // SMS/Phone providers
    'providers' => [
        'twilio' => [
            'driver' => 'twilio',
            'account_sid' => env('TWILIO_ACCOUNT_SID'),
            'auth_token' => env('TWILIO_AUTH_TOKEN'),
            'service_type' => env('TWILIO_SERVICE_TYPE', 'sms'), // 'sms' or 'verify'
            'verification_sid' => env('TWILIO_VERIFICATION_SID'), // Required for 'verify' service
            'from' => env('TWILIO_FROM'), // Required for 'sms' service
        ],
        'unifonic' => [
            'driver' => 'unifonic',
            'app_sid' => env('UNIFONIC_APP_SID'),
            'sender_id' => env('UNIFONIC_SENDER_ID'),
        ],
    ],

    // Email provider configuration
    'email' => [
        'driver' => 'email',
        'from_address' => env('OTP_EMAIL_FROM_ADDRESS', env('MAIL_FROM_ADDRESS', 'noreply@example.com')),
        'from_name' => env('OTP_EMAIL_FROM_NAME', env('MAIL_FROM_NAME', 'OTP Service')),
        'subject' => env('OTP_EMAIL_SUBJECT', 'Your Verification Code'),
    ],

    'otp_length' => env('OTP_LENGTH', 4),
    'otp_expiry' => env('OTP_EXPIRY', 5), // minutes
    'max_attempts' => env('MAX_ATTEMPTS', 3),
    'resend_delay' => env('RESEND_DELAY', 60), // seconds
    'block_duration' => env('BLOCK_DURATION', 30), // minutes after max attempts

    // Rate limiting configuration
    'rate_limit' => [
        'enabled' => env('OTP_RATE_LIMIT_ENABLED', true),
        'max_requests_per_hour' => env('OTP_MAX_REQUESTS_PER_HOUR', 3), // per phone number or email
        'block_duration' => env('OTP_BLOCK_DURATION', 60), // minutes to block after limit exceeded
    ],

    // Test mode configuration
    'test_mode' => env('OTP_TEST_MODE', false),
    'test_otp' => env('OTP_TEST_CODE', '8888'),
    'test_numbers' => [
        '+1234567890',
        '+9876543210',
        // Add more test numbers as needed
    ],
    'test_emails' => [
        'test@example.com',
        'demo@example.com',
        // Add more test emails as needed
    ],
];

Usage

Multi-Channel Support (Phone & Email)

The package supports sending OTPs through two channels: Phone (SMS) and Email. By default, OTPs are sent via phone, but you can easily switch channels.

Default Channel Configuration

Set your preferred default channel in .env:

OTP_DEFAULT_CHANNEL=phone  # or 'email'

Sending OTP via Phone (Default)

use Addicta\Otp\Facades\Otp;

// Send OTP to phone number (uses default channel: phone)
$result = Otp::generate('+1234567890');

// Or explicitly specify phone channel
$result = Otp::generate('+1234567890', 'phone');

if ($result['success']) {
    echo "OTP sent via SMS!";
    echo "Channel: " . $result['channel']; // 'phone'
}

Sending OTP via Email

use Addicta\Otp\Facades\Otp;

// Send OTP to email address
$result = Otp::generate('user@example.com', 'email');

if ($result['success']) {
    echo "OTP sent via email!";
    echo "Channel: " . $result['channel']; // 'email'
}

Verifying OTP (Works for Both Channels)

// Verification works the same way for both channels
$phone = '+1234567890';
$verifyResult = Otp::verify($phone, '1234');

// Or for email
$email = 'user@example.com';
$verifyResult = Otp::verify($email, '1234');

if ($verifyResult['success']) {
    echo "Verified successfully!";
}

Dynamic Channel Selection

You can let users choose their preferred verification method:

public function sendOtp(Request $request)
{
    $recipient = $request->input('recipient'); // phone or email
    $channel = $request->input('channel', 'phone'); // default to phone
    
    $result = Otp::generate($recipient, $channel);
    
    return response()->json($result);
}

Channel-Specific Features

Phone Channel:

  • Uses configured SMS provider (Twilio, Unifonic)
  • Supports Twilio Verify API
  • Custom message templates
  • Multilingual SMS messages

Email Channel:

  • Beautiful HTML email templates
  • Plain text fallback
  • Customizable sender information
  • Responsive design
  • Security warnings included

Email Template Customization

Publish the email views to customize them:

php artisan vendor:publish --provider="Addicta\Otp\OtpServiceProvider" --tag="otp-views"

This creates:

  • resources/views/vendor/otp/emails/otp.blade.php - HTML email template
  • resources/views/vendor/otp/emails/otp-text.blade.php - Plain text template

Response Format

Both channels return the same response structure:

[
    'success' => true,
    'message' => 'OTP sent successfully.',
    'remaining_time' => 60,
    'type' => 'success',
    'channel' => 'email' // or 'phone'
]

Multi-Language Support

The package supports multiple languages with built-in English and Arabic translations. You can customize messages by publishing and editing the translation files.

Available Languages:

  • English (en)
  • Arabic (ar)

Setting Application Locale:

In your Laravel application, set the locale in config/app.php:

'locale' => 'ar', // For Arabic
'locale' => 'en', // For English

Or dynamically in your application:

App::setLocale('ar'); // Switch to Arabic
App::setLocale('en'); // Switch to English

Customizing Messages:

After publishing translations, you can customize the messages in:

  • lang/vendor/otp/en/otp.php - English messages
  • lang/vendor/otp/ar/otp.php - Arabic messages

Rate Limiting

The package includes built-in rate limiting to prevent abuse and excessive OTP requests. Rate limiting uses a rolling window approach - tracking requests in the last 60 minutes per phone number with automatic blocking.

Configuration

Rate limiting can be configured in your .env file:

# Enable/disable rate limiting
OTP_RATE_LIMIT_ENABLED=true

# Maximum requests per phone number per hour
OTP_MAX_REQUESTS_PER_HOUR=3

# Block duration in minutes after limit exceeded
OTP_BLOCK_DURATION=60

How It Works

  • Per Phone Number: Rate limits are applied individually to each phone number
  • Rolling Window: Tracks requests in the last 60 minutes (not fixed hourly blocks)
  • Automatic Blocking: When limit is exceeded, phone is blocked for specified duration
  • Block Duration: Configurable block time (default: 60 minutes)
  • Cache-Based: Uses Laravel's cache system for tracking with automatic cleanup

Rate Limit Response

When rate limits are exceeded, the service returns:

[
    'success' => false,
    'message' => 'Rate limit exceeded. Maximum 3 requests per hour allowed. Blocked for 60 minutes.',
    'remaining_time' => 3600, // seconds until unblocked
    'type' => 'rate_limited'
]

When phone is blocked, the service returns:

[
    'success' => false,
    'message' => 'Phone number is blocked due to rate limiting. Try again in 45 minutes.',
    'remaining_time' => 2700, // seconds remaining
    'type' => 'rate_limited'
]

Response Types

The type field indicates the reason for the response:

  • success - OTP sent successfully
  • rate_limited - Rate limit exceeded or phone blocked
  • blocked - Phone blocked due to failed attempts
  • resend_delay - Resend delay active
  • send_failed - Failed to send OTP

Disabling Rate Limiting

To disable rate limiting entirely:

OTP_RATE_LIMIT_ENABLED=false

Use Cases

  • Production: Enable rate limiting to prevent abuse
  • Development: Disable rate limiting for easier testing
  • High Traffic: Adjust limits based on your application needs

Test Mode

The package includes a built-in test mode for development and testing purposes. This allows you to test OTP functionality without sending actual SMS messages.

Enabling Test Mode:

  1. Global Test Mode - Enable for all phone numbers:
OTP_TEST_MODE=true
OTP_TEST_CODE=8888

# Rate limiting configuration
OTP_RATE_LIMIT_ENABLED=true
OTP_MAX_REQUESTS_PER_HOUR=3
OTP_BLOCK_DURATION=60
  1. Specific Test Numbers - Add phone numbers to test list:
// In config/otp.php
'test_numbers' => [
    '+1234567890',
    '+9876543210',
    '+201120305686', // Your test number
],

Test Mode Behavior:

  • No SMS Sent: When test mode is active, no actual SMS is sent
  • Fixed OTP: Uses the configured test OTP code (default: 8888)
  • Same Verification: Test OTPs work exactly like real OTPs
  • Response Indicators: Test mode responses use the same format as regular responses

Test Mode Response Example:

[
    'success' => true,
    'message' => 'OTP sent successfully.',
    'remaining_time' => 60,
    'type' => 'success'
]

Use Cases:

  • Development and testing
  • Demo environments
  • CI/CD pipelines
  • Unit testing
  • Avoiding SMS costs during development

Using the Facade

use Addicta\Otp\Facades\Otp;

// Generate OTP
$result = Otp::generate('+1234567890');

if ($result['success']) {
    echo "OTP sent successfully!";
    echo "Expires in: " . $result['expires_in'] . " seconds";
} else {
    echo "Failed to send OTP: " . $result['message'];
}

// Verify OTP
$verifyResult = Otp::verify('+1234567890', '1234');

if ($verifyResult['success']) {
    echo "OTP verified successfully!";
} else {
    echo "Verification failed: " . $verifyResult['message'];
    if (isset($verifyResult['remaining_attempts'])) {
        echo "Remaining attempts: " . $verifyResult['remaining_attempts'];
    }
}

Using Dependency Injection

use Addicta\Otp\OtpService;

class AuthController extends Controller
{
    protected $otpService;

f
    public function __construct(OtpService $otpService)
    {
        $this->otpService = $otpService;
    }

    public function sendOtp(Request $request)
    {
        $phone = $request->input('phone');
        $result = $this->otpService->generate($phone);

        return response()->json($result);
    }
f
    public function verifyOtp(Request $request)
    {
        $phone = $request->input('phone');
        $code = $request->input('code');
        
        $result = $this->otpService->verify($phone, $code);

        return response()->json($result);
    }
}

Using the Manager Directly

use Addicta\Otp\OtpManager;

$manager = app(OtpManager::class);
$provider = $manager->driver(); // Gets the default provider
$result = $provider->send('+1234567890', 'Your OTP is: 1234');

Twilio Verify Service Usage

When using Twilio Verify service, the package handles OTP generation and verification seamlessly:

Sending OTP with Verify Service

use Addicta\Otp\Facades\Otp;

// Configure .env for Verify service
// TWILIO_SERVICE_TYPE=verify
// TWILIO_VERIFICATION_SID=VAxxxxxxxxxxxxx

// Generate and send OTP using Verify API
$result = Otp::generate('+1234567890');

if ($result['success']) {
    // OTP sent via Twilio Verify with custom code
    echo "Verification code sent!";
    echo "User will receive SMS from Twilio Verify service";
} else {
    echo "Error: " . $result['message'];
}

Verifying OTP with Verify Service

// The package handles verification automatically
$verifyResult = Otp::verify('+1234567890', '1234');

if ($verifyResult['success']) {
    // OTP verified successfully
    // User can proceed with registration/login
    echo "Phone number verified!";
} else {
    echo "Invalid code: " . $verifyResult['message'];
}

Switching Between SMS and Verify

You can easily switch between service types without changing your application code:

For SMS Service:

TWILIO_SERVICE_TYPE=sms
TWILIO_FROM=+1234567890

For Verify Service:

TWILIO_SERVICE_TYPE=verify
TWILIO_VERIFICATION_SID=VAxxxxxxxxxxxxx

Your application code remains the same regardless of which service you use!

API Reference

OtpService Methods

generate(string $phone): array

Generates and sends an OTP to the specified phone number.

Parameters:

  • $phone (string): Phone number in international format (e.g., +1234567890)

Returns:

[
    'success' => bool,
    'message' => string,
    'expires_in' => int, // seconds
    'remaining_time' => int, // if resend delay active
    'blocked_until' => Carbon, // if blocked
]

verify(string $phone, string $code): array

Verifies an OTP code for the specified phone number.

Parameters:

  • $phone (string): Phone number in international format
  • $code (string): OTP code to verify

Returns:

[
    'success' => bool,
    'message' => string,
    'remaining_attempts' => int, // if verification failed
]

Security Features

Rate Limiting

  • Resend Delay: Prevents immediate resending of OTPs (default: 60 seconds)
  • Max Attempts: Limits verification attempts (default: 3 attempts)
  • Block Duration: Temporary blocking after max attempts exceeded (default: 30 minutes)

OTP Management

  • Expiry: OTPs expire after configured time (default: 5 minutes)
  • Single Use: OTPs are automatically removed after successful verification
  • Cache Storage: OTPs are stored securely in Laravel's cache system

Error Handling

The package returns detailed error messages for various scenarios. All messages are translatable and will be returned in the current application locale:

English Messages:

// Rate limiting
[
    'success' => false,
    'message' => 'Please wait 45 seconds before requesting a new OTP.',
    'remaining_time' => 45
]

// Blocked phone
[
    'success' => false,
    'message' => 'Too many attempts. Please try again later.',
    'blocked_until' => Carbon::now()->addMinutes(30)
]

// Invalid OTP
[
    'success' => false,
    'message' => 'Invalid OTP.',
    'remaining_attempts' => 2
]

// Expired OTP
[
    'success' => false,
    'message' => 'OTP expired or not found.'
]

Arabic Messages (when locale is set to 'ar'):

// Rate limiting
[
    'success' => false,
    'message' => 'ูŠุฑุฌู‰ ุงู„ุงู†ุชุธุงุฑ 45 ุซุงู†ูŠุฉ ู‚ุจู„ ุทู„ุจ ุฑู…ุฒ ุชุญู‚ู‚ ุฌุฏูŠุฏ.',
    'remaining_time' => 45
]

// Blocked phone
[
    'success' => false,
    'message' => 'ู…ุญุงูˆู„ุงุช ูƒุซูŠุฑุฉ ุฌุฏุงู‹. ูŠุฑุฌู‰ ุงู„ู…ุญุงูˆู„ุฉ ู…ุฑุฉ ุฃุฎุฑู‰ ู„ุงุญู‚ุงู‹.',
    'blocked_until' => Carbon::now()->addMinutes(30)
]

// Invalid OTP
[
    'success' => false,
    'message' => 'ุฑู…ุฒ ุงู„ุชุญู‚ู‚ ุบูŠุฑ ุตุญูŠุญ.',
    'remaining_attempts' => 2
]

// Expired OTP
[
    'success' => false,
    'message' => 'ุงู†ุชู‡ุช ุตู„ุงุญูŠุฉ ุฑู…ุฒ ุงู„ุชุญู‚ู‚ ุฃูˆ ู„ู… ูŠุชู… ุงู„ุนุซูˆุฑ ุนู„ูŠู‡.'
]

Testing

The package includes comprehensive tests. Run them using:

# Run all tests
./vendor/bin/phpunit

# Run specific test suites
./vendor/bin/phpunit --testsuite=Unit
./vendor/bin/phpunit --testsuite=Feature

# Run with coverage
./vendor/bin/phpunit --coverage-html coverage

Supported Providers

Twilio

The package supports two Twilio service types:

1. SMS Service (Direct Messaging)

  • Service Type: sms
  • Best For: Simple OTP delivery with custom message formatting
  • Required Config: account_sid, auth_token, from
  • Features:
    • Full control over message content
    • Custom message templates with multilingual support
    • Direct SMS delivery
    • Lower cost per message

Configuration Example:

TWILIO_SERVICE_TYPE=sms
TWILIO_ACCOUNT_SID=your_account_sid
TWILIO_AUTH_TOKEN=your_auth_token
TWILIO_FROM=+1234567890

2. Verify API Service (Recommended)

  • Service Type: verify
  • Best For: Enhanced security and compliance features
  • Required Config: account_sid, auth_token, verification_sid
  • Features:
    • Built-in fraud detection
    • Automatic rate limiting and abuse prevention
    • Carrier-level integrations for better delivery
    • Custom OTP code support
    • Geographic and carrier analytics
    • Compliance with regulatory requirements

Configuration Example:

TWILIO_SERVICE_TYPE=verify
TWILIO_ACCOUNT_SID=your_account_sid
TWILIO_AUTH_TOKEN=your_auth_token
TWILIO_VERIFICATION_SID=your_verification_sid

Getting Your Verification SID:

  1. Log in to your Twilio Console
  2. Navigate to Verify โ†’ Services
  3. Create a new Verify Service or select an existing one
  4. Copy the Service SID (starts with VA...)

Key Differences:

Feature SMS Service Verify Service
Message Control Full customization Template-based
Fraud Detection Manual Built-in
Delivery Optimization Standard Carrier-optimized
Analytics Basic Advanced
Compliance Manual Automatic
Setup Complexity Simple Moderate
Cost Lower Higher

Choosing the Right Service:

  • Use SMS for: Simple applications, full message control, budget-conscious projects
  • Use Verify for: Production applications, enhanced security, compliance requirements

Documentation:

Unifonic

  • Driver: unifonic
  • Required Config: app_sid, sender_id
  • Documentation: Unifonic SMS API

Email Provider

The package includes a built-in email provider for sending OTPs via email.

Configuration

The email provider uses Laravel's mail system, so ensure you have your mail driver configured in config/mail.php or .env:

MAIL_MAILER=smtp
MAIL_HOST=smtp.mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=your_username
MAIL_PASSWORD=your_password
MAIL_ENCRYPTION=tls
MAIL_FROM_ADDRESS=noreply@yourapp.com
MAIL_FROM_NAME="${APP_NAME}"

Features

  • Beautiful Templates: Professional, responsive HTML email design
  • Plain Text Fallback: Automatic plain text version for email clients
  • Customizable: Publish and modify email templates to match your brand
  • Security Warnings: Built-in security notices to prevent phishing
  • Multi-Language: Supports all translated languages (English, Arabic, etc.)

Email Template Preview

The email includes:

  • Clear verification code display
  • Expiration time notice
  • Security warnings
  • Professional styling
  • Responsive design for mobile devices

Supported Mail Drivers

Works with all Laravel mail drivers:

  • SMTP
  • Mailgun
  • Postmark
  • Amazon SES
  • Sendmail
  • Log (for testing)

Requirements

  • PHP 8.2+
  • Laravel 10.0+
  • Twilio SDK (for Twilio provider)
  • Guzzle HTTP (for Unifonic provider)

License

This package is open-sourced software licensed under the MIT license.

Contributing

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add some amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

Support

For support, please open an issue on the GitHub repository or contact the maintainer.

Changelog

Version 0.9.0 (Current)

  • ๐Ÿš€ Multi-Channel Support: Major feature - Send OTPs via Phone (SMS) or Email
  • ๐Ÿ“ง Email OTP Provider: Complete email provider implementation with beautiful HTML templates
  • ๐ŸŽจ Professional Email Templates: Responsive HTML and plain text email templates
  • ๐ŸŒ Channel-Aware Translations: Email-specific messages in English and Arabic
  • โš™๏ธ Configurable Default Channel: Set default channel via environment variable (phone or email)
  • ๐Ÿงช Test Mode for Email: Support for test emails alongside test phone numbers
  • ๐Ÿ“Š Unified API: Same API for both channels - just change the recipient and channel parameter
  • ๐Ÿ”„ Backward Compatible: Existing phone-only implementations continue to work without changes

Version 0.8.0

  • Twilio Verify Service: Added full support for Twilio Verify API alongside traditional SMS service
  • Dual Service Types: Choose between 'sms' (direct messaging) or 'verify' (Twilio Verify API)
  • Custom OTP with Verify: Support for custom OTP codes in Twilio Verify service
  • Service-Specific Configuration: Automatic configuration validation based on selected service type
  • Enhanced Documentation: Comprehensive guide for choosing and configuring Twilio services
  • Improved Code Structure: Refactored provider with constants and better separation of concerns

Version 0.7.0

  • Rate Limiting: Implemented configurable rate limiting per phone number with rolling window approach
  • Rolling Window: Tracks requests in the last 60 minutes (not fixed hourly blocks) to prevent bypassing limits
  • Unified Response Format: Simplified all responses to use consistent structure with success, message, remaining_time, and type fields
  • Response Type Enum: Added OtpResponseType enum for type-safe response handling
  • Seconds-Based Timing: All timing fields now use seconds for easier frontend integration
  • Enhanced Security: Prevents users from bypassing rate limits by waiting for hour changes
  • Improved Testing: Added comprehensive tests for rolling window rate limiting

Version 0.1

  • Initial release
  • Twilio and Unifonic provider support
  • Rate limiting per phone number (hourly and daily limits)
  • Configurable rate limits via environment variables
  • Rate limit responses with retry information
  • Comprehensive test suite (26 tests)
  • Laravel auto-discovery support
  • Multi-language support (English & Arabic)
  • Translatable messages for all responses
  • Publishable translation files for customization
  • Test Mode for development and testing
  • Test phone numbers support
  • Fixed test OTP for consistent testing