Looking to hire Laravel developers? Try LaraJobs

signalbridge-laravel-sdk maintained by nugsoft

Description
Laravel SDK for SignalBridge SMS Gateway - Send SMS messages through multiple vendors with unified API
Author
Last update
2026/04/23 15:01 (dev-main)
License
Links
Downloads
414

Comments
comments powered by Disqus

SignalBridge Laravel SDK

Latest Version on Packagist Total Downloads

Official Laravel SDK for SignalBridge — a unified multi-channel communication and payment gateway.

Send SMS, WhatsApp messages, and initiate Mobile Money transactions through a single, clean Laravel API. Built by Nugsoft.

Channels

Channel Status Methods
SMS ✅ Available send(), sendBatch(), calculateSegments(), estimateCost()
WhatsApp ✅ Available send(), sendTemplate()
Mobile Money ✅ Available initiate(), verify(), disburse()
USSD 🔜 Planned push(), session(), respond()

Features

  • Multi-channel API — SMS, WhatsApp, Mobile Money, and USSD (planned) through one SDK
  • Channel-fluent interfaceSignalBridge::sms()->send(...), SignalBridge::whatsapp()->sendTemplate(...)
  • Backward compatible — existing SignalBridge::sendSms() calls still work
  • Balance & transaction management — account-level operations on the main client
  • Webhook management — full CRUD for outbound event webhooks
  • Export — download messages and transactions as CSV
  • Typed exceptions — specific exception classes for each error type
  • Facade + DI support — use either style
  • Laravel 10, 11, 12, 13 — tested on all current versions
  • PHP 8.1+

Requirements

  • PHP 8.1 or higher
  • Laravel 10.0, 11.0, 12.0, or 13.0
  • Guzzle HTTP 7.0+

Installation

composer require nugsoft/signalbridge-laravel-sdk

Optionally publish the config file:

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

Configuration

Add to your .env:

SIGNALBRIDGE_TOKEN=your_api_token_here
SIGNALBRIDGE_URL=https://signal-bridge.nugsoftapps.net/api

Getting your token:

curl -X POST https://signal-bridge.nugsoftapps.net/api/tokens \
  -H "Content-Type: application/json" \
  -d '{"email": "you@example.com", "password": "your-password", "expires_in_days": 365}'

You can also generate tokens from the SignalBridge dashboard under Settings → API Tokens.


Usage

Quick Start

use Nugsoft\SignalBridge\Facades\SignalBridge;

// SMS
SignalBridge::sms()->send('256700000000', 'Hello from SignalBridge!');

// WhatsApp
SignalBridge::whatsapp()->send('256700000000', 'Hello on WhatsApp!');

// Mobile Money — collect payment
SignalBridge::mobileMoney()->initiate('256700000000', 5000);

// Mobile Money — send payout
SignalBridge::mobileMoney()->disburse('256700000000', 50000);

Dependency Injection

use Nugsoft\SignalBridge\SignalBridgeClient;

class NotificationService
{
    public function __construct(private SignalBridgeClient $signalBridge) {}

    public function sendWelcome(string $phone, string $name): void
    {
        $this->signalBridge->sms()->send($phone, "Welcome {$name}!");
    }
}

SMS

Send a Single SMS

$result = SignalBridge::sms()->send(
    recipient: '256700000000',
    message: 'Your OTP is 123456',
    options: [
        'sender_id'    => 'MyApp',           // Optional
        'metadata'     => ['user_id' => 42], // Optional: stored for your records
        'is_test'      => false,             // Optional: test mode (no charge)
        'scheduled_at' => '2026-06-01T09:00:00Z', // Optional: ISO 8601
    ]
);
// $result['data']['message_id'], $result['data']['cost'], $result['data']['status']

Send a Batch of SMS

$result = SignalBridge::sms()->sendBatch(
    messages: [
        ['recipient' => '256700000000', 'message' => 'Hi Alice!', 'metadata' => ['user_id' => 1]],
        ['recipient' => '256700000001', 'message' => 'Hi Bob!',   'metadata' => ['user_id' => 2]],
    ],
    options: ['is_test' => false]
);
// $result['data']['successful'], $result['data']['failed']

Segment Calculation & Cost Estimation

$sms = SignalBridge::sms();

$segments = $sms->calculateSegments('Hello World'); // 1
$cost     = $sms->estimateCost('Hello World', segmentPrice: 1.00); // 1.00

Encoding rules:

  • GSM 7-bit (standard): 160 chars = 1 segment, 153 chars/segment thereafter
  • Unicode (emoji, Arabic, Chinese…): 70 chars = 1 segment, 67 chars/segment thereafter

WhatsApp

Send a Plain Message

SignalBridge::whatsapp()->send(
    recipient: '256700000000',
    message: 'Your order #1234 has been shipped.',
    options: ['metadata' => ['order_id' => 1234]]
);

Send a Template Message

Templates must be pre-approved in Meta Business Manager.

SignalBridge::whatsapp()->sendTemplate(
    recipient: '256700000000',
    templateName: 'order_confirmation',
    components: [
        [
            'type' => 'body',
            'parameters' => [
                ['type' => 'text', 'text' => 'Alice'],
                ['type' => 'text', 'text' => '#ORD-9821'],
                ['type' => 'text', 'text' => 'UGX 45,000'],
            ],
        ],
    ],
    options: ['language' => 'en_US']
);

Mobile Money

Collect a Payment (Request-to-Pay)

$tx = SignalBridge::mobileMoney()->initiate(
    phone: '256700000000',
    amount: 15000,
    currency: 'UGX',
    options: [
        'reference'    => 'INV-2026-001',
        'description'  => 'Invoice payment',
        'callback_url' => 'https://yourapp.com/webhooks/momo',
        'metadata'     => ['invoice_id' => 101],
    ]
);

$transactionId = $tx['data']['transaction_id'];
$status        = $tx['data']['status']; // 'pending'

Poll Transaction Status

$result = SignalBridge::mobileMoney()->verify('txn-uuid-here');
// $result['data']['status'] — 'pending' | 'completed' | 'failed'

Prefer webhooks over polling. Register a callback_url in initiate() or configure a webhook via createWebhook().

Disburse (Send Money)

SignalBridge::mobileMoney()->disburse(
    phone: '256700000000',
    amount: 50000,
    currency: 'UGX',
    options: [
        'reference'   => 'SALARY-APR-2026',
        'description' => 'April salary',
    ]
);

Account Operations

These methods are on the main SignalBridgeClient and apply across all channels.

Balance

$balance = SignalBridge::getBalance('UGX');
// ['balance' => 996.0, 'currency' => 'UGX', 'segment_price' => 1.0, ...]

$summary = SignalBridge::getBalanceSummary();

Transaction History

$transactions = SignalBridge::getTransactions([
    'type'       => 'debit',        // 'credit' | 'debit'
    'start_date' => '2026-01-01',
    'end_date'   => '2026-04-30',
    'per_page'   => 50,
    'page'       => 1,
]);

Export Data as CSV

// Save messages to a file
$csv = SignalBridge::exportMessages(['start_date' => '2026-04-01']);
Storage::put('exports/messages.csv', $csv);

// Save transactions to a file
$csv = SignalBridge::exportTransactions(['type' => 'debit']);
Storage::put('exports/transactions.csv', $csv);

Webhook Management

SignalBridge can POST events to your application when message or payment statuses change.

// Register a webhook
$webhook = SignalBridge::createWebhook(
    url: 'https://yourapp.com/webhooks/signalbridge',
    events: ['message.delivered', 'message.failed', 'payment.completed'],
    isActive: true
);
$secret = $webhook['data']['secret']; // Store this — shown only once

// List, update, delete
$list = SignalBridge::listWebhooks();
SignalBridge::updateWebhook($webhookId, ['is_active' => false]);
SignalBridge::deleteWebhook($webhookId);

// Rotate secret
$new = SignalBridge::regenerateWebhookSecret($webhookId);

Available events: message.sent, message.delivered, message.failed, message.permanently_failed, payment.completed, payment.failed, * (all)


Exception Handling

use Nugsoft\SignalBridge\Exceptions\InsufficientBalanceException;
use Nugsoft\SignalBridge\Exceptions\InsufficientPermissionsException;
use Nugsoft\SignalBridge\Exceptions\NoClientException;
use Nugsoft\SignalBridge\Exceptions\RateLimitedException;
use Nugsoft\SignalBridge\Exceptions\ServiceUnavailableException;
use Nugsoft\SignalBridge\Exceptions\SignalBridgeException;
use Nugsoft\SignalBridge\Exceptions\UnauthorizedException;
use Nugsoft\SignalBridge\Exceptions\ValidationException;

try {
    SignalBridge::sms()->send('256700000000', 'Hello');

} catch (InsufficientBalanceException $e) {
    $required  = $e->getRequiredBalance();
    $available = $e->getCurrentBalance();

} catch (ValidationException $e) {
    $errors     = $e->getErrors();
    $firstError = $e->getFirstError();

} catch (RateLimitedException $e) {
    // Slow down requests

} catch (ServiceUnavailableException $e) {
    // No active vendor configured

} catch (UnauthorizedException $e) {
    // Invalid or expired token

} catch (InsufficientPermissionsException $e) {
    // Role doesn't have access

} catch (SignalBridgeException $e) {
    $data = $e->getData(); // Raw API response body
}

Real-World Examples

OTP / Verification Code

use Nugsoft\SignalBridge\Facades\SignalBridge;
use Illuminate\Support\Facades\Cache;

public function sendOtp(Request $request): \Illuminate\Http\JsonResponse
{
    $code = random_int(100000, 999999);
    Cache::put("otp:{$request->phone}", $code, now()->addMinutes(5));

    SignalBridge::sms()->send(
        recipient: $request->phone,
        message: "Your verification code is {$code}. Valid for 5 minutes.",
        options: ['metadata' => ['action' => 'otp', 'ip' => $request->ip()]]
    );

    return response()->json(['success' => true]);
}

Order Confirmation via WhatsApp Template

public function confirmOrder(Order $order): void
{
    SignalBridge::whatsapp()->sendTemplate(
        recipient: $order->customer_phone,
        templateName: 'order_confirmation',
        components: [
            ['type' => 'body', 'parameters' => [
                ['type' => 'text', 'text' => $order->customer_name],
                ['type' => 'text', 'text' => $order->reference],
                ['type' => 'text', 'text' => number_format($order->total) . ' UGX'],
            ]],
        ]
    );
}

Collect Payment and Listen via Webhook

// 1. Initiate collection
$tx = SignalBridge::mobileMoney()->initiate(
    phone: $invoice->customer_phone,
    amount: $invoice->total,
    options: [
        'reference'    => $invoice->number,
        'callback_url' => route('webhooks.momo'),
        'metadata'     => ['invoice_id' => $invoice->id],
    ]
);

// 2. Handle webhook (routes/api.php → POST /webhooks/momo)
public function handle(Request $request): \Illuminate\Http\Response
{
    $status = $request->input('status');   // 'completed' | 'failed'
    $meta   = $request->input('metadata');

    if ($status === 'completed') {
        Invoice::find($meta['invoice_id'])->markPaid();
    }

    return response()->noContent();
}

Batch SMS from Database

Fetch phone numbers from your database and send in batches. The API accepts up to 100 messages per request, so chunk large datasets accordingly.

use App\Models\User;
use Nugsoft\SignalBridge\Facades\SignalBridge;

// Simple — send one message to all active users
User::where('is_active', true)
    ->select('phone', 'name')
    ->chunk(100, function ($users) {
        $messages = $users->map(fn ($user) => [
            'recipient' => $user->phone,
            'message'   => "Hi {$user->name}, your account has been updated.",
            'metadata'  => ['user_id' => $user->id],
        ])->toArray();

        SignalBridge::sms()->sendBatch($messages);
    });
// Personalised messages — different content per recipient
$notifications = Notification::with('user')
    ->where('status', 'pending')
    ->get()
    ->chunk(100);

foreach ($notifications as $batch) {
    $messages = $batch->map(fn ($n) => [
        'recipient' => $n->user->phone,
        'message'   => $n->body,
        'metadata'  => ['notification_id' => $n->id],
    ])->toArray();

    $result = SignalBridge::sms()->sendBatch($messages);

    // Mark sent
    $batch->each->update(['status' => 'sent']);
}
// With balance check before sending
$phones  = User::where('subscribed', true)->pluck('phone');
$balance = SignalBridge::getBalance('UGX');
$cost    = $phones->count() * SignalBridge::sms()->calculateSegments($message) * $balance['segment_price'];

if ($balance['available_balance'] < $cost) {
    throw new \RuntimeException("Insufficient balance. Need {$cost} UGX, have {$balance['available_balance']} UGX.");
}

$phones->chunk(100)->each(function ($chunk) use ($message) {
    SignalBridge::sms()->sendBatch(
        $chunk->map(fn ($phone) => ['recipient' => $phone, 'message' => $message])->toArray()
    );
});

Configuration Reference

// config/signalbridge.php
return [
    'url'               => env('SIGNALBRIDGE_URL', 'https://signal-bridge.nugsoftapps.net/api'),
    'token'             => env('SIGNALBRIDGE_TOKEN'),
    'timeout'           => env('SIGNALBRIDGE_TIMEOUT', 30),
    'default_sender_id' => env('SIGNALBRIDGE_SENDER_ID'),
    'logging'           => env('SIGNALBRIDGE_LOGGING', true),
];
Variable Required Default Description
SIGNALBRIDGE_TOKEN API authentication token
SIGNALBRIDGE_URL Production URL API base URL
SIGNALBRIDGE_TIMEOUT 30 HTTP request timeout (seconds)
SIGNALBRIDGE_SENDER_ID Default SMS sender ID (max 11 chars)
SIGNALBRIDGE_LOGGING true Log API errors to Laravel log

Laravel compatibility: 10, 11, 12, 13


Testing

composer test

License

MIT. See LICENSE.

Credits

  • Asaba William — CTO

Made with ❤️ by Nugsoft