Multi-Channel Notification Platform for Laravel
Our customer notification software provides a unified platform for sending transactional and marketing messages across SMS, email, and push notifications. Built on Laravel, it offers a single API, centralized template management, user preference controls, and comprehensive delivery analytics.
Send messages through any channel from a single API:
| Channel | Use Cases | Delivery Rate |
|---|---|---|
| SMS | Order confirmations, alerts, OTPs | 99%+ |
| Receipts, newsletters, reports | 97%+ | |
| Push | In-app alerts, reminders | 85%+ |
| Customer support, order updates | 98%+ |
<?php
namespace App\Services\Notifications;
use App\Models\NotificationTemplate;
use App\Models\User;
use Illuminate\Support\Facades\Notification;
class UnifiedNotificationService
{
public function send(User $user, string $templateKey, array $data = []): void
{
$template = NotificationTemplate::where('key', $templateKey)->firstOrFail();
$channels = $user->notificationPreferences()
->where('enabled', true)
->pluck('channel')
->toArray();
if (empty($channels)) {
$channels = ['sms']; // Default fallback
}
$notification = new DynamicNotification($template, $data);
Notification::send($user, $notification->via($channels));
}
}
---
## Notification Templates
Manage all notification content from a central interface:
```php
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::create('notification_templates', function (Blueprint $table) {
$table->id();
$table->string('key')->unique();
$table->string('name');
$table->text('description')->nullable();
$table->text('sms_body')->nullable();
$table->text('email_subject')->nullable();
$table->longText('email_body')->nullable();
$table->text('push_title')->nullable();
$table->text('push_body')->nullable();
$table->json('variables')->nullable();
$table->json('channels')->nullable(); // ['sms', 'email', 'push']
$table->boolean('is_active')->default(true);
$table->timestamps();
});
}
};
---
Render templates with dynamic data:
```php
<?php
namespace App\Services\Notifications;
use App\Models\NotificationTemplate;
use Illuminate\Support\Str;
class TemplateRenderer
{
public function render(NotificationTemplate $template, string $channel, array $data): string
{
$content = match ($channel) {
'sms' => $template->sms_body,
'email' => $template->email_body,
'push' => $template->push_body,
default => throw new \InvalidArgumentException("Unknown channel: {$channel}"),
};
foreach ($data as $key => $value) {
$content = Str::replace("{{$key}}", (string) $value, $content);
}
return $content;
}
public function getAvailableVariables(NotificationTemplate $template): array
{
preg_match_all('/\{\{(\w+)\}\}/', $template->sms_body . $template->email_body . $template->push_body, $matches);
return array_unique($matches[1]);
}
}
---
## User Preferences
Let users control how and when they receive notifications:
```php
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::create('user_notification_preferences', function (Blueprint $table) {
$table->id();
$table->foreignId('user_id')->constrained()->cascadeOnDelete();
$table->string('type', 64); // order_confirmation, marketing, shipping, etc.
$table->string('channel', 32); // sms, email, push, whatsapp
$table->boolean('enabled')->default(true);
$table->time('quiet_hours_start')->nullable();
$table->time('quiet_hours_end')->nullable();
$table->timestamps();
$table->unique(['user_id', 'type', 'channel']);
});
}
};
---
```php
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class UserNotificationPreference extends Model
{
protected $guarded = [];
public static function getEffectiveChannel(User $user, string $type): ?string
{
$preferences = static::where('user_id', $user->id)
->where('type', $type)
->where('enabled', true)
->get();
if ($preferences->isEmpty()) {
// Default: SMS if phone exists, otherwise email
return $user->phone ? 'sms' : 'email';
}
$now = now()->format('H:i');
foreach ($preferences as $pref) {
if ($pref->quiet_hours_start && $pref->quiet_hours_end) {
if ($now >= $pref->quiet_hours_start && $now <= $pref->quiet_hours_end) {
continue; // Skip during quiet hours
}
}
return $pref->channel;
}
return null; // All channels in quiet hours
}
}
---
## Delivery Analytics
Track every message's journey with detailed analytics:
```php
<?php
namespace App\Console\Commands;
use App\Models\SmsMessage;
use Illuminate\Console\Command;
class NotificationAnalytics extends Command
{
protected $signature = 'notifications:analytics {--days=30} {--format=table}';
protected $description = 'Show notification delivery analytics';
public function handle()
{
$since = now()->subDays($this->option('days'));
$totalSms = SmsMessage::where('created_at', '>=', $since)->count();
$totalEmail = EmailMessage::where('created_at', '>=', $since)->count();
$totalPush = PushNotification::where('created_at', '>=', $since)->count();
$channelStats = [
['SMS', $totalSms,
SmsMessage::delivered()->where('created_at', '>=', $since)->count(),
SmsMessage::failed()->where('created_at', '>=', $since)->count()],
['Email', $totalEmail,
EmailMessage::delivered()->where('created_at', '>=', $since)->count(),
EmailMessage::failed()->where('created_at', '>=', $since)->count()],
['Push', $totalPush,
PushNotification::delivered()->where('created_at', '>=', $since)->count(),
PushNotification::failed()->where('created_at', '>=', $since)->count()],
];
$this->table(
['Channel', 'Total', 'Delivered', 'Failed', 'Success Rate'],
array_map(function ($stat) {
$rate = $stat[1] > 0
? round(($stat[2] / $stat[1]) * 100, 1) . '%'
: 'N/A';
return [...$stat, $rate];
}, $channelStats)
);
// Trending notification types
$topTypes = SmsMessage::where('created_at', '>=', $since)
->selectRaw('type, COUNT(*) as count')
->groupBy('type')
->orderByDesc('count')
->limit(5)
->get();
$this->newLine();
$this->info('Top Notification Types:');
$this->table(
['Type', 'Volume'],
$topTypes->map(fn($t) => [$t->type, number_format($t->count)])->toArray()
);
}
}
---
## Pricing
| Feature | Starter | Professional | Enterprise |
|---------|---------|-------------|-----------|
| Channels | SMS + Email | SMS + Email + Push | All channels |
| Templates | 10 | Unlimited | Unlimited |
| Users | 1,000 | 10,000 | Unlimited |
| API Rate Limit | 100/min | 1,000/min | 10,000/min |
| Analytics | Basic | Advanced | Custom |
| Support | Email | Email + Chat | 24/7 Phone |
| **Price** | **$99/mo** | **$299/mo** | **Custom** |
Each plan includes 10,000 SMS messages. Additional messages billed at $0.005 each (volume discounts available).
## Integration Guide
### Installation
```bash
composer require laravelsms/notification-platform
php artisan vendor:publish --tag=notification-platform-config
php artisan migrate
---
### Configuration
```php
<?php
// config/notification-platform.php
return [
'default_channels' => ['sms', 'email'],
'track_opens' => true,
'track_clicks' => true,
'queue' => 'notifications',
'channels' => [
'sms' => [
'driver' => env('SMS_DRIVER', 'laravelsms'),
'from' => env('SMS_FROM', 'YourApp'),
],
'email' => [
'driver' => env('MAIL_MAILER', 'smtp'),
'from' => env('MAIL_FROM_ADDRESS'),
],
'push' => [
'driver' => env('PUSH_DRIVER', 'firebase'),
'api_key' => env('FIREBASE_API_KEY'),
],
],
];
---
### Sending Notifications
```php
<?php
namespace App\Http\Controllers;
use App\Services\Notifications\UnifiedNotificationService;
use Illuminate\Http\Request;
class OrderController extends Controller
{
public function __construct(
protected UnifiedNotificationService $notifications
) {}
public function ship(int $orderId)
{
$order = Order::findOrFail($orderId);
$order->update(['status' => 'shipped']);
$this->notifications->send(
$order->user,
'order_shipped',
[
'order_number' => $order->order_number,
'tracking_url' => $order->tracking_url,
'estimated_delivery' => $order->estimated_delivery->format('M d'),
]
);
return redirect()->back()->with('success', 'Order marked as shipped.');
}
}
---
## Platform Dashboard
The included dashboard gives you:
- **Real-time delivery metrics** — Live view of messages sent, delivered, and failed
- **Channel breakdown** — Per-channel performance comparison
- **Template performance** — Which notification types drive the most engagement
- **User preference reports** — How users configure their notification settings
- **Cost analysis** — Per-channel cost breakdown with billing projections
## Start Free Trial
Try the full platform free for 14 days. No credit card required.
[Start Free Trial](/contact)
Already have our [Laravel SMS API](/services/laravel-sms-api)? The notification platform extends it with multi-channel support and template management. Need enterprise features? See our [enterprise SMS solution](/services/enterprise-sms-solution-laravel) or [custom development](/services/custom-laravel-sms-development) options.