kaydee123/msg91-php
PHP 8.0–8.5 client for MSG91 SMS & OTP: send single/bulk and template-based SMS, DLT-compliant messaging for India, send/verify/resend OTP (text/voice), fluent chainable API, strong error handling, framework-agnostic.
composer require kaydee123/msg91-php
use Kaydee123\Msg91\Msg91Client;
$client = new Msg91Client('YOUR_AUTH_KEY');
$response = $client->sms()
->template('YOUR_TEMPLATE_ID')
->numbers('919876543210')
->send();
$response = $client->otp()
->template('YOUR_OTP_TEMPLATE_ID')
->number('919876543210')
->send();
Where to look first:
// For transactional messages (e.g., order confirmations)
$response = $client->sms()
->transactional() // Explicitly set route (default)
->template('ORDER_CONFIRMATION_TEMPLATE_ID')
->variables([
'order_id' => 'ORD12345',
'amount' => '99.99',
'date' => date('Y-m-d'),
])
->numbers('919876543210')
->send();
// Generate and send OTP during user registration
$response = $client->otp()
->template('REGISTRATION_OTP_TEMPLATE_ID')
->number('919876543210')
->length(6) // Custom OTP length
->expiry(5) // Shorter expiry for security
->send();
// Store OTP reference (e.g., in session or DB) for later verification
session(['otp_reference' => $response->getFlowId()]);
// Verify OTP on form submission
$isValid = $client->otp($userSubmittedOtp)
->number('919876543210')
->verify();
// Send personalized messages to multiple users
$recipients = [
['mobiles' => '919876543210', 'name' => 'John', 'amount' => '100.00'],
['mobiles' => '919876543211', 'name' => 'Jane', 'amount' => '200.00'],
];
$response = $client->sms()
->template('PAYMENT_RECEIPT_TEMPLATE_ID')
->recipients($recipients)
->send();
// For promotional campaigns (India)
$response = $client->sms()
->promotional()
->sender_id('YOUR_SENDER_ID')
->mobiles('919876543210,919876543211')
->dlt_template_id('YOUR_DLT_TEMPLATE_ID')
->message('Exclusive offer: 20% off! Use code PROMO20')
->send();
Register the client as a singleton in AppServiceProvider:
public function register()
{
$this->app->singleton(Msg91Client::class, function ($app) {
return new Msg91Client(config('services.msg91.auth_key'));
});
}
config/services.php)'msg91' => [
'auth_key' => env('MSG91_AUTH_KEY'),
'base_url' => env('MSG91_BASE_URL', 'https://control.msg91.com/api/'),
'timeout' => env('MSG91_TIMEOUT', 60),
'debug' => env('MSG91_DEBUG', false),
],
use Kaydee123\Msg91\Msg91Client;
class AuthController extends Controller
{
public function __construct(private Msg91Client $msg91) {}
public function sendOtp(Request $request)
{
$response = $this->msg91->otp()
->template('REGISTRATION_OTP_TEMPLATE_ID')
->number($request->phone)
->send();
return response()->json($response->getData());
}
}
public function resendOtp(Request $request)
{
try {
$response = $this->msg91->otp()
->number($request->phone)
->viaText() // or viaVoice()
->retry();
return response()->json(['success' => true]);
} catch (\Kaydee123\Msg91\Exceptions\ApiException $e) {
if ($e->getStatusCode() === 400 && strpos($e->getMessage(), 'Flow ID') !== false) {
// Handle invalid flow ID (e.g., retry with new OTP)
return $this->sendOtp($request);
}
return response()->json(['error' => $e->getMessage()], 400);
}
}
$response = $client->sms()
->template('TEMPLATE_ID')
->numbers('919876543210')
->send();
if ($client->getConfig()->getDebug()) {
\Log::info('MSG91 Response', [
'data' => $response->getData(),
'status' => $response->getStatus(),
'message' => $response->getMessage(),
]);
}
91...) require a template() to be set due to DLT compliance.->template('YOUR_OTP_TEMPLATE_ID') for Indian numbers.InvalidArgumentException if template is missing.211: DLT Template Id Missing.dlt_template_id is set for promotional SMS:
->dlt_template_id('YOUR_DLT_TEMPLATE_ID')
Flow ID expires after 24 hours. Retrying after expiry fails with 400: Flow ID Missing or Invalid.try {
$client->otp()->number('919876543210')->retry();
} catch (\Kaydee123\Msg91\Exceptions\ApiException $e) {
if ($e->getStatusCode() === 400) {
$client->otp()->template('TEMPLATE_ID')->number('919676543210')->send();
}
}
203: Invalid sender ID.429: Too Many Requests.$attempts = 0;
$maxAttempts = 3;
$delay = 1000; // 1 second
while ($attempts < $maxAttempts) {
try {
$response = $client->sms()->template('ID')->numbers('919876543210')->send();
break;
} catch (\Kaydee123\Msg91\Exceptions\ApiException $e) {
if ($e->getStatusCode() !==
How can I help you explore Laravel packages today?