Idempotency

Mental model

An idempotent operation can be safely repeated without creating additional business effects.

This is especially important for payments and order creation.

The Problem

Client

  │ POST /payments

Payment Service

  ├── charge card ✓

  └── response lost


Client retries


Payment Service

  └── charge card AGAIN ❌

The client cannot tell whether the first request succeeded.

Idempotency Key

POST /payments
 
Idempotency-Key: 8c5e...

The server stores the result associated with the key.

idempotency_key

      ├── request fingerprint
      ├── status
      ├── response
      └── created_at

Java Concept

String key = request.getHeader("Idempotency-Key");
 
var existing = repository.findByKey(key);
 
if (existing.isPresent()) {
    return existing.get().response();
}

The database must enforce uniqueness:

CREATE UNIQUE INDEX
idx_idempotency_key
ON idempotency_keys(key);

The unique constraint is important because two requests can arrive simultaneously.

Race Condition

Request A ──┐
            ├── find key → not found
Request B ──┘
            └── find key → not found

Both could proceed unless the database provides a concurrency-safe uniqueness guarantee.

Interview answer

Never rely only on “check then insert.” Use a unique constraint and design the operation around the possible race.

.NET Concept

var existing =
    await db.IdempotencyKeys
        .SingleOrDefaultAsync(x => x.Key == key);

Then persist the key/result as part of the operation, backed by a unique database constraint.

Idempotency and Kafka

Kafka consumers can also receive duplicates.

A consumer might store the event ID:

processed_events
----------------
event_id UNIQUE

Then:

if (processedEventRepository.exists(event.id())) {
    return;
}

In production, the business update and processed-event record should be designed carefully so a crash cannot leave them inconsistent.

What Makes an API Idempotent?

PUT is defined to be idempotent by HTTP semantics.

POST is not inherently idempotent, but a payment API can be made operationally idempotent using an idempotency key.

Interview Questions

Why UUID?

A UUID gives us a globally unique identifier with extremely low collision probability. But a UUID alone does not provide idempotency. We still need server-side deduplication.

What if the same idempotency key is reused with different request data?

Reject it. The key should identify one logical operation, and the server can compare a request fingerprint/hash with the original request.

Where should the idempotency record live?

For a service backed by PostgreSQL, a database table is often appropriate because uniqueness and transactional behavior are important.

Remember

UUID identifies. Unique constraint enforces. Idempotency key deduplicates.