itxshakil/laravel-fast2sms
Laravel Fast2SMS is a complete Fast2SMS integration for Laravel, supporting SMS, OTP, DLT, and WhatsApp with a fluent, type-safe API. It includes Laravel Notifications, queue support, a powerful fake for testing, typed exceptions, and cost-saving safeguards.
Installation:
composer require itxshakil/laravel-fast2sms
php artisan vendor:publish --provider="Itxshakil\Fast2SMS\Fast2SMSServiceProvider" --tag="config"
Publish the config file to config/fast2sms.php and update your Fast2SMS API credentials.
First Use Case: Send an SMS via the facade:
use Itxshakil\Fast2SMS\Facades\Fast2SMS;
Fast2SMS::send([
'message' => 'Hello from Laravel!',
'numbers' => ['+919876543210'],
'senderId' => 'YOURSENDERID'
]);
Itxshakil\Fast2SMS\Facades\Fast2SMS (for quick usage).app('fast2sms') for dependency injection.config/fast2sms.php for API keys, default sender IDs, and rate limits.Fast2SMS::fake() in tests (see Debugging Tips).// Using facade
Fast2SMS::send([
'message' => 'Your OTP is 123456',
'numbers' => ['+919876543210'],
'senderId' => env('FAST2SMS_SENDER_ID'),
]);
// Using service container (recommended for DI)
$client = app('fast2sms');
$client->send(['message' => 'Hello', 'numbers' => ['+911234567890']]);
Extend the Fast2SMSChannel for notifications:
use Itxshakil\Fast2SMS\Notifications\Fast2SMSChannel;
use Illuminate\Notifications\Notification;
class SMSNotification extends Notification
{
public function via($notifiable)
{
return [Fast2SMSChannel::class];
}
public function toFast2SMS($notifiable)
{
return [
'message' => 'Hello, ' . $notifiable->name,
'numbers' => [$notifiable->phone],
'senderId' => 'YOURSENDERID',
];
}
}
Dispatch via:
$user->notify(new SMSNotification());
Use Laravel queues to defer SMS delivery:
Fast2SMS::queue([
'message' => 'Deferred message',
'numbers' => ['+919876543210'],
]);
Configure the queue connection in config/fast2sms.php:
'queue' => [
'connection' => 'sqs', // or 'database', 'redis', etc.
'queue' => 'sms-queue',
],
Process large recipient lists in batches:
$recipients = User::pluck('phone')->toArray();
$chunkSize = 50; // Fast2SMS API limit
array_chunk($recipients, $chunkSize)->each(function ($chunk) {
Fast2SMS::send([
'message' => 'Bulk message',
'numbers' => $chunk,
]);
});
Fast2SMS::sendWhatsApp([
'message' => 'Hi via WhatsApp!',
'numbers' => ['+919876543210'],
'templateId' => 'YOUR_TEMPLATE_ID', // Optional for templates
]);
config/fast2sms.php:
'debug' => env('FAST2SMS_DEBUG', false),
retry helper for transient failures:
retry(5, function () {
Fast2SMS::send([...]);
}, 100);
config/fast2sms.php:
'rate_limits' => [
'sms' => 1, // per second
'whatsapp' => 0.5, // per second
],
Sender ID Validation:
Number Formatting:
+919876543210). Strip country codes if needed:
$number = '+91' . str_replace('+91', '', $user->phone);
Queue Stuck Jobs:
php artisan queue:work --sleep=3 --tries=3
Character Limits:
API Key Exposure:
config/fast2sms.php to version control. Use .env:
FAST2SMS_API_KEY=your_key_here
FAST2SMS_SENDER_ID=YOURSENDERID
Fast2SMS::fake() records every field of the dispatched payload on each entry of sentSms(), so OTP and DLT sends are fully assertable:
use Itxshakil\Fast2SMS\Facades\Fast2SMS;
Fast2SMS::fake();
Fast2SMS::send([
'numbers' => ['+919876543210'],
'route' => 'dlt',
'senderId' => 'YOURSENDERID',
'entityId' => '1701150000000000000',
'templateId' => '1707160000000000000',
'variablesValues' => '123456',
'language' => 'english',
'flash' => 0,
'scheduleTime' => null,
]);
// Assert on the actual OTP code
Fast2SMS::assertSent(fn ($sms) => $sms->parameters->variablesValues === '123456');
// Assert on DLT metadata
$sms = Fast2SMS::sentSms()->first();
expect($sms->parameters->templateId)->toBe('1707160000000000000')
->and($sms->parameters->senderId)->toBe('YOURSENDERID');
Fields available on ->parameters: numbers, message, route, variablesValues, senderId, entityId, templateId, language, flash, scheduleTime.sentSms()[n]->parameters only held numbers, message and route. If any assertion used array access (->parameters['message'], ->parameters['numbers']), switch it to property access (->parameters->message, ->parameters->numbers) — the richer DTO is what makes OTP (variablesValues) and DLT assertions possible.try {
Fast2SMS::send([...]);
} catch (\Itxshakil\Fast2SMS\Exceptions\InvalidNumberException $e) {
// Handle invalid numbers
} catch (\Itxshakil\Fast2SMS\Exceptions\RateLimitExceededException $e) {
// Retry or notify admin
}
Custom Responses:
Override the default response handling by binding a custom Fast2SMSResponse class:
$client = app('fast2sms')->setResponseHandler(MyCustomResponseHandler::class);
Middleware: Add middleware to the Fast2SMS client for pre/post-processing:
$client->withMiddleware(new LogSMSMiddleware());
Template Management: For WhatsApp, dynamically fetch template IDs from a database or cache:
$templateId = cache()->remember("whatsapp_template_{$type}", now()->addHours(1), function () {
return Template::where('type', $type)->value('fast2sms_id');
});
Webhook Validation: If using Fast2SMS webhooks (e.g., for delivery reports), validate signatures:
use Itxshakil\Fast2SMS\WebhookValidator;
$validator = new WebhookValidator(request()->header('X-Signature'));
if (!$validator->validate(request()->getContent())) {
abort(403);
}
config/fast2sms.php to avoid repetition:
'defaults' => [
'senderId' => env('FAST2SMS_SENDER_ID', 'DEFAULTSENDER'),
],
'http' => [
'timeout' => 30, // seconds
'connect_timeout' => 10,
],
env() helpers or .env files for different environments:
FAST2SMS_API_KEY=prod_key
FAST2SMS_API_KEY_STAGING=staging_key
Then reference in config:
'api_key' => env('FAST2SMS_API_KEY_' . app()->environment(), env('FAST2SMS_API_KEY')),
How can I help you explore Laravel packages today?