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

Filament Webhooks Laravel Package

jeffersongoncalves/filament-webhooks

A Filament plugin that adds a webhook management UI to your Laravel admin panel: list endpoints, fire test calls, and inspect delivery logs and responses without leaving Filament, making third-party integrations easier to debug and maintain.

View on GitHub
Deep Wiki
Context7

Getting Started

Install

composer require jeffersongoncalves/filament-webhooks

Register the plugin in your panel provider (app/Providers/Filament/AdminPanelProvider.php):

use JeffersonGoncalves\FilamentWebhooks\WebhooksPlugin;

public function panel(Panel $panel): Panel
{
    return $panel
        // ...
        ->plugin(WebhooksPlugin::make());
}

Publish and migrate. Check the package's service provider for tags before running blind — the usual Filament layout is:

php artisan vendor:publish --tag="filament-webhooks-config"
php artisan vendor:publish --tag="filament-webhooks-migrations"
php artisan migrate
php artisan filament:optimize-clear   # or: php artisan optimize:clear

Where to look first, in order

  1. config/filament-webhooks.php — table names, queue connection/name, retry counts, timeouts, signing toggle. This is the file that answers 80% of "why didn't it fire?" questions.
  2. The published migrations — confirm the endpoints and deliveries tables and what columns exist (secret, events, url, status, response, attempts). You will query these directly when debugging.
  3. The Filament resource classes — they show the exact model/field names the UI writes to, which is what you should mirror in seeders and tests.
  4. resources/lang/ — as of 3.1.0 this ships en plus ar, az, de, es, fa, fr, hi, it, ja, nl, pl, pt, ru, tr, uk, uz, zh_CN.

First use case (5 minutes)

  1. Log into the panel, open the Webhooks resource, create an endpoint pointing at https://webhook.site/<your-uuid>.
  2. Subscribe it to a model event you already emit (e.g. order.created).
  3. Fire it from tinker: Order::first()->update(['status' => 'paid']); — or dispatch whatever event your endpoint subscribes to.
  4. Run a queue worker (php artisan queue:work) and watch the delivery row appear in the panel with status, response code, and body.

If step 3 succeeds but step 4 shows nothing, it is almost always the queue, not the plugin.

Implementation Patterns

Let the UI own the endpoint list, let code own the event names. Endpoints and their subscribed events are runtime data — they belong in the database and the admin panel. The set of available event names is code. Expose them from a single source (a config array or an enum) and have your dispatch site validate against it so a typo in the panel fails loudly instead of silently never matching.

Dispatch through one seam. Rather than calling Http::post() from a dozen observers, funnel every outbound hook through a single helper/job:

Webhook::dispatch('order.created', $order->toWebhookPayload());

This gives you one place to add queueing, signing, retries, tenant scoping, and observability later.

Queue everything, always. Webhook delivery is network I/O against a third party. Do it in a job on a dedicated queue (webhooks) so a slow customer endpoint can never starve your default queue. Configure the connection and queue name in the config rather than relying on defaults.

Verify on the receiving side with HMAC, and design for rotation. If the package signs payloads, compute the signature over the raw request body — not over json_decode/json_encode, which reorders keys. Store two active secrets per endpoint so you can rotate without dropping in-flight deliveries:

foreach ($endpoint->secrets as $secret) {
    if (hash_equals(hash_hmac('sha256', $raw, $secret), $header)) {
        return true;
    }
}

Fire after commit. If your events are dispatched inside a DB transaction, the receiver can be told about an order that then rolls back. Add $afterCommit = true on the event class or dispatch from an DB::afterCommit() callback.

Model the payload explicitly. Don't serialize whole models. Build a small toWebhookPayload(): array (or a dedicated Resource class) per event type so adding a column never accidentally leaks a password or remember_token to a customer's server.

Tenancy/authorization. In a multi-tenant panel, scope the webhook resource query by tenant_id and register a policy on the endpoint model. Outbound URL creation is a privilege — treat create permission on webhooks as equivalent to manage integrations, not as a normal editor right.

Testing without the network. Two patterns, both cheap:

Queue::fake();     // assert the job was queued with the right event
Http::fake();      // or let it run and assert the outbound request shape

Prefer Http::fake() at least once per event type — it catches payload keys you renamed and forgot to update.

Localization (new in 3.1.0). Set app.locale to one of the 18 supported locales and the resource labels, form fields, and status strings follow automatically. To override a string without forking the package, publish the translation files using the package's lang tag and edit only the keys you care about; missing keys fall back to en, so partial overrides are safe. If you maintain custom locales, keep your keys aligned with the shipped en file when you upgrade.

Extension points worth checking before you patch vendor code. Filament plugin ecosystems usually expose the resource/navigation registration on the plugin object (navigation group, icon, slug, ->authorize()), and the config file typically lets you swap the endpoint model or the job class. Subclass and re-register rather than editing published files.

Gotchas and Tips

  • No queue worker, no webhooks. The single most common "bug" is a stopped worker or a job dispatched to a queue name the worker isn't listening on. Run queue:work --queue=default,webhooks or give webhooks their own supervisor process.
  • Config cache. After changing the plugin config or registering it in a new panel, run php artisan optimize:clear. Filament plugins that appear "missing" in production are usually a stale cached panel config.
  • filament:optimize order matters in deploy scripts — clear cached components before the new config is cached, or the resource list can drift from the code.
  • Timeouts must be shorter than your retry budget. A 60s timeout with 3 retries means a flapping endpoint ties up a worker for three minutes. Set an explicit, short HTTP timeout in config.
  • Retries need idempotency on the receiver. The package will retry on 5xx and timeouts; your receiver must tolerate duplicates. Send a delivery/UUID header and have consumers dedupe on it. Never retry on 4xx.
  • SSRF is a real risk with user-supplied URLs. If panel users can enter arbitrary endpoints, block private ranges (127.0.0.0/8, 10/8, 172.16/12, 192.168/16, 169.254/16, ::1) at validation time. Otherwise a low-privileged panel user can probe your internal network from your app server.
  • Secrets in the database are plaintext unless cast. Check whether the endpoint model uses encrypted casts for the secret column, and grep your payload/response logs — the panel stores response bodies, so anything sensitive the receiver echoes back is now in your DB and visible to panel users with the right policy.
  • Response bodies can be huge. Truncate before persisting; a receiver returning an HTML error page will bloat delivery rows fast. Add a pruning/retention command (model:prune on deliveries older than N days) from day one.
  • Debugging order: (1) is there a delivery row at all? no → dispatch/queue problem; (2) does it show attempts = 0? no → job never ran, check failed_jobs and worker logs; (3) got a status code? → the problem is on the receiver. The delivery log is the whole debugger; don't reach for Log::info before reading it.
  • Local development receivers need a public URL. Use a tunnel (expose, ngrok) or Http::fake() in tests — don't disable TLS verification on the endpoint to "make it work"; the package's HTTP client config should not be a place to relax verify.
  • Upgrading to 3.1.0 is safe from a code standpoint — it is a translations-only feature release plus docs/CI housekeeping, with no migrations, no config key changes, and no breaking API changes. If you have a cached config or cached views in production, php artisan optimize:clear after composer install; otherwise upgrade cost is zero. If you forked or overrode the package's English lang files, re-check for key additions before deploying so your overrides stay complete.
  • Watch the 3.x → 4.x line. This plugin targets Filament 3.x; if your panel is on Filament 4, confirm compatibility in composer.json constraints before adopting, since Filament v4 moved several plugin registration APIs.
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.
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode
jjsquady/round-robin