A modern, flexible Laravel package for integrating any SMS gateway that provides a REST API. Perfect for Laravel 10+ applications with full support for notifications, multiple gateways, and modern authentication methods.
⭐ Star this repo to show support!
- Features
- Requirements
- Installation
- Quick Start
- Configuration
- Usage
- Advanced Features
- Real Provider Examples
- Testing
- Changelog
- Support
- ✅ Universal Compatibility - Works with any REST API SMS provider
- ✅ Multiple Gateways - Configure and switch between multiple SMS providers
- ✅ Laravel Notifications - Full integration with Laravel's notification system
- ✅ Modern Auth - Support for Bearer tokens, API keys, Basic Auth, and custom headers
- ✅ Bulk SMS - Send to multiple recipients in a single call
- ✅ JSON & Form Data - Support for both JSON payloads and form-encoded requests
- ✅ Request Wrapping - Handle complex API structures with wrapper support
- ✅ Type Safe - Built with PHP 8.1+ strict types
- ✅ Dependency Injection - Modern Laravel service container integration
- ✅ Comprehensive Logging - Built-in request/response logging
- ✅ Easy Testing - Mock-friendly architecture
- PHP 8.1 or higher
- Laravel 10.x, 11.x, or 12.x
- Guzzle HTTP Client 7.8+
composer require gr8shivam/laravel-sms-apiphp artisan vendor:publish --provider="Gr8Shivam\SmsApi\SmsApiServiceProvider"This creates config/sms-api.php in your application.
Edit config/sms-api.php and add your SMS provider credentials (see Configuration below).
use Gr8Shivam\SmsApi\SmsApiFacade as SmsApi;
// Simple usage
SmsApi::sendMessage("9876543210", "Hello from Laravel!");
// Or using helper
smsapi("9876543210", "Hello from Laravel!");SmsApi::sendMessage(["9876543210", "9876543211"], "Hello everyone!");$response = SmsApi::sendMessage("9876543210", "Hello!")
->response();
$statusCode = SmsApi::sendMessage("9876543210", "Hello!")
->getResponseCode();
$isSuccess = SmsApi::sendMessage("9876543210", "Hello!")
->isSuccessful(); // Returns true for 2xx status codesOpen config/sms-api.php after publishing.
return [
// Default country code (added to numbers automatically)
'country_code' => env('SMS_API_COUNTRY_CODE', '91'),
// Default gateway to use
'default' => env('SMS_API_DEFAULT_GATEWAY', 'your_gateway'),
// HTTP client timeouts
'timeout' => env('SMS_API_TIMEOUT', 30),
'connect_timeout' => env('SMS_API_CONNECT_TIMEOUT', 10),
// Optional message validation
'validation' => [
'enabled' => env('SMS_API_VALIDATION_ENABLED', false),
'max_length' => env('SMS_API_MAX_LENGTH', 1000),
],
];For simple GET/POST requests:
'your_gateway' => [
'method' => 'POST', // GET, POST, PUT, PATCH, DELETE
'url' => 'https://api.smsgateway.com/send',
'params' => [
'send_to_param_name' => 'mobile', // Your provider's "to" param name
'msg_param_name' => 'message', // Your provider's "message" param name
'others' => [
'api_key' => env('SMS_GATEWAY_KEY'),
'sender_id' => env('SMS_SENDER_ID'),
],
],
'headers' => [
'Accept' => 'application/json',
],
'add_code' => true, // Automatically add country code
],For JSON requests with complex structures:
'advanced_gateway' => [
'method' => 'POST',
'url' => 'https://api.provider.com/v2/send',
'params' => [
'send_to_param_name' => 'recipient',
'msg_param_name' => 'text',
'others' => [
'priority' => 'high',
'ttl' => 3600,
],
],
'headers' => [
'Authorization' => 'Bearer ' . env('SMS_API_TOKEN'),
'Content-Type' => 'application/json',
],
'json' => true, // Send as JSON payload
'jsonToArray' => true, // Send single number as array: ["9876543210"]
'wrapper' => 'data', // Wrap payload in {"data": {...}}
'wrapperParams' => [
'campaign_id' => 'welcome_sms',
],
'add_code' => true,
],Result payload example:
{
"data": [
{
"recipient": ["919876543210"],
"text": "Your message",
"campaign_id": "welcome_sms"
}
],
"priority": "high",
"ttl": 3600
}'gateway' => [
'headers' => [
'Authorization' => 'Bearer ' . env('SMS_API_TOKEN'),
],
],In .env:
SMS_API_TOKEN=your_bearer_token_here'gateway' => [
'headers' => [
'X-API-Key' => env('SMS_API_KEY'),
],
],'gateway' => [
'headers' => [
'Authorization' => 'Basic ' . base64_encode(env('SMS_USERNAME') . ':' . env('SMS_PASSWORD')),
],
],'gateway' => [
'params' => [
'others' => [
'api_key' => env('SMS_API_KEY'),
],
],
],Send parameters as JSON payload instead of query string or form data.
'json' => true,When json is true, controls whether a single mobile number is sent as:
true:["9876543210"](array)false:"9876543210"(string)
'jsonToArray' => false,Wraps the JSON request in a named object. Required by some providers.
'wrapper' => 'sms', // Creates: {"sms": [{...}]}Adds parameters inside the wrapper (separate from regular params).
'wrapperParams' => [
'campaign' => 'summer_sale',
'priority' => 1,
],Automatically prepend country code to phone numbers.
'add_code' => true, // 9876543210 becomes 919876543210The smsapi() helper provides the most convenient way to send SMS.
// Quick send
smsapi("9876543210", "Welcome to our platform!");
// Or
smsapi()->sendMessage("9876543210", "Welcome!");smsapi("9876543210", "Your OTP is 1234", [
'template_id' => 'OTP_TEMPLATE',
'priority' => 'high'
]);smsapi("9876543210", "Hello", [], [
'X-Custom-Header' => 'value',
'X-Request-ID' => uniqid()
]);smsapi()->gateway('backup_gateway')
->sendMessage("9876543210", "Message via backup gateway");smsapi()->countryCode('1') // USA
->sendMessage("5551234567", "Hello from USA!");$recipients = ["9876543210", "9876543211", "9876543212"];
smsapi($recipients, "Bulk message to all!");smsapi()->addWrapperParams([
'campaign' => 'newsletter',
'tracking_id' => '12345'
])
->sendMessage("9876543210", "Newsletter message");smsapi()
->gateway('primary_gateway')
->countryCode('91')
->addWrapperParams(['campaign' => 'promo'])
->sendMessage("9876543210", "Promotional offer!", [
'template_id' => 'PROMO_123'
]);The facade provides the same functionality with explicit imports.
use Gr8Shivam\SmsApi\SmsApiFacade as SmsApi;
// Basic usage
SmsApi::sendMessage("9876543210", "Hello!");
// With gateway selection
SmsApi::gateway('gateway_name')
->sendMessage("9876543210", "Hello!");
// With country code
SmsApi::countryCode('44') // UK
->sendMessage("7911123456", "Hello from UK!");
// Bulk SMS
SmsApi::sendMessage(
["9876543210", "9876543211"],
"Bulk message"
);
// Get response
$response = SmsApi::sendMessage("9876543210", "Test")
->response();
// Get status code
$code = SmsApi::sendMessage("9876543210", "Test")
->getResponseCode();
// Check success
$success = SmsApi::sendMessage("9876543210", "Test")
->isSuccessful();Laravel SMS API integrates seamlessly with Laravel's notification system.
In your User model (or any Notifiable model):
use Illuminate\Notifications\Notifiable;
class User extends Authenticatable
{
use Notifiable;
/**
* Route notifications for SMS API channel
*/
public function routeNotificationForSmsApi()
{
return $this->phone; // Return the phone number column
}
}php artisan make:notification WelcomeNotificationnamespace App\Notifications;
use Illuminate\Notifications\Notification;
use Gr8Shivam\SmsApi\Notifications\SmsApiChannel;
use Gr8Shivam\SmsApi\Notifications\SmsApiMessage;
class WelcomeNotification extends Notification
{
public function via($notifiable)
{
return [SmsApiChannel::class];
}
public function toSmsApi($notifiable)
{
return (new SmsApiMessage)
->content("Welcome {$notifiable->name}!");
}
}$user = User::find(1);
$user->notify(new WelcomeNotification());With Parameters:
public function toSmsApi($notifiable)
{
return (new SmsApiMessage)
->content("Your OTP is: {$this->otp}")
->params([
'template_id' => 'OTP_VERIFY',
'priority' => 'high'
]);
}With Headers:
public function toSmsApi($notifiable)
{
return (new SmsApiMessage)
->content($this->message)
->params(['campaign' => 'marketing'])
->headers(['X-Campaign-ID' => '12345']);
}Unicode Message:
public function toSmsApi($notifiable)
{
return (new SmsApiMessage)
->content("नमस्ते! Welcome")
->unicode();
}Using Static Constructor:
public function toSmsApi($notifiable)
{
return SmsApiMessage::create("Hello {$notifiable->name}!")
->addParam('template_id', 'WELCOME_001')
->addHeader('X-Priority', 'high');
}Return String (Shorthand):
public function toSmsApi($notifiable)
{
return "Welcome to our platform!"; // Automatically converted to SmsApiMessage
}Use send_sms() for operations where you want to catch exceptions:
if (send_sms("9876543210", "Hello!")) {
echo "SMS sent successfully!";
} else {
echo "SMS failed. Error logged.";
}$sms = smsapi()->sendMessage("9876543210", "Hello!");
// Get raw response
$response = $sms->response();
// Get status code
$code = $sms->getResponseCode();
// Check if successful
if ($sms->isSuccessful()) {
// 2xx status code
}$message = new SmsApiMessage("Your message here");
// Get message length
$length = $message->length();
// Check if empty
if ($message->isEmpty()) {
// Handle empty message
}
// Estimate SMS segments (for cost calculation)
$segments = $message->estimateSegments(); // Returns 1, 2, 3...
// Get preview
$preview = $message->preview(50); // First 50 charactersEnable validation in config:
'validation' => [
'enabled' => true,
'max_length' => 1000,
],Then validate:
try {
$message->validate();
} catch (\InvalidArgumentException $e) {
// Handle validation error
}$gateway = $user->isPremium() ? 'premium_gateway' : 'basic_gateway';
smsapi()->gateway($gateway)
->sendMessage($user->phone, "Relevant message");// .env
SMS_API_DEFAULT_GATEWAY=twilio
SMS_API_COUNTRY_CODE=1
SMS_API_TIMEOUT=60
TWILIO_ACCOUNT_SID=your_sid
TWILIO_AUTH_TOKEN=your_token
TWILIO_FROM_NUMBER=+15551234567// Array of numbers
$recipients = User::where('notify_sms', true)
->pluck('phone')
->toArray();
smsapi($recipients, "Important announcement!");All requests and responses are automatically logged using Laravel's logging system:
// Check logs/laravel.log for:
// [INFO] SMS Gateway Response Code: 200
// [INFO] SMS Gateway Response Body: {...}
// [ERROR] SMS Gateway Response Code: 400
// [ERROR] SMS Gateway Response Body: {...}'twilio' => [
'method' => 'POST',
'url' => 'https://api.twilio.com/2010-04-01/Accounts/' . env('TWILIO_ACCOUNT_SID') . '/Messages.json',
'params' => [
'send_to_param_name' => 'To',
'msg_param_name' => 'Body',
'others' => [
'From' => env('TWILIO_FROM_NUMBER'),
],
],
'headers' => [
'Authorization' => 'Basic ' . base64_encode(env('TWILIO_ACCOUNT_SID') . ':' . env('TWILIO_AUTH_TOKEN')),
],
'add_code' => true,
],Usage:
smsapi()->gateway('twilio')->sendMessage("5551234567", "Hello from Twilio!");'msg91' => [
'method' => 'POST',
'url' => 'https://control.msg91.com/api/v2/sendsms',
'params' => [
'send_to_param_name' => 'to',
'msg_param_name' => 'message',
'others' => [
'authkey' => env('MSG91_AUTH_KEY'),
'sender' => env('MSG91_SENDER_ID'),
'route' => '4',
'country' => '91',
],
],
'json' => true,
'wrapper' => 'sms',
'add_code' => false,
],Usage:
smsapi()->gateway('msg91')->sendMessage("9876543210", "Hello from MSG91!");'aws_sns' => [
'method' => 'POST',
'url' => 'https://sns.us-east-1.amazonaws.com/',
'params' => [
'send_to_param_name' => 'PhoneNumber',
'msg_param_name' => 'Message',
'others' => [
'Action' => 'Publish',
],
],
'headers' => [
'Authorization' => 'AWS4-HMAC-SHA256 ...', // Use AWS SDK for proper signing
],
'add_code' => true,
],'nexmo' => [
'method' => 'POST',
'url' => 'https://rest.nexmo.com/sms/json',
'params' => [
'send_to_param_name' => 'to',
'msg_param_name' => 'text',
'others' => [
'api_key' => env('NEXMO_API_KEY'),
'api_secret' => env('NEXMO_API_SECRET'),
'from' => env('NEXMO_FROM'),
],
],
'json' => true,
'add_code' => true,
],'generic_api' => [
'method' => 'POST',
'url' => 'https://api.smsprovider.com/v1/send',
'params' => [
'send_to_param_name' => 'to',
'msg_param_name' => 'message',
'others' => [
'sender' => 'YourApp',
],
],
'headers' => [
'Authorization' => 'Bearer ' . env('SMS_BEARER_TOKEN'),
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
'json' => true,
'add_code' => true,
],composer testuse Gr8Shivam\SmsApi\Tests\AbstractTestCase;
use Gr8Shivam\SmsApi\SmsApiFacade as SmsApi;
class MyFeatureTest extends AbstractTestCase
{
/** @test */
public function it_sends_sms()
{
$this->mockSmsGateway(200, 'Success');
$response = SmsApi::sendMessage("9876543210", "Test");
$this->assertEquals(200, $response->getResponseCode());
$this->assertTrue($response->isSuccessful());
}
}See CHANGELOG.md for version history and breaking changes.
Latest Version: 4.0.0
- PHP 8.1+ and Laravel 10+ support
- Modern type hints and strict types
- Bearer token and modern auth support
- Optional message validation
- Enhanced notification system
- Comprehensive test suite
- Check logs:
storage/logs/laravel.log - Verify config: Ensure gateway credentials are correct
- Test manually:
php artisan tinker >>> smsapi()->sendMessage("YOUR_NUMBER", "Test")->response();
$sms = smsapi()->sendMessage("9876543210", "Test");
dd([
'code' => $sms->getResponseCode(),
'response' => $sms->response(),
'success' => $sms->isSuccessful()
]);php artisan config:clear
php artisan cache:clear- Store credentials in
.env, never hardcode - Use queued notifications for bulk SMS:
$user->notify(new WelcomeNotification()); // Use ShouldQueue trait
- Implement retry logic for critical messages
- Monitor costs using
estimateSegments() - Test with mock gateway before production
- Log all SMS for audit trail
- Issues: GitHub Issues
- Documentation: README.md
Developed by Shivam Agarwal
MIT License - see LICENSE file for details.
If this package helps you, please give it a star on GitHub!
Made with ❤️ for the Laravel community