▲ Beta | Verdict is currently in beta — v0.7.0, pre-1.0 →

The open-source fraud engine that returns a verdict.

Verdict scores every event against rules you can read and answers allow / review / deny in under 100ms — a modular monolith you can split into services the day you outgrow it.

$docker run -p 4000:4000 verdict/engine
Live decision

One request in. One verdict out.

An event arrives, features are read, rules fire, a score resolves — and the caller gets a decision plus the exact signals behind it. Nothing hidden.

Features

Everything a fraud team reaches for.

In one deployable — not five SaaS invoices and a data-sharing agreement.

01

Real-time decision API

One synchronous call returns a verdict, a score, and every signal that fired — inside a hard latency budget.

allowreviewdeny+ challenge
02

Rules you can read

A declarative DSL, versioned in git, hot-reloaded and diffable in review. No black box to trust on faith.

when velocity.attempts > 4
  then score +28
03

Velocity feature store

Redis-backed counters and rolling aggregates computed at write time — attempts per minute, spend per hour.

5attempts / 2m3devices / user
04

Weighted risk scoring

Combine rule hits and features into a transparent 0–100 score. Swap in an ML model behind the same port later.

score = 61 // 28 + 19 + 14
band = review // 35–69
05

Case management

Every review verdict opens a case. Analysts triage a queue, take action, and leave an audit trail.

cse_71ausr_3f9a · paymentREVIEW
06

Feedback loop

Chargebacks and analyst decisions become labels. Backtest a new rule against them before it touches prod.

label: fraudlabel: legit→ backtest
07

Entity graph

Link users, devices, cards and phones to surface rings — the shared fingerprints one event can't reveal.

UDC☎ring?
08

Local-market signals

Detectors Western tools skip — SIM-swap and OTP abuse, agent fraud, cash-on-delivery abuse — plus gateway connectors.

chapatelebirrsms-otp+9
09

Self-hosted & private

Your data never leaves your infra. One Docker deploy today; the same code splits into services under load.

apache-2.0single binary
Configure

Declarative from the first line.

Rules, policies and connectors are code — reviewed, versioned and rolled back like everything else you ship.

++++
// rules/card.authorize.vd — versioned, hot-reloaded
rule r_velocity {
  when  velocity.attemptsLast2m > 4
  then  score += 28, tag "velocity"
}
rule r_takeover {
  when  device.firstSeen == true && geo.ipSimMismatch == true
  then  score += 33, tag "takeover"
}
Architecture

A modular monolith whose seams are already service boundaries.

Seven bounded contexts, each owning its data, talking over an event bus and typed ports — never a shared table. Ships as one process. Every arrow that crosses a context is exactly where you'd cut to extract a service.

ONE DEPLOYABLE · SPLIT ALONG THE SEAMSIngestnormalizeRulesevaluate DSLScoringweight → 0–100Decisionapply policyFeature Storevelocity · aggregatesCasesFeedbackallowreviewdenyeventhitsscorefeaturesfeaturesreviewlabelstunes
ONE REQUEST IN, ONE VERDICT OUT — WITH A FEEDBACK ARC THAT KEEPS THE RULES HONEST
A

Ports & adapters

Every context depends on interfaces, not implementations. Redis, MySQL, Kafka and the ML scorer are swappable adapters.

B

Append-only verdict log

Decisions are events, never mutated. Replay the log to backtest a rule change or reconstruct any verdict.

C

Extract without rewrite

Scoring melting under load? It already talks over the bus. Move it to its own service; nothing upstream changes.

Roadmap

From a rules engine to a fraud platform — in public.

Each phase ships a coherent, usable slice. The order is deliberate: a decision loop first, then depth, then the human layer, then intelligence and the surfaces that make it easy to integrate — and now the hardening that makes it production-ready.

v0.1Shipped

The decision loop

A verdict, end to end.

  • Event ingest & normalize
  • Declarative rules engine
  • Sync decision API
  • Redis velocity counters
  • Append-only verdict log
v0.4Shipped

Decisioning depth

Smarter, safer verdicts.

  • Weighted risk scoring
  • Step-up / challenge
  • Block / allow / watch lists
  • Versioned policies
  • Idempotency & outbox
v0.7Shipped

Human in the loop

Grey areas get a person.

  • Case management
  • Analyst audit trail
  • Label + chargeback capture
  • Operator dashboard
  • Password auth · Postgres
v0.8Shipped

Intelligence

Learn from every label.

  • Analytics read-model
  • Adaptive scoring model
  • Rule & policy backtesting
  • Entity graph & rings
  • Per-user anomaly detection
v0.9Shipped

Built to integrate

Wire it in, in an afternoon.

  • MCP server (LLM-native)
  • Outbound webhooks
  • OpenAPI & Swagger UI
  • API activity log
  • Slack / Telegram / webhook alerts
v1.0Shipped

Production-ready

Hardened for real traffic.

  • Fail-closed config & container hardening
  • Atomic idempotency & transactional outbox
  • Schema migrations & indexes
  • Observability, metrics & durable webhooks
  • Auth hardening, scoped keys & revocation
  • Load & failure testing
  • Data retention & pruning
v1.1Now

Scale & operability

Run it big, run it calm.

  • Durable, throttled notifications
  • Batch & async decisions
  • Config-change audit log
  • Dashboard / docs test coverage
  • Cloud-backed, hot-swappable model
  • Storage stats & disk reclaim
  • Typed tables for high-volume reads
  • SDK development (client SDKs)
v1.2Shipped

Smarter signals

Catch more, explain it all.

  • IP geolocation & impossible travel
  • Device fingerprinting & cloning signals
  • Trained ML scorer (synthetic data)
  • Explainable per-feature reasons
v2.0Vision

Ecosystem & scale

Split, connect, grow.

  • Broker event bus (Kafka/BullMQ)
  • Distributed tracing
  • Multi-tenant & RBAC
  • Managed feature store
  • Streaming ingest
Principles

Elegant is a constraint, not a coat of paint.

A contributor should be able to hold one context in their head. These are the rules the codebase enforces.

01

No shared tables

Contexts own their data and talk through events and typed ports. The schema can never become the coupling.

02

Dependency injection

Adapters arrive through constructors; a default instance is exported. Every unit tests against a mock, not real Redis.

03

Transactional integrity

Money, stock and case state move inside $transaction. A verdict is written, or nothing is.

04

Fail on purpose

Each policy declares fail-open or fail-closed. A degraded scorer never silently blocks or waves through.

05

Additive by default

New signals, outcomes and fields — never a breaking change to a live integration. Old callers keep working.

06

Slow work is async

Enrichment, graph updates and notifications run on queues. The decision path stays inside its budget.

++++

Ship a verdict this afternoon.

Clone it, write three rules, and point your payment path at /v1/decisions. Grow into the platform on your own timeline.