How to Build a fraud detection Agent Using CrewAI in TypeScript for fintech

By Cyprian AaronsUpdated 2026-04-21
fraud-detectioncrewaitypescriptfintech

A fraud detection agent in fintech watches transactions, customer behavior, and account signals, then flags suspicious activity before money moves or losses compound. The point is not just classification; it is triage, explanation, and escalation with an audit trail that compliance teams can defend.

Architecture

  • Transaction intake service

    • Receives card payments, ACH transfers, wallet movements, and login events.
    • Normalizes raw payloads into a single fraud-case schema.
  • Risk enrichment layer

    • Pulls customer history, device fingerprint, IP geolocation, velocity checks, chargeback history, and KYC status.
    • Keeps the agent from making decisions on one event in isolation.
  • CrewAI agent layer

    • Uses a Crew with specialized Agents for detection, investigation, and decisioning.
    • Produces structured outputs instead of free-form chat.
  • Policy and compliance guardrail

    • Enforces thresholds for hold, step-up auth, manual review, or allow.
    • Records the rationale for audit and model governance.
  • Case management sink

    • Writes alerts to your SIEM, ticketing system, or fraud ops queue.
    • Stores immutable evidence for regulators and internal review.

Implementation

1) Define the fraud case schema and tools

Keep the agent input tight. In fintech, the fewer degrees of freedom you give an LLM, the easier it is to audit and control.

import { z } from "zod";
import { Agent, Crew, Task } from "@crew-ai/crewai";

const FraudCaseSchema = z.object({
  transactionId: z.string(),
  customerId: z.string(),
  amount: z.number().positive(),
  currency: z.string(),
  merchantCategory: z.string(),
  country: z.string(),
  ipAddress: z.string(),
  deviceId: z.string(),
  velocity24h: z.number(),
  chargebackRate90d: z.number(),
  kycStatus: z.enum(["verified", "pending", "failed"]),
});

type FraudCase = z.infer<typeof FraudCaseSchema>;

async function fetchCustomerRisk(customerId: string) {
  return {
    historicalFraudScore: 0.82,
    accountAgeDays: 14,
    failedLogins24h: 6,
    recentDeviceChanges: true,
  };
}

2) Create specialized agents

Use one agent to assess risk factors and another to produce a compliance-friendly recommendation. This keeps reasoning separated from policy.

const riskAnalyst = new Agent({
  role: "Fraud Risk Analyst",
  goal: "Assess whether a transaction is suspicious using available signals",
  backstory:
    "You analyze payment patterns, velocity anomalies, device risk, and KYC status.",
});

const complianceReviewer = new Agent({
  role: "Fraud Compliance Reviewer",
  goal: "Convert risk findings into a defensible operational action",
  backstory:
    "You apply fintech controls such as step-up auth, hold-for-review, or allow.",
});

3) Build the crew workflow

This pattern works well in production because each task has one job. The first task generates risk analysis; the second turns that analysis into an action with rationale.

export async function evaluateFraud(input: unknown) {
  const fraudCase = FraudCaseSchema.parse(input);
  const enrichment = await fetchCustomerRisk(fraudCase.customerId);

  const analysisTask = new Task({
    description: `
Analyze this transaction for fraud risk.

Transaction:
${JSON.stringify(fraudCase)}

Enrichment:
${JSON.stringify(enrichment)}

Return:
- risk_score from 0 to 100
- key_risk_factors as a list
- recommended_action as one of allow | step_up_auth | manual_review | block
`,
    expectedOutput: "Structured fraud analysis with score and action recommendation",
    agent: riskAnalyst,
  });

  const decisionTask = new Task({
    description: `
Review the fraud analysis and produce an operational decision.
Include:
- final_decision
- justification
- audit_notes
Keep the output concise and suitable for case management.
`,
    expectedOutput: "Final fraud decision with audit-ready justification",
    agent: complianceReviewer,
    contextTasks: [analysisTask],
  });

  const crew = new Crew({
    agents: [riskAnalyst, complianceReviewer],
    tasks: [analysisTask, decisionTask],
    verbose: false,
    memory: false,
    process: "sequential",
  });

  const result = await crew.kickoff();
  
}

4) Return a machine-readable response

Do not ship raw model text to downstream systems. Parse it into your own contract so your rules engine can act on it deterministically.

export async function handleFraudEvent(eventBody: unknown) {
const result = await evaluateFraud(eventBody);

return {
status: "queued_for_review",
result,
};
}

In practice, wrap result parsing around your own JSON schema or strict output parser before writing to a queue. If the model cannot produce valid structured output, fail closed and route to manual review.

Production Considerations

  • Data residency

Keep PII inside the region required by your regulator. If your CrewAI runtime calls external services or hosted models, verify where prompts, traces, and logs are stored.

  • Auditability

Persist every input signal used in the decision path:

  • transaction payload
  • enrichment values
  • prompt version
  • model version
  • final action

This matters when disputes turn into regulator questions.

  • Guardrails

Enforce hard thresholds outside the LLM:

  • block high-risk transfers above a policy cutoff
  • require step-up auth for moderate-risk cases
  • send ambiguous cases to manual review

The agent recommends; policy decides.

  • Monitoring

Track false positives, false negatives, review queue volume, average time-to-decision, and post-decision chargeback rates. If you do not monitor drift by merchant category or geography, you will miss attack patterns early.

Common Pitfalls

  1. Letting the agent make final money-movement decisions

    Use the agent for assessment and explanation. Final authorization should sit behind deterministic rules plus human review for edge cases.

  2. Sending too much raw PII into prompts

    Minimize fields to what is necessary for risk scoring. Tokenizing account identifiers and redacting sensitive fields reduces exposure without hurting detection quality.

  3. Skipping structured outputs

    Free-form responses are hard to route into case systems. Force schema validation before downstream action so malformed output cannot trigger an incorrect block or release.

  4. Ignoring regional compliance constraints

    A fraud agent that works in dev can still fail in production if logs cross borders or retention policies are wrong. Align storage locations, access controls, and retention windows with PCI DSS, GDPR where applicable, and your local banking regulations.


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