To make an n8n webhook idempotent, identify the intended event, claim it atomically and record whether its business action actually completed. A separate 'check if seen, then create' sequence can race. A permanent seen flag can also discard unfinished work after a crash. Design duplicate suppression and recovery together.
The example below receives a fictional lead event and creates a CRM record. It is a provider-neutral design exercise, not a ready-to-import workflow or a guarantee of exactly-once processing. The destination's own deduplication and lookup capabilities determine how safely you can recover an uncertain result.
Key takeaways
- Use a stable event identity that survives delivery retries.
- Let one atomic operation decide which worker owns processing.
- Distinguish receipt, work in progress, completed work and uncertain outcome.
- Reconcile a remote result before retrying a consequential create.
Identify the event and the business action separately
Suppose a form service sends event lead-147 to your webhook. Its retry still represents lead-147, even though n8n assigns another execution to the new delivery. The n8n execution ID identifies an attempt; it does not identify the original event.
Read the sender's documentation and verify which identifier is stable across retries. Scope it to the source and, where relevant, the customer or account. A local inbox key might represent source, account and event ID. Do not assume that a timestamp or a changing request signature is a reliable event identity.
Also identify the business action: create the CRM lead for this particular submission. Two distinct provider events can sometimes describe the same business action, while two similar-looking submissions may be intentionally separate. Decide those rules from the sender's event model and your product requirements; deduplicating by email alone could discard a legitimate second inquiry.
Persist receipt and use an atomic claim
A read-then-write approach leaves a gap: two workers can both observe that an event is absent before either writes it. Use a durable store with an appropriate unique constraint and an atomic operation to establish one record for the event. PostgreSQL documents INSERT conflict handling for this purpose at the database-operation level.
That database guarantee does not extend automatically to the later CRM request. Store the event's processing state and the result reference as separate facts. A worker should obtain a controlled processing claim; another delivery should inspect the existing record rather than blindly trigger another create.
For a durable-inbox design, acknowledge the sender after verified receipt has been persisted, then process the accepted work. If persistence fails, the response should follow the sender's documented retry contract. Returning success before durable receipt can leave no reliable path to recover a lost event.
| State | Meaning | Repeated delivery or recovery |
|---|---|---|
| Received | The validated event is stored; action has not completed. | Ensure one controlled processing claim is scheduled. |
| Processing | A worker owns a recorded claim. | Avoid competing work; investigate an expired or stuck claim. |
| Completed | The destination result is confirmed and referenced. | Return the appropriate acknowledgment without repeating creation. |
| Retryable failure | A failure is known and the next attempt is safe under the contract. | Retry with bounded policy and retained event identity. |
| Outcome uncertain | The destination may have created the record, but no receipt was retained. | Look up or reconcile the result before another creation attempt. |
| Needs review | The input or result needs a human decision. | Preserve the event and route it to the named operator. |
Walk through the two crash windows
First, the worker claims lead-147 and stops before calling the CRM. A permanent processed flag would cause every later delivery to be discarded, leaving no CRM lead. The recorded state should instead show unfinished work and permit controlled recovery.
Second, the CRM creates the lead but the worker loses the response before saving the CRM record ID. Repeating the create without checking can produce a duplicate. Use the destination's supported idempotency mechanism where available, or reconcile using a unique external reference that the destination reliably supports. If neither is possible, route the uncertainty for review rather than claiming an exactly-once guarantee.
If claims expire, prevent an old worker from continuing consequential work after another worker takes ownership. The implementation may need versioned claims or another concurrency control suited to the destination. A timeout on a claim alone does not prove the previous worker has stopped.
Can your integration recover an uncertain result?
Bring the sender, destination and intended side effect. We can scope event identity, durable state and an operator recovery path.
Keep enough history for the sender's retry behavior
Choose the inbox retention window from the sender's documented redelivery behavior, manual replay requirements and your operating policy. A convenient short expiry can allow an old retry to appear new after its record disappears. Keeping every payload forever creates a different data-management problem.
Retain the minimum information needed to identify the event and its outcome, with access and retention appropriate to the data. A record identifier and processing receipt may be enough after the full payload is no longer needed. Keep personal data out of routine alert messages.
Separate validation failures from transient dependency failures. An invalid input or an unauthorized request usually needs correction, not unlimited retries. Set an owner for the exception path and record why the workflow stopped.
Verify records across repeated and concurrent deliveries
In a test environment, deliver the same synthetic event twice, then concurrently. Confirm one intended CRM record and an understandable inbox history. Next stop the worker after its claim, and separately simulate a lost response after destination creation. Observe the recovery result in both systems.
Send a genuinely new submission from the same email address too. It should follow the product's intended rule rather than disappear because it resembles an earlier request. Finally, replay an older event after the proposed retention boundary and document the behavior.
Use those observations to approve the workflow. If a destination cannot reliably reconcile a create, disclose that limit and choose an operator path or a different integration boundary. MUBBITS can help implement the durable event record and recovery contract around the systems you already use.
Duplicate-event acceptance request
Use when commissioning or reviewing a webhook workflow.
For [sender] to [destination], identify the stable event ID, business uniqueness rule, durable receipt, atomic processing claim and confirmed outcome reference. Demonstrate repeated and concurrent delivery, a crash before the action, a lost response after the action and a distinct new event with similar data. Document any destination limitation and the operator recovery path.Frequently asked questions
Can we use the n8n execution ID as the deduplication key?
It identifies an execution attempt. A retry may start another execution for the same original event, so use the sender's stable event identity or another explicitly defined business key.
Why is a seen flag insufficient?
It does not distinguish completed work from an interrupted attempt. A crash after setting the flag may cause retries to be blocked even though the business action never completed.
Does this guarantee exactly-once side effects?
No. The durable inbox and atomic claim protect particular boundaries. A remote action also needs supported idempotency or reliable reconciliation; otherwise uncertain outcomes need an explicit recovery limit or review path.
Let’s work through your next step.
Tell us what you’re building, what you’ve tried, and where you need a hand. We’ll work with you to define a practical way forward.

