MARKET: E-commerce — Returns Fraud Detection & Processing
Automate return requests — detect fraud patterns, verify purchase history, process legitimate returns, escalate suspicious ones to loss prevention
halo
// ============================================================
// MARKET: E-commerce — Returns Fraud Detection & Processing
// PURPOSE: Automate return requests — detect fraud patterns,
// verify purchase history, process legitimate returns,
// escalate suspicious ones to loss prevention
// ============================================================
// --- Policies ---
policy PII : Redact(CreditCard) & Redact(SSN)
policy FraudPolicy : Block(RefundAbuse) & Block(WardrobeReturn)
policy CostGuard : MaxSpend(0.50)
// --- Tools ---
tool OrdersAPI : REST("api.shopify.com/admin/orders", apiKey: Env.SHOPIFY_KEY)
tool PaymentGW : POST("api.stripe.com/v1/refunds", apiKey: Env.STRIPE_KEY)
tool CXSlack : POST("hooks.slack.com/services/cx-team")
// --- Store ---
tool ReturnHistory : VectorStore(Env.PINECONE_KEY, namespace: "return-patterns")
tool FraudSignals : VectorStore(Env.PINECONE_KEY, namespace: "fraud-indicators")
// --- Struct ---
schema ReturnDecision {
approved : Boolean
refund_amount : Number
fraud_score : Number
action : String
}
// --- Agents ---
agent ReturnBot [openai/gpt-4o-mini, temp: 0.0]
equips OrdersAPI, PaymentGW
requires PII, CostGuard
agent FraudDetector [anthropic/claude-sonnet-4, temp: 0.0]
equips ReturnHistory, FraudSignals
requires PII, FraudPolicy, CostGuard
// --- The Pipeline ---
@timeout(2m)
@retry(2, 5s)
pipeline ProcessReturn(request: ReturnRequest) -> ReturnDecision:
request
// Step 1: Fan-out — verify order and check fraud signals in parallel
|* {
ReturnBot.verify_order(
tool: OrdersAPI,
order_id: context.data.request.order_id,
customer_id: context.data.request.customer_id
),
FraudDetector.score_risk(
customer_id: context.data.request.customer_id,
return_reason: context.data.request.reason,
item_value: context.data.request.item_price,
days_since_purchase: context.data.request.days_owned
)
}
// Step 2: Gate — if fraud score is high, escalate immediately
|? (context.data.score_risk.fraud_score > 70)
|> CXSlack.post(
message: "🚩 FRAUD ALERT — manual review required",
order: context.data.verify_order,
fraud: context.data.score_risk,
channel: "loss-prevention"
)
|! yield(CXSlack, context.data.score_risk, [context.data.verify_order], 4h)
~> listen(CXSlack.Reaction)
// Step 3: Gate — auto-approve if fraud score is low and within policy
|? (context.data.score_risk.fraud_score < 30)
// Step 4: Process the refund
|> ReturnBot.issue_refund(
tool: PaymentGW,
order_id: context.data.request.order_id,
amount: context.data.request.item_price,
method: "original_payment"
)
// Step 5: Log the return for future pattern detection
|> ReturnHistory.log(
customer: context.data.request.customer_id,
amount: context.data.request.item_price,
reason: context.data.request.reason,
fraud_score: context.data.score_risk.fraud_score
)