AlgoMaster Logo

Understanding Idempotency

High Priority13 min readUpdated September 13, 2026
Listen to this chapter
Unlock Audio

Imagine placing a bookstore order and losing the connection before the confirmation arrives. The server may have saved the order, but the application has no response to confirm it. It now has an uncomfortable choice: repeat the request and risk another order, or stop and leave the customer unsure whether the purchase worked.

Idempotency helps APIs handle this uncertainty by controlling what repeated requests do.

This chapter explains how to reason about repeated effects, distinguish a retry from a new operation, and identify the limits of an idempotency guarantee.

1. Uncertain Outcomes

A timeout tells the caller that it did not receive a response within its waiting period. It does not establish whether the server received the request, started processing it, or committed its changes. A commit is the point at which a change becomes durable in the relevant storage system.

Consider an order-creation endpoint that creates a new order on every accepted submission. The following is an intentionally unprotected flow:

Outcome unknownCreate an orderInsert order_901CommittedApp does not receive creation responseRepeat the submissionInsert order_902CommittedCreated order order_902Customer appBookstore APIOrder databaseCustomer appBookstore APIOrder database
9 / 9
algomaster.io

The database successfully handled both requests. The problem is that two network attempts represented one purchase intention, while the endpoint treated them as two purchases.

Disabling the checkout button can reduce accidental clicks, but it cannot resolve a lost response. A duplicate can also arrive from a client library, a background job, or a caller recovering after a restart. The API needs a contract that makes the consequences of repetition clear.

2. Repeated Effects

An operation is idempotent when repeating the same request has the same intended server-side effect as performing it once.

For a fixed operation that changes business state, we can write the idea as:

This is a model of the intended effect, not a comparison of every database byte. Assume no unrelated operation changes the relevant state between applications.

Setting a cart item's quantity to three fits this model. Increasing its quantity by one does not. Starting at quantity two, the assignment produces three after either one or two applications; the increment produces three and then four.

The distinction is visible in the resulting state:

The assignment describes a desired state. The increment describes additional work relative to the current state. Both can be useful operations, but they need different duplicate-handling behavior.

Other operation shapes follow the same reasoning:

Scroll
Intended operationEffect of an identical repeatIdempotent by this operation's meaning?
Set a delivery preference to leave_at_doorPreference remains leave_at_doorYes
Ensure a particular book belongs to a set of favoritesBook remains a single memberYes
Remove a particular saved addressAddress remains absentYes
Toggle a notification preferencePreference changes backNo
Append another occurrence of a book to an ordered listThe operation adds another occurrenceNo
Create another order with a new server-assigned IDThe operation creates another orderNo

These classifications assume the implementation preserves the stated meaning. “Add to favorites” is ambiguous until the API defines whether favorites are a set with unique membership or a list that accepts repeated entries.

3. HTTP Methods and API Contracts

HTTP defines safe methods, PUT, and DELETE as idempotent. POST has no general idempotency guarantee. PATCH likewise has no general guarantee, although particular patch operations can be idempotent.

Method semantics are a promise the implementation must honor. Renaming an endpoint from POST to PUT does not repair code that creates another independent order each time it runs.

Consider a fictional bookstore API over HTTPS at api.bookstore.example. It exposes an existing cart item as a small resource with only one editable field: quantity. The path identifies the book. The examples assume an authorized customer and no intervening cart edits; credentials are nonfunctional placeholders.

The customer requests an absolute quantity:

The service commits the replacement:

Repeating the request establishes quantity three again. The API must not interpret the repeated body as “add three more.” Here, cart edits do not reserve inventory or initiate payment, so there are no additional business actions hidden behind the assignment.

A specific PATCH document can also express an assignment. For example, on a separate document endpoint that supports JSON Patch and already contains a quantity member:

Repeatedly replacing that member with three is idempotent with respect to the assignment. By comparison, this JSON Patch instruction appends to an existing notes array:

Applying it twice adds two entries if the endpoint allows duplicates. JSON Patch uses the media type application/json-patch+json; these instructions do not imply that the cart endpoint supports PATCH.

POST can support an application-defined guarantee for repeated submissions. The server needs an explicit way to recognize one operation and prevent additional effects. Clients can rely on that documented contract, but cannot infer it from POST or matching payloads alone.

4. Effects and Responses

Idempotency concerns effects, so repeated attempts need not return identical responses.

Suppose the customer removes the cart item:

The first request removes it:

This API returns an error when an authorized caller repeats the deletion of an absent item:

Both attempts leave the item absent. Returning 204 for an already absent item would also be a possible API convention; idempotency does not prescribe which of these responses the service chooses.

All HTTP JSON bodies here are exactly the single lines these examples show, without a trailing newline.

If the first response never reached the client, the later 404 does not prove who removed the item or when. Its meaning also depends on the authorization policy: an API might use 404 to conceal a resource the caller cannot access. Do not turn every not-found response into universal proof of successful deletion.

The same distinction applies to reads. Repeated GET requests can return different stock counts because inventory changes independently. That does not make GET non-idempotent; reading the stock count does not request another inventory change.

Some APIs replay a stored response for duplicate submissions. That can help a client recover an operation's result, but response replay is an additional behavior. Returning the same bytes without preventing duplicate business effects would not provide idempotency.

5. Operation Identity

A logical operation is one intended business action. An attempt is one effort to carry it out, such as an HTTP request. One logical operation may require several attempts.

For checkout, sending the same books and delivery address twice might mean “retry my purchase” or “place a second identical purchase.” A server cannot reliably distinguish those intentions from the body alone. Deduplicating every matching payload would incorrectly suppress legitimate orders.

Resource identity can sometimes make the intent clear. Repeating an assignment to the same cart item targets the same state. A server-assigned order-creation endpoint instead needs a way to distinguish a repeated submission from another purchase. An idempotency key is an identifier that an API can accept to associate multiple attempts with one logical operation. Its behavior requires server support and a documented contract.

The contract must identify the scope in which an operation is unique. An operation identifier for one customer must not let another customer retrieve its result. If duplicate recognition expires, clients also need to know the supported time window. The service may treat a retry arriving after that window as a new submission.

Changing the requested quantity or delivery address is not simply another identical attempt. The service must define how it handles different input that a client associates with an existing operation identity; it should not silently treat two different intentions as interchangeable.

Business rules can provide a different kind of uniqueness. A rule allowing only one full cancellation of an order applies across all callers and attempts. A duplicate-submission rule applies to attempts the API identifies as the same operation. The two can complement each other, but they answer different questions.

6. Business Effects Beyond One Row

A resource can look correct while the overall operation still produces duplicates.

Consider an intentionally flawed cancellation handler. Every request sets the order's status to cancelled and then independently issues a refund. Repeating the status assignment has no additional effect on the order row, but repeating the refund creates another financial effect. The unchanged status is insufficient evidence that cancellation is idempotent.

The intended cancellation outcome includes all of its promised business effects:

Assume this bookstore supports one full cancellation and one associated full refund for an eligible order. Correcting the handler requires tying stock release and refund processing to that cancellation, so repeated attempts do not release stock or refund money again.

This matters when work crosses service boundaries. If the payment service completes a refund but the bookstore receives no response, the bookstore cannot conclude that no refund occurred. Recording completion only after the response arrives leaves that outcome uncertain. Before retrying the refund, the bookstore needs duplicate protection from the payment service or a reliable way to check the outcome.

Idempotency and atomicity are different properties. Atomicity means a defined group of changes happens entirely or not at all. Idempotency controls the effect of repetition. A database transaction can make an order update atomic without making an external refund part of that transaction.

Operational records are different again. HTTP permits separate request logs and revision history for repeated idempotent requests. Recording two attempts does not mean two purchases occurred. The practical distinction is whether an effect merely records processing or performs more of the business action the caller requested.

7. Guarantee Boundaries

Idempotency does not mean a handler executes exactly once. The server may receive the request twice, check permissions twice, and perform repeated internal work while preserving one intended effect. It also does not guarantee eventual success: an unavailable service may never complete the operation.

An idempotency guarantee must hold when duplicates overlap, not only when they arrive one after another. A flawed “check whether it exists, then create it” sequence allows two requests to both observe absence and create separate records. The implementation must enforce the uniqueness rule even when requests run at the same time. Merely observing that sequential retries work does not establish the guarantee.

Different operations introduce a separate issue. Suppose customer A assigns quantity three, customer B changes it to five, and A's delayed retry assigns three again. The assignment is idempotent, yet A's retry overwrites B's change. Preventing stale writes requires a concurrency policy, such as checking a resource version when applying the change. Idempotency alone does not provide that protection.

Failures remain subject to ordinary validation and permissions. In the example cart API, quantity must be an integer from one through twenty. Sending {"quantity":-1} receives 422 Unprocessable Content without changing the cart; resending it unchanged does not correct the input. A signed-in customer who lacks write access receives 403 Forbidden where the API permits disclosing the cart's existence. A prior successful attempt does not grant permanent permission to repeat it or view its result.

Finally, define how long the target retains its meaning. Deleting a stable, never-reused identifier is easier to reason about than deleting whatever currently occupies a reusable name. Re-adding the same book to a cart is an intervening operation: an old DELETE can remove the newly added item. A retry contract should account for resource lifecycle and concurrent changes instead of promising that any historical request remains appropriate forever.

Summary

Idempotency makes repeated attempts preserve the intended effect of one operation. Assignments and removals often have this property naturally; increments, toggles, appends, and independent creations generally need additional duplicate protection.

Judge the complete business effect, including work other services perform. Distinguish one operation's retries from new intentions, and document the scope and lifetime of any duplicate-recognition guarantee. Different responses and repeated internal execution are compatible with idempotency; stale-write protection, atomicity, permissions, and eventual success require separate reasoning.