How to Stop an AI Agent From Creating Duplicate Records
A retried "create" call doesn't update an existing contact, ticket, or row — it makes a second one. Here's why that happens across CRMs, databases, and ticketing tools, and how Swytchcode prevents it.
Key takeaways
- -A "create contact" or "create ticket" call almost never checks whether a matching record already exists — call it twice and you get two separate records, not one updated one.
- -This shows up across CRMs, support/ticketing tools, and plain databases alike, because the underlying cause is the same: a create endpoint that was never built to recognize a repeat.
- -Some record-creation APIs support an upsert pattern keyed on an external ID, which turns a risky create into a safe repeat — but it has to be used deliberately, not assumed.
- -Swytchcode only auto-retries a create call when that method is actually safe to repeat, and surfaces the failure instead of guessing when it isn't.
- -Where no safe repeat mechanism exists, the fix is checking for an existing record before creating a new one — a lookup-then-create pattern instead of a blind create.
An agent is told to log a new contact, or open a support ticket, or add a row for a new order. It calls the "create" endpoint. The response is slow, or doesn't come back cleanly, and the agent — not knowing whether the first call actually landed — calls create again.
Now there are two contacts for the same person, two tickets for the same issue, or two rows for the same order. Nobody asked for a duplicate. The create endpoint just did exactly what create endpoints do: it created something, twice.
Why "create" is the riskiest verb in the API
Most create endpoints have no concept of "I've already seen this." They take whatever fields you send and make a new record from them, every single time, because that's literally the job of a create call. Nothing about the shape of the request tells the API this is a retry rather than a genuinely new contact, ticket, or row — unless you've specifically built it to notice.
This is the same problem that causes duplicate charges and duplicate emails, wearing a different hat. It shows up constantly in CRMs (a contact created twice from one webhook retry), ticketing tools (a support ticket opened twice for one email), and plain databases (an order row inserted twice from one checkout event) — anywhere an agent's job includes "add this if it doesn't already exist."
The upsert escape hatch — where it exists
Some record-creation APIs support an upsert: create the record if it doesn't exist, update it if it does, keyed on something stable like an external ID or an email address. Where that's available, it turns a risky create into something much closer to idempotent — call it five times with the same key and you still have one record, just updated in place. The catch is that it's not universal, and it's not automatic just because the provider offers it somewhere in its API. You have to actually use the upsert method rather than the plain create, and that's a deliberate choice, not a default behavior to assume.
How Swytchcode handles the ones that don't
Swytchcode applies the same rule to a create call as it does to any other write: it only retries automatically when an idempotency key is attached and the method is actually built to honor one. Where a create endpoint has no such guarantee — which is common — a failed or ambiguous response is surfaced as an error rather than silently retried into a second record. You find out there's a problem instead of finding out there are two contacts.
Setting it up
swy search <crm-or-ticketing-tool>
swy discover "find or create a contact" --project <tool>
swy info <tool>.<method>swy discover is worth running with the exact phrasing of the job, not just "create contact" — a lot of providers expose a separate find-or-create or upsert method sitting right next to the plain create one, and it only helps if you actually add the right one to the allowlist.
The pattern that works everywhere: look up before you create
When there's no upsert and no idempotency key, the reliable fix is a lookup-then-create pattern: search for a matching record first — by email, by order ID, by whatever field actually identifies "this is the same thing" — and only create if that search comes back empty. It costs one extra read before the write, which is a lot cheaper than cleaning up duplicate contacts in a CRM six months later.
A duplicate record is rarely a sign the agent made a bad decision — it's a sign the create call it was asked to repeat was never built to recognize a repeat. Reach for an upsert where the provider offers one, fall back to look-up-then-create where it doesn't, and let Swytchcode's default of not retrying an unprotected write catch the cases in between.
Related reading
- What Is API Idempotency? A Plain-English Guide. The underlying concept behind the upsert pattern described here.
- How to Connect HubSpot to Claude Code. A worked example for one CRM an agent might be creating contacts in.
- How to Connect Salesforce to Claude Code. The same pattern for a different CRM.
- How to Log Every API Call an AI Agent Makes. How you actually confirm whether a record was already created.
FAQ
Can I build an agent with Swytchcode that safely creates records across several tools?
Yes — the pattern is the same regardless of how many tools are involved: check whether that tool's create method is idempotency-aware or offers an upsert, use it if so, and fall back to a lookup-then-create check if not. Swytchcode applying the same retry rule everywhere means you're not reinventing this per integration.
Can I add a policy that blocks an agent from creating records outside certain fields?
Yes. A policy rule can restrict which fields an agent is allowed to set on a create call, or require approval for a create matching certain conditions — useful for anything where a wrong or duplicated record has downstream consequences, like billing or support routing.
Does Swytchcode retry a create call automatically if it fails?
Only when that specific method carries an idempotency guarantee. Otherwise the failure is surfaced rather than retried, since a blind retry on an unprotected create is exactly how a second record gets made.
How do I know if a provider's create endpoint supports an upsert?
Run swy discover with the job phrased as "find or create" or "update or create" against that integration — providers that support it usually expose it as a separate, named method rather than a flag on the plain create call.
More content
How to Stop an AI Agent From Booking the Same Meeting Twice
A scheduling agent that checks availability and then books the slot has a gap between those two steps — and a retry can fall straight into it. Here's how Swytchcode closes that gap.
How to Stop an AI Agent From Sending the Same Email Twice
Most email APIs have no idempotency key to catch a repeat send, which makes a duplicate email a harder problem than a duplicate charge. Here's how Swytchcode handles the gap.
How to Stop an AI Agent From Charging a Customer Twice
A timed-out payment call and a retry loop is all it takes for an agent to charge someone twice. Here's why that happens and how Swytchcode's per-call idempotency and approval policies stop it.
