API Idempotency: Complete Guide to Preventing Duplicate Requests

API Idempotency: Complete Guide to Preventing Duplicate Requests

Your user clicks the “Send Money” button. Nothing happens. They click it again. And again.

Later, you get a support ticket. The user was charged five times instead of once. Their bank account is negative. They are furious.

This is what happens without idempotency. A fundamental concept in API design that most developers do not think about until something breaks.

What Idempotency Actually Means

Idempotency is simple. Performing the same operation multiple times produces the same result as performing it once.

In API terms, sending the same request twice should not cause double the effect. You requested a payment of $100 twice. The user is charged $100, not $200.

Without idempotency, your API is fragile. It assumes the network is perfect and requests never retry. But the real world is messy.

Why The Network Is Trying To Break Your API

Network failures are not rare edge cases. They are normal.

A user loses cellular connection. A server is slow to respond. The client assumes the request failed and retries it.

From your API perspective, without idempotency, you just processed the same payment twice. Money moved. Records changed. The damage is done.

The Idempotency Key: Your Request’s Unique Fingerprint

The solution is simple. The client generates a unique identifier for each request called an idempotency key.

This key is sent with every request, typically in the headers. When your API receives a request with an idempotency key, it checks: Has this key been seen before?

If yes, return the cached response from the previous request. If no, process the request normally and store the response with that key.

How It Works In Practice

Example: A payment request includes Idempotency-Key: “12345-abc-xyz”.

Your API receives it. It checks the storage: “Have I seen 12345-abc-xyz before?” No. So it processes the payment and stores the response.

A retry arrives with the same key. Your API recognises it and returns the cached response without re-processing. One payment. Not two.

The Three States Of Request Processing

When a client sends an idempotency key, three scenarios can happen.

The first request arrives, gets processed, and the response is cached. Perfect scenario.

The second request with the same key arrives later. Your API recognises it and returns the cached response. Also perfect.

The Tricky Part: Concurrent Requests

A client sends a request with a key. Your API is still processing it. The client sees the slow response and retries with the same key.

Now your API has two copies of the same request being processed simultaneously. This is where things break.

Some implementations lock on the idempotency key. Other requests with the same key wait. When the lock releases, return the cached response. This prevents duplicate processing.

Which HTTP Methods Need Idempotency

Not all requests need idempotency keys.

GET requests are naturally idempotent. You can fetch the same resource a thousand times and get the same response. No changes happen.

POST requests are not idempotent by default. Each POST creates new data. Without idempotency, five POST requests create five resources.

PUT and DELETE are naturally idempotent. Updating a resource to state X multiple times leaves it in state X.

When To Add Idempotency Keys

Any API endpoint that modifies data should support idempotency keys.

Creating user accounts, placing orders, updating profiles, deleting resources, and sending notifications. All of these benefit from idempotency.

If it changes state, it needs idempotency. Simple rule.

Storing Responses Efficiently

Store idempotency responses in a fast, distributed cache.

Redis is the standard choice. Store each response with the idempotency key as the key. Set an expiry time. Redis automatically deletes old entries.

For larger scales, key-value stores like DynamoDB work well. The important part is that lookup must be fast.

Real Example: The Duplicate Notification Disaster

A notification service sends alerts to users. Network timeout. The client retries.

Without idempotency, users get duplicate notifications. Your product looks broken.

With idempotency, the second request returns the same response as the first. Users get notified once. System works correctly.

The Payment Processing Scenario

Imagine a payment gateway. A user pays for an order. The payment processes. But the response is lost due to network failure.

The user retries. Without idempotency, the system charges them twice and creates two orders.

With idempotency, the second request returns the same response as the first. One payment. One order. Problem solved.

Common Mistakes With Idempotency

Over-complicating it is mistake number one. Idempotency is simple. Do not make it complex.

Forgetting to handle in-flight requests is mistake two. A retry arrives while the first request is still processing.

Not storing responses long enough is mistake three. If you delete the response after 5 minutes, a late retry gets processed twice.

Building Idempotency Into New APIs

Start with the basics. Define that your API requires idempotency keys for all write operations.

Clients must include the Idempotency-Key header on every POST, PUT, or PATCH request.

The key format does not matter as long as it is unique. UUIDs are common. Timestamps work less well.

Monitoring And Maintenance

Check which idempotency keys are accessed frequently.

If a key has never been retried, it is working correctly. If keys are retried many times, your system is unreliable.

Monitor this data. It tells you about network quality and client behavior.

The Bigger Picture: Building Reliable Systems

Idempotency is not just a nice-to-have. It is foundational to building reliable systems.

It transforms your API from one that breaks under normal network conditions to one that is robust and resilient.

Understanding idempotency is understanding production engineering. Frameworks come and go. Reliable APIs last forever.

The Edge Cases That Matter

What if a request is still being processed when a retry arrives? Use request-level locking to handle this.

What if the cache fills up? Implement an eviction strategy like least recently used.

What if network latency causes a race condition? Use database constraints or atomic operations to ensure only one write succeeds.

When To Implement Idempotency

You have a write operation. Implement idempotency immediately.

Do not wait until something breaks. Do not wait until a customer loses money.

Idempotency is infrastructure. Treat it like security or backups. Non-negotiable.

The Cost Of Not Having It

One day, a user retries a payment request. You process it twice.

Another day, your mobile app has a bug. It retries all requests aggressively. Thousands of duplicate operations.

You spend weeks issuing refunds. Your customers are angry. Your reputation takes a hit.

Idempotency prevents all of this. The cost is minimal. The benefit is enormous.

Final Truth

The best time to implement idempotency was when you first launched.

The second-best time is right now. Before something breaks. Before customers lose money.

Build idempotent APIs. Sleep well at night.

Post a Comment

Previous Post Next Post