REST API Idempotency and Safe Methods

Networks fail. A phone loses signal, a server times out, and a client sends the same request again. Good API design makes that retry harmless. Two ideas make this possible: safe methods and idempotent methods.

The Elevator Button

Press the call button on an elevator once, and the elevator comes. Press it five more times, and the elevator still comes once. The result stays the same no matter how many presses happen. That behavior defines idempotency. A request is idempotent when repeating it leaves the server in the same state as sending it once.

Safe Methods

A safe method never changes data. It only reads. GET, HEAD, and OPTIONS fall into this group. Browsers, search engines, and caches rely on this promise, so a GET request must never delete a record or send an email.

Idempotent Methods

An idempotent method may change data, but repeating it adds no further change. PUT replaces a resource with a full new version. Sending the same PUT three times leaves one resource with one final state. DELETE removes a resource. The second DELETE finds nothing left to remove, and the server state stays the same.

The Special Case of POST

POST creates new resources, so each call usually produces a new record. Sending a payment request twice could charge a customer twice. POST is neither safe nor idempotent by default.

Method Overview

MethodSafeIdempotent
GETYesYes
HEADYesYes
PUTNoYes
DELETENoYes
PATCHNoDepends on the change
POSTNoNo

The Retry Problem

Client sends POST /payments (amount 50)
        │
        ▼
Server charges 50 ──→ response lost on the network
        │
Client waits... times out... sends again
        │
        ▼
Server charges 50 again   ✗  customer pays 100

The Idempotency Key Solution

An idempotency key makes POST safe to retry. The client generates a unique value, such as a UUID, and sends it in a header. The server stores the key with the result of the first request. A repeated request with the same key returns the stored result and skips the second charge.

POST /payments
Idempotency-Key: 7c9e6679-7425-40de-944b-e07fc1f90ae7
Content-Type: application/json

{ "amount": 50, "currency": "USD" }
Attempt 1: key unseen  ──→ process payment ──→ save result
Attempt 2: key found   ──→ return saved result (no new charge)

Why Clients Depend on This

HTTP libraries, load balancers, and mobile SDKs retry idempotent requests automatically after a network failure. A well-designed API makes those retries safe. A poorly designed API turns each retry into a risk of duplicate orders, duplicate emails, or lost data.

Design Rules

  • Keep every GET request free of side effects.
  • Use PUT when the client knows the full final state of a resource.
  • Return 204 or 404 for a repeated DELETE, and document the choice.
  • Require idempotency keys on payment, order, and booking endpoints.
  • Expire stored keys after a set period, such as 24 hours.

Common Mistakes

Counters Inside PUT

A request such as "add 1 to stock" breaks idempotency, because each repeat changes the number again. Send the final value, such as "stock equals 25", instead.

Changing Data Through GET

A link like /orders/9/cancel that works on GET can trigger during page previews or crawler visits. Use POST or DELETE for actions that change data.

Reusing Keys Across Different Requests

Each unique operation needs its own key. Servers should reject a reused key that arrives with a different body.