A webhook is a message about an event, not proof that a business action has happened exactly once. The sender may retry delivery, messages may arrive in an unexpected order, and your receiver may stop after accepting an event but before finishing its work. A reliable design treats those possibilities as ordinary conditions to handle.

Consider a fictional document service that receives a notification when a batch finishes. Its receiver needs to record the event, reconcile the batch result, and notify an internal reviewer. This guide separates those responsibilities so a repeated notification does not create duplicate review tasks and a temporary worker failure does not cause the event to disappear.

Read the sender's contract first

Determine what the sender actually promises about event identity, retries, ordering, authentication, and retention. Different services make different commitments. Do not apply an assumption learned from one provider to every webhook integration.

Stripe's webhook documentation discusses signature verification, duplicate events, event ordering, and returning a successful response promptly. Those are provider-specific instructions, but they illustrate the categories of behavior a receiving team should investigate for any sender.

For the document example, write down which field identifies the delivery event and which field identifies the completed batch. They serve different purposes. Two events might concern the same batch, and a later batch update might be legitimate new information rather than a duplicate to discard.

Verify receipt before trusting the payload

Use the sender's documented verification method and preserve the representation it requires. Some signature schemes depend on the raw request bytes, so parsing and reserializing the body before verification may change what is being checked. Use the supported verification library when appropriate.

Apply request size limits and reject unsupported content before allowing it to consume unbounded resources. Keep endpoint secrets outside source code and broad logs. Plan rotation so a legitimate sender can transition credentials without forcing an undocumented outage.

Verification establishes that a message meets the sender's authenticity checks; it does not authorize every action described by arbitrary fields in the body. Validate the event type and relevant account context against the integration's configuration before scheduling business work. Treat unexpected event types as explicit cases rather than guessing what they should trigger.

Make acceptance durable and narrowly scoped

Store an accepted event in a durable inbox or equivalent record before acknowledging the acceptance that your receiver contract promises. Capture its identity, relevant payload reference, receipt time, and processing status. Keep storage and access consistent with the data's sensitivity.

Separate this acceptance step from lengthy work such as downloading artifacts or generating a review package. Once durable acceptance succeeds, a worker can process the event according to the receiver's design. If durable storage fails, do not respond as though the event has safely entered your system.

The acknowledgement should not mean that all business effects are finished unless that is genuinely the contract. This distinction lets the sender stop retrying receipt while your system independently manages the accepted work. It also gives operators a visible record to inspect when processing later stalls.

Deduplicate delivery without erasing business updates

Use an atomic uniqueness rule for the appropriate event identity. Two receiver instances can see the same event at nearly the same time, so a separate check followed by an unprotected insert may race. The chosen persistence mechanism must support the coordination your implementation requires.

Store what happened to the accepted event rather than merely remembering that an identifier was seen. If an earlier attempt is still processing or failed after acceptance, a duplicate delivery should not make the underlying work vanish. Delivery deduplication and processing recovery are related but distinct responsibilities.

In the example, a batch-completed event creates one reconciliation task under its event identity. A later batch-corrected event is not automatically a duplicate. The business logic checks the batch version and determines whether a new review task or an update to an existing task is appropriate.

Give side effects their own operation identity

After reading the event, the worker may create a review task in another service. Use a stable operation identity for that intended effect where the destination supports one. Persist the destination reference and accepted result so the system can recognize a repeated attempt.

A crash after the destination accepts the task but before the local record is saved creates an ambiguous outcome. Simply retrying the request may duplicate the task. Plan a reconciliation method that can determine whether the intended task already exists, or use the destination's documented idempotency contract.

Do not describe the whole pipeline as exactly once merely because the inbox has a unique constraint. The guarantee must cover every relevant side-effect boundary. The process automation guide uses this distinction to keep durable workflow state separate from assumptions about downstream execution.

Handle ordering through state and versions

Avoid assuming that delivery order is the same as business order. Compare an event's version or relevant state against the record already accepted by your application. Where necessary and permitted, retrieve the current authoritative object from the sender before applying a transition.

For the document example, a late notification about an older batch version should not overwrite a newer accepted review result. Preserve the late event in the history with a reason for its disposition. That gives operators an explanation without reverting the business object.

Define how deletion, cancellation, and correction interact with completion. These cases often reveal hidden ordering assumptions. A canceled batch might still have partial artifacts, and a completion message might arrive after the cancellation notification. The correct response depends on the business contract, not on whichever event the receiver happened to process last.

Bound retries and make failures actionable

Classify failures before retrying. A temporarily unavailable artifact store may justify another attempt. A missing required identifier or a denied account relationship may need a corrected integration. Keep permanent validation errors out of an automatic loop that cannot repair them.

Use attempt limits, elapsed-time limits, and a schedule that avoids repeatedly overwhelming an unavailable dependency. Persist the attempt history and next eligible time. A process restart should not reset an exhausted task into an unlimited new retry cycle.

Move unresolved items to a visible needs-attention state with an owner and repair instructions. Include the last known safe point and whether a side effect may already have occurred. An operator should not need to choose blindly between losing the work and duplicating an action.

Test the awkward boundaries deliberately

Send the same signed test event twice. Deliver two relevant events in reverse order. Stop the worker before and after creating the review task. Make the destination accept a request while withholding the response. Test what happens when the receiver's durable storage is unavailable.

For each case, specify the expected business outcome in advance. Inspect both the event record and the downstream review task. Passing an endpoint health check does not demonstrate that the full delivery and side-effect lifecycle behaves correctly under interruption.

Keep replay tools controlled and auditable. An authorized replay should preserve the original event context while recording the new processing attempt. The job lifecycle reference provides a compact model for distinguishing queued, running, failed, and completed work without rewriting history during repair.

Conclusion: repeated delivery should be uneventful

A resilient webhook workflow verifies the sender, stores acceptance durably, deduplicates at the appropriate identity, and coordinates business effects separately. It expects delayed, repeated, and interrupted work rather than treating those cases as exceptional surprises. When each boundary has a clear contract, retries become a recovery mechanism instead of a source of duplicate actions.