Practical guide

Why automation retries create duplicates and how to prevent them

Handle retries without repeating a completed action. Learn stable IDs, unknown outcomes and a recovery decision tree for tasks, records and notifications.

Person using a laptop while seated in an office
Illustrative photograph: Campaign Creators / Unsplash.

Your system sends a request to create a task. The destination saves it, but the reply is interrupted. Retrying the same request can create a second task. The practical question is whether the first action happened.

Give the intended action a stable identity

Keep the source record ID and destination record ID together. For a proposed enquiry-to-task workflow, a key could combine the source system, enquiry ID and action type. Use a new version only when your update rules call for a distinct action. An email address alone is usually a poor identity: one customer can submit several legitimate enquiries.

Some APIs support idempotency keys or unique constraints. Others require a lookup and a durable record of completed actions. Check the actual destination’s guarantees; a search followed by a write can still race if two executions run together.

Server hardware inside a data-centre rack
Illustrative stock photograph, not evidence of our project: Kvistholt Photography / Unsplash.

Use a three-way recovery decision

Observed stateNext action
Confirmed successSave the result ID; do not create again
Confirmed failure before writeFollow the agreed retry policy
Unknown outcomeInspect destination using the stable key; review if unresolved

“No response” belongs in the third row until evidence resolves it. A timeout is a transport observation, not a business-state conclusion. For customer-facing actions with weak lookup support, retain an explicit review state instead of blindly repeating.

Recover without creating twice: Receive a stable ID; Look up the destination; Choose one route; Verify and record
Recover without creating twice
Original illustrative guide: Set It Once. A timeout can occur after the destination has already saved the record.
Read the text version
  1. Receive a stable ID. Keep the same ID on every retry.
  2. Look up the destination. Does the corresponding record exist?
  3. Choose one route. Reuse the record or create it once.
  4. Verify and record. Retain the destination ID and outcome.

Decide what a changed record means

A repeat event and a changed source record are different. If a customer corrects a phone number, your policy may update the original task. If they send a new enquiry, your policy may create a new task. Write that distinction before choosing a duplicate-removal feature.

Asana documents webhook event handling. A workflow responding to those events still needs its own policy for repeated delivery, record changes and execution history. Event delivery alone does not provide end-to-end exactly-once execution.

Test interruption and concurrent execution

  1. Send the same source event twice.
  2. Send a legitimate second enquiry from the same email.
  3. Update the first source record.
  4. In a controlled environment, run two handlers for the same key.
  5. Simulate missing confirmation and inspect the destination before recovery.

Record how many destination records exist and why. Confirmed duplicates should be reconciled with care; do not delete records automatically without an agreed recovery policy.

If your software lacks stable IDs or lookup support, treat that as a design constraint. It may justify a custom adapter, a review queue or a simpler manual process.

Why “check, then create” can still create two records

Consider two workers receiving the same hypothetical event E-27 almost simultaneously. Both look for an existing task. Both see none. Both create one. The lookup was reasonable, but the separate lookup and write did not protect against concurrency. A delay between them does not establish correctness either.

The implementation needs a supported way to claim the intended action atomically, a destination uniqueness rule, or an API idempotency facility with understood scope. Which option is possible depends on the actual systems. A spreadsheet flag checked by two independent runs is not automatically a lock. Ask the implementer to demonstrate the simultaneous-event case rather than only replaying events one at a time.

Keep event identity and action identity separate

A source can send different events about the same record: created, edited and reassigned. Deduplicating only the delivery event prevents one repeated delivery, but may still create a new task for every edit. Conversely, treating every event for one customer as identical may suppress legitimate new enquiries.

For an illustrative design, identify the intended action by source enquiry E-27 plus the operation “create follow-up task”. Later corrections update that task under a separate version rule. Store the destination ID and current state: pending, confirmed, failed before write or unknown. A history of these decisions is more informative than a single “processed” checkbox.

Treat API idempotency as a documented contract

Some APIs accept an idempotency key. Stripe documents one such mechanism, but its retention and retry behaviour are specific to that API and version. Do not assume a header with the same name works on every destination, persists indefinitely or permits changing the original request parameters.

Read the destination’s supported behaviour, keep the key free of personal data and verify its lifetime against the recovery window. If the destination has no such facility, use an alternative supported design and document remaining limitations. After an uncertain write, the recovery question is still whether the intended effect already exists.

Test the same event twice, two concurrent deliveries, an edited source, a lost confirmation and a retry after the key-retention window. A design that passes only the first test can look reliable in a demo while still producing duplicates in production.

Technical reference: Stripe’s API-specific idempotency contract.

Take one practical next step

If this is a problem in your team, explore custom development. Describe one task, the software you use and the result you need. Scope and terms are agreed before work begins.

Sources and further reading

Quick answers

Frequently asked questions

Can I deduplicate by email address?

Only if that matches the actual business rule. It can wrongly merge separate enquiries from the same customer.

Does retrying guarantee delivery?

No. It can also repeat an action. Check the destination's retry and idempotency behaviour.

What if I cannot tell whether the first write happened?

Keep the outcome unresolved and route it for inspection. Do not claim failure or success without evidence.

Martin Iliev, founder of Set It Once

About the author

Martin builds Set It Once to help people spend less time on repeated work. His guides explain what you can try, how to check the result and where the limits are.

More about Martin

All articles

Privacy & cookie notice

Privacy & cookies

Updated 5 October 2026. This notice covers the public Set It Once marketing website and its enquiry form.

Who is responsible?

Martin Iliev operates Set It Once and is responsible for the personal data collected through this website. For privacy questions or to exercise your rights, email miliev@setitonce.com or use the contact form. You do not need to provide a website address for a privacy request.

What we collect and why

When you send an enquiry, we receive your name, email address, optional website address and message. We use these to respond and take steps towards a possible service agreement at your request (GDPR Article 6(1)(b)). Security and abuse prevention rely on our legitimate interest in protecting the website (Article 6(1)(f)). The form temporarily uses a keyed hash of your IP address to limit repeated submissions for 60 seconds. Hosting infrastructure processes connection information such as IP addresses and requested URLs to deliver and protect the site.

There is no marketing subscription, sale of enquiry data or automated decision-making about you. Do not send passwords, API keys or sensitive client information.

Who can access the information?

Enquiries are stored in the private WordPress administration area and accessed by authorised administrators. Namecheap provides our website and email hosting and processes data to operate these services. Email addressed to miliev@setitonce.com is also forwarded to a Gmail account operated by Google so Martin can receive and handle correspondence. Their privacy notices explain their processing: Namecheap and Google. External links such as LinkedIn load only when you follow them; those websites have their own privacy notices.

International processing

Namecheap and Google may process information outside your country, including in the United States. Namecheap describes the contractual safeguards for covered services in its Data Processing Addendum. Google describes processing locations and safeguards in its Privacy Policy. Contact us if you need details about the processing of your enquiry.

How long we keep information

We retain enquiries while handling the request and necessary follow-up. We review enquiries after six months and remove closed enquiries that are no longer needed. Records required for an active service, a legal obligation or a legal claim may be retained for that purpose. This review covers WordPress records and related email copies; it is a manual review, not automatic deletion. Hosting logs and backups have separate retention arrangements with the provider. You can ask us for information about your particular record or request deletion.

Your rights

You may request access, correction, erasure, restriction, objection and portability where applicable. You may withdraw optional browser-storage consent through Privacy settings without affecting earlier lawful processing. We normally respond to rights requests within one month; legal exceptions may apply. You may complain to your local supervisory authority, including the Bulgarian Commission for Personal Data Protection.

Cookies and browser storage

Google Analytics 4 is optional and loads only after your explicit consent. It measures page visits and basic engagement, using browser/device information and an online identifier. Google processes the network address to provide the service; GA4 does not log or store individual IP addresses. We do not enable advertising features, Google Signals or automatic form tracking. Page URLs and referrers sent by this website exclude query strings and fragments; form contents are not sent. No third-party geolocation service is used. Fonts and images are hosted on this website. Necessary WordPress authentication and security cookies may be used when you sign in. These are separate from optional analytics and currency memory.

LocalStorage is browser storage rather than a cookie; the same preference controls cover it. Automatic currency suggestion uses your browser time zone locally. It is approximate and is not sent to a geolocation provider. If browser storage is unavailable, your choices apply only to the current page.

Online payment processing is not active on this page. Payment-provider information and purchase terms will be added before checkout is enabled.