How to Build a fraud detection Agent Using AutoGen in TypeScript for payments
A fraud detection agent for payments does one job: inspect transaction context, reason over risk signals, and return a decision or escalation path fast enough to sit inside a payment flow. It matters because the difference between a safe approval and a bad chargeback is often measured in milliseconds, and your agent has to balance fraud loss, false declines, compliance, and auditability.
Architecture
- •
Transaction intake layer
- •Accepts payment events from your checkout, gateway, or risk service.
- •Normalizes fields like amount, currency, merchant ID, BIN, device fingerprint, IP, country, velocity counters, and prior disputes.
- •
Risk context fetcher
- •Pulls supporting data from internal systems:
- •customer history
- •chargeback history
- •account age
- •shipping mismatch
- •device reputation
- •recent auth failures
- •Pulls supporting data from internal systems:
- •
AutoGen agent
- •Uses
AssistantAgentto analyze the transaction. - •Produces structured output:
approve,review, ordecline, plus reasons and evidence.
- •Uses
- •
Tool layer
- •Exposes deterministic functions to the agent through
registerFunction. - •Keeps the model away from direct database access and enforces policy checks in code.
- •Exposes deterministic functions to the agent through
- •
Decision sink
- •Writes the result to your risk engine, case management system, or payment orchestration layer.
- •Stores an immutable audit record for compliance and dispute handling.
Implementation
1) Install and define the transaction contract
Use the AutoGen TypeScript package and keep the transaction schema strict. Fraud workflows fail when the model gets vague inputs or when downstream systems cannot trust the shape of the response.
npm install @autogenai/autogen typescript zod
import { z } from "zod";
export const PaymentTransactionSchema = z.object({
transactionId: z.string(),
merchantId: z.string(),
customerId: z.string(),
amount: z.number().positive(),
currency: z.string().length(3),
country: z.string().length(2),
binCountry: z.string().length(2),
deviceFingerprint: z.string(),
ipAddress: z.string(),
velocity24h: z.number().int().nonnegative(),
chargebacks90d: z.number().int().nonnegative(),
accountAgeDays: z.number().int().nonnegative(),
});
export type PaymentTransaction = z.infer<typeof PaymentTransactionSchema>;
export const FraudDecisionSchema = z.object({
decision: z.enum(["approve", "review", "decline"]),
riskScore: z.number().min(0).max(100),
reasons: z.array(z.string()).min(1),
});
2) Wire up AutoGen with payment-safe tools
The pattern here is simple: let the agent reason, but keep all sensitive lookups and policy enforcement in deterministic tools. In AutoGen TypeScript, that means creating an AssistantAgent and registering functions it can call during analysis.
import { AssistantAgent } from "@autogenai/autogen";
import { PaymentTransactionSchema } from "./schemas";
type RiskSignals = {
priorChargebacks: number;
deviceReputation: "good" | "unknown" | "bad";
ipRisk: number;
};
const getRiskSignals = async (customerId: string): Promise<RiskSignals> => {
// Replace with real internal service calls.
return {
priorChargebacks: customerId === "cust_123" ? 3 : 0,
deviceReputation: "unknown",
ipRisk: customerId === "cust_123" ? 82 : 12,
};
};
const policyCheck = (amount: number, country: string) => {
if (amount > 5000 && country !== "US") return "manual_review";
return "ok";
};
export const fraudAgent = new AssistantAgent({
name: "fraud_detector",
systemMessage:
"You assess payment fraud risk. Return only structured JSON with decision, riskScore, and reasons. Be conservative on high-risk signals. Never request raw PAN or CVV.",
});
fraudAgent.registerFunction(
{
name: "getRiskSignals",
description: "Fetch internal fraud risk signals for a customer",
parameters: {
type: "object",
properties: {
customerId: { type: "string" },
},
required: ["customerId"],
},
returns: {
type: "object",
properties: {
priorChargebacks: { type: "number" },
deviceReputation: { type: "string" },
ipRisk: { type: "number" },
},
required: ["priorChargebacks", "deviceReputation", "ipRisk"],
},
funcAsync,
3) Execute the analysis with a guarded prompt
The prompt should include normalized payment context plus tool outputs. Keep PCI-sensitive data out of the model payload unless you have a hard reason and legal approval; tokenized identifiers are enough for most fraud decisions.
async function funcAsync(argsObj?: any) {
}
Let's fix that with a complete runnable pattern:
import { AssistantAgent } from "@autogenai/autogen";
import { PaymentTransactionSchema } from "./schemas";
type RiskSignals = {
priorChargebacks: number;
};
const getRiskSignals = async (customerId?: string): Promise<RiskSignals> => ({
});
const policyCheck = (amount?: number): string =>
Keep learning
- •The complete AI Agents Roadmap — my full 8-step breakdown
- •Free: The AI Agent Starter Kit — PDF checklist + starter code
- •Work with me — I build AI for banks and insurance companies
By Cyprian Aarons, AI Consultant at Topiax.
Want the complete 8-step roadmap?
Grab the free AI Agent Starter Kit — architecture templates, compliance checklists, and a 7-email deep-dive course.
Get the Starter Kit