Skip to main content

Returns fraud detection for retail and eCommerce — wardrobing, serial returner, refund anomaly detection, behavioral fingerprinting, policy simulation

Project description

returnguard

AI-powered returns fraud detection for retail and eCommerce — score return requests, detect wardrobing, serial returners, bot patterns, and policy abuse. No $50K enterprise contract required.

PyPI version Python 3.8+

The Problem

Returns fraud costs US retailers $101B/year. AI-generated fraud has "exploded overnight." Enterprise solutions (Happy Returns, Narvar) target only large retail — Shopify has zero built-in fraud scoring. Mid-market merchants are on their own.

Installation

pip install returnguard

Quick Start

from returnguard import FraudScorer, ReturnRequest, ReturnReason
from datetime import datetime, timedelta

scorer = FraudScorer(
    return_rate_threshold=0.30,
    high_value_threshold=150.0,
    velocity_limit=3,
)

request = ReturnRequest(
    return_id="RET-001",
    order_id="ORD-5521",
    customer_id="CUST-42",
    sku="SKU-JACKET-XL",
    quantity=1,
    reason=ReturnReason.CHANGED_MIND,
    order_date=datetime.utcnow() - timedelta(days=3),
    order_value=220.00,
    channel="shopify",
)

result = scorer.score(request)
print(result.risk_level)        # RiskLevel.HIGH
print(result.score)             # 0.6
print(result.signals)           # [FraudSignal.WARDROBING]
print(result.recommended_action)  # "Require photo evidence + manual review"

Fraud Signals Detected

Signal Description
HIGH_RETURN_RATE Customer's return rate exceeds threshold
WARDROBING Use-and-return: changed_mind + < 7 days + high-value item
VELOCITY Too many returns in a short window
SERIAL_RETURNER Customer has been flagged multiple times
POLICY_ABUSE Return submitted after policy window

Customer Profile Tracking

from returnguard import CustomerProfile

profile = CustomerProfile(
    customer_id="CUST-42",
    total_orders=20,
    total_returns=8,
    flagged_count=2,
)

result = scorer.score(request, profile=profile)
# Score accounts for historical return behaviour

Risk Levels & Actions

Risk Level Score Recommended Action
LOW 0.0–0.30 Auto-approve
MEDIUM 0.30–0.55 Flag for manual review
HIGH 0.55–0.75 Require photo evidence
CRITICAL 0.75–1.0 Block + escalate to fraud team

Batch Scoring

from returnguard import batch_score, abatch_score

# Sync
scores = batch_score(requests, scorer.score, max_workers=8)

# Async
scores = await abatch_score(requests, scorer.score, max_concurrency=8)

Advanced Features

Pipeline

from returnguard import FraudPipeline

pipeline = (
    FraudPipeline()
    .filter(lambda s: s.score > 0.5, name="high_risk_only")
    .map(lambda scores: sorted(scores, key=lambda s: -s.score), name="sort_by_risk")
    .with_retry(count=2)
)

high_risk = pipeline.run(all_scores)
print(pipeline.audit_log())

Caching

from returnguard import FraudCache

cache = FraudCache(max_size=1000, ttl_seconds=600)

@cache.memoize
def score_with_cache(request):
    return scorer.score(request)

print(cache.stats())

Validation

from returnguard import ReturnValidator, ReturnRule

validator = ReturnValidator()
validator.add_rule(ReturnRule("max_days", 60, "Return window expired"))
validator.add_rule(ReturnRule("max_order_value", 1000, "High-value item requires manual review"))

valid, errors = validator.validate(request)

Diff & Trend

from returnguard import diff_scores, RiskTrend

diff = diff_scores(previous_scores, current_scores)
print(diff.summary())  # {'added': 3, 'removed': 1, 'modified': 2}

trend = RiskTrend(window=20)
for score in historical_scores:
    trend.record(score.score)
print(trend.trend())       # "increasing"
print(trend.volatility())  # 0.12

Streaming & NDJSON

from returnguard import stream_scores, scores_to_ndjson

for score in stream_scores(results):
    process(score)

for line in scores_to_ndjson(results):
    file.write(line)

Audit Log

from returnguard import AuditLog

log = AuditLog()
log.record("scored", "RET-001", detail="risk=high")
log.record("blocked", "RET-001")
entries = log.export()

Changelog

v1.2.1 (2026-04-10)

  • Fixed type error in SimulationResult.to_dict()max() key now uses explicit lambda for reliable SupportsRichComparison resolution
  • Fixed Pylance reportMissingImports on optional opentelemetry imports in ReturnSpanEmitter — guarded with # type: ignore[import-untyped] (runtime behaviour unchanged; opentelemetry remains optional)

v1.2.0 (2026-03-xx)

  • Added RefundAnomalyDetector — statistical anomaly detection on refund amounts
  • Added BehaviorFingerprinter — fingerprint customer return behaviour patterns
  • Expanded SEO keywords for PyPI discoverability

v1.0.1

  • Advanced features update: pipeline, caching, validation, diff/trend, streaming, audit log

v1.0.0

  • Initial release: core fraud scoring, wardrobing, serial returner, velocity, policy abuse detection

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

returnguard-1.2.1.tar.gz (24.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

returnguard-1.2.1-py3-none-any.whl (21.9 kB view details)

Uploaded Python 3

File details

Details for the file returnguard-1.2.1.tar.gz.

File metadata

  • Download URL: returnguard-1.2.1.tar.gz
  • Upload date:
  • Size: 24.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.9

File hashes

Hashes for returnguard-1.2.1.tar.gz
Algorithm Hash digest
SHA256 b41f4460335d520e6f70f3c10da1409fdfa12dd8ff124b849912eeb8b3dc8c79
MD5 3689817516397dd04649584d6936f97d
BLAKE2b-256 9db78fdb213b0672f2209d3d40e5e163caea69e642814e098c6f3d8ad83ba7d4

See more details on using hashes here.

File details

Details for the file returnguard-1.2.1-py3-none-any.whl.

File metadata

  • Download URL: returnguard-1.2.1-py3-none-any.whl
  • Upload date:
  • Size: 21.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.9

File hashes

Hashes for returnguard-1.2.1-py3-none-any.whl
Algorithm Hash digest
SHA256 4909d7644bfb6250eee839d4cc6e9755ff492600c729e2af48bcc109bf2dedd8
MD5 b885d316a9919294451f12f866d79d89
BLAKE2b-256 e61a8b3cb3fec7e3f7d3577d8f95d4ea6e59281f770f497770ad1b6975626c7f

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page