Event-Driven vs. Batch Processing in Payment Systems: When Each Makes Sense

Event-Driven vs. Batch Processing in Payment Systems: When Each Makes Sense

15.05.2026

The answer is almost never "just go real-time."

There's a recurring conversation in every payment platform build. Someone — usually with a background in consumer tech — will ask why we're not processing everything in real time. Events, webhooks, streaming. Why wait for a batch when you can react instantly?

It's a reasonable question. And the answer is more nuanced than most architecture blog posts would have you believe.

The appeal of event-driven

Event-driven architecture is elegant when the problem fits. A payment comes in, an event fires, downstream systems react. No polling. No stale data. No waiting for the nightly batch to discover that something went wrong twelve hours ago.

For payment initiation, event-driven makes sense. A merchant submits a payout request, and you want that flowing through your system immediately — validated, queued, sent to the bank. Latency matters. The merchant is watching.

For fraud detection, same story. You want to evaluate a transaction before it goes out, not in a batch report the next morning.

For notifications — payment confirmed, payment failed, funds received — events are the natural fit. Something happened, someone needs to know, tell them now.

So far, so obvious.

Where batch still wins

But payment systems aren't just about initiating payments and sending notifications. A huge part of the work happens after money moves: reconciliation, settlement, reporting, compliance.

And this is where batch processing isn't just acceptable — it's correct.

Bank statements arrive in batches

This is the most practical reason, and it's one that event-driven purists tend to overlook. Banks don't stream their data to you. They send files. CSV, MT940, CAMT.053, sometimes PDF (yes, really). These files arrive once or twice a day, and they contain the bank's authoritative view of what happened.

Your event-driven system might know that you initiated a payment at 2:15 PM. The bank statement will tell you whether it actually settled. Until that statement arrives, your internal state is an expectation, not a fact.

Trying to shoehorn bank statement processing into an event-driven model doesn't make it faster. The data arrives when the bank sends it. Building an event-driven pipeline that triggers once a day when a file drops is just a batch process wearing a costume.

Reconciliation is inherently batch

Reconciliation is the process of comparing two sets of records and identifying discrepancies. By definition, you need both sets before you can compare them. Your internal ledger is one set. The bank statement is the other.

You can't reconcile in real time because one side of the comparison doesn't exist yet. You need to wait for the bank's version of events, then match it against yours, then investigate the gaps.

Running this as a scheduled batch — once the bank statement arrives, trigger the matching process, flag exceptions, generate the report — is clean, predictable, and auditable. It produces a single, timestamped reconciliation output that you can review, sign off on, and store for compliance.

An event-driven approach to reconciliation would mean reacting to each bank statement line as it arrives, maintaining partial match state, dealing with ordering issues, and somehow producing a coherent view of completeness. It's possible, but it's solving a problem that doesn't exist. Nobody needs to reconcile one transaction at a time. They need to reconcile the day.

Reporting has a cadence

Your operations manager doesn't want a streaming dashboard that updates every second. They want a daily cash position report that's right. They want to see: here's what we started with, here's what came in, here's what went out, here's where we are.

That report needs to be generated after all the day's activity is settled. If you generate it from a streaming system, you need to define what "end of day" means, wait for all events to flush, handle late-arriving data, and somehow mark the report as final. Or you can run a batch at an agreed cut-off time, capture the state, and produce the report.

The batch version is simpler to build, simpler to debug, and simpler to trust.

The hybrid approach (what actually works)

In practice, every payment system we've built is a hybrid. The division is usually clean:

Event-driven for the hot path:

  • Payment initiation and execution
  • Real-time validation and fraud checks
  • Status updates and notifications
  • Webhook delivery to merchants

Batch for the cold path:

  • Bank statement ingestion and parsing
  • Daily reconciliation
  • Cash position and settlement reports
  • Regulatory and compliance reporting
  • Month-end close processes

The two paths share data but operate on different timelines. The event-driven path tells you what's happening now. The batch path tells you what actually happened, confirmed by the bank.

The real question to ask

The right question isn't "should we use events or batches?" It's "who is the consumer of this output, and when do they need it?"

If the consumer is a merchant waiting for a payment status — events. If the consumer is an operations manager closing the day's books — batch. If the consumer is a regulator asking for a report — batch. If the consumer is a fraud engine evaluating a transaction in flight — events.

Most of the time, the answer is obvious once you frame it this way. The architecture follows the operational need, not the other way around.

A word about overengineering

We've inherited systems where someone built a full event-sourced, CQRS architecture for what turned out to be 200 transactions a day with a single bank integration. The event store had six months of data that nobody ever replayed. The CQRS read models were rebuilt nightly from scratch because it was easier than debugging the projection logic.

Don't build for a scale you don't have. Don't adopt patterns because they're intellectually satisfying. The goal is a system that processes payments correctly, reconciles reliably, and can be understood by the person who'll maintain it after you leave.

If that means a cron job and a SQL query, that's fine. It's not glamorous, but it works, and it'll still work three years from now when nobody remembers why you chose Kafka.


Zenlime designs and builds payment platforms for financial services companies. We're happy to talk architecture — start a conversation.