How to Build a transaction monitoring Agent Using AutoGen in TypeScript for lending
A transaction monitoring agent for lending watches borrower activity, flags suspicious or risky patterns, and routes cases for review before they become losses or compliance issues. In lending, that matters because the same system has to catch fraud, early delinquency signals, AML-adjacent behavior, and policy breaches without blocking legitimate borrowers.
Architecture
- •
Transaction ingestion layer
- •Pulls events from loan servicing systems, card rails, ACH feeds, or payment webhooks.
- •Normalizes them into a single schema: borrower ID, amount, timestamp, channel, merchant, geography.
- •
Risk policy engine
- •Applies deterministic rules first.
- •Examples: velocity spikes, payment reversals, repeated failed debits, offshore transfers on domestic-only products.
- •
AutoGen agent orchestrator
- •Uses
AssistantAgentandUserProxyAgentto analyze ambiguous cases. - •Produces a structured decision:
clear,review, orescalate.
- •Uses
- •
Case management sink
- •Writes alerts to your investigation queue.
- •Stores the model output, evidence, and decision trail for audit.
- •
Audit and compliance store
- •Persists prompts, tool calls, outputs, and rule hits.
- •Needed for model governance, explainability, and regulator review.
Implementation
1) Install AutoGen for TypeScript and define your event contract
Use the TypeScript package that exposes the AutoGen agent classes. Keep your transaction shape strict from day one; lending workflows break fast when payloads are loose.
npm install @autogen-ai/autogen zod
import { z } from "zod";
export const TransactionSchema = z.object({
transactionId: z.string(),
borrowerId: z.string(),
loanId: z.string(),
amount: z.number().positive(),
currency: z.string().length(3),
timestamp: z.string(),
channel: z.enum(["ach", "card", "wire", "cash", "wallet"]),
merchantCountry: z.string().length(2),
borrowerCountry: z.string().length(2),
failedAttempts24h: z.number().int().nonnegative(),
chargebacks90d: z.number().int().nonnegative(),
});
export type Transaction = z.infer<typeof TransactionSchema>;
2) Create a policy-first monitor with an AutoGen agent
The pattern here is simple: rules filter obvious cases, then AutoGen handles gray areas. That keeps cost down and makes the system easier to defend in audits.
import { AssistantAgent } from "@autogen-ai/autogen";
const monitorAgent = new AssistantAgent({
name: "lending_txn_monitor",
systemMessage: `
You are a transaction monitoring analyst for a lending platform.
Classify each event as clear, review, or escalate.
Focus on fraud risk, repayment abuse, AML-adjacent indicators,
policy violations, and borrower hardship signals.
Return JSON only with fields:
decision, reason, evidence[], recommendedAction.
`,
});
function applyRules(txn: Transaction) {
const hits: string[] = [];
if (txn.amount > 5000) hits.push("high_amount");
if (txn.failedAttempts24h >= 5) hits.push("failed_attempt_spike");
if (txn.chargebacks90d >= 3) hits.push("chargeback_pattern");
if (txn.merchantCountry !== txn.borrowerCountry) hits.push("cross_border_activity");
return hits;
}
async function analyzeTransaction(txn: Transaction) {
const ruleHits = applyRules(txn);
if (ruleHits.length >= 2) {
return {
decision: "review",
reason: "Deterministic policy threshold reached",
evidence: ruleHits,
recommendedAction: "Create case for analyst review",
};
}
const prompt = `
Transaction:
${JSON.stringify(txn)}
Rule hits:
${JSON.stringify(ruleHits)}
Decide whether this should be clear, review, or escalate.
Return JSON only.
`;
const result = await monitorAgent.send({ content: prompt });
return result;
}
3) Add a reviewer loop for ambiguous cases
For lending operations you usually want a second pass when the first output is not machine-actionable. Use UserProxyAgent to simulate an analyst workflow or to collect human input in production.
import { UserProxyAgent } from "@autogen-ai/autogen";
const reviewer = new UserProxyAgent({
name: "case_reviewer",
});
async function handleTransaction(txnInput: unknown) {
const txn = TransactionSchema.parse(txnInput);
const analysis = await analyzeTransaction(txn);
if (typeof analysis === "string") {
return { status: "error", message: analysis };
}
if ((analysis as any).decision === "escalate") {
const humanNote = await reviewer.send({
content: `Review required for ${txn.transactionId}. Summary:\n${JSON.stringify(analysis)}`,
});
return {
transactionId: txn.transactionId,
status: "escalated",
analysis,
humanNote,
};
}
return {
transactionId: txn.transactionId,
status: (analysis as any).decision,
analysis,
};
}
4) Persist audit records before you ship alerts downstream
Do not treat the model response as the final artifact. In lending you need replayable evidence for disputes, internal audit, and regulator questions.
type AuditRecord = {
transactionId: string;
};
async function writeAudit(record: AuditRecord & Record<string, unknown>) {
}
async function processIncomingEvent(eventPayload: unknown) {
}
async function processIncomingEvent(eventPayload);
The important pattern is not the storage library. It is the sequence:
- •validate input
- •apply deterministic rules
- •call AutoGen only when needed
- •persist prompt/output/evidence
- •emit alert or clear the transaction
Production Considerations
- •
Keep data residency explicit
- •If borrower data must stay in-region, deploy the agent and its storage in that region only.
- •Do not send PII to external tools unless your legal basis and vendor agreements cover it.
- •
Log everything needed for audit
- •Store raw input hashes, rule hits, model output, timestamps, and analyst overrides.
- •For lending reviews this is non-negotiable when disputes or model governance checks happen.
- •
Use guardrails before LLM calls
- •Redact SSNs, account numbers, salary details, and full addresses unless strictly required.
- •Pass only the minimum data needed for classification.
- •
Separate alerting from decisioning
- •The agent should recommend actions.
- •A policy service or human reviewer should approve adverse actions like account restriction or loan servicing holds.
Common Pitfalls
- •
Letting the model do all the screening
- •Bad move. Obvious thresholds should be handled by code first.
- •Fix it by using rules for high-confidence triggers and AutoGen only for ambiguous cases.
- •
Sending raw borrower data into prompts
- •This creates privacy and residency problems fast.
- •Fix it by tokenizing identifiers and redacting sensitive fields before calling
AssistantAgent.
- •
Skipping an audit trail
- •If you cannot explain why a case was flagged, you will have problems in compliance reviews.
- •Fix it by persisting inputs, outputs, rule hits, and human overrides for every decision path.
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