websms-nz/laravel-websms

Laravel package for the WebSMS Connexus API — send SMS, send OTP, balance checks, and a notification channel.

Maintainers

Package info

gitlab.com/icepicknz/laravel-websms

Homepage

Issues

pkg:composer/websms-nz/laravel-websms

Statistics

Installs: 0

Dependents: 0

Suggesters: 0

Stars: 0

v0.1.0 2026-05-02 22:56 UTC

This package is not auto-updated.

Last update: 2026-05-02 14:14:31 UTC


README

Laravel package for the WebSMS Connexus API — send SMS, OTP / 2FA codes, and templated appointment reminders from any Laravel 10/11/12 application. Includes a notification channel so any Notifiable can receive SMS via ->via('websms').

NZ and AU phone numbers are normalised automatically (027 123 456764271234567, 0412 345 67861412345678).

Installation

composer require websms-nz/laravel-websms

Publish the config file:

php artisan vendor:publish --tag=websms-config

Add credentials to your .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

Get credentials at https://websms.co.nz/members/api-keys.php.

Usage

Send an SMS

use WebSms;

WebSms::send('+64211234567', 'Hello from Laravel.');

Send an OTP / 2FA code

WebSMS generates a code if you don't supply one. The response includes the code so you can persist it for verification.

$response = WebSms::otp()->send('+64211234567');
//   => ['success' => true, 'code' => '482917', 'message_id' => '...']

session(['otp_code' => $response['code']]);

// Or supply your own:
WebSms::otp()->send('+64211234567', code: '123456', company: 'Acme');

Send a templated appointment reminder

Templated server-side at $0.08 + GST per SMS part (or your custom rate if lower). Only the fields you supply are included in the message body.

WebSms::appointment()->send(
    to:      '+64211234567',
    company: 'Sunrise Wellness Clinic',
    name:    'Barry',
    date:    '28/10/25',
    time:    '11:15am',
    replyY:  true,
    callUs:  '09-555-1234',
    address: '42 Main Street, Auckland',
);
//   => "Hi Barry, your next appointment with Sunrise Wellness Clinic is on
//       28/10/25 at 11:15am. Reply Y to confirm or Pls call us on 09-555-1234
//       to re-book. Our Address: 42 Main Street, Auckland. Std SMS charges apply."

// Minimal call (company falls back to config('websms.appointment.company') / otp.company):
WebSms::appointment()->send(to: '+64211234567', company: 'Acme Trades');

// Sandbox (no send, no charge — for integration testing):
WebSms::appointment()->send(to: '+64211234567', company: 'Acme', sandbox: true);

Check balance / number lookup

WebSms::balance();
WebSms::lookup('+64211234567');  // returns carrier + porting info for NZ numbers

Receive inbound replies (MO) and delivery reports (DLR)

WebSMS posts inbound SMS replies and delivery reports as JSON to a single URL configured in your WebSMS members area. The package ships a controller that parses the payload and dispatches Laravel events you can listen for.

1. Mount the controller in routes/web.php:

use WebSmsNz\Laravel\Http\WebhookController;

Route::post('/webhooks/websms', [WebhookController::class, 'handle'])
    ->withoutMiddleware([\App\Http\Middleware\VerifyCsrfToken::class]);

2. Paste the URL into the Webhook URL field on https://websms.co.nz/members/api-keys.php. Recommended: append a secret — https://yourapp.com/webhooks/websms?secret=... — and set the same value as WEBSMS_WEBHOOK_SECRET in your .env (the controller will reject mismatched requests with 401).

3. Listen for events anywhere in your app:

use Illuminate\Support\Facades\Event;
use WebSmsNz\Laravel\Events\WebSmsMessageReceived;
use WebSmsNz\Laravel\Events\WebSmsDeliveryReportReceived;

Event::listen(WebSmsMessageReceived::class, function ($event) {
    // $event->from, ->to, ->body, ->messageId, ->timestamp, ->encoding, ->network, ->raw
    Log::info("Reply from {$event->from}: {$event->body}");
});

Event::listen(WebSmsDeliveryReportReceived::class, function ($event) {
    // $event->messageId, ->status, ->statusCode, ->timestamp, ->details, ->raw
    if ($event->isFailed()) {
        Log::warning("DLR failed for {$event->messageId}: {$event->status}");
    }
});

Or generate proper queued listeners with php artisan make:listener so heavy work runs on the queue rather than blocking the webhook response.

Notification channel

class AppointmentReminder extends Notification
{
    public function via($notifiable): array
    {
        return ['websms'];
    }

    public function toWebSms($notifiable): \WebSmsNz\Laravel\Notifications\WebSmsMessage
    {
        return \WebSmsNz\Laravel\Notifications\WebSmsMessage::make(
            "Kia ora {$notifiable->first_name}, your appointment is tomorrow at 1:00pm."
        );
    }
}

The notifiable should expose the recipient phone number via either:

public function routeNotificationForWebSms($notification)
{
    return $this->mobile_number;
}

…or simply have a phone_number attribute.

CLI sanity check

php artisan websms:test +64211234567 --message="Hello from Laravel"

Configuration reference

See config/websms.php after publishing. The two required keys are client_id and client_secret; everything else has sensible defaults.

KeyEnvRequiredDefault
client_idWEBSMS_CLIENT_IDyes
client_secretWEBSMS_CLIENT_SECRETyes
base_urlWEBSMS_BASE_URLnohttps://websms.co.nz/api/connexus
fromWEBSMS_FROMno(uses shared shortcode)
otp.companyWEBSMS_OTP_COMPANYnoAPP_NAME
otp.commentWEBSMS_OTP_COMMENTnoValid for 5 minutes.
appointment.companyWEBSMS_APPOINTMENT_COMPANYnofalls back to otp.company
timeoutWEBSMS_TIMEOUTno10 seconds
webhook_secretWEBSMS_WEBHOOK_SECRETno(no auth on webhook controller)
cache_storeWEBSMS_CACHE_STOREnoapplication's default cache store (used for token cache)

Errors

All API and network failures are wrapped in WebSmsNz\Laravel\Exceptions\WebSmsException. The original API response (where available) is accessible via $exception->getApiResponse().

License

MIT