Why are webhook events delivered more than once, and how should processing be made idempotent?
Assume webhook delivery can be at least once and that lost acknowledgements can create duplicates. Deduplicate before side effects using the provider's stable event ID, such as sg_event_id or svix-id. Pause non-idempotent downstream effects until repeated IDs are safely ignored.
First 15 minutes
- Compare duplicate SendGrid payloads by sg_event_id when that field is included.
- Check for non-2xx Event Webhook responses that trigger SendGrid retries for up to 24 hours.
- Compare Resend duplicates by svix-id and confirm already processed IDs are skipped.
Now
- Store and skip repeated sg_event_id or svix-id values before executing downstream side effects.
Next 24 hours
- Make event-ID persistence and the downstream side effect one idempotent processing path.
Next 7 days
- Use the provider event timestamp when application state depends on event order, because Resend does not guarantee delivery order.
Technical checks
Engineering
- Persist and deduplicate SendGrid sg_event_id values when included.
- Confirm the SendGrid endpoint returns a 2xx response for successful processing so non-2xx retry behavior is not triggered.
- Use the Resend created_at timestamp rather than arrival order when event order must be reconstructed.
Verification criteria
- Replay payloads with the same sg_event_id and confirm the downstream effect occurs once.
- Confirm successful SendGrid processing returns 2xx and no non-2xx retry sequence continues.
- Replay a stored Resend svix-id and confirm it is skipped as already processed.
Escalation criteria
- Escalate internally when a repeated sg_event_id is not skipped and executes a downstream side effect after local deduplication is enabled.
- After confirming a stored svix-id is skipped and the downstream side effect occurs once, treat further delivery of that ID as documented at-least-once behavior rather than an escalation condition.
Prevention
- Treat SendGrid sg_event_id as the deduplication key when included.
- Store Resend svix-id values and skip IDs already processed.
- Use created_at rather than arrival order where Resend event ordering matters.
Business impact
- At-least-once delivery can repeat downstream effects when a lost acknowledgement causes the provider to deliver the same event again.
Provider notes
- SendGrid retries Event Webhook POSTs after non-2xx responses at increasing intervals for up to 24 hours.
- Resend provides at-least-once delivery and does not guarantee delivery order.
Open questions
- Event-ID field names, retry schedules, replay tools and ordering guarantees vary by ESP and webhook product.
- Whether current duplicates share the same provider event ID or represent distinct upstream events requires payload and persistence inspection.
- The current handler's acknowledgement timing and atomicity relative to side effects are unknown until code and database transactions are reviewed.
Sources (4)
- Twilio SendGrid Event Webhook Overview — Duplicate eventsTwilio SendGrid
- Twilio SendGrid Event Webhook Overview — General troubleshootingTwilio SendGrid
- Managing Webhooks — FAQ: What are the delivery guarantees?Resend
- Managing Webhooks — FAQ: Do events arrive in order?Resend


