Outbox
CommunityDiscord, Slack, Microsoft Teams and signed-webhook notification channels for Laravel, built on the native notification system. Write a normal Notification class, return a message object, done.
Author:
Boris Stiner
Package health
BetaAutomated checks of this plugin's Composer package
15 checks
- Skipped: GitHub Actions pinned to SHA
- Skipped: GitLab CI includes pinned to SHA
- Passed: Open security advisories
- Passed: Dependabot PR responsiveness — No open Dependabot PRs.
- Skipped: Renovate MR responsiveness
- Passed: Dependabot or Renovate configured
- Passed: Dependency update cooldown configured
- Passed: Provides a security policy
- Passed: Abandoned or archived — No consulted source marks the package abandoned (packagist, github).
- Passed: Commit and release recency — Active: last commit 5 days ago; last release 6 days ago.
-
Passed:
composer.lock not committed by library
—
composer.lockis absent from the released dist archive. - Passed: Dist archive is lean
-
Passed:
Current Laravel version supported
—
Package dependencies resolve together with current Laravel
13.0. -
Passed:
Current PHP version supported
—
Constraint
^8.3supports current PHP8.5. - Skipped: Current Symfony version supported
filament/
namespace. Review the source and install at your own risk. Found
malware or an unresolved security issue the author won't
address?
Report it
.
Documentation
Configurable notification channels for Laravel - Discord, Slack, Microsoft Teams, and generic signed webhooks - built on Laravel's native notification system. No new APIs to learn: write a normal Notification class, return a message object, done.
#Requirements
- PHP 8.3+
- Laravel 13
#Installation
composer require stboris/filament-outbox
Optionally publish the config:
php artisan vendor:publish --tag="filament-outbox-config"
#Usage
#Discord
use Stboris\FilamentOutbox\Messages\DiscordMessage;
use Stboris\FilamentOutbox\Messages\DiscordEmbed;
class TradeOpened extends Notification
{
public function via(object $notifiable): array
{
return ['discord'];
}
public function toDiscord(object $notifiable): DiscordMessage
{
return DiscordMessage::make()
->username('Trading Bot')
->embed(fn (DiscordEmbed $embed) => $embed
->title('LONG opened - BTCUSDT')
->color('#2A78D6')
->fields([
'Entry price' => '$100.00',
'Invested' => '$500.00',
])
->timestamp());
}
}
The webhook URL is resolved in this order:
->to($url)on the messagerouteNotificationForDiscord()on the notifiableconfig('filament-outbox.discord.webhook_url')(envOUTBOX_DISCORD_WEBHOOK_URL)
#Slack (incoming webhook)
use Stboris\FilamentOutbox\Messages\SlackMessage;
public function via(object $notifiable): array
{
// The 'slack' alias is only claimed when laravel/slack-notification-channel
// is not installed; the class name always works.
return [\Stboris\FilamentOutbox\Channels\SlackChannel::class];
}
public function toSlack(object $notifiable): SlackMessage
{
return SlackMessage::make('Trade closed - +$42.00')
->section('*LONG closed - BTCUSDT*');
}
#Microsoft Teams (Workflows webhook)
Sends Adaptive Cards to the webhook URL of a Power Automate workflow (the "When a Teams webhook request is received" trigger) - the mechanism that replaces the retired Office 365 Connector webhooks.
use Stboris\FilamentOutbox\Messages\TeamsMessage;
public function via(object $notifiable): array
{
return ['teams'];
}
public function toTeams(object $notifiable): TeamsMessage
{
return TeamsMessage::make('Deploy finished without errors.')
->title('Deployment')
->color('good')
->facts(['Version' => 'v2.14.0', 'Environment' => 'production']);
}
->block([...]) appends raw Adaptive Card elements; ->card([...]) replaces the generated card entirely.
#Generic webhook
use Stboris\FilamentOutbox\Messages\WebhookMessage;
public function via(object $notifiable): array
{
return ['webhook'];
}
public function toWebhook(object $notifiable): WebhookMessage
{
return WebhookMessage::make([
'event' => 'trade.closed',
'symbol' => 'BTCUSDT',
'pnl' => 42.0,
])->header('X-Source', 'my-app');
}
When a secret is configured (OUTBOX_WEBHOOK_SECRET or ->secret(...) on the message), the raw JSON body is signed with HMAC-SHA256 and the hex digest is sent in the X-Outbox-Signature header, so receivers can verify authenticity:
hash_equals($request->header('X-Outbox-Signature'), hash_hmac('sha256', $request->getContent(), $secret));
#Testing an endpoint
Verify any endpoint from the command line before relying on it:
php artisan outbox:test discord --to="https://discord.com/api/webhooks/..."
php artisan outbox:test slack # uses the configured default URL
php artisan outbox:test teams --to="https://.../workflows/.../invoke"
php artisan outbox:test webhook --message="Custom check"
#Resilient sending
Transient failures - connection errors, HTTP 429 rate limits, and 5xx responses - are automatically retried with exponential backoff (2 attempts by default, configurable via http.retry in the config). Permanent client errors (4xx) fail immediately with a descriptive CouldNotSendNotification exception.
#Testing
composer test
#License
MIT.
The author
From the same author
Featured Plugins
A selection of plugins curated by the Filament team
Custom Dashboards
Let your users build and share their own dashboards with a drag-and-drop interface. Define your data sources in PHP and let them do the rest.
Filament
Custom Fields
Eliminate custom field migrations forever. Let your users create and manage form fields directly in Filament admin panels with 20+ built-in field types, validation, and zero database changes.
Relaticle
Advanced Tables (formerly Filter Sets)
Supercharge your tables with powerful features like user-customizable views, quick filters, multi-column sorting, advanced table searching, convenient view management, and more. Compatible with Resource Panel Tables, Relation Managers, Table Widgets, and Table Builder!
Kenneth Sese