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

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.
Related troubleshooting
This guide draws on the linked documentation. Examples are illustrative unless explicitly identified as measured results.
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
AI Streaming Arrives All at Once Behind NGINX
API Key Committed to Git: What to Do Next
API Timeout: Is It Safe to Retry?
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.