Design problems
Payments & fintechHardSDE-2 35 min

Design real-time fraud detection for payments

Asked at
AmazonCREDPaytmPhonePeRazorpayStripe

The interviewer asks

“Design a fraud detection system for a payments company that scores every transaction in real time, before it is approved, and decides to allow, challenge or block it. It should catch new fraud patterns quickly and keep false declines low.”

What a strong answer looks like

A strong answer puts a risk scoring service inline in the payment authorisation path with a strict latency budget (tens of milliseconds) and a defined fallback when it is slow. The score combines a rules engine (fast to change, explainable, used for known patterns and regulatory blocks) with an ML model (usually gradient-boosted trees) that reads features from an online feature store. Most of the work is in features: velocity counters over sliding windows, device and network signals, user and merchant profiles, and graph links, computed by a stream processor and served in a few milliseconds. Decisions are logged with everything needed to explain and replay them, labels (chargebacks, user reports, confirmed fraud) flow back weeks later, and new models go through shadow mode and champion-challenger. The hard parts are the latency budget, training/serving feature consistency, delayed and biased labels, and balancing fraud loss against false declines.

Concepts to mention

Inline scoring with an explicit latency budgetFallback policy on timeout (degraded rules, not blind fail-open)Online feature store with sliding-window velocity featuresRules engine plus ML model plus decision thresholdsAllow, challenge (step-up), blockLogging features at decision time to avoid training/serving skewDelayed labels and selection biasShadow mode and champion-challengerGraph features for mule accounts and fraud ringsPrecision vs false declines measured in money

1 Requirements

Functional

  • Score every payment (card, UPI, wallet) before authorisation and return allow, challenge (step-up: OTP, 3-D Secure, re-enter PIN) or block, with reason codes
  • Rules engine that analysts can update without a deploy (block lists, velocity limits, merchant-specific rules)
  • ML model scoring with features about user, device, merchant, payment instrument and network
  • Case management: queue suspicious transactions for analysts, record their decisions
  • Ingest labels: chargebacks, user fraud reports, analyst outcomes; use them for training and monitoring
  • Shadow mode and A/B testing for new rules and models

Non-functional

  • Scoring latency p99 under 50 ms inside a payment that has a total budget of a few hundred ms
  • Throughput: ~10k transactions/s average, ~50k/s peak (festive sale, salary day)
  • Availability 99.99%; if scoring fails or times out, the payment still gets a decision from a fallback policy
  • Fresh features: a transaction must be visible in velocity counters within ~1 s
  • Every decision explainable and replayable for audits and disputes
  • Rule changes live within minutes; model changes within a day, with safe rollback

Out of scope (say it out loud)

  • Merchant onboarding risk (KYB) and credit risk
  • Anti-money-laundering transaction monitoring (batch, regulatory reporting)
  • Chargeback dispute representment workflow
  • Payment processing itself

2 Estimates

Transactions~800M/day, ~10k/s average, ~50k/s peakA large Indian PSP or gateway: UPI alone runs at hundreds of millions of transactions a day nationally; assume this system sees ~800M/day; peaks 4-5x
Feature lookups~1M key reads/s at peak~20 entity keys per transaction (user, device, card, VPA, merchant, IP, plus windows) × 50k/s
Counter updates~500k/s at peak~10 counters per transaction (per entity × window) updated by the stream job
Online feature store size~1-2 TB~500M entities (users, devices, VPAs, cards, merchants) × ~2-4 KB of features and window state
Decision log~4 TB/day800M decisions × ~5 KB (features snapshot, scores, rule hits) ≈ 4 TB; Parquet compresses ~5x
Fraud rate and labels~0.01-0.1% of transactionsVery imbalanced classes: tens to hundreds of thousands of fraud labels per day at most, arriving days to weeks later

3 API

EndpointWhat it does
gRPCRisk.ScoreInline: transaction (amount, instrument, payer, payee, merchant, device, IP, location) → decision, score, reasons, decision_id. Deadline 50 ms
Kafkapayments.eventsAuthorisation results and payment outcomes, consumed by the feature pipeline
Kafkarisk.labelsChargebacks, user reports, analyst verdicts keyed by transaction id
POST/rulesCreate or update a rule (condition, action, priority, mode: shadow or active), versioned with approval
GET/cases?status=openAnalyst queue with evidence: transaction, linked entities, rule hits, model explanation
POST/cases/{id}/verdictAnalyst marks fraud or legitimate; becomes a label and may update block lists

4 Data model

online_featuresRedis Cluster / Aerospike (in-memory, replicated)
key = entity_type:entity_id → hash of features (txn_count_1m, txn_count_1h, amount_sum_24h, distinct_payees_24h, first_seen, avg_amount_30d, device_count)

Single-digit ms reads with pipelining. Partition by entity key. TTLs per window to bound memory.

window_stateFlink keyed state (RocksDB) with checkpoints to S3
entity keysliding window buckets (for example 60 one-minute buckets for 1h)

Stream job computes counters and pushes results to the online store; checkpoints let it recover without recounting.

decision_logKafka → S3 (Parquet/Iceberg)
decision_idtxn_idtsfeature_vectormodel_versionmodel_scorerules_versionrule_hitsdecisionlatency_ms

Exact features used at decision time; used for audit, replay and training (point-in-time correct by construction).

labelsPostgres + S3
txn_idlabel (fraud, legit, unknown)source (chargeback, report, analyst)reason_codelabel_time

Joined to decision_log for training; label_time lets you build training sets that only use labels known at a given date.

rulesPostgres, cached in scoring service memory
rule_idversionexpressionactionprioritymodeownercreated_at

Scoring nodes reload a compiled rule set on change (pub/sub notification) with a version number in every decision.

entity_graphGraph store (Neo4j / JanusGraph) or adjacency tables
nodes: userdeviceVPAcardbank accountIP; edges with first_seencount

Offline and near-real-time graph features (cluster size, links to known fraud) are precomputed and written to the online store; no graph traversal in the hot path.

5 Architecture

CLIENTSEDGESERVICESASYNCDATAEXTERNALscore (50 ms)batch feature readfeaturesrules (cached)authorise if allowedtxn outcomedecision logvelocity countersnew model versiongraph + profile featsverdicts = labelsreview queuePayer app / checkoutPayment APIRisk scoring serviceAuthorisation serviceCase management UIModel server (GBDT)Flink feature pipelineKafka (payments,labels)Training & graph jobsOnline feature storePostgres (rules,labels)S3 decision log + lakeCard network / NPCI /bank
ClientEdge / gatewayService / workerQueue / streamCacheDatabase / storageAI / modelThird partyrequestasync (event / queue)

Hover a box to highlight its connections.

6 Request flows

Score a UPI payment

  1. 1User pays ₹18,000 to a new VPA at 1:40 AM from a device first seen 2 hours ago. Authorisation service calls Risk.Score with a 50 ms deadline.
  2. 2Risk service runs hard rules first in memory (blocked VPA, blocked device, sanctioned entity): no hit.
  3. 3It reads features for payer, device, payee VPA, IP and merchant from the feature store in one pipelined batch (~3-5 ms): payer's first transfer to this payee, device age 2 h, 4 transfers in the last 10 minutes, payee received money from 37 new payers today.
  4. 4Model server scores the feature vector (~2-5 ms): probability of fraud 0.83.
  5. 5Decision policy combines score, amount and rules: above the block threshold for new-device high-value transfers → block, with reasons 'new device', 'payee velocity'. Lower scores might get a challenge instead.
  6. 6Risk returns the decision in ~20 ms total; the decision log record goes to Kafka asynchronously.
  7. 7The payment event updates velocity counters in Flink within a second, so the next attempt from this device sees 5 attempts, not 4.
  8. 8Because the payee looks like a mule account, a case is opened for analysts and the payee's risk profile is updated.

Label feedback and retraining

  1. 1Chargebacks and user fraud reports arrive days or weeks later and are written to the labels topic with the original txn_id.
  2. 2Nightly jobs join labels to the decision log (which already holds the exact features used), building a point-in-time correct training set.
  3. 3A new model is trained and evaluated on a recent time-based holdout (not a random split), focusing on precision at the operating threshold and money saved.
  4. 4The new model runs in shadow mode for a week (scores logged, not used), then serves 5-10% of traffic as challenger before full rollout.

7 Deep dives

The latency budget and the fallback

Fraud scoring sits inside authorisation, so every millisecond is paid by every payment. A practical budget at p99: 5 ms network and parsing, 10 ms feature reads, 5 ms model inference, 2 ms rules, leaving headroom inside a 50 ms deadline. To hit it: read all features in one pipelined batch (or one multi-get per shard) instead of 20 sequential calls; keep the rules and model in memory on the scoring nodes or in a sidecar to avoid an extra hop; use tree models that infer in microseconds to a few milliseconds on CPU; avoid any synchronous graph traversal or database query. Then decide the timeout behaviour explicitly, because a scoring outage will happen. Fail-closed (block when unsure) stops fraud but turns an outage into a payments outage. Fail-open (allow everything) keeps payments flowing but invites attackers who notice. The usual answer is a degraded policy: if the model or feature store times out, apply a simple local rule set (amount caps for new devices, block list from local cache) and allow the rest, and alert immediately. Hedged requests to a second replica after p95 latency also cut tail latency. Interviewers want to hear the budget broken down and the fallback chosen deliberately.

Real-time velocity features

Most fraud signal is 'how unusual is this compared to recent behaviour': how many payments from this device in 10 minutes, how many new payers sent money to this VPA today, total amount from this card in 24 hours. These are sliding-window aggregates over entity keys. Compute them in a stream processor (Flink) keyed by entity, with windows built from small buckets (for example 60 one-minute buckets for a 1-hour window), and push the current values to the online store after each event. An alternative used by many teams is to update counters directly in Redis on the authorisation path (INCR on time-bucketed keys with TTL), which gives the freshest data but adds writes to the hot path; a hybrid keeps a few critical counters inline and the rest in Flink. Freshness matters: attackers run bursts of attempts within seconds, so a feature that lags a minute misses the attack; aim for under a second. Use the same feature definitions for training: logging the exact feature vector at decision time into the decision log is the simplest way to avoid training/serving skew, because training then uses exactly what the model saw. Watch out for hot keys: a big merchant's counters get updated thousands of times per second; shard the counter and sum on read.

Rules plus model, and the decision policy

Rules and models do different jobs. Rules are for known, crisp patterns and for reacting within minutes to a new attack ('block payments over ₹5,000 to VPAs created in the last 24 hours from this bank'), for regulatory requirements, and for allow lists. They are readable and fast to change but brittle and hard to maintain once there are thousands. The model (gradient-boosted trees such as XGBoost or LightGBM) generalises across hundreds of weak signals and is robust to small changes. Combine them in a decision policy layer: hard block rules first, then the model score, then thresholds that depend on context (amount, merchant category, user tenure), mapped to allow, challenge or block. Challenge (OTP, 3-D Secure, PIN re-entry, cooling-off for first-time large transfers) is valuable because it stops many fraudsters while costing honest users only a little friction. Every rule should run in shadow mode before going active, and rules need owners and expiry dates, or the rule set rots. Measure both sides: fraud basis points caught and false positive rate (good users declined or challenged), with the money impact of each, because a false decline often loses a customer, not just a transaction.

Labels: delayed, partial and biased

Fraud labels are hard. Chargebacks can arrive weeks after the payment; for UPI, fraud often shows up as user complaints and bank reports rather than chargebacks. Many frauds are never reported, so 'not labelled' does not mean 'legitimate'. Train on transactions old enough that most labels have arrived (for example 60-90 days), and use the time when a label became known so the training set only contains information available at that date. There is also selection bias: transactions you blocked never produce outcome labels, so the model learns only from what earlier systems let through. Counter this by letting a tiny random sample of would-be-blocked, low-amount transactions go through with step-up authentication (exploration), or by using analyst review outcomes on blocked cases. Evaluate on a time-based holdout because fraud patterns drift. Monitor in production: score distribution, block rate, challenge pass rate and feature drift per day; a sudden change in block rate usually means a broken feature, not a fraud wave. Feed analyst verdicts back quickly as fast labels, and use them to retrain more often for the patterns attackers change fastest.

8 Trade-offs

Inline synchronous scoring vs async post-authorisation detection

Inline scoring can stop fraud before money moves, which is essential for UPI where transfers are instant and hard to reverse. It adds latency and becomes part of the payment's availability. Async detection after authorisation is cheaper and can use heavier models and graph analysis, but can only catch fraud after the fact (useful for blocking accounts and mule detection). Use both: inline for decisions, async for deeper analysis that updates features and block lists.

Stream-computed features vs inline counters

Flink-computed features keep the auth path read-only and support complex windows, but have a small lag. Inline Redis counters are freshest but add writes and failure modes to payments. Most teams do a hybrid with a few inline counters for burst attacks.

Gradient-boosted trees vs deep learning

Trees are fast on CPU, strong on tabular features and easy to explain with SHAP. Deep models (sequence models over a user's history, graph neural networks) can catch subtler patterns but cost more to serve and explain. Start with trees; add embeddings from deep models as features computed offline.

9 Bottlenecks

Feature store reads at 10x

At 500k transactions/s, feature reads reach ~10M keys/s. Co-locate features for an entity in one hash so one read fetches many features, keep a small in-process cache for slow-changing profiles (merchant risk, user tenure), and scale the in-memory store horizontally by entity key.

Hot merchant or hot payee keys

A large merchant during a sale produces thousands of updates per second on the same counter. Shard counters into N sub-keys and sum on read, or have Flink pre-aggregate per second before writing.

10 Failure handling

Feature store unavailable

Scoring falls back to the degraded policy (local rules and cached block lists), payments continue with tighter limits for risky segments, and on-call is paged. Features rebuild from Flink checkpoints and Kafka replay when it recovers.

Bad model or broken feature in production

Block rate jumps from 0.3% to 4% within minutes. Automated guards compare live decision rates with the expected range and roll back to the previous model version or switch the broken feature to a default value. All models are versioned, and rollback is a config change.

Flink pipeline lag

Velocity features go stale, and burst attacks may slip through. Alert on consumer lag in seconds; while lag is high, the scoring service tightens thresholds for new devices and high amounts until features are fresh again.

11 What impresses

  • Breaking the 50 ms budget into feature read, inference and rules, and saying what happens on timeout
  • Logging the exact feature vector per decision so training data matches serving
  • Explaining label delay and selection bias and how to handle them
  • Using challenge as a middle option and measuring false declines, not only fraud caught
  • Precomputing graph features offline instead of traversing a graph in the hot path
  • Monitoring block rate as a health signal to catch broken features fast

12 Mistakes

  • Querying the transactional database for velocity counts on every payment
  • Only rules, or only a model, with no way to react to new attacks in minutes
  • Training on randomly split data, leaking future information
  • Ignoring what happens when the fraud service is down
  • Treating unlabelled transactions as legitimate without thought
  • Optimising accuracy on a 0.05% fraud rate (a model that says 'never fraud' is 99.95% accurate)

13 Follow-ups

Q1How would you detect mule accounts that receive money from many victims?
Q2A new scam pattern appears today. How fast can you stop it, and how?
Q3How would you explain to a user why their payment was blocked?
Q4How do you choose the block threshold?
Q5How would you share fraud signals across merchants without leaking their data?
Q6How would you use an LLM in this system, and where would you not use one?

Saved on this device. Create a free account to keep it on every device.

Practise this with Sam

A real mock interview, out loud, with an honest scorecard. Free to start.

Start free