laravel-notification-channels/discord
Send Discord messages from your Laravel app through the notification system. This channel lets you post rich embeds, files, and webhook messages using Laravel's familiar notification classes.
via() returns DiscordChannel::class, the notifiable supplies a webhook URL, and DiscordMessage/DiscordEmbed produce the JSON payload with embeds, colors, fields, footers, and timestamps. An in-house HTTP client would mean owning payload formatting, retry plumbing, and webhook secret handling as bespoke code. The saving per feature is small; across every roadmap item that wants to post to Discord it compounds, and it removes a recurring class of "the alert silently didn't send" bugs.via() array, any existing or planned notification (deploy failures, incident opened, billing anomaly, health-check down, new signup digest) can gain Discord in an afternoon. This makes "ship alerts to Discord" an estimate of hours, not a spike — which changes whether it lands in the current cycle or gets deferred.#ops via Notification::route('discord', $webhook)->notify(...) — no model, no user, no bot. That's the same shape as cron monitors, failed-job hooks, and health checks, so a single integration unlocks a family of internal-tooling tickets.routeNotificationForDiscord() on the notifiable means the webhook can live as an encrypted column per team/tenant, in config for single-channel apps, or be passed on-demand. That decides whether "each customer configures their own Discord channel" is a v1 feature or a v2 feature — and it's cheap enough here to argue for v1.retry_after) are normal operation, and oversized payloads fail as runtime 400s — i.e. the alert silently never arrives. On-call paging must not ride solely on this path.^1.8 and smoke-testing one real notification on every bump is a small, ongoing maintenance tax we should accept explicitly rather than discover.composer require and a webhook URL in config/services.php.toArray() is the request body, which makes payload contract tests straightforward to write and review.mail/slack in via() is a one-line change with a feature flag; the channel is thin enough to subclass or swap if you need custom transport or global payload decoration.^1.8 bump.$hidden, log/tracker redaction), fix that first. The credential handling is more work than the integration.For executives — one paragraph: Discord is where a meaningful share of engineering and community conversation already happens, and we can post into it from our existing notification system with a small, MIT-licensed, purpose-built Laravel package rather than custom code. The integration is measured in hours, has no hosting footprint, no bot to operate, and no new infrastructure — it reuses our queue and our existing notification classes. The tradeoff is honest and bounded: it's a one-way broadcast channel (no interactive bot), and because Discord rate-limits and rejects oversized payloads, we will use it to mirror alerts, not as the sole path for on-call paging. Recommended decision: adopt, pin to ^1.8, treat the webhook URL as a production secret with a documented rotation runbook.
For engineering — the summary: Thin, readable, community Laravel notification channel for Discord webhooks. DiscordChannel::send() resolves the webhook from routeNotificationForDiscord() on the notifiable; DiscordMessage::toArray() is literally the JSON body; DiscordEmbed covers title/description/color/fields/footer/thumbnail/image/author/timestamp. Three integration rules: (1) queue it on a dedicated queue with tries/backoff, because 429 is an operating condition and a burst shouldn't starve mail; (2) suppress @everyone/@here by default via allowedMentions(['parse' => []]) and allow it deliberately; (3) test in two layers — Notification::fake() proves routing only, so add a payload-contract test asserting embed shape and Discord's size limits, plus one Http::fake() test confirming the resolved URL is actually posted to. Gotchas to design around: no config file means no global default, so gate the channel in via() when the webhook is null rather than throwing jobs into the failed queue; a regenerated webhook looks like a permanent outage, so put that queue in failed-job alerting; and the URL must be encrypted at rest, hidden from JSON, and scrubbed from Telescope/Sentry. First build: #ops deploy-failure alert — roughly 15 minutes and it exercises routing, payload building, and queueing end to end.
How can I help you explore Laravel packages today?