Looking to hire Laravel developers? Try LaraJobs

laravel-websms maintained by websms-nz

Description
Laravel package for the WebSMS Connexus API — send SMS, send OTP, balance checks, and a notification channel.
Author
Last update
2026/05/03 00:56 (dev-master)
License
Downloads
0

Comments
comments powered by Disqus

WebSMS for Laravel

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.

Key Env Required Default
client_id WEBSMS_CLIENT_ID yes
client_secret WEBSMS_CLIENT_SECRET yes
base_url WEBSMS_BASE_URL no https://websms.co.nz/api/connexus
from WEBSMS_FROM no (uses shared shortcode)
otp.company WEBSMS_OTP_COMPANY no APP_NAME
otp.comment WEBSMS_OTP_COMMENT no Valid for 5 minutes.
appointment.company WEBSMS_APPOINTMENT_COMPANY no falls back to otp.company
timeout WEBSMS_TIMEOUT no 10 seconds
webhook_secret WEBSMS_WEBHOOK_SECRET no (no auth on webhook controller)
cache_store WEBSMS_CACHE_STORE no application'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