Skip to content

Fraud Module

The fraud module provides the core fraud detection infrastructure. External scoring intelligence lives in extensions (ext_ipqs, ext_maxmind, ext_signifyd, ext_riskified); the core provides data models, rule orchestration, and admin UI.

Architecture

Fraud assessment runs in two phases during checkout:

  1. Pre-payment (before process_payment): blocklist matching, velocity checks, address mismatch detection, proxy/VPN/Tor signals, and the extension's score_checkout() method.
  2. Post-payment (after process_payment): AVS/CVV rule evaluation and the extension's score_post_payment() method (for Signifyd/Riskified chargeback guarantee providers).

Scores from both phases are merged. The worst decision wins (block > review > allow).

Key Files

File Purpose
modules/fraud/models.py FraudRule, FraudBlocklist, CustomerRiskEvent
modules/fraud/services.py FraudAssessmentService — core rule engine
modules/fraud/resolvers.py GraphQL queries (dashboard, review queue) and mutations (approve/decline, rules CRUD, blocklist CRUD)
modules/fraud/types.py Strawberry GraphQL types
modules/auth/strategies.py FraudContext, FraudScore, FraudScoringStrategy
modules/payment/strategies.py PaymentResult (structured fraud fields)
tasks/fraud.py recalculate_customer_risk Temporal activity

Models

FraudRule

Configurable rules evaluated at checkout. Channel-scoped (nullable channel_id).

rule_type Description
velocity_ip Max orders per IP in a time window
velocity_email Max orders per email in a time window
velocity_customer Max orders per customer in a time window
velocity_value Max total $ per customer in a time window
avs_mismatch Hold when AVS response indicates no match
cvv_mismatch Hold when CVV response indicates no match

Config JSON: {"window_hours": 24, "threshold": 5}

FraudBlocklist

Blocked or flagged values. Checked during pre-payment assessment.

entry_type Example
ip 192.168.1.1
email bad@example.com
email_domain tempmail.com
country RU
postal_code 90210

CustomerRiskEvent

Immutable audit log for fraud activity. Displayed on the customer detail page.

GraphQL API

Queries

  • fraudDashboard — aggregated metrics for the dashboard page
  • fraudReviewQueue(limit, offset) — orders pending fraud review
  • fraudRules(channelId) — configured rules
  • fraudBlocklist(channelId, entryType) — blocklist entries
  • customerRiskEvents(customerId, accountId, limit) — risk timeline

Mutations

  • approveFraudReview(orderId) — approve an order, transition to AwaitingFulfillment
  • declineFraudReview(orderId, reason) — decline and cancel
  • createFraudRule(...) / updateFraudRule(...) / deleteFraudRule(...) — rule CRUD
  • addToFraudBlocklist(...) / removeFromFraudBlocklist(...) — blocklist CRUD

Permissions

Codename Scope
fraud.review View dashboard, review queue, approve/decline
settings.edit Manage rules and blocklist

Order Risk Fields

Added to the orders table:

Column Type Description
risk_score Decimal(5,4) 0.0000 (safe) to 1.0000 (fraud)
risk_level String(10) low, medium, high, critical
risk_factors JSONB Array of factor objects
avs_result String(10) AVS response code from gateway
cvv_result String(10) CVV response code from gateway

Building a Fraud Extension

Implement FraudScoringStrategy from modules/auth/strategies.py:

class MyFraudStrategy(FraudScoringStrategy):
    @property
    def provider_name(self) -> str:
        return "my_provider"

    async def score_login(self, context: FraudContext) -> FraudScore:
        # IP-based login risk
        ...

    async def score_checkout(self, context: FraudContext) -> FraudScore:
        # Pre-payment scoring
        ...

    async def score_post_payment(self, context: FraudContext) -> FraudScore:
        # Post-auth scoring (for guarantee providers)
        ...

    async def report_decision(self, order_id, decision, analyst_id=None):
        # Feedback loop for ML training
        ...

Register in your extension's on_activate:

strategy_resolver.register(
    FraudScoringStrategy,
    MyProxyStrategy(),
    name="fraud_scoring",
    extension_name=self.name,
)

The FraudContext provides 30+ fields covering IP, geo, buyer identity, billing/shipping addresses, payment data, and order details. See the dataclass in modules/auth/strategies.py for the full list.