Idempotent HTTP Requests
Understand HTTP idempotency, how repeated requests behave, which methods are idempotent, and how idempotency keys make APIs safer to retry.
Idempotency is one of the most important concepts when designing reliable HTTP APIs. It describes what happens when the same request is performed more than once and is especially important when a client cannot determine whether an earlier request succeeded.
Network failures can happen after a server has processed a request but before the client receives the response. If the client retries the request, the server may receive the same operation twice. Whether that is safe depends partly on the idempotency characteristics of the operation.
GET and PUT are defined as idempotent HTTP methods, while POST and PATCH are not inherently idempotent. However, idempotency can also be implemented at the application level, for example by using idempotency keys for operations such as payment creation or order submission.
What Does Idempotent Mean?
An HTTP method is idempotent when making the same request multiple times has the same intended effect on the server as making it once.
PUT /api/users/42
Content-Type: application/json
{
"name": "Alex",
"role": "developer"
}If this exact PUT request is sent once or several times, the intended final state of the user should be the same: the user has the specified name and role.
Idempotency does not mean that every response must be identical. Response headers, timestamps, logging information, metrics, or other incidental effects can differ between requests. The important property is the intended effect on the resource or server state.
A Simple Example
Suppose an API allows a client's name to be changed with PUT:
PUT /api/users/42
Content-Type: application/json
{
"name": "Alex"
}Sending the request once changes the name to Alex. Sending the same request again still leaves the name as Alex.
The second request does not mean that the name should become something different. It asks the server to establish the same intended state again.
Idempotency Does Not Mean Read-Only
A common misunderstanding is that idempotent requests cannot modify data. That is incorrect. An idempotent operation can change server state; the important property is that repeating the same operation does not produce additional intended changes after the first successful application.
| Operation | Idempotent? | Why |
|---|---|---|
| Set user status to active | Yes | Repeating it keeps the status active |
| Replace a resource with a representation | Yes | Repeating it establishes the same representation |
| Delete a resource | Yes | After the first deletion, repeating the request does not create another deletion effect on the resource |
| Create a new order | Usually no | Repeating it can create another order |
| Increment a counter | No | Every repetition changes the counter again |
Idempotency vs Safety
Idempotency and safety are different HTTP concepts. A safe method is intended for operations that do not request a state change. An idempotent method may change state while still having idempotent semantics.
| Property | Meaning |
|---|---|
| Safe | The method is intended to be read-only with respect to the requested resource state |
| Idempotent | Repeating the same request has the same intended effect as performing it once |
GET is both safe and idempotent. PUT is idempotent but not safe because it can modify a resource. DELETE is also idempotent even though it changes server state.
Which HTTP Methods Are Idempotent?
| Method | Idempotent | Safe |
|---|---|---|
| GET | Yes | Yes |
| HEAD | Yes | Yes |
| OPTIONS | Yes | Yes |
| PUT | Yes | No |
| DELETE | Yes | No |
| POST | No | No |
| PATCH | Not inherently | No |
The table describes the HTTP method semantics. An individual application can also design a particular endpoint to behave idempotently even when the HTTP method itself is not defined as idempotent.
GET Is Idempotent
GET is defined as a safe and idempotent method. It is intended to retrieve a representation of a resource rather than request a state-changing operation.
GET /api/products/123Sending this request once or multiple times should have the same intended effect on the resource: no requested modification is made.
The server can still record logs, update metrics, perform authentication checks, or perform other internal work. Those incidental effects do not change the method's HTTP semantics.
PUT Is Idempotent
PUT is idempotent because its semantics are based on creating or replacing the target resource representation at a known URI.
PUT /api/users/42
Content-Type: application/json
{
"name": "Alex",
"email": "[email protected]"
}Repeating the same request should establish the same intended state rather than creating a new user each time.
DELETE Is Idempotent
DELETE is also defined as idempotent. Consider:
DELETE /api/users/42The first request may remove the user. Repeating the request does not remove another copy of that user because the resource has already been removed.
The responses can differ. The first request might return 204 No Content, while a subsequent request might return 404 Not Found. Different responses do not automatically make the operation non-idempotent.
POST Is Not Inherently Idempotent
POST is not defined as an idempotent HTTP method. This is particularly important for resource creation.
POST /api/orders
Content-Type: application/json
{
"productId": 123,
"quantity": 1
}If the request creates an order, sending the same request twice can create two orders. That is an additional intended effect, so the operation is not naturally idempotent.
PATCH Is Not Inherently Idempotent
PATCH is used for partial modifications, but the HTTP method itself does not guarantee idempotency.
A PATCH operation that sets a value can be idempotent:
PATCH /api/users/42
Content-Type: application/json
{
"status": "active"
}Repeatedly setting the status to active produces the same intended state.
An operation that increments a value is different:
{
"operation": "increment",
"amount": 10
}If every request increases a balance by 10, repeating the same request produces another change. That operation is not idempotent.
Idempotency and Retries
One of the most important reasons to understand idempotency is request retries. Networks are unreliable, and a client can lose the response even when the server successfully processed the request.
Imagine that a client sends a request to create an order. The server creates the order and sends a response, but the connection fails before the client receives it.
Client → POST request → Server
Client ← response ← Server
connection fails
Client: "Did the request succeed?"The client cannot necessarily distinguish between these two situations:
- The request never reached the server.
- The server received and processed the request, but the response was lost.
If the client simply sends the POST again, it could accidentally create a second order.
Why Retrying PUT Is Easier
Suppose a client uses PUT to establish a user's profile:
PUT /api/users/42
Content-Type: application/json
{
"name": "Alex",
"role": "developer"
}If the client does not receive the response, repeating the same PUT request should establish the same intended resource state. This makes retries easier to reason about.
Why POST Needs More Care
A POST operation that creates a new resource can produce a new result each time it is submitted. Therefore, a client should not automatically assume that an unknown outcome means it is safe to repeat the request.
For operations where duplicate processing would be harmful, the API can provide an application-level mechanism such as an idempotency key.
What Is an Idempotency Key?
An idempotency key is a unique value generated by the client and sent with a request. The server uses the key to recognize repeated attempts belonging to the same logical operation.
POST /api/payments
Content-Type: application/json
Idempotency-Key: 7f2d9b3e-8c12-4e6a-example
{
"amount": 4999,
"currency": "USD",
"orderId": "order-123"
}If the client does not receive a response, it can retry the request with the same idempotency key. The server can recognize that the retry represents the same logical operation rather than a new operation.
How Idempotency Keys Work
- The client generates a unique key for a logical operation.
- The client sends the key with the request.
- The server stores or otherwise tracks the key and the operation's result.
- If the same key is received again, the server can recognize the duplicate attempt.
- The server returns the previously established result or applies the API's documented duplicate-request behavior.
The exact implementation is application-specific. An idempotency key is not automatically provided by HTTP itself; it is an API-level convention.
Idempotency Key vs Request ID
An idempotency key should not be confused with a request ID used for tracing or logging.
| Concept | Purpose |
|---|---|
| Idempotency key | Allows the server to recognize repeated attempts of the same logical operation |
| Request ID | Helps identify and trace an individual request through logs and services |
A system can use both. A request ID can change for each network attempt, while the same idempotency key can be reused when those attempts represent one logical operation.
Idempotency Keys and Payments
Payments are a common example because duplicate processing can have serious consequences. A client might submit a payment and then lose the connection before receiving confirmation.
POST /api/payments
Idempotency-Key: payment-attempt-8f42
{
"amount": 2500,
"currency": "USD"
}If the client retries with the same key, the payment service can distinguish the retry from an entirely new payment request, provided the service implements idempotency keys according to its documented contract.
The Idempotency Key Must Be Reused for Retries
If a client generates a completely new idempotency key for every retry, the server may interpret every attempt as a new operation.
First attempt:
Idempotency-Key: abc123
Retry:
Idempotency-Key: abc123The same key associates both network attempts with the same logical operation.
Idempotency Keys Should Represent One Operation
A client should generally generate a new key for a genuinely new operation. Reusing an old key for an unrelated operation can cause the server to treat the new request as a duplicate.
| Situation | Idempotency key |
|---|---|
| First attempt at creating an order | Generate a new key |
| Retry because response was lost | Reuse the same key |
| User intentionally creates another order | Generate a new key |
| Retry after a documented transient failure | Usually reuse the same key when the API supports it |
Server-Side Storage of Idempotency Keys
A server needs a way to recognize previously processed keys. Depending on the architecture, the information can be stored in a database, distributed cache, or another durable or coordinated storage system.
A simplistic implementation might associate the key with the request parameters and the resulting response.
{
"key": "payment-attempt-8f42",
"requestHash": "example-hash",
"status": "completed",
"responseStatus": 201
}Production systems need to consider concurrency, expiration, storage failures, multiple application instances, and what happens if two requests with the same key arrive at nearly the same time.
Concurrency and Idempotency
Two identical requests can arrive concurrently rather than sequentially. A server must therefore prevent both requests from independently performing the operation before either one has recorded the idempotency key.
This often requires atomic operations, unique database constraints, distributed locking, or another concurrency-control mechanism appropriate for the system.
Idempotency and Databases
Database constraints can help enforce idempotent application behavior. For example, an order table can contain a unique idempotency key associated with the operation.
CREATE UNIQUE INDEX idx_orders_idempotency_key
ON orders (idempotency_key);A unique constraint can prevent multiple rows from being created with the same key. The application still needs to define how duplicate requests are handled and how the original result is returned.
Idempotency Is Not the Same as Exactly-Once Delivery
Idempotency is sometimes confused with exactly-once delivery. They are related but different concepts.
A network can deliver the same request more than once. An idempotent operation makes repeated processing safe with respect to its intended state. It does not mean that the network delivered the message exactly once.
This distinction is especially important in distributed systems, where messages can be duplicated, delayed, retried, or delivered after a timeout.
Idempotency and At-Least-Once Processing
Many distributed systems prefer at-least-once delivery because it is safer to retry a message than to risk losing it. The trade-off is that consumers may receive duplicates.
Making the processing operation idempotent allows the system to tolerate those duplicate deliveries.
Idempotent vs Non-Idempotent Operations
| Operation | Typical behavior |
|---|---|
| Set account status to suspended | Idempotent |
| Replace user profile | Idempotent |
| Delete a specific resource | Idempotent |
| Create a new resource with a server-generated ID | Usually non-idempotent |
| Increment a counter | Non-idempotent |
| Append an event to a list | Usually non-idempotent |
Making an API Operation Idempotent
An API operation can often be designed to be idempotent even when its HTTP method does not inherently guarantee idempotency.
- Define a stable identifier for the logical operation.
- Accept an idempotency key when duplicate processing is possible.
- Store enough information to recognize repeated attempts.
- Make duplicate processing return a consistent logical result.
- Use database constraints where appropriate.
- Handle concurrent requests using atomic operations.
- Define how long idempotency keys remain valid.
- Document what happens when the same key is reused with different request data.
Idempotency and Request Payloads
A robust API should define what happens if the same idempotency key is reused with a different payload.
First request:
Idempotency-Key: abc123
{
"amount": 100
}
Later request:
Idempotency-Key: abc123
{
"amount": 500
}Treating these as the same operation would be dangerous because the payloads conflict. APIs commonly reject such reuse or otherwise define explicit behavior.
Idempotency and HTTP Status Codes
An idempotent operation can return different HTTP status codes on repeated requests. What matters is the intended effect rather than requiring the exact same status code every time.
First request:
DELETE /api/users/42
HTTP/1.1 204 No Content
Repeated request:
DELETE /api/users/42
HTTP/1.1 404 Not FoundThe different responses do not change the fact that DELETE is defined as idempotent. After the first successful deletion, repeating the deletion does not create another deletion effect on the resource.
Retries Should Not Be Blind
Idempotency makes retries easier to reason about, but it does not mean every failed request should automatically be retried.
- Determine whether the method and endpoint are safe to retry.
- Consider whether the server might already have processed the request.
- Use an idempotency key for supported non-idempotent operations.
- Respect server rate limits and retry-related response headers when applicable.
- Use bounded retries rather than retrying indefinitely.
- Apply backoff between repeated attempts when appropriate.
- Avoid retrying permanent client errors such as invalid request data.
Exponential Backoff
When an operation is appropriate for retrying, clients often use exponential backoff. Instead of immediately sending another request after every failure, the client waits for progressively longer intervals.
Attempt 1 → wait
Attempt 2 → wait longer
Attempt 3 → wait longer again
Attempt 4 → stop after the configured retry limitRandom jitter is often added to backoff intervals so that many clients recovering from the same failure do not retry simultaneously.
Idempotency in Frontend Applications
Frontend applications can encounter the same uncertainty as backend clients. A user might click a button, the browser sends a request, and the connection temporarily fails before the frontend receives the response.
For operations such as creating an order, submitting a payment, or registering a resource, the frontend and backend need a clear strategy for duplicate requests.
The frontend should not attempt to solve server-side idempotency by simply disabling a button. UI protection can reduce accidental duplicate clicks, but it cannot protect against network retries, browser refreshes, multiple clients, or requests that reach the server more than once.
Idempotency in REST APIs
REST APIs benefit from meaningful HTTP semantics. GET can retrieve resources, PUT can establish a representation at a known URI, DELETE can remove a resource, and POST can submit data for processing or create a resource in a collection.
Following these semantics makes API behavior easier for clients to understand. When a custom operation needs stronger retry guarantees, an API can document an application-level idempotency mechanism.
Idempotency in GraphQL
GraphQL does not use HTTP methods in exactly the same way as a REST API. Queries are generally read operations, while mutations represent operations that can change application state.
GraphQL mutations are not automatically idempotent simply because the request is sent to a single endpoint. If a mutation can be retried, its schema and server implementation need to define how duplicate operations are handled.
mutation CreateOrder($input: CreateOrderInput!) {
createOrder(input: $input) {
id
status
}
}An application can include an idempotency key in the mutation input when the API is designed to support it.
Testing Idempotent APIs
Testing idempotency means checking what happens when the same logical operation is submitted more than once. A request builder or API testing tool can be used to send repeated requests and inspect the resulting status codes and response bodies.
- Send the original request.
- Record the response and resulting resource state.
- Send the same request again.
- Compare the resulting resource state.
- For idempotency-key APIs, repeat the request with the same key.
- Try concurrent duplicate requests when the operation is sensitive to race conditions.
- Test reuse of an idempotency key with a different payload if the API supports idempotency keys.
Example Test Scenario
POST /api/orders
Content-Type: application/json
Idempotency-Key: order-attempt-123
{
"productId": 42,
"quantity": 1
}Send this request twice with the same key. The expected result depends on the API contract, but a properly designed idempotency mechanism should prevent the retry from unintentionally creating a second logical order.
Common Idempotency Mistakes
Mistake 1: Assuming Every Request Is Idempotent
Not every HTTP operation can safely be repeated. Treating POST or an arbitrary PATCH operation as automatically retryable can result in duplicate records or repeated side effects.
Mistake 2: Confusing Different Responses With Non-Idempotency
An idempotent operation can return different responses on repeated requests. Idempotency concerns the intended effect on server state, not whether the response body and status code are identical.
Mistake 3: Generating a New Key for Every Retry
If an API uses idempotency keys, generating a new key for each retry defeats the purpose because the server cannot associate the attempts with the same logical operation.
Mistake 4: Storing Only the Key
A production idempotency implementation usually needs more context than a key alone. It may need to associate the key with the request, operation status, result, expiration information, and other metadata.
Mistake 5: Ignoring Concurrent Requests
Two requests with the same key can arrive at nearly the same time. If both requests check for the key before either one records it, both could process the operation. Idempotency logic therefore needs appropriate concurrency control.
Idempotency Checklist
- Know whether the HTTP method is inherently idempotent.
- Do not assume PATCH operations are idempotent.
- Treat non-idempotent POST operations carefully when retries are possible.
- Use idempotency keys for supported operations that need duplicate protection.
- Reuse the same key when retrying the same logical operation.
- Generate a new key for a genuinely new operation.
- Define key expiration and duplicate-request behavior.
- Protect against concurrent requests with the same key.
- Validate that the same key is not reused with incompatible request data.
- Test duplicate and retry scenarios explicitly.
Frequently Asked Questions
What is an idempotent HTTP request?
An idempotent HTTP request is one where making the same request multiple times has the same intended effect on server state as making it once. The responses do not have to be identical.
Which HTTP methods are idempotent?
GET, HEAD, OPTIONS, PUT, and DELETE are defined as idempotent HTTP methods. POST is not inherently idempotent, and PATCH is not inherently idempotent.
Is POST idempotent?
POST is not inherently idempotent. Repeating a POST can create multiple resources or trigger an operation multiple times. An API can, however, add application-level idempotency using mechanisms such as idempotency keys.
Is PATCH idempotent?
PATCH is not inherently idempotent. A specific PATCH operation can be idempotent if repeating it produces the same intended state, but other PATCH operations, such as increments or appends, may not be.
Why is DELETE idempotent?
DELETE is idempotent because repeating the request does not create another deletion effect on the same resource after it has already been deleted. A later request can still return a different status such as 404.
What is an idempotency key?
An idempotency key is a unique client-generated value associated with one logical operation. The server uses it to recognize retries or duplicate submissions and prevent them from being processed as separate operations.
Can an idempotent request return different responses?
Yes. Idempotency concerns the intended effect on server state, not identical responses. For example, the first DELETE request might return 204 while a repeated request might return 404.
Why does idempotency matter for payments and orders?
Network failures can occur after a payment or order has been processed but before the client receives the response. Without duplicate protection, retrying the request could perform the operation again. Idempotency keys can allow the server to recognize the retry as the same logical operation.
Conclusion
Idempotency means that repeating the same request has the same intended effect on server state as performing it once. GET, PUT, and DELETE are defined as idempotent HTTP methods, while POST and PATCH are not inherently idempotent.
The concept becomes especially important when network failures make the result of a request uncertain. Idempotent operations are easier to retry safely, while sensitive non-idempotent operations may require application-level mechanisms such as idempotency keys.
Reliable APIs should define their retry behavior explicitly, protect important operations against duplicate processing, handle concurrent requests correctly, and document how idempotency keys work. For frontend and backend developers, understanding idempotency is essential for building APIs that behave predictably when requests are repeated.