Common Questions

Handle Duplicate Webhook Events

Handle duplicate webhook delivery with durable event tracking and idempotent effects, including the crash window between processing and acknowledgment.

·3 min read
Repeated webhook deliveries handled with an event record and a single committed business change.
Illustrative diagram. Follow the checks in the guide for your own environment.

The essentials

  • Webhook delivery can be repeated.
  • A sender may retry after a timeout even when your application already processed the event.
On this page

Webhook delivery can be repeated. A sender may retry after a timeout even when your application already processed the event. Make duplicate handling part of the receiver's design rather than assuming one HTTP delivery equals one business action.

Distinguish delivery from the underlying event

Log the provider event identifier, event type, relevant object identifier and your processing status. Do not log full sensitive payloads unless your retention and access policy requires them.

Stripe's webhook documentation explicitly discusses duplicate events and retry behavior. Other providers have their own contracts, so check the one you use.

Two deliveries with the same event ID and two distinct events about the same object require different reasoning. The latter may be legitimate state changes.

Use durable, atomic deduplication

An in-memory set disappears on restart and may not be shared across workers. Store event handling state durably with a uniqueness constraint scoped to the provider and event identity.

Use an atomic insert or equivalent claim operation. A separate “check, then insert” sequence can race when two workers receive the event together.

Suggested states are received, processing, completed and failed, with enough information to retry safely. Do not mark completion before the required work is durably recorded.

Handle the difficult crash window

Suppose your worker sends an external notification and crashes before marking the event completed. Reprocessing can send it twice.

Where possible, use an idempotency key supported by the external service. For database-driven workflows, a transactional outbox can record intended work alongside the state change, followed by a controlled dispatcher.

These are architectural patterns, not a promise of exactly-once behavior across arbitrary services. Define which effect must happen once and how you will reconcile uncertain outcomes.

Acknowledge at the right point

Verify authenticity using the provider's documented procedure. Persist accepted work durably, then respond within the provider's timing requirements. Move slow processing out of the request path when appropriate.

Do not return success before durable acceptance if a crash would lose the event. Conversely, doing every slow task synchronously can trigger avoidable redelivery.

Test failure, not just success

Send the same fixture twice, send it concurrently and simulate a worker restart between state changes. Verify one intended business effect and an inspectable processing history.

Use the provider's test environment and harmless actions. Keep the expected state transitions with the fixture.

For AI agent workflows, deduplicate the event that starts the agent before paying for a second run. The model should not be responsible for deciding whether the triggering event was already processed.

This guide draws on the linked documentation. Examples are illustrative unless explicitly identified as measured results.

L

Practical guides published by Lucivo, developed with AI assistance and references to official documentation. Examples are illustrative unless a guide explicitly documents a hands-on test. Check the linked sources for current product details.

Related articles

The Weekly Breakdown

High signal AI & software stories.
Direct to your inbox. No hype.

Independent analysis of AI models, developer tools, and computing architectures. Delivered every Sunday morning. 100% free.

Zero spam·One-click unsubscribe·Sunday delivery