revolution/laravel-notification-mastodon
A Laravel notification channel for sending notifications to Mastodon. Publish status updates directly from your app using Laravel's notification system, with simple configuration and support for the Mastodon API so you can integrate posting into existing workflows.
Architecture fit
The package follows Laravel's first-class notification channel contract: a notifiable declares via() returning 'mastodon', the channel resolves toMastodon($notifiable), and a value object (MastodonMessage) carries status text, visibility, content warning, and media. That means it composes with the framework primitives we already rely on — queued notifications, Notification::fake(), NotificationSent/NotificationFailed events, and on-demand routing via Notification::route('mastodon', ...) for system/brand accounts. Architectural fit is high if our use case is "post a status as a side effect of a domain event" (release announcements, incident notices, marketing drops). It is a poor fit for anything requiring conversation threading, reply ingestion, or analytics on engagement — it is fire-and-forget outbound only.
Integration feasibility
Feasible in days, not weeks. The real integration cost is not the package but the Mastodon-side setup: every target instance requires an OAuth application registration, a write:statuses (and write:media if attaching) scoped token, and per-account routing. Because Mastodon is federated, credentials are per-instance-per-account, so routeNotificationForMastodon() must return instance host + token, not a single global API key. That pushes work into our user/tenant model (encrypted token storage, rotation, revocation handling) and into configuration management rather than into the package itself.
Technical risk
Idempotency-Key on POST /api/v1/statuses; confirm the package surfaces it, otherwise we must enforce WithoutOverlapping/RateLimited middleware or a dedupe key in the payload./api/v2/instance.Key questions
Idempotency-Key, and does it return/expose the created status ID for later deletion or auditing?Stack fit Strong fit for a Laravel monolith or modular monolith already emitting domain events. The channel plugs into the existing notification layer with no new infrastructure beyond outbound HTTP and the queue. If we run Horizon/Redis, we already have the primitives for rate limiting and concurrency control that this package assumes but does not provide.
Migration path
There is nothing to migrate from — greenfield. The correct move is to wrap, not adopt directly: define an internal SocialPost/Announcement notification that lists 'mastodon' in via(), and keep the third-party class behind a thin adapter or a forked copy in our vendor namespace. That gives us a one-file swap if the package stalls, and lets us normalize payloads if we later add other networks.
Compatibility Validate three axes before committing: PHP/Laravel constraint coverage against our matrix, the target instance's Mastodon version (v2 instance endpoint for limits and configuration), and token scope. Pin the dependency with a caret constraint, commit the lockfile, and add a smoke test that posts to a disposable test instance in CI so an upstream break surfaces before a release.
Sequencing
ShouldQueue, named rate limiter per account/instance, retry policy, dead-letter handling.NotificationSent/NotificationFailed, emit metrics and structured logs with payload redaction.Maintenance Low code surface (~a few hundred lines) but non-trivial dependency risk. Budget for a quarterly health check: last commit, open issues, Laravel major compatibility. MIT licensing means the exit ramp is "fork and own it," which caps worst-case cost at roughly a day of engineering. Our wrapper is the actual asset; the package is disposable.
Support Support burden lands on the platform team, not the vendor. Most tickets will be credential and policy issues ("token revoked," "instance admin suspended the account," "post rejected by content rules"), not package bugs. Publish a runbook: how to rotate tokens, how to re-drive a failed notification, how to delete a bad post.
Scaling Outbound volume is inherently small — Mastodon enforces roughly 300 statuses per 5 minutes per account and tighter media limits, and each instance sets its own thresholds. The scaling concern is fan-out across accounts/instances, not throughput: N accounts × M instances means N×M credential sets and independent rate limiters. Use per-account named limiters backed by Redis and keep workers horizontally scalable; the HTTP calls are I/O-bound and cheap.
Failure modes
WithoutOverlapping.Ramp-up Minimal. Any Laravel developer who has written a custom notification channel is productive in under a day; the unfamiliar knowledge is Mastodon operations (app registration, token scopes, instance limits, moderation), which is a half-day of reading plus a staging exercise. The dominant ramp-up cost is organizational — deciding who owns brand accounts, who holds tokens, and who is on the hook when a post misfires — not technical.
How can I help you explore Laravel packages today?