Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Discord Notification Channel Laravel Package

awssat/discord-notification-channel

Send Laravel notifications directly to Discord with a dedicated notification channel. Configure a webhook, define notification classes, and deliver messages or embeds through Laravel’s familiar notification system. Lightweight integration for Laravel/PHP apps.

View on GitHub
Deep Wiki
Context7

Getting Started

Install

composer require awssat/discord-notification-channel

No service provider or config publish is needed for the basic flow — the package registers itself via Laravel's package discovery.

Where to look first

  • The DiscordChannel class (Awssat\DiscordNotificationChannel\DiscordChannel) — this is what you add to via().
  • The DiscordMessage builder — this is the fluent object you return from toDiscord().
  • The GitHub README's test/example block — it's the fastest reference for the exact method names (embeds, fields, colors) since the API is small.

First use case

A low-volume operational notification (e.g., "new order", "deploy finished", "backup failed") sent to a single Discord webhook:

  1. Create a webhook in Discord (Server Settings → Integrations → Webhooks) and copy the URL.
  2. Store it in config/services.php or .env (DISCORD_WEBHOOK=...).
  3. Implement routeNotificationForDiscord() on the notifiable (or set the webhook at send-time) so the channel knows where to POST.
  4. Create a notification with DiscordChannel::class in via() and a toDiscord() method returning a DiscordMessage.

That's the whole loop: install → webhook → route → notify. Resist the urge to build a full "notification bus" on day one; start with one webhook to one channel and iterate.

Implementation Patterns

Basic notification

use Awssat\DiscordNotificationChannel\DiscordChannel;
use Awssat\DiscordNotificationChannel\DiscordMessage;

public function via($notifiable): array
{
    return [DiscordChannel::class];
}

public function toDiscord($notifiable): DiscordMessage
{
    return DiscordMessage::create()
        ->content("Order #{$notifiable->id} was paid");
}

Embeds for structured output

Discord reads best as embeds rather than raw content. Use embeds when you have a title, fields, and a link (e.g., "Payment failed" + amount + customer + link back to your admin panel). Keep content for @here-style mentions or short summaries, and use the embed for the payload.

Routing

Two common routing strategies:

  • Per-model — implement routeNotificationForDiscord() on the notifiable (User, Team, etc.) returning the webhook URL.
  • Per-purpose — store multiple webhooks in config/services.php (discord.webhooks.orders, discord.webhooks.alerts) and pick one inside the notification.

The second scales better once you have "orders" vs "errors" vs "deploys" channels, because it keeps the webhook choice next to the notification intent instead of scattered across models.

On-demand notifications

For one-off messages from a controller or artisan command, use Notification::route('discord', $webhookUrl)->notify(new SomethingHappened()). This is the fastest way to add Discord pings to existing code without wiring a notifiable.

Queue it

Implement ShouldQueue on the notification. The channel does a blocking HTTP call; queueing turns a 100–400ms webhook round-trip into a background job and lets Laravel's retry policy handle transient Discord 5xx / 429s. Pair with backoff() and a $tries cap.

Fan-out to multiple channels

Discord is a side channel, not a primary one. The idiomatic pattern is via() returning [MailChannel::class, DiscordChannel::class] — email/DB is the source of truth, Discord is the "look at this now" signal. Don't put payloads in Discord that exist nowhere else.

Testing

Use Notification::fake() and Notification::assertSentTo($user, OrderPaid::class) — you're asserting the notification was dispatched, not the HTTP call. If you want to assert the webhook body itself, either Queue::fake() and inspect the job, or wrap the channel in a mock. Avoid hitting Discord in the test suite entirely.

Integration tip

Wrap the channel in a small domain service (Notifier::orderPaid($order)) so controllers/jobs don't sprinkle Notification::route('discord', ...) everywhere. That single indirection point is where you later add throttling, feature flags, and "don't send at 3am" logic.

Gotchas and Tips

Discord's rate limits are aggressive and per-webhook. A burst of 10 notifications in 2 seconds can get you 429'd, and Discord returns a retry_after hint that Laravel's HTTP client won't honor automatically. Mitigations: queue + ->delay(), coalesce multiple events into one embed per notification, and for anything bursty (e.g., error alerts), implement your own per-webhook token bucket or use Redis::throttle() in the notification's middleware().

Embed limits are hard caps, not soft warnings. Title ≤ 256, description ≤ 4096, field name ≤ 256, field value ≤ 1024, max 25 fields, total embed ≤ 6000 chars. Truncate in toDiscord() (Str::limit(...)) — Discord rejects the whole webhook, not just the field. This bites hardest on exception messages and stack traces; ship a Str::limit($e->getMessage(), 1000) helper.

Color is a decimal integer, not a hex string. ->color(0x00ff00) and ->color(65280) work; ->color('#00ff00') does not. Keep a small constants class (Discord::GREEN, Discord::RED) so callers don't guess.

Webhook URLs are credentials. Anyone with the URL can post as your bot. Keep them in .env / a secrets manager, never in config/*.php committed to git, and rotate if leaked. On Laravel Cloud/Forge, use environment variables, not config files.

Silent failures are the default failure mode. The channel throws on non-2xx, but if you're using Notification::route(...) inside a try/catch (or the notifier is inside a queued job that has $tries = 1), a dead webhook is invisible. Add a health check that POSTs a tiny payload to each webhook daily, or forward channel exceptions to your error tracker.

ShouldQueue + afterCommit — if you fire notifications inside a DB transaction, queue + afterCommit() or the webhook can fire before the row is committed and the message references a phantom record.

Notifiable routing is optional but easy to miss. If routeNotificationForDiscord() returns null, the channel has nowhere to send. The failure message ("No webhook configured") is usually fine, but if you support multiple webhooks per user, return an array and dedupe — the channel will POST to each.

Version pinning. This is a 94-star community package, not a first-party Laravel one. Pin to a caret constraint (^x.y), add it to your composer update watchlist, and keep a one-line fallback (a plain Http::post($webhook, $payload) inside a queued job) so that if the package stalls you can drop it without touching call sites.

Extension point. If you need custom behavior (signing, dedupe, retries with backoff), subclass DiscordChannel and override the send method, or wrap the channel behind your own DiscordNotifier service. Both are cheaper than forking — forking a 94-star package creates a maintenance burden when you upgrade Laravel.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle
glavweb/extra-bundle
glavweb/api-bundle
glavweb/admin-bundle
adachsoft/api-version-bundle
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
cgv/localized-resource