Skip to content

Idempotency in REST APIs — Complete Guide

DodaTech Updated 2026-06-28 4 min read

In this tutorial, you will learn about Idempotency in REST APIs. We cover key concepts, practical examples, and best practices to help you master this topic.

Idempotency in REST APIs means making the same request multiple times produces the same result as making it once, preventing duplicate side effects and ensuring reliable communication over unreliable networks.

flowchart TD
  A[Client] -->|Same Request x3| B[Server]
  B -->|Same Response x3| A
  A -->|POST Without Key| C[Server]
  C -->|3 Resources Created| A
  A -->|POST With Key| D[Server]
  D -->|Same Resource Returned| A
  style A fill:#e1f5fe
  style B fill:#c8e6c9
  style D fill:#c8e6c9
  style C fill:#ffcdd2

An idempotent operation guarantees that calling it once or multiple times has the same effect. GET is idempotent: reading the same resource 100 times returns the same data. PUT is idempotent: replacing a resource with the same data does the same thing each time. DELETE is idempotent: deleting a resource that already does not exist changes nothing.

POST is not idempotent. If you POST the same order twice, the customer gets charged twice. This is why payment systems use idempotency keys. A client generates a unique key for each request. If the request fails due to a network error, the client retries with the same key, and the server recognizes it as a duplicate.

Think of idempotency keys like a hotel reservation confirmation number. If you call the hotel to confirm and the call drops, you call back with the same confirmation number. The hotel knows you already booked and does not create a duplicate reservation.

Example: Idempotent GET

import requests

# Calling GET 3 times produces the same result
for i in range(3):
    response = requests.get("https://api.example.com/users/42")
    print(f"Attempt {i+1}: {response.json()['name']}")

Expected output:

Attempt 1: Alice
Attempt 2: Alice
Attempt 3: Alice

Example: Non-Idempotent POST Without Idempotency Key

import requests

data = {"name": "Test", "email": "test@example.com"}
for i in range(3):
    response = requests.post("https://api.example.com/users", json=data)
    print(f"Attempt {i+1}: Created user {response.json()['id']}")

Expected output:

Attempt 1: Created user 101
Attempt 2: Created user 102
Attempt 3: Created user 103

Example: POST With Idempotency Key

import requests
import uuid

data = {"amount": 5000, "currency": "USD"}
idempotency_key = str(uuid.uuid4())

headers = {"Idempotency-Key": idempotency_key}
for i in range(3):
    response = requests.post(
        "https://api.example.com/payments",
        json=data,
        headers=headers
    )
    print(f"Attempt {i+1}: {response.json()['status']}")

Expected output:

Attempt 1: completed
Attempt 2: completed (duplicate, returned cached)
Attempt 3: completed (duplicate, returned cached)

Common Mistakes

  1. Assuming all POST requests are idempotent — Most POST requests are not idempotent. Only operations like POST to a search endpoint might be idempotent.
  2. Not implementing idempotency keys for critical operations — Payment processing, order creation, and account registration must use idempotency keys.
  3. Expiring idempotency keys too quickly — Keys should live long enough to cover retry Windows, typically 24 hours for payment operations.
  4. Ignoring idempotency in Distributed Systems — When multiple API instances Process requests, idempotency checks must use a shared store like Redis.
  5. Returning different response bodies for duplicate requests — An idempotent request should return the same response each time, not just prevent side effects.

Practice Questions

  1. Which HTTP methods are idempotent?
  2. Why is POST not idempotent?
  3. What is an idempotency key used for?
  4. How would you implement idempotency for a payment API?
  5. Challenge: Implement an idempotency middleware in Python that stores idempotency keys in a dictionary and returns cached responses for duplicate requests.

FAQ

Why is DELETE idempotent?

After the first DELETE, the resource is gone. Subsequent DELETEs do nothing different. The server returns 204 or 404 but the end state is the same.

Is PATCH idempotent?

PATCH is not guaranteed to be idempotent. A patch that increments a counter changes state each time. Use PUT or carefully designed PATCH for idempotent updates.

How long should idempotency keys be stored?

Store keys for at least 24 hours for general APIs. Payment systems often store keys for 7+ days to cover chargeback windows.

Can a GET request have side effects?

No, GET is defined as safe (no side effects) by HTTP specification. If your GET creates a log entry, that is acceptable as a side effect but the resource state must not change.

Does idempotency mean the same response every time?

Yes, for idempotent operations the response should also be the same. Returning different data for the same GET request violates idempotency.

Mini Project

Build a Python class that wraps a payment API with idempotency support. The class should generate unique idempotency keys, store responses for completed requests, and return cached responses for retries. Test with simulated network failures.

What's Next

Now learn about HTTP status codes in REST API Design.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro