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

By Cyprian AaronsUpdated 2026-04-21
loan-approvalcrewaitypescriptinsurance

A loan approval agent for insurance automates the first pass on financing requests tied to policies, premiums, or broker-dealer arrangements. It reads applicant data, checks underwriting rules, flags compliance issues, and produces a decision package that an underwriter can approve, reject, or escalate.

Architecture

  • Input adapter

    • Pulls loan application data from your CRM, policy admin system, or case management queue.
    • Normalizes fields like applicant identity, income, policy status, claim history, and requested amount.
  • Policy/rules layer

    • Enforces insurance-specific constraints before any LLM reasoning.
    • Handles hard stops such as sanctions hits, missing consent, lapsed policy status, or prohibited jurisdictions.
  • CrewAI crew

    • Coordinates specialized agents for risk review, compliance review, and final decision synthesis.
    • Produces a structured recommendation instead of free-form text.
  • Audit trail store

    • Persists prompts, tool calls, intermediate outputs, and final decisions.
    • Needed for model governance, adverse action review, and regulator audits.
  • Human review queue

    • Routes borderline cases to an underwriter.
    • Keeps the agent in assistive mode where regulations require human sign-off.

Implementation

1. Install CrewAI for TypeScript and define your decision schema

Use TypeScript types first. In lending workflows you want a strict output shape so downstream systems can validate the result without parsing prose.

// types.ts
export type LoanDecision = "approve" | "reject" | "escalate";

export interface LoanApplication {
  applicationId: string;
  applicantName: string;
  applicantCountry: string;
  annualIncome: number;
  requestedAmount: number;
  policyNumber?: string;
  policyStatus?: "active" | "lapsed" | "cancelled";
  consentToProcessData: boolean;
  sanctionsHit: boolean;
}

export interface DecisionResult {
  decision: LoanDecision;
  riskScore: number; // 0-100
  reasons: string[];
  requiredActions: string[];
}

2. Create agents with explicit responsibilities

CrewAI works best when each agent has one job. For insurance lending, split compliance from risk so you can audit each reasoning path separately.

// crew.ts
import { Agent } from "@crew-ai/crewai";
import { ChatOpenAI } from "@langchain/openai";

const llm = new ChatOpenAI({
  model: "gpt-4o-mini",
  temperature: 0,
});

export const complianceAgent = new Agent({
  role: "Insurance Compliance Reviewer",
  goal: "Check whether the loan application violates insurance compliance rules.",
  backstory:
    "You review insurance-linked lending applications for consent, sanctions, jurisdictional restrictions, and policy status.",
  llm,
});

export const riskAgent = new Agent({
  role: "Credit and Policy Risk Analyst",
  goal: "Assess repayment risk using application facts and insurance context.",
  backstory:
    "You evaluate financial capacity alongside policy conditions and claim-related indicators.",
  llm,
});

export const decisionAgent = new Agent({
  role: "Loan Decision Synthesizer",
  goal: "Combine compliance and risk findings into a structured recommendation.",
  backstory:
    "You produce a final underwriting recommendation for human review or automated routing.",
  llm,
});

3. Add tasks with structured outputs and build the crew

Keep task descriptions concrete. The agent should not invent missing data; it should escalate when fields are absent or contradictory.

// workflow.ts
import { Crew } from "@crew-ai/crewai";
import { Task } from "@crew-ai/crewai";
import { complianceAgent, riskAgent, decisionAgent } from "./crew";
import type { LoanApplication } from "./types";

export function buildLoanApprovalCrew(application: LoanApplication) {
  const complianceTask = new Task({
    description: `
Review this insurance-linked loan application for compliance issues.
Rules:
- Reject if consentToProcessData is false.
- Reject if sanctionsHit is true.
- Escalate if policyStatus is lapsed or cancelled.
- Escalate if applicantCountry is outside approved jurisdictions.

Application:
${JSON.stringify(application)}
`,
    agent: complianceAgent,
    expectedOutput:
      "A concise compliance summary with explicit pass/fail/escalate signals.",
    outputJsonSchema: {
      type: "object",
      properties: {
        status: { type: "string", enum: ["pass", "fail", "escalate"] },
        reasons: { type: "array", items: { type: "string" } },
      },
      required: ["status", "reasons"],
      additionalProperties: false,
    },
  });

  const riskTask = new Task({
    description: `
Assess repayment and portfolio risk for this application.
Consider income vs requestedAmount ratio, policy status stability, and any red flags from the application data.
Do not make legal/compliance determinations here.
`,
    agent: riskAgent,
    expectedOutput:
      "A numeric risk assessment with reasons and recommended handling.",
    outputJsonSchema: {
      type: "object",
      properties: {
        riskScore: { type: "number" },
        reasons: { type: "array", items: { type: "string" } },
      },
      required: ["riskScore", "reasons"],
      additionalProperties: false,
    },
    context:[complianceTask],
    

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