How to Build a loan approval Agent Using CrewAI in TypeScript for banking

By Cyprian AaronsUpdated 2026-04-21
loan-approvalcrewaitypescriptbanking

A loan approval agent automates the first pass of credit decisioning: it gathers applicant data, checks policy rules, scores risk, and produces a recommendation with an audit trail. In banking, that matters because you want faster turnaround without losing control over compliance, explainability, and human override.

Architecture

  • Applicant intake service

    • Accepts structured loan applications from your CRM or origination system.
    • Normalizes fields like income, employment type, requested amount, and jurisdiction.
  • Policy retrieval layer

    • Pulls underwriting rules from a controlled source of truth.
    • Keeps product-specific thresholds separate from agent logic.
  • Risk analysis agent

    • Evaluates affordability, debt-to-income ratio, and basic eligibility.
    • Produces a recommendation with reasons, not just a score.
  • Compliance review agent

    • Checks for missing disclosures, prohibited attributes, and jurisdiction-specific constraints.
    • Flags cases that need manual review instead of auto-decision.
  • Decision orchestrator

    • Coordinates multiple agents using CrewAI.
    • Consolidates outputs into approve / reject / refer-to-human.
  • Audit and logging pipeline

    • Stores prompts, tool calls, model outputs, and final decisions.
    • Supports model risk management reviews and regulator audits.

Implementation

1) Set up the TypeScript project

Install CrewAI for TypeScript and define the application shape. Keep your application payload typed because banking workflows break fast when fields drift.

npm install @crewai/crewai zod dotenv
// types.ts
export type LoanApplication = {
  applicantId: string;
  fullName: string;
  country: string;
  requestedAmount: number;
  annualIncome: number;
  monthlyDebtPayments: number;
  creditScore: number;
  employmentStatus: "employed" | "self-employed" | "unemployed";
};

export type LoanDecision = {
  decision: "approve" | "reject" | "refer";
  reasons: string[];
  riskFlags: string[];
};

2) Define agents with explicit banking roles

CrewAI’s Agent class is the right place to encode responsibilities. Keep the underwriting logic separate from compliance logic so one model call does not become a policy blob.

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

const loanSchema = z.object({
  applicantId: z.string(),
  fullName: z.string(),
  country: z.string(),
  requestedAmount: z.number().positive(),
  annualIncome: z.number().positive(),
  monthlyDebtPayments: z.number().nonnegative(),
  creditScore: z.number().int().min(300).max(850),
});

export const riskAgent = new Agent({
  role: "Loan Risk Analyst",
  goal:
    "Assess affordability and repayment risk using provided application data only.",
  backstory:
    "You are a conservative bank underwriter. You do not invent facts. You return a clear recommendation with reasons.",
});

export const complianceAgent = new Agent({
  role: "Banking Compliance Reviewer",
  goal:
    "Check the application for policy violations, missing information, and jurisdictional concerns.",
});

3) Create tasks that produce structured output

Use Task objects to force each agent to do one job. In production, this keeps your audit trail readable and makes it easier to test each step independently.

const riskTask = new Task({
  description:
    "Review the loan application and calculate whether debt burden appears acceptable. Return a recommendation and reasons.",
  expectedOutput:
    "A JSON object with decision, reasons, and riskFlags.",
});

const complianceTask = new Task({
  description:
    "Review the same loan application for compliance issues such as missing fields, unsupported jurisdiction, or suspicious inconsistencies.",
  expectedOutput:
    "A JSON object with decision guidance and compliance flags.",
});

4) Run the crew and merge the outputs

This is the orchestration pattern you want. The crew executes specialist tasks in sequence or parallel depending on your configuration; then your application code applies final bank policy rules before releasing any outcome.

// index.ts
import "dotenv/config";
import { Crew } from "@crewai/crewai";
import { LoanApplication } from "./types";
import { riskAgent, complianceAgent } from "./crew";

const application: LoanApplication = {
  applicantId: "LN-10492",
  fullName: "Jordan Smith",
  country: "ZA",
  requestedAmount: 250000,
  annualIncome: 720000,
  monthlyDebtPayments: 9000,
creditScore:   employmentStatus
};
// index.ts continued
const taskInput = {
applicantId:"LN-10492",fullName:"Jordan Smith",country:"ZA",requestedAmount":250000}

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