Reliable webhooks are not built by assuming every event arrives once, in order, and on time. They are built by verifying the sender, acknowledging receipt quickly, processing asynchronously, making each operation safe to repeat, and giving failed events a visible recovery path.
A webhook endpoint is only the front door. The reliable system starts after the event crosses it.
This matters when a webhook creates an order, updates a customer record, starts an approval, provisions access, or moves financial data. A successful test proves the happy path. It does not prove the integration will behave correctly during timeouts, duplicate deliveries, provider outages, or malformed payloads.
Webhook reliability begins with the delivery contract
Before choosing infrastructure, document what the sending platform actually promises. Does it retry automatically? For how long? Can events arrive more than once? Is order guaranteed? Can an operator request redelivery?
Those answers vary. Stripe’s webhook documentation describes automatic retries in live mode, possible duplicate events, and delivery without an ordering guarantee. GitHub documents a different failure model: failed deliveries are not automatically redelivered, so recovery is manual or must be automated by the receiving team.
The safe general rule is to design as though duplicates, delays, and gaps can happen. Record provider-specific limits in the integration runbook instead of burying them in code or assuming one vendor behaves like another.
Verify first, then acknowledge quickly
A public endpoint should not trust a payload because it resembles the expected JSON. Validate the provider’s signature against the raw request body, enforce its replay protection, confirm the event type is accepted, and reject invalid requests before they trigger business actions.
Once the request is verified and safely recorded, return success quickly. Do not keep the sender waiting while your endpoint updates a CRM, calls an accounting platform, generates a document, and sends notifications. GitHub’s webhook guidance, for example, tells receivers to respond within ten seconds and recommends a queue for background processing.
This creates a clean boundary: the endpoint accepts a valid event; a worker performs the business process. Slow downstream systems no longer turn a valid delivery into an unnecessary sender retry.
Make every business action duplicate-safe
A duplicate event should not create a duplicate invoice, send the same customer email twice, or provision a second account. Store the provider’s event or delivery identifier before processing and place a uniqueness constraint around it. If it was already accepted, return success without repeating the work.
That check is necessary, but important operations should also be idempotent at the business layer. Use a stable operation key such as “fulfill order 1842” rather than “run fulfillment now.” Check the destination’s current state before writing. When a downstream API supports idempotency keys, send one derived from the business operation and preserve it across retries.
Why both layers? A worker can crash after the downstream system completes its work but before the local event is marked complete. The next attempt must recognize the business result, not merely the delivery record.
Use bounded retries, not endless loops
Retry failures likely to be temporary: connection timeouts, rate limits, or transient server errors. Space attempts with exponential backoff and jitter so a struggling service is not hit by every failed job at once.
Do not retry permanent failures forever. A missing required field, revoked credential, deleted destination record, or unsupported event type needs correction or a deliberate disposition. Classify errors, cap attempts, and preserve the original payload plus a sanitized error history.
Also decide where retry responsibility lives. Provider redelivery can help an event reach your endpoint. Your queue handles failures after acceptance. A downstream API may have its own retry policy. Without a written boundary, these layers can multiply attempts and make incidents harder to understand.
Give failed events a recovery queue and an owner
After the final automated attempt, move the event to a recovery queue instead of dropping it or leaving it in an undifferentiated log. Show the event type, business object, received time, attempt count, last error, next action, and owner.
Recovery should support three explicit outcomes: retry after correction, mark as safely resolved, or escalate for investigation. Replaying an event must use the same duplicate-safe path as the original attempt.
This is where engineering meets operations. As we explained in API Integrations Break When Nobody Owns the Process, a technically sound connection still fails the business when nobody owns exceptions. The queue makes that ownership concrete.
Measure outcomes, not endpoint uptime
A green health check does not tell you whether yesterday’s events completed. Track each event through distinct states: received, verified, accepted, processing, completed, retrying, and awaiting recovery.
- delivery volume and signature failures
- time from receipt to business completion
- duplicate rate and deduplication results
- retry count by provider, event type, and downstream service
- recovery-queue age and unresolved-event count
Alert on stalled outcomes and growing queue age, not every isolated retry. A transient failure may recover normally. An event that was accepted but did not complete within the business deadline needs attention.
Test failures before the workflow becomes critical
Exercise the receiver with duplicate deliveries, invalid signatures, out-of-order events, downstream timeouts, rate limits, expired credentials, worker restarts, and manual replay. Confirm that each scenario produces the intended state, metric, and operator action.
A practical readiness review should answer:
- Can we prove an event came from the expected sender?
- Can the same event or business action run twice without damage?
- Can we see every accepted event that has not completed?
- Can an operator recover one event without editing production data?
- Do we know which retry behavior belongs to the provider, our queue, and the downstream API?
Build the recovery path with the happy path
Webhook reliability is not a single setting. It is a chain of decisions that keeps one delivery problem from becoming a duplicate transaction, an invisible backlog, or a manual database repair.
If webhooks are becoming part of a critical workflow, Eckman Design can help map the delivery contract, duplicate-safe processing, monitoring, and operator recovery before the integration becomes expensive to untangle. Start a practical integration review.
Discussion
0 Comments