Components and the Payment Flow
In one line: the component list is good and the flow that connects them is wrong in a way worth understanding precisely — because it is the difference between orchestrating a payment and holding someone's money.
The architecture
| Component | Role | Note |
|---|---|---|
| Payment service | Receives the payment event, stores it, initial security checks, forwards to fraud detection | The orchestrator |
| Fraud detection | Real-time pattern analysis; flags suspicious activity | Blocks the malicious |
| Risk check system | Device fingerprinting, transaction history, location → a risk score: proceed, challenge, or block | Scores the ambiguous |
| Payment gateway (PSP) | Security checks, routes to card networks; also session management, refunds, invoices | Third party |
| Card networks | Visa, Mastercard — verify card information | External |
| Wallet | Merchant balances; per-seller updates for multi-seller orders | Mutable state |
| Ledger | Appends immutable entries — transaction ID, amount, parties | The audit trail |
| Reconciliation | Compares the internal ledger against the PSP's daily settlement file | Catches everything else's bugs |
| Dispute management | Chargebacks, regulatory compliance, dispute records | Months-long tail |
Fraud detection and risk check are two components because they answer different questions
The design poses this as a question — "if a fraud detection system is already in place, what value does a dedicated risk check system provide?" — and its answer is worth sharpening.
Fraud detection is binary and about intent. Is this transaction malicious? Stolen card, account takeover, known-bad device. The output is block or allow.
Risk assessment is continuous and about exposure. How much could this transaction cost us if it goes wrong, even absent fraud? A legitimate customer buying an expensive item they may dispute, a merchant with a high chargeback rate, a shipping address in a jurisdiction with weak recourse.
Fraud: "Is this person who they claim to be?" -> yes / no Risk: "What is our expected loss on this?" -> a score
The score is what makes the third option possible. Binary systems have two outcomes and lose money on both — blocking a good customer costs a sale plus goodwill, and false positives in fraud detection are expensive. A score enables "challenge": step up to 3-D Secure, request additional verification, or hold for manual review.
Separating "is it malicious" from "how much do we stand to lose" turns a binary decision into a graded one, and the middle option is where the money is. The same instinct as the canary in the previous chapter: an intermediate state you can measure beats a coin flip.
The architectural benefit the design hints at is real too: fraud detection needs to be synchronous and fast (it gates the payment), while much of risk assessment can be asynchronous — build the profile in the background and consult a cached score. Two different latency budgets, so two components.
The ledger being immutable is the design's most important correct decision
"The ledger service appends a new, immutable entry to the ledger database… creating an auditable trail of all financial operations."
Append-only is right, and it is worth being explicit about why, because it is the property everything downstream depends on.
Financial records are evidence. A disputed transaction may be examined months later by a customer, a bank, an auditor, or a regulator. A mutable record cannot serve that purpose — if a row can be changed, its current value proves nothing about what happened.
Corrections are new entries, not edits. This is the discipline that follows: a mistaken $50 credit is not deleted, it is offset by a reversing entry of −$50, and both remain visible. The history shows the error and the correction, which is exactly what an auditor wants to see.
Immutability makes concurrency easy. Appends do not conflict. This is the same property that made that building block's artifact storage and that building block's operation log tractable, and it is the fix for the lost-update problem in the wallet's mutable balance column from Lesson 3.
Append-only is what makes a record trustworthy, and it makes concurrency trivial as a side effect. The design gets this right and then, per Lesson 3, gives the ledger no amount column to append.
The flow the design specifies
- A customer clicks pay, triggering the payment service.
- The payment service processes the customer's information and sends details to the risk check system.
- If it passes, the payment service forwards the request to the payment gateway.
- The gateway validates and forwards to the card issuer's bank.
- The issuer's bank processes the request and sends the payment to the merchant's account via the payment service.
- The merchant's account balance is updated.
Step 5 has the money flowing through the payment service, which is not how card payments work
"The issuer's bank processes the request and sends the payment to the merchant's account via the payment service."
Funds do not take that path. The actual movement is:
Issuer bank -> Cards network -> Acquiring bank -> Merchant's account
The payment service is never in the funds path. It orchestrates: it collects details, calls out for authorization, records what happened, and updates its own view of a merchant's balance. It does not receive or forward money.
Why this matters beyond accuracy:
It collapses the two phases Lesson 1 established. Step 5 has authorization and settlement happening in one synchronous request. In reality step 5 ends at "authorized", and the money moves in a batch hours or days later. There is no capture step in this flow, no settlement, and no window in which a hold exists — which is why the outstanding-authorization sweep and the settlement-file ingestion are both absent from the design.
It has regulatory consequences. A system that holds and forwards customer funds is a money transmitter, which in most jurisdictions requires licensing, capital requirements, and a supervisory regime. A system that orchestrates while a licensed PSP moves the funds is not. That boundary is an architectural decision with a legal cost attached, and describing it wrongly in an interview signals you have not thought about where your system sits in the chain.
Know which side of the funds flow your system is on — orchestrator or custodian. Almost every design you would build is the former, and the design should say so.
What the flow should be
The synchronous part ends at 'authorized', and everything after it is asynchronous
This is the structural point the design misses, and it is the reason the pub-sub component exists.
Before the response to the customer: persist the intent, score for fraud, authorize with the issuer. All synchronous, all on the latency-critical path, all of it required before you can tell the customer whether their purchase succeeded.
After the response: capture, ledger entries, wallet update, settlement, reconciliation. Nobody is waiting.
That is the same split by who is waiting rule from Lesson 1, applied to the architecture rather than to the phases. And it explains the block list's pub-sub entry — "decouple services like payment processing, wallets, and ledgers" — which is exactly the boundary in the diagram above.
The trap is that moving work behind a queue makes it asynchronous, not optional. A ledger entry that fails after the customer saw "success" is a payment that happened and was not recorded. Lesson 7 is about precisely that hazard.
Decoupling changes when work happens, not whether it must.
'The service processes each order separately and updates each seller's wallet' is a bigger requirement than it looks
"For purchases involving multiple sellers, the service processes each order separately and updates each seller's wallet."
One customer payment of $150 splitting across three sellers means one authorization and three separate balance movements, plus the platform's own fee.
That is a genuine distributed-transaction problem:
Customer charged $150 — ONE authorization, atomic at the issuer -> Seller A credited $80 -> Seller B credited $45 -> Seller C credited $20 -> Platform fee $5
If seller B's credit fails after A's succeeds, the money is charged and only partly distributed. Two-phase commit across independent wallets is unattractive; the workable answers are:
Make it one atomic write. All wallet movements and ledger entries for a payment go into a single transaction in a single store. Possible because the amounts are small and the stores are the same system — and this is what a proper double-entry ledger gives you naturally, since the split is just more entries in one balanced set.
Or make it a saga with compensations. Each credit is independent, retried until it succeeds, with the whole thing reversible by compensating entries.
The first is far better here, and it is another argument for the ledger design in Lesson 5: a multi-seller split is one balanced set of ledger entries, not three independent balance updates.
Where the design says encryption happens
The design's answer on encryption is reasonable and worth recording: client-side before transmission, in transit via TLS, at the payment gateway, and at rest — plus access controls and PCI DSS compliance.
Three of the four are right. The fourth — "payment details may be temporarily stored and should be encrypted at rest… when the payment service receives a payment event, it stores the event details in the database after applying the necessary encryption" — is the one Lesson 3 flagged. Encrypting the CVV does not make storing it permissible, and encrypting the PAN keeps your database in PCI scope rather than removing it.
The item that would change the picture is absent: client-side encryption to whom? If the browser encrypts card data with the PSP's key and passes an opaque token onward, your servers never hold anything sensitive. If it encrypts with your key, you are still in scope. The recipient of the encryption is the entire question, and the design does not say.
Key takeaway
The component list is sound: fraud detection and risk assessment answer different questions — is it malicious versus what is our expected loss — and separating them turns a binary decision into a graded one where the middle option is where the money is. The immutable ledger is the design's most important correct decision, because append-only is what makes a record trustworthy and makes concurrency trivial as a side effect. The flow is where it breaks: step 5 routes funds through the payment service, which collapses authorization and settlement into one synchronous step and misstates a boundary with regulatory consequences — orchestrator versus custodian. The correct structure is synchronous through "authorized" and asynchronous after, split by who is waiting — and decoupling changes when work happens, not whether it must.
Next: the ledger the design should have built.