Adarsh Puthane
FeaturedIn progress · Milestone 1 of 7
PythonFastAPIPostgreSQLRedis StreamsDockerPydanticFraud Detection

Payment Fraud Detection Engine

Explainable ALLOW / REVIEW / DENY decisions on payments in real time. Ingestion is built; detection is next.

Where it stands: Milestone 1 of 7. The engine ingests and stores payment events today. Detection starts in Milestone 2, so it doesn't flag fraud yet.

Why I'm building it

I investigate payment fraud by hand at work; this is the system I'd want behind that work. It should catch card testing, cloned cards and account takeovers, and explain why it flagged something.

The target: an ALLOW / REVIEW / DENY decision on every payment in under 100 ms, from explainable rules plus an ML risk score.

Architecture

architecture
builtplanned
  1. Client
    payment & card-added events
    (built)
  2. FastAPI ingest
    strict Pydantic contracts
    (built)
  3. PostgreSQL
    source of truth
    Redis Stream
    events:incoming
    (built)
  4. Feature engine
    velocity · amount z-scores · travel
    (planned)
  5. Rules engine
    explainable rules
    ML scorer
    XGBoost + SHAP
    (planned)
  6. Decision
    ALLOW / REVIEW / DENY
    (planned)
  7. Audit log
    (planned)
  8. Analyst dashboard
    (planned)

analyst labels feed back into the ML scorer (planned)

Milestone 1 built the first three stages. Everything from the feature engine down is planned.

What's built (Milestone 1)

  • FastAPI endpoints for payment events, card-added events, ordered batches of up to 1,000, lookup and health.
  • Every event is saved to PostgreSQL (JSONB) and published to a Redis Stream.
  • Strict Pydantic contracts: unknown fields rejected, timezone-aware timestamps, future timestamps refused.

Results

Milestone 1 checks against the ingestion layer.
CheckResult
10,000-event replay0 validation errors, ~4,100 events/s batched
Single-event latency3.9 ms p50 · 5.5 ms p95
Duplicate re-sendAll detected, nothing processed twice
Tests58 automated tests in CI

Design decisions

The security angle: what the engine refuses to do matters as much as what it does.

  • No real card numbers, ever.

    Events carry tokens. A Luhn check rejects anything that looks like a card number, even with spaces, dashes or hidden in a token. The error never echoes it back.

  • Idempotent ingestion.

    Retries are safe, so duplicates can't inflate velocity signals.

  • One ordered stream.

    Card testing (“3 cards added, then ₹1 probes”) depends on true event order.

  • Persist first, roll back on stream failure.

    The API returns 503 so the client retries cleanly.

  • Labels never travel with events.

    No label leakage into the model.

Synthetic data

A generator simulates 500 users over 30 days (~36,000 events, 5% fraud), with realistic innocent noise and five injected attacks:

  • Card testingSeveral cards added in quick succession, then tiny ₹1 probe payments to find out which ones work.
  • CVV brute forceRepeated attempts on the same card, cycling through CVV values until one is accepted.
  • Impossible travelThe same account paying from two places too far apart for the time between the payments.
  • Amount spikeA payment far above what the account normally spends.
  • Account takeoverSomeone else gets into an account and starts moving money out of it.

Roadmap

  1. 1.Ingestion✅
  2. 2.Feature engine (velocity counters, amount z-scores, impossible travel)
  3. 3.Rules engine
  4. 4.ML risk scorer (XGBoost + SHAP)
  5. 5.Decision service & audit log
  6. 6.Analyst dashboard
  7. 7.Write-up & demo
View the repository on GitHub