symfony/webhook
Part of the Symfony ecosystem, symfony/webhook eases both sending and consuming webhooks in PHP applications. It provides building blocks for dispatching outgoing webhooks and validating incoming ones, integrating cleanly with Symfony's event and HTTP components.
Build vs. buy on webhook plumbing: The component gives you two reusable primitives — inbound RequestParserInterface implementations (with signature verification and payload normalization) and outbound transports/endpoints — that would otherwise be bespoke code in every integration. A PM decision to "standardize webhook handling" rather than "write per-provider handlers" is exactly what this package supports. Note this is a Symfony component consumed inside Laravel, not a Laravel package: Illuminate\Http\Request extends Symfony\Component\HttpFoundation\Request, so the bridge is real but must be documented once by us.
Roadmap sequencing for event-driven features: If the roadmap contains "real-time order updates," "payment status sync," or "marketplace event bus," this component front-loads the commodity work (HMAC verification, payload parsing, retry-aware delivery) so engineering time lands on business logic. That can move a first integration from a multi-sprint effort to a spike plus a parser class — for a single, well-understood provider (Stripe, GitHub, Slack).
Scope discipline on in-house webhook infrastructure: Choosing this explicitly says "we will not own a webhook framework." That is a defensible product bet because the component is maintained in lockstep with Symfony (it ships as part of the symfony/symfony monorepo, split out for standalone install), so security fixes arrive on Symfony's release cadence rather than ours. The trade-off is that we adopt Symfony's abstractions and versioning policy.
Use cases that fit well: inbound signature-verified receivers for a known set of providers; internal service-to-service event notifications where both ends are ours (so payload schema is under our control); fan-out of domain events to customer-configured endpoints where a transport abstraction pays for itself once there are 3+ endpoint types; and Messenger-queued consumption, which maps cleanly onto Laravel queues/Horizon.
Use cases that do not differentiate: one-off webhook receivers (a controller with hash_hmac is ~20 lines and cheaper to own), high-volume ingestion needing per-tenant rate limiting or replay windows, or anything requiring provider-specific verification schemes that no existing parser covers — you would be writing the parser anyway, so the component only saves you the dispatch scaffolding.
Decision-grade caveat on the adoption signal: 56 stars and 0 listed dependents reflect a split-repository artifact, not real usage — most consumers install symfony/webhook transitively or use the monorepo, and the dependency graph does not capture that. Do not read this as low adoption; also do not read Symfony's brand as proof of fit for Laravel. The honest signal is: mature release history (6.3 → 8.1), thin README, documentation hosted externally, and changelogs that are mostly "no significant changes" (expected for a stable component). Treat the 2026-09-15 release date as a metadata artifact and verify the real pin during the spike.
Explicit non-goal: this is not a webhook product (no delivery dashboard, no replay UI, no per-endpoint observability, no secret rotation UX). If the roadmap promises customers "manage your webhook endpoints," this component is the engine under that feature, not the feature. Budget separately for the admin surface, retry visibility, and dead-letter handling.
Adopt when:
RemoteEvents.Look elsewhere when:
hash_hmac with hash_equals is less code, fewer abstractions, and easier for a Laravel-only team to maintain. Adopting a framework component for a single receiver is resume-driven, not product-driven.composer update.Gate before committing: run a spike on one real provider, measure the parser code volume honestly, and confirm the Symfony version constraint resolves against the actual Laravel/Symfony matrix in composer.lock. If the spike produces more glue than business logic, stop.
Executive summary. We have recurring webhook work on the roadmap — payment confirmations, status syncs, customer-configured event endpoints — and today each one is rebuilt from scratch, including the security-sensitive parts. This component is Symfony's maintained implementation of that plumbing: it verifies inbound signatures, normalizes payloads, and dispatches events, and it plugs into our existing queue infrastructure. The recommendation is a contained pilot on one high-value integration, not an org-wide standard, with a go/no-go on measured effort.
Why now, in business terms.
hash_equals-style verification and idempotency hooks is materially safer than per-provider hand-rolling, and it is auditable.For engineering. Treat it as scaffolding, not a framework. Inbound: bridge the request, select a parser, verify the signature, map to a RemoteEvent, dispatch onto the queue. Outbound: define transports and endpoints instead of scattering Http::post calls, so retry semantics live in one place. It is decoupled from Serializer as of 7.2, so your existing validation and casting stay intact. Concrete costs to plan for: pin the 7.x branch explicitly (v8 requires PHP 8.4), write the Laravel Request bridge helper once, and write the parser for our first provider — that parser is the pilot's real deliverable, and it is reusable regardless of whether we keep the component.
For security and compliance. Default posture improves: signature verification is a first-class concept rather than an afterthought, malformed payloads are rejected at the parser boundary, and idempotency keys protect financial and provisioning flows from duplicate processing. Two requirements come with adoption and must be owned: secret storage (config/Vault, with rotation) and network-level controls (IP allowlisting where the provider publishes ranges). Neither is provided by the package — say so plainly rather than implying the component covers them. Also note the component gives us hooks, not an audit log; we log webhook receipt ourselves.
Decision requested. Approve a two-week spike on a single integration, with success defined as: parser shipped and tested, version constraints resolved in composer.lock, and a written comparison of glue code written vs. glue code avoided. If the spike shows more bridging than business logic, we drop it and keep the parser.
How can I help you explore Laravel packages today?