Laravel SMS Package
composer require websms-nz/laravel-websms
What's in the package?
A small, focused Composer package for Laravel 10, 11 and 12. Wraps the WebSMS Connexus API behind a clean facade, plugs into Laravel's notification channels, and ships a webhook controller for inbound replies and delivery reports. PHP 8.1+, Guzzle 7, MIT licensed.
Auto-discovery means you only run one Composer command and add two values to .env — no manual service-provider or facade alias registration.
What it covers
- Send SMS —
WebSms::send($to, $body) - OTP / 2FA codes —
WebSms::otp()->send($to)with auto-generated or custom code - Appointment reminders —
WebSms::appointment()->send(to: …, name: …, date: …, time: …)at the templated $0.08 + GST per part rate - Notification channel — any Notifiable can receive SMS via
->via('websms') - Inbound webhook — controller dispatches
WebSmsMessageReceived(replies) andWebSmsDeliveryReportReceived(delivery reports) Laravel events - NZ & AU number normalisation —
027 123 4567→64271234567automatically - Bearer token auth — 24-hour tokens cached in your default cache store
Code examples
Drop-in usage from any controller, job, or notification
Send a single SMS
use WebSms;
WebSms::send(
'+64211234567',
'Your order has shipped.'
);
Send an OTP / 2FA code
$res = WebSms::otp()->send('+64211234567');
// $res['code'] is the generated code
session(['otp_code' => $res['code']]);
Templated appointment reminder
WebSms::appointment()->send(
to: '+64211234567',
company: 'Sunrise Wellness Clinic',
name: 'Barry',
date: '28/10/25',
time: '11:15am',
replyY: true,
callUs: '09-555-1234',
);
Notification channel
public function via($notifiable): array
{
return ['websms'];
}
public function toWebSms($notifiable): WebSmsMessage
{
return WebSmsMessage::make(
"Hi {$notifiable->first_name}, …"
);
}
Listen for inbound replies
use WebSmsNz\Laravel\Events\WebSmsMessageReceived;
Event::listen(WebSmsMessageReceived::class,
function ($event) {
Log::info("Reply from {$event->from}: "
. $event->body);
}
);
Listen for delivery reports
use WebSmsNz\Laravel\Events\WebSmsDeliveryReportReceived;
Event::listen(WebSmsDeliveryReportReceived::class,
function ($event) {
if ($event->isFailed()) {
// re-queue, alert, etc.
}
}
);
Quick setup
Get your API credentials
Log in to the WebSMS Members Area and open API Keys. Create a new key and copy the Client ID and Client Secret.
Install the package
composer require websms-nz/laravel-websms
Optional: publish the config file with
php artisan vendor:publish --tag=websms-config
to override defaults like the OTP company name or appointment-reminder template.
Add credentials to .env
WEBSMS_CLIENT_ID=your_client_id
WEBSMS_CLIENT_SECRET=your_client_secret
# Optional. If omitted, WebSMS routes via a shared shortcode.
WEBSMS_FROM=2190
# Optional. Defaults to your APP_NAME.
WEBSMS_OTP_COMPANY=YourApp
Sanity check from the CLI
php artisan websms:test +64211234567 --message="Hello from Laravel"
Confirms the credentials, token exchange, and outbound routing are all wired up before you write any code.
(Optional) Receive inbound replies and delivery reports
Mount the webhook controller at any path in routes/web.php:
use WebSmsNz\Laravel\Http\WebhookController;
use App\Http\Middleware\VerifyCsrfToken;
Route::post('/webhooks/websms', [WebhookController::class, 'handle'])
->withoutMiddleware([VerifyCsrfToken::class]);
Then paste https://yourapp.com/webhooks/websms into the Webhook URL field on the API Keys page. Append ?secret=... and set WEBSMS_WEBHOOK_SECRET in .env for an extra check.
Composer: websms-nz/laravel-websms on Packagist · Source: gitlab.com/icepicknz/laravel-websms
Why this package
Idiomatic Laravel
Auto-discovered service provider, facade alias, publishable config, notification channel, and Artisan command — works the way Laravel devs already expect.
NZ & AU normalisation
Pass numbers in whatever format your data already uses. 027 123 4567 and +64 27 123 4567 both work.
OTP as a first-class call
No template wrangling. WebSms::otp()->send($phone) generates a code, sends it, and returns it for verification.
Appointment template
Server-rendered reminder body at the templated rate ($0.08 + GST per part). Pass only the fields you want included.
Inbound webhook + events
Single controller, two typed events. Listen anywhere in your app or queue listeners with php artisan make:listener.
MIT licensed, open source
View source on GitLab →
Ship SMS from Laravel today
Composer install, two env vars, and you're sending. No infrastructure, no contracts, pay only per message.
Frequently asked questions
Common questions about sending SMS from Laravel
How do I send SMS from a Laravel application?
composer require websms-nz/laravel-websms, set WEBSMS_CLIENT_ID and WEBSMS_CLIENT_SECRET in your .env, and call WebSms::send($phone, $body) from anywhere in your app. The package auto-discovers via Laravel's package discovery — no manual provider registration.
Does the package include a Laravel notification channel?
'websms' to a Notification's via() array and implement toWebSms($notifiable) returning a WebSmsMessage. The channel resolves the recipient phone number from routeNotificationForWebSms() or a phone_number attribute on the notifiable.
Can I send OTP / 2FA codes?
WebSms::otp()->send($phone) — WebSMS generates a code, sends the SMS, and returns the code so you can persist it for verification. You can also supply your own code with WebSms::otp()->send($phone, code: '123456') and override the company brand label per call.
How do I receive inbound replies (MO) and delivery reports (DLR)?
WebSmsNz\Laravel\Http\WebhookController at any URL in routes/web.php, paste that URL into the API Keys page in the WebSMS members area, then listen for WebSmsMessageReceived (MO) and WebSmsDeliveryReportReceived (DLR) events. Set WEBSMS_WEBHOOK_SECRET and append ?secret=... to the webhook URL for defence-in-depth.
Which Laravel and PHP versions are supported?
Do I need a sender ID or shortcode to send?
WEBSMS_FROM is optional — if you don't set it, WebSMS routes outbound SMS via a shared shortcode at no extra cost. Set it only if you have a registered alphanumeric sender ID or a dedicated shortcode you want messages to come from.
Are NZ and Australian phone numbers handled automatically?
027 123 4567, +64 27 123 4567, or 0412 345 678 — the package normalises to the international format the API expects (64271234567, 61412345678) before each call.
How are API tokens managed?
client_id + client_secret at /auth/token for a 24-hour bearer token, then caches it in your application's default cache store (or a specific store via WEBSMS_CACHE_STORE). Subsequent calls reuse the cached token until ~60 seconds before expiry.
Where do API errors surface?
WebSmsNz\Laravel\Exceptions\WebSmsException. The original API response (where one was returned) is accessible via $exception->getApiResponse() for logging or programmatic handling.
Other integrations
Other ways to wire SMS into your stack