expertsystemsau/transmitsms-laravel-client

Laravel notification channel and integration for the TransmitSMS API

Installs: 19

Dependents: 0

Suggesters: 0

Security: 0

Stars: 0

Watchers: 0

Forks: 0

Open Issues: 0

pkg:composer/expertsystemsau/transmitsms-laravel-client

v1.6.0 2026-01-16 05:23 UTC

This package is auto-updated.

Last update: 2026-01-16 05:33:54 UTC


README

Latest Version on Packagist Total Downloads License

Laravel notification channel and integration for the TransmitSMS API.

Installation

composer require expertsystemsau/transmitsms-laravel

Publish the configuration file:

php artisan vendor:publish --tag="transmitsms-config"

Configuration

Add your credentials to your .env file:

TRANSMITSMS_API_KEY=your-api-key
TRANSMITSMS_API_SECRET=your-api-secret
TRANSMITSMS_FROM=YourSenderID

Usage

Facade

use ExpertSystems\TransmitSms\Laravel\Facades\TransmitSms;

// Send an SMS
TransmitSms::sendSms('+61400000000', 'Hello from Laravel!');

// Get account balance
$balance = TransmitSms::getBalance();

Notifications

Create a notification that uses the TransmitSMS channel:

use Illuminate\Notifications\Notification;
use ExpertSystems\TransmitSms\Laravel\Notifications\TransmitSmsMessage;

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

    public function toTransmitSms($notifiable): TransmitSmsMessage
    {
        return TransmitSmsMessage::create('Your order has been shipped!')
            ->from('MyStore');
    }
}

Add the routeNotificationForTransmitsms method to your notifiable model:

class User extends Authenticatable
{
    use Notifiable;

    public function routeNotificationForTransmitsms($notification): ?string
    {
        return $this->phone_number;
    }
}

Then send notifications:

$user->notify(new OrderShipped());

DLR & Reply Callbacks

The package provides automatic handling for DLR (Delivery Receipt), Reply, and Link Hit callbacks. When you send an SMS, you can specify a job to be dispatched when a callback is received.

Quick Start

use App\Jobs\UpdateOrderSmsStatusJob;
use App\Jobs\ProcessCustomerReplyJob;
use ExpertSystems\TransmitSms\Laravel\Notifications\TransmitSmsMessage;

class OrderShipped extends Notification
{
    public function __construct(public Order $order) {}

    public function via($notifiable): array
    {
        return ['transmitsms'];
    }

    public function toTransmitSms($notifiable): TransmitSmsMessage
    {
        return TransmitSmsMessage::create("Your order #{$this->order->id} has shipped!")
            ->from('MYSTORE')
            ->onDlr(UpdateOrderSmsStatusJob::class, [
                'order_id' => $this->order->id,
            ])
            ->onReply(ProcessCustomerReplyJob::class, [
                'order_id' => $this->order->id,
                'customer_id' => $notifiable->id,
            ]);
    }
}

Creating Handler Jobs

DLR Handler Job:

namespace App\Jobs;

use App\Models\Order;
use ExpertSystems\TransmitSms\Data\DlrCallbackData;
use ExpertSystems\TransmitSms\Laravel\Contracts\HandlesDlrCallback;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;

class UpdateOrderSmsStatusJob implements HandlesDlrCallback, ShouldQueue
{
    use InteractsWithQueue, Queueable;

    public function __construct(
        public DlrCallbackData $dlr,
        public array $context,
    ) {}

    public function handle(): void
    {
        $order = Order::find($this->context['order_id']);

        $order->update([
            'sms_status' => $this->dlr->status,
            'sms_delivered_at' => $this->dlr->isDelivered()
                ? now()->parse($this->dlr->datetime)
                : null,
        ]);

        if ($this->dlr->isFailed()) {
            // Handle failure - maybe send email instead
            Log::warning('SMS delivery failed', [
                'order_id' => $order->id,
                'error' => $this->dlr->errorDescription,
            ]);
        }
    }
}

Reply Handler Job:

namespace App\Jobs;

use App\Models\SmsConversation;
use ExpertSystems\TransmitSms\Data\ReplyCallbackData;
use ExpertSystems\TransmitSms\Laravel\Contracts\HandlesReplyCallback;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;

class ProcessCustomerReplyJob implements HandlesReplyCallback, ShouldQueue
{
    use Queueable;

    public function __construct(
        public ReplyCallbackData $reply,
        public array $context,
    ) {}

    public function handle(): void
    {
        SmsConversation::create([
            'order_id' => $this->context['order_id'],
            'customer_id' => $this->context['customer_id'],
            'direction' => 'inbound',
            'message' => $this->reply->message,
            'mobile' => $this->reply->mobile,
            'received_at' => $this->reply->receivedAt,
        ]);
    }
}

Link Hit Handler Job:

namespace App\Jobs;

use ExpertSystems\TransmitSms\Data\LinkHitCallbackData;
use ExpertSystems\TransmitSms\Laravel\Contracts\HandlesLinkHitCallback;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;

class TrackLinkClickJob implements HandlesLinkHitCallback, ShouldQueue
{
    use Queueable;

    public function __construct(
        public LinkHitCallbackData $linkHit,
        public array $context,
    ) {}

    public function handle(): void
    {
        LinkClick::create([
            'campaign_id' => $this->context['campaign_id'],
            'mobile' => $this->linkHit->mobile,
            'url' => $this->linkHit->url,
            'clicked_at' => $this->linkHit->clickedAt,
        ]);
    }
}

Global Event Listeners

In addition to per-message handlers, you can listen to events for all callbacks:

// App\Providers\EventServiceProvider.php
use ExpertSystems\TransmitSms\Laravel\Events\DlrReceived;
use ExpertSystems\TransmitSms\Laravel\Events\ReplyReceived;
use ExpertSystems\TransmitSms\Laravel\Events\LinkHitReceived;

protected $listen = [
    DlrReceived::class => [
        \App\Listeners\LogDlrCallback::class,
    ],
    ReplyReceived::class => [
        \App\Listeners\LogReplyCallback::class,
    ],
    LinkHitReceived::class => [
        \App\Listeners\LogLinkHitCallback::class,
    ],
];

Example listener:

namespace App\Listeners;

use ExpertSystems\TransmitSms\Laravel\Events\DlrReceived;
use Illuminate\Support\Facades\Log;

class LogDlrCallback
{
    public function handle(DlrReceived $event): void
    {
        Log::info('DLR callback received', [
            'message_id' => $event->dlr->messageId,
            'mobile' => $event->dlr->mobile,
            'status' => $event->dlr->status,
            'context' => $event->context,
        ]);
    }
}

Webhook Configuration

The webhook routes are automatically registered. You can customize them in config/transmitsms.php:

'webhooks' => [
    // Enable/disable webhook routes
    'enabled' => env('TRANSMITSMS_WEBHOOKS_ENABLED', true),

    // Route prefix (e.g., /webhooks/transmitsms/dlr)
    'prefix' => env('TRANSMITSMS_WEBHOOKS_PREFIX', 'webhooks/transmitsms'),

    // Middleware for webhook routes
    'middleware' => ['api'],

    // Custom signing key (defaults to APP_KEY)
    'signing_key' => env('TRANSMITSMS_SIGNING_KEY'),

    // DLR callback settings
    'dlr' => [
        'enabled' => true,
        'path' => 'dlr',
        'queue' => env('TRANSMITSMS_DLR_QUEUE', 'default'),
    ],

    // Reply callback settings
    'reply' => [
        'enabled' => true,
        'path' => 'reply',
        'queue' => env('TRANSMITSMS_REPLY_QUEUE', 'default'),
    ],

    // Link hits callback settings
    'link_hits' => [
        'enabled' => true,
        'path' => 'link-hits',
        'queue' => env('TRANSMITSMS_LINK_HITS_QUEUE', 'default'),
    ],
],

Callback Data Objects

DlrCallbackData properties:

Property Type Description
messageId int The message ID
mobile string Recipient phone number
status string Status: delivered, failed, pending
datetime ?string Delivery timestamp
senderId ?string Sender ID used
errorCode ?string Error code if failed
errorDescription ?string Error description

Helper methods: isDelivered(), isFailed(), isPending()

ReplyCallbackData properties:

Property Type Description
messageId int Original message ID
mobile string Sender phone number
message string Reply message text
receivedAt string Timestamp when received
responseId ?int Reply ID
longcode ?string Number replied to
firstName ?string Sender first name
lastName ?string Sender last name

LinkHitCallbackData properties:

Property Type Description
messageId int Message ID
mobile string Recipient phone number
url string URL that was clicked
clickedAt string Click timestamp
userAgent ?string Browser user agent
ipAddress ?string IP address

How It Works

  1. Sending: When you use onDlr(), onReply(), or onLinkHit(), the package builds a signed callback URL containing your handler class and context data.

  2. Receiving: When TransmitSMS calls the webhook, the package:

    • Verifies the HMAC signature
    • Parses the callback data into a DTO
    • Dispatches a global event (for logging/monitoring)
    • Dispatches your handler job with the data and context
  3. Security: The callback URL includes an HMAC signature to prevent tampering. Only callbacks with valid signatures are processed.

┌─────────────────────────────────────────────────────────────────────┐
│  Your App                                                           │
│  ────────                                                           │
│  TransmitSmsMessage::create('Hello')                               │
│      ->onDlr(MyJob::class, ['id' => 1])                           │
│                    │                                                │
│                    ▼                                                │
│  Package builds signed callback URL                                │
│  https://app.com/webhooks/transmitsms/dlr?h=...&c=...&s=...       │
└─────────────────────────────────────────────────────────────────────┘
                     │
                     ▼
┌─────────────────────────────────────────────────────────────────────┐
│  TransmitSMS                                                        │
│  ───────────                                                        │
│  Sends SMS → Receives DLR → Calls your webhook URL                 │
└─────────────────────────────────────────────────────────────────────┘
                     │
                     ▼
┌─────────────────────────────────────────────────────────────────────┐
│  Your App (Webhook)                                                 │
│  ─────────────────                                                  │
│  WebhookController:                                                │
│    1. Verify signature ✓                                           │
│    2. Parse DlrCallbackData                                        │
│    3. Dispatch DlrReceived event                                   │
│    4. Dispatch MyJob with data + context                           │
└─────────────────────────────────────────────────────────────────────┘

License

The MIT License (MIT). Please see License File for more information.