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:
- Pre-payment (before
process_payment): blocklist matching, velocity checks, address mismatch detection, proxy/VPN/Tor signals, and the extension'sscore_checkout()method. - Post-payment (after
process_payment): AVS/CVV rule evaluation and the extension'sscore_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 pagefraudReviewQueue(limit, offset)— orders pending fraud reviewfraudRules(channelId)— configured rulesfraudBlocklist(channelId, entryType)— blocklist entriescustomerRiskEvents(customerId, accountId, limit)— risk timeline
Mutations¶
approveFraudReview(orderId)— approve an order, transition to AwaitingFulfillmentdeclineFraudReview(orderId, reason)— decline and cancelcreateFraudRule(...)/updateFraudRule(...)/deleteFraudRule(...)— rule CRUDaddToFraudBlocklist(...)/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.