spatie/laravel-webhook-client
Receive webhooks in Laravel apps with signature verification, payload storage, and queued processing. Handle incoming HTTP calls securely and dispatch jobs so your app processes webhook events reliably.
Architecture fit. This is a narrow, opinionated inbound-webhook component rather than a webhook platform. It implements one pipeline: signature validation → profile filter → persist to webhook_calls → dispatch queued job → HTTP response. That maps cleanly onto any "third party calls us about an event" integration, and it deliberately enforces the right shape (fast 200, async processing, payload stored before processing) rather than leaving it to each team to get wrong. Fit is high if the receiving service is already Laravel with a working queue fleet. Fit is poor if we want a single polyglot webhook gateway: Route::webhooks, the Eloquent WebhookCall model, the config file, and the container-bound extension points make it Laravel-coupled by design.
Integration feasibility. Low effort, high leverage. Installation is three Artisan commands plus config, one route, and one job class. The extension seams — SignatureValidator, WebhookProfile, WebhookResponse, custom WebhookCall model, ProcessWebhookJob — cover most real customization without forking. Rough sizing: one to two developer-days for a first endpoint; per-provider validator work thereafter.
Technical risk.
sha256= prefix, form-encoded bodies). The default should be treated as a template, not a solution.InvalidWebhookSignatureEvent. 500 is retryable for most senders, so a rotated or misconfigured secret becomes a retry storm rather than a clean drop. Decide this intentionally.WebhookProfile hook is the only pre-persist interception point, so dedup must be custom-built.failed_jobs with no first-class reprocessing path.Key questions. Which providers, and what are their exact signing schemes? Peak and burst request volume? What idempotency guarantees does each event type need? What PII or retention constraints apply to stored payloads and headers? Do we need replay? Which queue driver and worker SLA? Which Laravel and PHP versions are in the estate? Is multi-tenant isolation required at the endpoint, secret, or storage layer?
Stack fit. Native for a Laravel service: works against MySQL/Postgres (JSON payload column), any Laravel queue backend (Redis, SQS, database), and Horizon for visibility. Does not fit if intake is standardized outside PHP — adopting it there would make one service's webhook handling inconsistent with the rest.
Migration path. If teams currently hand-roll webhook controllers, migrate one provider at a time. Stand the new endpoint up alongside the old one behind a flag, dual-deliver for a short window, and diff persisted payloads against the legacy path before cutting over. This is the cheapest way to prove validator correctness against real traffic.
Compatibility. Pin to a release whose Laravel and PHP constraints match our estate, and whose published migration fits our migration conventions (table naming, ID strategy, JSON column support on the target DB driver). Verify against our exact framework version, not just latest.
Sequencing.
SignatureValidator — assume the default is insufficient until proven otherwise.WebhookProfile for dedup and event filtering.ProcessWebhookJob; keep it short, idempotent, and delegating to domain services rather than containing business logic.configs array — multi-endpoint support is config-only and cheap once the first path is proven.Maintenance. Small code surface, real ongoing ownership. The config file is per-endpoint and will accumulate provider quirks. Every new provider means a validator, a job, and a config entry — budget incremental effort per integration, not a one-time cost. Spatie ships frequently; maintain a dependency-update cadence backed by tests that cover signature validation and job dispatch.
Support. Community only — GitHub issues, no SLA. If webhook intake is revenue-critical, that gap must be absorbed internally: a named owner, documented signing schemes per provider, and a runbook for "webhooks are failing."
Scaling. Ingest itself is cheap — validate, insert, dispatch, return 200. The bottleneck is the worker pool, not the endpoint. Persisted volume is the real cost driver: every call is a row, plus full payload, plus headers if store_headers is *. The default delete_after_days of 30 caps growth, but retention trades off against replay and audit needs and should be an explicit decision. At high volume, plan indexing discipline on webhook_calls and consider a dedicated connection.
Failure modes. None of these are alerted by default:
WebhookCall, request still returns 200 → silent loss.failed_jobs, no automatic replay.Each needs a deliberate monitoring decision before go-live.
Ramp-up. A mid-level Laravel developer can ship the first endpoint in a day from the README. The harder work — dedup, replay posture, retention, alerting — is exactly what the README does not cover, and where a TPM should set the definition of done. Recommended rollout: treat the first integration as a pilot with full observability, then templatize it (config snippet, validator base class, job scaffold, alert set) so subsequent providers are a repeatable pattern rather than a fresh design exercise.
How can I help you explore Laravel packages today?