How to Build a fraud detection Agent Using AutoGen in TypeScript for payments

By Cyprian AaronsUpdated 2026-04-21
fraud-detectionautogentypescriptpayments

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
  • AutoGen agent

    • Uses AssistantAgent to analyze the transaction.
    • Produces structured output: approve, review, or decline, plus reasons and evidence.
  • Tool layer

    • Exposes deterministic functions to the agent through registerFunction.
    • Keeps the model away from direct database access and enforces policy checks in code.
  • 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

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

Related Guides