Payment fraud costs businesses billions annually. The challenge isn't just building a model that detects fraud. It's building a system that does it in under 50 milliseconds, maintains per-card behavioral history in real-time, explains its decisions, and handles 27:1 class imbalance without drowning in false alarms.
A streaming fraud detection system that scores transactions in real-time. A FastAPI inference service loads an XGBoost model, pulls per-card velocity features from Redis, returns a fraud probability with explanation, and updates the card history. A monitoring dashboard shows the system running live with a demo button visitors can click.
IEEE-CIS Fraud Detection dataset from Vesta Corporation (a real payment processor). 590,540 transactions over 182 days. 3.5% fraud rate (27:1 class imbalance). 434 raw features including anonymous pre-engineered signals from Vesta's internal systems.
| Feature | What It Captures | Signal Strength |
|---|---|---|
| amount_deviation | How far this transaction is from the card's typical spend | Fraud: 0.154 vs legit: -0.006 |
| is_rapid_txn | Less than 60 seconds since the card's last transaction | Fraud: 5.9% vs legit: 3.2% |
| is_night | Transaction between midnight and 6am | Fraud: 26.4% vs legit: 24.1% |
| txn_count_card | Total transactions on this card in the dataset | Low-count cards are riskier |
| time_since_last_txn | Seconds since this card's previous transaction | Very short gaps are suspicious |
Trained XGBoost and LightGBM with class imbalance handling (scale_pos_weight=27.5). Iterated through 4 rounds of hyperparameter tuning:
| Iteration | Change | AUC-PR | Notes |
|---|---|---|---|
| 1 | Default params, 300 trees | 0.499 | Barely above random |
| 2 | 1000 trees, lr=0.02, stronger regularization | 0.519 | Hit max iterations |
| 3 | 2000 trees, early stopping | 0.530 | Still wants more room |
| 4 | 3000 trees, lr=0.01, removed correlated features | 0.531 | Final. Leaner model. |
| Metric | Value |
|---|---|
| AUC-PR | 0.531 |
| AUC-ROC | 0.917 |
| Recall | 64.1% |
| Precision | 35.5% |
| Inference latency (p50) | 2.8ms |
| Throughput | 160+ transactions/sec |
The key insight: a single transaction in isolation tells you almost nothing. But "this is the 4th transaction in 10 minutes from a card that normally spends $50, and this one is $500" is very suspicious. Redis stores per-card history with sub-millisecond read/write. Features computed at prediction time:
Data expires after 48 hours (TTL). Memory capped at 256MB with LRU eviction.
Every prediction comes with the top 5 features driving the decision. The API response includes reasons like "Transaction amount: $5000.00" and "Amount vs card average: 4.2 std devs from normal." This is critical for human reviewers who need to decide whether to block or allow a flagged transaction.
Transaction → FastAPI (/predict)
↓
Redis feature store (read card history)
↓
XGBoost inference (2.8ms)
↓
Response: { fraud: true, probability: 0.82, reasons: [...] }
↓
Redis feature store (update card history)