A payment provider needs to tell your application the moment a payment succeeds, fails, or gets disputed, often well after the original request that initiated it has finished. Webhooks solve this by having the third-party service make an HTTP request to an endpoint you provide whenever a relevant event occurs, inverting the usual direction of communication.
Verifying Webhook Signatures
Any endpoint publicly reachable on the internet, which a webhook receiver necessarily is, can be hit by anyone, not just the legitimate provider. Verifying a cryptographic signature included in the request headers, computed by the provider using a shared secret, confirms the request genuinely originated from that provider and was not forged or tampered with in transit.
$payload = $request->getContent();
$signature = $request->header('Stripe-Signature');
try {
$event = StripeWebhook::constructEvent($payload, $signature, $endpointSecret);
} catch (Exception $e) {
return response('Invalid signature', 400);
}Responding Quickly and Processing Asynchronously
Most webhook providers expect a response within a short timeout window and will retry the request if it does not get a fast 200 OK, which can result in duplicate event delivery if your processing logic is slow. Returning a fast acknowledgment immediately, then queuing the actual processing work as a background job, avoids both the timeout-retry problem and any risk of a slow downstream operation blocking the provider's own systems.
Designing for Idempotency
Because providers may deliver the same event more than once (a retry after a slow response, a network hiccup), webhook handlers need to be idempotent — processing the same event twice should produce the same end result as processing it once. Recording processed event IDs and checking for that ID before processing again is the standard, reliable way to achieve this.
Logging Webhook Payloads for Debugging
A webhook that silently fails to process correctly, with no record of what was actually received, leaves you debugging blind when a customer reports a payment that never updated their account. Logging every received webhook payload, even just to a dedicated table, before attempting to process it, gives you a concrete record to inspect after the fact regardless of whether processing succeeded.
Handling Out-of-Order Delivery
Webhooks are not guaranteed to arrive in the same order the underlying events occurred, particularly across retries and provider-side queuing delays. Designing handlers to check the current state before applying an update, rather than assuming events always arrive in a strict chronological sequence, avoids a late-arriving older event accidentally overwriting a more recent, correct state.
Local Development and Testing Webhooks
A webhook provider needs a publicly reachable URL to deliver events to, which a local development machine behind a router and firewall does not naturally have. Tunneling tools (ngrok and similar) expose a local server temporarily through a public URL, letting you receive and debug real webhook deliveries during development without deploying to a public server first.
Webhook Retry Behavior and Exponential Backoff
Most providers retry failed webhook deliveries (a non-2xx response, a timeout) using exponential backoff, spacing retries further apart over time, and eventually give up after a defined number of attempts or time window. Understanding your specific provider's retry schedule and final-failure behavior matters for deciding whether you need your own dead-letter handling for events that never successfully deliver.
Case Study: The Duplicate-Charge Bug From Unhandled Webhook Retries
An e-commerce platform processed payment-success webhooks by directly crediting a customer's order balance each time the webhook fired, with no check for whether that specific event had already been processed. During a period of elevated latency, a payment provider retried several webhook deliveries after timeouts that had actually succeeded server-side just slowly, and the platform credited some orders twice, double-fulfilling them. The fix was straightforward once diagnosed: record each processed event's unique ID and skip processing if that ID had already been seen, making the handler properly idempotent.
A Glossary for This Topic
Webhook — an HTTP callback a third-party service makes to your endpoint when an event occurs. Signature verification — cryptographically confirming a webhook genuinely originated from the claimed provider. Idempotency — the property that processing the same event multiple times produces the same result as once. Dead-letter handling — a fallback process for events that fail all delivery/processing attempts. Exponential backoff — a retry strategy spacing attempts progressively further apart.
Frequently Asked Questions
Should I always verify webhook signatures? Yes, without exception, since an unverified webhook endpoint can be triggered by anyone who finds the URL. What status code should a webhook handler return? A 2xx status as soon as the event is safely queued, not after full processing completes. How long should I keep records of processed event IDs? At least as long as the provider's documented retry window, with some safety margin beyond that.
Step-by-Step: Building a Reliable Webhook Receiver
Create a dedicated route and controller for the webhook endpoint, excluded from CSRF protection since the request originates from a third party with no session. Verify the signature header against the raw request body before parsing anything as JSON. Log the raw payload and signature verification result for debugging. Check the event ID against a table of already-processed events; skip if already seen. Queue the actual business logic as a background job and return a 200 response immediately. Process the queued job, updating application state and marking the event ID as processed.
A Comparison Table: Webhook vs Polling
Webhooks: near-instant notification, requires a publicly reachable endpoint, more efficient for the provider. Polling: works behind any firewall, introduces delay equal to the polling interval, wastes requests checking for nothing new. Webhooks with polling fallback: most resilient, most complex to implement, recommended for critical integrations.
Security Considerations Checklist
Always verify signatures using the raw, unparsed request body, since parsing and re-serializing JSON before verification can alter byte-for-byte content in ways that break signature validation. Never expose internal error details in the webhook response, since that response may be logged or inspected by infrastructure outside your control. Restrict webhook endpoints to expected source IP ranges where the provider publishes them, as an additional layer beyond signature verification.
Accessibility Considerations
Webhooks have no direct accessibility dimension as a server-to-server mechanism, but any admin-facing webhook log or status dashboard built around them should follow standard accessible-table and status-indicator practices for the team members who rely on it.
How This Plays Out at Different Scales
A small integration can process a webhook synchronously within the request if processing is genuinely fast and simple. A growing application needs the queue-and-acknowledge pattern described earlier as standard practice. A large platform receiving high webhook volume typically needs dedicated infrastructure (a message queue, dead-letter handling, replay tooling) treating webhook ingestion as its own reliability-critical subsystem.
What to Do When You Inherit a Webhook Handler With No Idempotency Protection
Inheriting a webhook handler that directly applies state changes with no record of previously-processed event IDs is a duplicate-processing incident waiting to happen, exactly as shown in the case study above. Add an events table recording processed IDs before changing any existing handler logic, test that reprocessing a previously-seen event ID is now a safe no-op, and only then consider it production-safe.
Final Checklist Before Trusting a Webhook Integration
Signatures are verified against the raw request body before any parsing occurs. Processed event IDs are recorded and checked to guarantee idempotent handling. Heavy processing is queued, with a fast 2xx response returned immediately. Failed processing is logged with enough detail to debug without needing to reproduce the original event. Source IPs are restricted where the provider publishes a known range.
Closing Thought, Revisited
Webhooks invert the normal request direction, and that inversion is exactly where assumptions about "this will only happen once" tend to quietly break down, as the duplicate-charge case study shows. Idempotent-by-design handling is not a nice-to-have refinement here; it is the baseline correctness requirement for any handler accepting retryable third-party events.
Webhook Versioning as Providers Evolve Their Payloads
A provider updating their webhook payload format (adding fields, restructuring nested data) can break a handler written against an earlier, less flexible parsing assumption. Reading fields defensively, tolerating unexpected additional fields gracefully, and pinning to a specific documented API/webhook version where the provider supports it, reduces the chance of a provider-side change silently breaking your integration.
Replaying Webhooks for Recovery
Most providers offer a dashboard or API for manually replaying a specific past webhook event, valuable when your own processing failed due to a bug now fixed, or downtime that caused legitimate events to be missed entirely. Designing your idempotent processing logic to safely handle a replayed, already-old event is what makes this recovery mechanism actually usable without risking duplicate side effects.
Monitoring Webhook Health Over Time
A webhook integration that silently stops receiving expected events (a provider-side configuration change, an expired endpoint URL) can go unnoticed for a long time if nothing actively monitors for it. Alerting when expected event types haven't arrived within a normal time window, rather than only reacting to explicit error responses, catches this class of silent failure that error-rate monitoring alone would miss.
Webhook Endpoint URL Rotation
Occasionally rotating the webhook endpoint URL itself (alongside the shared secret used for signature verification) reduces the value of an old, possibly-leaked URL to an attacker, similar in spirit to credential rotation elsewhere in a system. This is a lower-priority hardening step compared to signature verification itself, but worth doing periodically for high-value integrations.
Webhook Testing Tools and Provider Dashboards
Most major providers offer a dashboard feature to send a test webhook event on demand, useful for verifying your endpoint is reachable and correctly configured without needing to trigger a real underlying event (an actual payment, an actual shipment) just to test the integration end to end.
Webhook Endpoint Versioning as Your Own API Evolves
If your application itself exposes webhooks to other developers (not just consumes them), version your webhook payload format deliberately and document breaking changes clearly, the same discipline expected of any public API, since the developers integrating with your webhooks face the exact same fragility concerns discussed earlier from the consumer side.