>_ Analyst Engineering

Event-Driven Requirements: Specifying Systems That Talk in Events

Cover for a guide on event-driven requirements, specifying systems that communicate through events on a message queue.

Event-driven requirements specify how a system behaves when services talk through events instead of direct calls. The happy path is easy. The real requirements live in ordering, duplicates, retries, and the windows where services briefly disagree.

Event-driven requirements define how a system behaves when its services communicate by publishing and consuming events on a message queue, rather than calling each other directly. They specify each event’s schema and key, who publishes and who consumes it, the ordering and delivery guarantees, idempotency for duplicate events, retry and failure handling, and the consistency model. The catch is that asynchronous systems introduce a whole class of problems synchronous ones never face, and if your requirements ignore them, the system will surface them in production as double debits, stuck payments, and customers told their money moved when it has not.

Modern payment platforms are event-driven at their core, and Kafka is where most analysts hit a wall, because the behavior is invisible from the UI and absent from most specs. Writing requirements for these systems is a systems analyst and functional analyst skill, and it starts with accepting that asynchronous is genuinely harder. Validating these event flows directly, instead of assuming they work, is exactly what Automate Kafka Validation with Postman is built for.

What does an event-driven requirement specify?

An event-driven requirement specifies the full contract and behavior of an event flow, not just the happy-path payload. There is a predictable set of elements to cover for each event.

The event contract: the topic, the schema with every field and type, and the key that determines partitioning and ordering. The producer and consumers: which service publishes the event and which services consume it, because one event often has several independent consumers. The ordering guarantee: whether events for the same key are processed in order, which depends on partitioning. The delivery guarantee: at-least-once, at-most-once, or exactly-once, which dictates whether consumers must handle duplicates. The idempotency rule: how a consumer detects and ignores a redelivered event. The failure handling: retries, backoff, and what goes to a dead-letter queue. And the consistency model: what state each consumer reaches and the window during which they disagree.

Miss any of these and you have left the asynchronous system underspecified in exactly the place it bites. The event schema templates and the rest of the artifacts I use for this live in Real-World BA Deliverables.

How do you specify an event contract?

Specify the event contract like an API request schema: every field typed and constrained, plus the key. The difference is that an event has no synchronous response, so the contract is the only agreement between a producer and consumers who may never call each other directly.

Take a payment.received event on a payments topic. Specify the schema field by field, and crucially specify the key, because the key determines which events are ordered relative to each other.

topic: payments.received
key:   uetr            // events for one payment stay ordered
value: {
  "uetr":        "string, required, unique end-to-end reference",
  "paymentId":   "string, required",
  "amount":      "decimal, required, > 0",
  "currency":    "string, required, ISO 4217",
  "status":      "string, required, enum [RCVD]",
  "occurredAt":  "timestamp, required, ISO 8601"
}

The key choice is a requirement with real consequences. Keying by UETR guarantees that all events for one payment land on the same partition and are processed in order, so a payment.received is never processed after a later payment.accepted for the same payment. Get the key wrong and you get out-of-order processing that no amount of consumer logic fully fixes. This level of precision is the same discipline as writing a good API requirement, applied to the asynchronous world.

Why ordering, duplicates, and retries are requirements, not edge cases

In an event-driven system, out-of-order delivery, duplicate delivery, and retries are not rare edge cases; they are the normal operating conditions of the platform. So they are first-class requirements, and the happy path is the small part.

Ordering. If two events for the same payment can be processed out of order, the requirement must say how the consumer handles it: reject the stale event, reconcile by version, or rely on partitioning by key to prevent it. Duplicates. Because most queues deliver at least once, a consumer will eventually receive the same event twice. The requirement must specify idempotency: detect the duplicate by event id or business key and ensure processing it again has no additional effect. In payments this is the difference between one debit and two. Retries. When a consumer fails to process an event, the requirement must define the retry policy, the backoff, the maximum attempts, and what happens after: dead-letter queue, alert, manual intervention. A payment that silently fails to process and is never retried is the worst outcome, and it happens when retries are unspecified.

I have seen all of these go wrong in production because the requirement covered only the successful, in-order, single-delivery case. The fix is to treat the abnormal as normal and specify it. The systematic way to find these cases is to test them: deliberately deliver a duplicate, force an out-of-order pair, kill a consumer mid-process, and watch what happens. That happy-path-then-break-it method is the one I walk through in You Don’t Understand the System Until You Test It.

What is eventual consistency, and why must requirements address it?

Eventual consistency means that after an event, the services that react to it reach a consistent state over time rather than instantly, so there is a window where they disagree. That window is visible to users, which makes it a requirements problem, not just an architecture one.

Here is a real example. A payment.posted event is consumed independently by the ledger service and the notification service. The notification service is faster, so the customer gets a “payment sent” push a full second before the ledger has actually posted the debit. If the ledger then rejects, the notification was already wrong. Nothing in a happy-path spec catches this, because each service does its job correctly; the problem is the gap between them. The requirement has to define what each surface shows during the inconsistency window and which state is authoritative, or you ship a system that occasionally lies to customers.

So event-driven requirements must explicitly answer: during the window between an event and full consistency, what does the customer see, what is the source of truth, and what happens if a downstream consumer later rejects. Those answers are real requirements with compliance and trust implications. Drawing the flow as a sequence diagram with independent consumers is the fastest way to see the window and ask the right questions about it.

How event-driven requirements connect to the rest of the spec

Event-driven requirements do not replace your API and functional requirements; they complete them for the asynchronous parts of the flow. A single business action typically mixes both: a synchronous API call to accept the request, then asynchronous events to process it. The full specification covers the API contract for the synchronous hops and the event contracts for the asynchronous ones, tied together by a sequence view.

This is why the technical business analyst who can reason about events is so valuable in payments: most specs stop at the API and leave the event layer to chance, which is precisely where the expensive defects hide. Being able to read a topic, validate an event, and specify its contract is a technical skill, and the path to building it, from APIs to event streams, is mapped in The Technical Skills Guide for BAs.

The takeaway

Event-driven requirements specify how services behave when they talk through events: the event contract and key, the producer and consumers, ordering, delivery guarantees, idempotency, retries, and eventual consistency. The happy path is the easy part. The requirements that matter handle duplicates, out-of-order delivery, retries, and the windows where services briefly disagree, because those are the normal conditions of an asynchronous system.

Specify those explicitly and you prevent the double debits and stuck payments that underspecified event systems produce. Start with Automate Kafka Validation with Postman and The Technical Skills Guide for BAs, or browse everything at The Tech BA Toolkit.

Ahmed is a Senior Technical Business Analyst with 10+ years in banking and payments. He builds practical guides and tools for analysts at The Tech BA Toolkit.

Tags: Business Analysis, Event-Driven Architecture, Kafka, Requirements, Systems Analysis

Newsletter

Subscribe

Practical, no-fluff playbooks for technical analysts who analyze, code, test, and support. New articles straight to your inbox.

No spam. Unsubscribe anytime.