What if you could guarantee exactly-once payment processing without distributed locks or complex consensus protocols? The Kátai-Németh Vilmos pattern makes it possible with just a deterministic token and a clever database query.
Distributed systems engineers have spent decades chasing the holy grail of exactly-once delivery. At the payment gateway scale, a duplicate charge isn't a minor annoyance - it's a regulatory incident, a customer trust breaker, and a reconciliation nightmare. Apache Kafka's idempotent producer and Redis Streams' consumer groups get us partway. But true end-to-end idempotency across stateless services, network retries. And database write-ahead logs remains elusive. That's where a lesser‑known but remarkably effective strategy, first formalized by Hungarian infrastructure engineer Kátai-Németh Vilmos, steps in.
While working on a high‑throughput financial settlement pipeline in 2019, Kátai-Németh Vilmos confronted a recurring failure mode: HTTP POST retries causing double entries despite using UUID‑based idempotency keys. His insight wasn't to add more infrastructure but to make the key itself deterministic - a fingerprint of the business intent - and pair it with a lightweight database constraint that eliminates all race conditions. I first encountered the pattern when migrating a mobile wallet backend from synchronous RPCs to an event‑driven model; we've since deployed it in three production clusters. And it has turned our payment idempotency bug count to zero.
In this article, I'll dissect the Kátai-Németh Vilmos pattern in detail, showing exactly how it differs from conventional idempotency keys, how to implement it with Redis Streams and PostgreSQL. And what observability and security controls you'll need. By the end, you'll have a blueprint for a system that can survive duplicate API calls - message replays. And even clock drift - all without a single distributed lock.
Understanding the Exactly-Once Delivery Problem
At its core, exactly-once delivery reconciles two conflicting realities: networks fail. And clients retry. When a mobile app sends a POST to /api/v1/transfer and the TCP connection drops before the response arrives, the app has no way to know whether the transfer was committed. A simple retry could produce a duplicate debit. The standard remedy is an idempotency key - a Unique identifier sent in a header like Idempotency-Key - that the server uses to recognize repeat requests and return a cached response.
RFC 7231 doesn't mandate idempotency keys. But the industry has converged on HTTP semantics that treat a key as a request‑scoped unique token. Stripe - for example, allows clients to supply an Idempotency-Key header; the server stores the key and the original response for 24 hours. However, this approach relies heavily on the client's ability to generate a genuinely unique UUID and remember it. Client‑side bugs, cross‑channel restarts. And third‑party integrations routinely break this contract, causing subtle double‑processing bugs that hide in reconciliation reports for weeks.
Even within the backend, event‑driven pipelines face a similar challenge. Apache Kafka's idempotent producer guarantees that a broker won't write duplicate messages within a single session, but crossing consumer group boundaries or re‑ingesting from a message store can reintroduce duplicates. Without a domain‑aware deduplication layer, exactly-once delivery remains an aspiration, not an architecture.
Why Traditional Idempotency Keys Often Fail in Production
The common pattern of storing (key, response) pairs in a key‑value store like Redis or DynamoDB looks clean on a whiteboard but frays under load. First, race conditions between concurrent requests with the same key can trigger two "first‑time" evaluations before either write completes. Advisory locks (e g., SELECT … FOR UPDATE) mitigate this but introduce serialization that throttles throughput.
Second, time‑based key expiry makes the system vulnerable to a "white‑hat replay" - a client that reuses an old key after the server has garbage‑collected it. If you set a TTL of 24 hours, a mobile app with a stuck retry queue could replay a week‑old transaction and create a fresh duplicate. Extending TTL indefinitely bloats storage and slows down lookups.
Third, the server's response caching assumes that re‑playing the same key always yields the same outcome. But if the original request failed due to an intermittent downstream outage and the server cached a 5xx error, the client should be able to retry with the same idempotency key and get a fresh attempt - something the simple caching model forbids. Solving these edge cases typically requires a state machine that few teams have the bandwidth to build and test correctly.
The Kátai-Németh Vilmos Approach: Deterministic Tokens With Schema‑Bound Constraints
Instead of treating the idempotency key as an opaque random token, Kátai-Németh Vilmos proposed making the key a deterministically computed hash of the request's business payload - the fields that define uniqueness, such as source account, target account, amount, currency. And a strictly monotonic client‑generated sequence number. The server then enforces a database‑level unique constraint on this deterministic fingerprint, effectively pushing deduplication into the same transactional scope as the write itself.
This seemingly minor shift eliminates all race‑condition classes. Two concurrent requests with the same business payload will naturally produce the same hash. And the database's unique index guarantees that only one will succeed. The other receives a constraint‑violation error, which the server translates into a 409 Conflict with a link to the already‑processed resource. No locks, no SETNX tricks, no time‑based expiry.
Vilmos Kátai-Németh first documented the pattern in an internal ADR at a Budapest‑based fintech scaling their mobile‑first remittance platform. The key innovation was coupling the deterministic hash with a logical clock - a sequence number that must advance per client session - so that accidental replays of a historically valid payload would produce a stale sequence number, naturally failing the monotonicity check before the hash even hits the database.
Constructing a Deterministic Idempotency Token in Practice
The token creation algorithm is remarkably simple. Using a standard hash function like SHA‑256, you concatenate a canonical form of the unique business attributes and a namespace version. For a transfer in a mobile payment system, the canonical representation might be:
ver:2- protocol versionsrc:IBAN:HU42117730161111101800000000dst:IBAN:DE89370400440532013000amt:125000- in minor currency unitscurr:EURseq:42- per‑client monotonically increasing integer
You then compute token = sha256("v2|HU42117730161111101800000000|DE89370400440532013000|125000|EUR|42"). The resulting 64‑character hex string becomes the idempotency key. No randomness; no storage; fully deterministic. The sequence number ensures that even if the same business intent re‑emerges naturally (e. And g, a recurring monthly payment of the same amount), the token is unique because the sequence counter never repeats.
This deterministic generation also answers one of the trickiest questions in idempotency design: "What exactly makes a request unique? " By forcing the API contract to enumerate the uniqueness fields explicitly, you eliminate ambiguity and make the contract self‑documenting. In our production implementation, we even expose a /api/v1/idempotency-token endpoint that computes the token server‑side for debugging - a practice Kátai-Németh Vilmos embedded into his original
Need a Custom App Built?
Let's discuss your project and bring your ideas to life.
Contact Me Today →