Published 12 Nov 2026

Idempotency Matters More Now That AI Is Calling Your API

AI agents decide at runtime how many times to call your API, which turns every POST into a retry risk. Make operations naturally idempotent where you can, detect and replay where you can't, and enforce it at write time.

Idempotency means making the same request more than once leaves the server in the same state as making it once.

A GET is the easy example. Call it a hundred times, the data does not move. PUT and DELETE are meant to behave the same way: setting a resource to a value twice gives you the same resource, and deleting something that is already deleted leaves it deleted.

Two things are worth pinning down before going further, because both get muddled.

Idempotent is not the same as identical. A second DELETE may return a 404 where the first returned a 204. The response changed, the server state did not. Idempotency is a claim about state, not about what comes back.

The spec says PUT and DELETE are idempotent. Your implementation might not be. A PUT that appends rather than replaces, or a DELETE that decrements a counter, is not idempotent no matter what the verb implies. PATCH is not idempotent by specification either, which catches people who lump it in with PUT.

Where it actually bites is POST. The client is asking you to do something with a payload: process it, calculate against it, charge against it, store it. Run that twice and you have done the work twice.

The argument against bothering

The usual pushback is that the same team owns the client. In a closed system, handling duplicate calls on the client side is often about as easy as handling them on the server, so why build it twice.

It was never a great argument. A client loses connectivity before the response lands and retries, with no way to know the first call succeeded. Race conditions on their side fire the same request twice. A load balancer retries. A user double-clicks.

But the argument has gotten materially worse in the last two years, for a specific reason.

The caller is not deterministic anymore

More and more systems are wiring AI into existing APIs. An agent gets a tool definition and decides at runtime how many times to call it.

That removes every constraint a client application used to provide. There is no debounce you wrote. There is no code review of the call sequence, because there is no call sequence until the model produces one. The model can call the same endpoint with the same payload twice in the same plan, retry on an ambiguous result, or reissue a call after a timeout without knowing whether the first attempt landed.

The important part is that this is happening to APIs nobody redesigned. Somebody points an agent at an internal service that was built in 2019 for one known client, and the threat model changes without a line of that API’s code changing. The assumption it relied on, that the caller is something you wrote and can reason about, is quietly no longer true.

Any caller outside your control gets you here eventually. AI just made “outside your control” the common case instead of the exception.

Two ways to get there

Idempotency and duplicate detection are related but not the same thing, and the distinction matters when you build it.

Make the operation naturally idempotent. Key the work on something the client supplies, and write it as an upsert. Same key, same result, no bookkeeping. This is the cleanest option when the shape of the work allows it.

Detect the duplicate and replay the answer. Record what you have seen, and when a repeat arrives, hand back the original outcome rather than doing the work again. This is what you need when the work has external side effects that cannot be made naturally idempotent, like charging a card or sending a message.

Most real systems end up with the second, because the first only works when you own the whole effect.

Two things that catch people building it

Concurrent duplicates. A read-then-write duplicate check handles a retry that arrives a minute later. It does not handle two identical requests arriving at the same moment, where both check, both find nothing, and both proceed. The check has to be enforced at write time with a unique constraint or a lock, not as a lookup before the insert.

How long you remember. Duplicate detection means keeping keys around, and keeping them forever is not a plan. The retention window is a real decision driven by how long a client might plausibly retry, and it is the same decision as how long status records live.

Duplicate detection is not a nicety you add when a client misbehaves. It is the front line of a production API, and the set of callers you cannot reason about is growing.