nugsoft/signalbridge-laravel-sdk

Laravel SDK for SignalBridge SMS Gateway - Send SMS messages through multiple vendors with unified API

Maintainers

Package info

github.com/nugsoft/signalbridge-laravel-sdk

pkg:composer/nugsoft/signalbridge-laravel-sdk

Statistics

Installs: 32

Dependents: 0

Suggesters: 0

Stars: 1

Open Issues: 0

v2.0.0 2026-04-23 13:01 UTC

This package is not auto-updated.

Last update: 2026-04-23 13:06:36 UTC


README

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 interface β€” SignalBridge::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