System Design

Designing Idempotent APIs: Why Every Endpoint Should Be Safe to Retry

The Retry Problem Network failures happen. When a client sends a request and does not get a response, it does not know if the request failed or the response was...

calendar_today May 1, 2026 schedule 2 min read

The Retry Problem

Network failures happen. When a client sends a request and does not get a response, it does not know if the request failed or the response was lost. The natural reaction is to retry. But if the original request succeeded, a retry might create duplicate resources or charge a customer twice. Idempotency solves this.

What Idempotency Means

An idempotent operation produces the same result regardless of how many times it is executed. GET, PUT, and DELETE are naturally idempotent in REST. POST is not — and that is where most problems occur. The solution: give clients a way to make POST idempotent.

Idempotency Keys

The pattern I use most: clients generate a unique idempotency key (UUID) and send it with each POST request. The server stores the key with the response. If the same key arrives again, return the cached response without re-executing the operation.

async function handlePayment(req, res) {
  const { idempotencyKey, amount, customerId } = req.body;
  
  // Check if we already processed this request
  const cached = await redis.get(`idem:${idempotencyKey}`);
  if (cached) {
    return res.status(200).json(JSON.parse(cached));
  }
  
  // Process the payment
  const result = await paymentGateway.charge(amount, customerId);
  
  // Cache the response with TTL
  await redis.set(`idem:${idempotencyKey}`, JSON.stringify(result), { EX: 86400 });
  
  return res.status(200).json(result);
}

Storage Considerations

Idempotency keys need durable storage. Redis works for most cases with proper TTL. For financial systems, store keys in the primary database with the transaction record. The key must be unique per client — include the client ID in the cache key to prevent collisions.

Key Takeaways

  • Make every POST endpoint idempotent using client-provided keys
  • Store the full response, not just a processed flag — retries expect the same response
  • Set appropriate TTLs — 24 hours covers most retry scenarios
  • Document idempotency requirements clearly in your API docs
  • Test retry behavior in your integration test suite
Written by

Senior Software Engineer specializing in cloud architecture, real-time systems, and enterprise-scale applications.

Share this article

Related Articles

The Fallacy of Zero-Trust Networks Without Identity Verification

Oct 12, 2024 · 1 min read

From Monolith to Microservices: A Practical Migration Guide

Sep 14, 2024 · 2 min read

Event-Driven Architecture: When to Use It and When to Avoid It

Apr 28, 2026 · 2 min read