Blog
Event-Driven Architectures for Payment Systems
Designing event-driven payment platforms for fintech. Idempotency, saga patterns, and exactly-once semantics from production deployments.
Payment systems are the hardest type of event-driven system to get right. A misplaced message in a recommendation engine means a user sees the wrong product. A misplaced message in a payment system means money moves to the wrong account — and that is a regulatory incident with real financial consequences.
We have designed and built event-driven payment platforms for fintechs processing hundreds of thousands of transactions daily. Here is the pattern that works.
Who Is This Guide For?
This guide is for software architects and platform engineers designing payment systems for fintech and financial services. If you are moving from a synchronous payment flow to an event-driven architecture, this is for you.
By the End of This, You’ll Know…
- How to implement idempotency keys for payment events
- The saga pattern for multi-step payment workflows
- How to achieve exactly-once semantics without sacrificing throughput
- Why outbox patterns prevent dual-write consistency failures
The Idempotency Key Pattern
The fundamental challenge in event-driven payments is duplicate events. A network timeout, a broker restart, or a consumer crash can cause the same event to be delivered twice. If the second delivery triggers a second payment, you have a problem.
The solution is an idempotency key — a unique identifier for each payment event that consumers use to detect and discard duplicates.
| |
The idempotency store must be:
- Durable: Survive consumer restarts and broker failures
- Consistent: Strongly consistent read-after-write to prevent race conditions
- TTL-expiring: Keys should expire after a reasonable window (typically 24-72 hours)
A pattern we use is the outbox table — the idempotency key is written to a database table in the same transaction as the payment state update:
| |
If the consumer crashes before processing, the outbox message is re-published by a background worker. The consumer checks the idempotency store and skips duplicate events.
The Saga Pattern for Multi-Step Payments
A payment flow is rarely a single step. A typical flow: validate → authorise → capture → settle → notify. Each step may involve different services — the ledger service, the risk service, the notification service — and each can fail independently.
The saga pattern orchestrates multi-step workflows with compensating transactions for rollback:
| |
We implement sagas using a lightweight orchestrator with persistent state, not a distributed transaction. The orchestrator tracks each step’s state in a database and triggers compensating transactions on failure.
Exactly-Once Semantics
Exactly-once delivery in event-driven systems is a myth at the transport level. What you can achieve is effectively-once processing — ensuring that even if an event is delivered multiple times, it produces the same result.
The combination of idempotency keys (for duplicate detection) and outbox patterns (for reliable publication) gives you effectively-once semantics across the entire pipeline.
What You Can Actually Use Today
| Tool | Purpose | Source |
|---|---|---|
| Apache Kafka | Event broker with exactly-once semantics | Open source |
| Debezium | CDC from database to Kafka | Open source |
| Temporal | Saga orchestration and workflow engine | Open source |
FAQ
Can I use Kafka transactions for exactly-once payments? Kafka transactions provide exactly-once semantics between producer and broker, and between broker and consumer — but only when the consumer writes to Kafka as its sink. If your consumer writes to a database, you still need an idempotency layer between the database write and the Kafka commit.
What is the difference between choreographed and orchestrated sagas? Choreographed sagas have services reacting to events without a central coordinator. Orchestrated sagas use a central orchestrator (like Temporal or a custom service) to manage the workflow state. For payment systems, orchestrated sagas provide better observability and simpler compensation logic.
How long should idempotency keys live? Until the payment lifecycle is complete. For most payment systems, 72 hours is sufficient — long enough to cover any retry and recovery window, but short enough to avoid unbounded storage growth.
Further Reading
For a deeper discussion of data platform architecture, see our Financial Data Platforms service.