Skip to main content

PIX received

Topic topology, key choice, idempotency, retry, DLQ, replay, and observability in a PIX-receiving flow.

This case study describes, end-to-end, how a digital bank models receiving a PIX (Brazil's instant payment system) as an event-driven flow — covering the decisions that typically come up in an interview when the interviewer asks you to "describe a real system you'd design with Kafka."

The domain event

When the Central Bank's Instant Payment System (SPI) confirms a PIX settlement, the service responsible for that integration publishes a PixRecebido event — a fact that already happened, not a command.

{
  "eventId": "8f14e45f-...",
  "endToEndId": "E00000000202401010000abcdef12345",
  "contaId": "acc_9182734",
  "valor": 15000,
  "moeda": "BRL",
  "pagador": { "nome": "...", "documento": "..." },
  "recebidoEm": "2026-07-31T14:02:11Z"
}

Topic topology

Topic and configuration

ItemDecision
Topicpix.recebido
KeycontaId
Partitions24 (sized for the receiving peak, not the average volume)
Replication factor3
Retention7 days (enough for operational replay; long-term audit lives in a data lake, not the topic)

Why the key is contaId

Dica de entrevista

The key choice isn't about distributing uniformly — it's about which events need to stay ordered relative to each other. Every event for the same account (PIX received, PIX sent, balance hold) must land on the same partition so consumers process them in the correct order. Using eventId as the key, for example, would distribute better across partitions, but would destroy per-account ordering — a common mistake made by people optimizing for throughput without understanding the ordering requirement.

Independent consumers

ProducerTopic: paymentsPartition 0Partition 1Partition 2Consumer Group: notification-serviceConsumer 0Consumer 1Consumer 2
Multiple Consumer Groups read the same pix.recebido topic independently.
  • saldo-service: credits the amount to the account, within an idempotent transaction (see below).
  • notificacao-service: sends a push notification, "You received a PIX of R$ 150.00."
  • extrato-service: writes the entry to the statement for later lookup.
  • antifraude-service: assesses the receipt against risk rules (e.g., too many PIX transfers to new accounts in a short window).

Each of these is an independent Consumer Group. A slowdown in antifraude-service doesn't delay crediting the balance — they advance offsets completely decoupled from each other.

Idempotency

Why idempotency is mandatory here

At-least-once delivery guarantees (the most common setup in production) imply the same PixRecebido event can be delivered to the saldo-service more than once — for example, after a rebalance or a commit retry. Without protection, that would credit the same PIX twice.

The saldo-service keeps a processed_events table with a uniqueness constraint on eventId. Before applying the credit, it tries to insert the eventId; if the insert fails due to a uniqueness violation, the event has already been processed and the operation is skipped — the check and the credit application happen in the same database transaction, guaranteeing atomicity even under concurrency.

Retry and DLQ

If the saldo-service fails to process an event (e.g., the database is momentarily unavailable), the error is treated as transient: Spring Kafka retries with exponential backoff. After a configured number of attempts, the event is published to the pix.recebido.dlq topic (Dead Letter Topic) for manual investigation — without blocking processing of the following events in the same partition (avoiding the "poison pill" effect).

Replay

If a bug in the extrato-service generates entries with the wrong amount, the fix involves: (1) fixing the bug, (2) resetting the extrato-service Consumer Group's offset to the start of the affected range (respecting the 7-day retention), and (3) letting the fixed service reprocess the events, rebuilding the statement entries from scratch for that range — with no interaction with saldo-service, notificacao-service, or antifraude-service, which aren't affected by another group's replay.

Observability

Monitored metrics

MetricWhy
Consumer lag per groupDetects whether antifraud or statement processing is falling behind incoming volume
DLQ message rateSignals persistent failures requiring investigation
Producer → consumer latencyTime between PIX confirmation and balance update, critical to user experience
correlationId/eventId in logsLets you trace a specific PIX across every service that processed it

Resumo

The PIX-received flow illustrates why Kafka gets chosen for this kind of problem: a single domain event, a key chosen to preserve per-account ordering, multiple independent consumers, idempotency required because of at-least-once guarantees, a DLQ to isolate persistent failures, and replay as a correction tool — all without coupling the service that receives the PIX to the services that react to it.