system-design

Design a Fraud Detection System

Difficulty: Tier 3 Asked at: Tabby, Careem Pay, Stripe, banks, Amazon Time budget: 45–60 min

Fraud detection sits in the payment path and must answer “is this transaction fraudulent?” in milliseconds, using signals about the user, device, and behavior — while fraudsters constantly adapt. It blends real-time low-latency scoring with rules + ML models and a feature store, plus the subtle tension of precision vs recall (block fraud without blocking real customers). A MENA fintech favourite (Tabby, Careem Pay).

Prerequisites: Design Payment System, Batch vs Stream, Design Ad Click Aggregator


1. Requirements

Functional:

Non-functional:

Out of scope: payment processing (separate), the ML training pipeline internals.


2. Estimation


3. The core: real-time scoring with a feature store

🚨 The pattern: at transaction time, gather features, run them through rules + a model, produce a risk score, decide. The trick to doing it in milliseconds is a feature store that serves precomputed features instantly.

flowchart TB
    Txn[Transaction] --> Scorer[Scoring Service]
    Scorer --> FS[(Feature Store<br/>precomputed features)]
    Scorer --> Live[Live features<br/>velocity this session]
    Scorer --> Rules[Rules engine<br/>hard blocks]
    Scorer --> Model[ML model<br/>risk score]
    Scorer --> Decision{Approve /<br/>Deny / Review}
    Stream[Event stream] --> FeatureCompute[Feature computation<br/>batch + streaming]
    FeatureCompute --> FS
    Decision --> Feedback[(Labels: confirmed fraud)]
    Feedback --> Retrain[Model retraining]

Features are computed offline (batch: user’s historical stats) and in near-real-time (streaming: velocity, recent behavior) and stored in a feature store for fast lookup. At scoring time, the service fetches features, applies rules (instant hard blocks: blacklisted card, impossible geo velocity) and an ML model (nuanced risk score), and decides. Confirmed-fraud labels feed retraining.


4. Deep dives

4a. Rules + ML (defense in depth)

🚨 Use both. Rules are fast, explainable, catch known patterns, and give instant hard blocks (velocity limits, blocklists) — but they’re rigid and gameable. ML models catch subtle/novel patterns via many features but are slower to update and less explainable. Layer them: rules for clear-cut cases and guardrails, model for the gray area. This gives coverage + speed + adaptability.

4b. Features & the feature store

The score is only as good as its features: velocity (transactions per hour/day for this user/card/device), historical behavior (typical amount, locations), device fingerprint, network reputation, graph features (shared devices/cards across accounts). 🚨 Precompute expensive features offline and serve them from a feature store so real-time scoring is a fast lookup + a model inference, not a data-gathering exercise — exactly the pattern from the news feed ranking and ad aggregator.

4c. Velocity & streaming features

Many fraud signals are rates — “10 transactions in 2 minutes,” “same card from 3 countries in an hour.” Compute these with streaming aggregation over the event stream (windowed counts, like the ad-click aggregator), updating the feature store continuously so velocity features are fresh at scoring time.

4d. Precision vs recall — the central trade-off

🚨 Catching more fraud (recall) means blocking more legit users (hurting precision), and vice versa. A too-aggressive system blocks real customers (lost revenue, angry users); too-lax lets fraud through (losses). Tune the decision threshold, and use a three-way outcome (approve / deny / flag for human review) so borderline cases go to review rather than a hard wrong decision. Different actions have different risk tolerances (a $5 vs $5,000 transaction). This business-aware balancing is the senior insight.

4e. Adaptivity & feedback loop

Fraud evolves (fraudsters probe and adapt), so the system must too. Feed confirmed fraud and chargebacks back as labels to retrain models regularly; monitor for drift (model performance degrading); allow rapid rule updates to respond to a new attack in hours, not weeks. The feedback loop is what keeps it effective.

4f. Explainability & audit

Decisions affect customers and are regulated → record why each decision was made (which rules fired, score, key features). Human reviewers need this; regulators may require it. Favor models with some explainability for high-stakes denials.


5. Bottlenecks & scaling further

  1. Scoring latency → feature store (precomputed) + fast model inference + rules short-circuit.
  2. Feature freshness (velocity) → streaming aggregation into the feature store.
  3. Precision/recall balance → tunable thresholds + approve/deny/review three-way + per-context risk.
  4. Adaptivity → feedback labels + frequent retraining + fast rule updates + drift monitoring.
  5. Throughput → stateless scoring services scale horizontally.

6. Trade-off summary

Decision Chosen Alternative Why
Detection Rules + ML (layered) One or the other Speed/explainability of rules + subtlety of ML
Features Precomputed + streaming, feature store Compute live Real-time scoring must be a fast lookup
Outcome Approve / deny / review Binary block/allow Borderline → human review, not a wrong hard call
Threshold Tuned per context/risk Fixed Balance precision vs recall by stakes
Model Retrained on feedback Static Fraud adapts; the system must too

7. Follow-up questions

Why use both rules and machine learning instead of just one? Because they have complementary strengths and weaknesses, and layering them gives coverage no single approach provides. Rules are fast, deterministic, and fully explainable, and they give instant hard blocks for known- bad patterns — a blacklisted card, an impossible geo-velocity, a hard limit — which you want as guardrails and for clear-cut cases; but rules are rigid, must be hand-written, and are gameable once fraudsters learn them. ML models, fed many features, catch subtle and novel patterns that no one wrote a rule for and adapt as they're retrained; but they're slower to update, harder to explain, and can't be trusted alone for hard blocks. So you use rules for the obvious cases and as fast safety rails, and the model for the nuanced gray area, combining instant explainable blocks with adaptive pattern detection. This defense-in-depth also degrades gracefully: if the model is uncertain, rules still catch blatant fraud, and if a new attack slips past the model, you can deploy a rule in hours while the model retrains. Relying on only rules is brittle; only ML is slow to react and opaque — together they're stronger.
How do you score a transaction in milliseconds when good features are expensive to compute? By precomputing the expensive features ahead of time and serving them from a feature store, so scoring becomes a fast lookup plus a model inference rather than a data-gathering exercise. Features like a user's 30-day spending history, typical locations, or graph relationships are computed offline in batch and continuously updated, and velocity-style features (transactions in the last few minutes) are maintained by streaming aggregation over the event stream — both written into a low-latency feature store keyed by user/card/device. At transaction time the scoring service does a quick feature-store read to assemble the feature vector, runs the rules (which can short-circuit to an instant block) and a fast model inference, and returns a decision, all within the tens-of-milliseconds budget. The essential idea is to move the heavy computation off the critical path: never compute expensive aggregates live during checkout; compute them in advance and just look them up. It's the same precompute-features-serve-fast pattern used for feed ranking, adapted to fraud.
Explain the precision-versus-recall trade-off and how you manage it. Recall is the fraction of actual fraud you catch; precision is the fraction of your fraud flags that are truly fraud. They pull against each other: making the system more aggressive (lower risk threshold to block) catches more fraud (higher recall) but also flags more legitimate transactions (lower precision), which blocks real customers, loses revenue, and angers users; making it more lenient does the reverse, letting fraud through. There's no free lunch — you're choosing where on that curve to sit. You manage it by tuning the decision threshold to the business's tolerance and, crucially, by not forcing a binary choice: a three-way outcome — approve, deny, or flag for human review — routes borderline cases to review rather than a hard wrong decision, recovering both a false block and a missed fraud at the cost of review effort. You also vary the threshold by context and stakes: a small low-risk purchase can be approved more freely, while a large or high-risk one gets stricter scrutiny, so you spend friction where the expected loss justifies it. Balancing these with business awareness, rather than optimizing one metric, is the senior insight.
Fraud patterns change constantly. How does the system keep up? Through a feedback loop and fast update paths. Confirmed fraud and chargebacks are captured as labels and fed back to retrain the models regularly, so the model learns new patterns as they emerge rather than going stale against last month's fraud. You monitor for model drift — degrading precision/recall on recent data — as a signal to retrain or investigate. Because model retraining takes time, you also keep a fast rule-update path: when a new attack is spotted, analysts can deploy a targeted rule within hours to stanch it immediately while the model catches up, giving you both rapid tactical response and slower strategic adaptation. Streaming features keep velocity signals current in real time. This combination — labeled feedback driving frequent retraining, drift monitoring, instant rule deployment, and fresh streaming features — is what lets the system co-evolve with adaptive fraudsters instead of being a static filter they quickly learn to bypass.

8. What junior / mid / senior answers look like


Further reading