The probe
Unlike most system design questions, fraud detection has two hard constraints that conflict: latency (fraud checks must complete in < 100ms inline with the payment flow) and accuracy (false positives block legitimate transactions — costly; false negatives allow fraud — also costly). The architecture must serve both.
Step 1 — Clarify
- Inline (synchronous, blocks payment) or async (payment proceeds, flag for review later)? - Correct answer: both. Hard blocks for obvious fraud, async review for suspicious. - What signals are available: card data, user history, device fingerprint, IP, merchant category?
- False positive tolerance: rejecting 1% of legitimate transactions costs real revenue - Target: catch > 99% of fraud while blocking < 0.1% of legitimate transactions
Step 2 — Data Model
- transactions: tx_id, user_id, card_id, merchant_id, amount, country, device_fingerprint, ip, timestamp
- user_risk_profile: user_id, 30-day spend velocity, typical merchant categories, typical geographies, last_known_device, updated_at
- card_risk_signals: card_id, is_reported_stolen, chargebacks_30d, countries_used_7d - merchant_risk: merchant_id, fraud_rate_30d, category, country
Step 3 — Architecture (two-layer)
Layer 1 — Inline rules engine (< 10ms): Hard rules that block obviously fraudulent transactions:
- Card reported stolen → hard block
- Transaction country ≠ any of user’s last 5 countries AND amount > $500 → block - 5 failed auth attempts in last 60 seconds → block
- Amount > 10× user’s average transaction → flag for step-up auth
Implemented as: rules stored in Redis (fast read), evaluated in-memory per transaction. No ML — pure boolean rules. Fast enough to be fully synchronous.

