How to Build a loan approval Agent Using CrewAI in TypeScript for payments
A loan approval agent for payments takes an application, checks eligibility, pulls the right signals from your internal systems, and returns a decision package with reasons, risk flags, and next actions. For payments teams, this matters because loan decisions affect funding flows, settlement timing, fraud exposure, and regulatory auditability.
Architecture
- •
Application intake service
- •Receives borrower data from your payment or lending UI.
- •Normalizes fields like identity, income, repayment history, and requested amount.
- •
Credit and risk tool layer
- •Wraps calls to KYC, AML, bureau, bank-account verification, and transaction history services.
- •Exposes deterministic tools to the agent through CrewAI.
- •
Loan approval agent
- •Uses
Agentfrom CrewAI to reason over structured inputs and tool outputs. - •Produces a decision: approve, reject, or manual review.
- •Uses
- •
Decision workflow
- •Uses
TaskandCrewto orchestrate analysis steps. - •Separates data extraction, policy evaluation, and final recommendation.
- •Uses
- •
Audit and compliance logger
- •Stores prompts, tool calls, outputs, timestamps, model version, and decision rationale.
- •Required for payments compliance reviews and dispute handling.
- •
Policy gate
- •Applies hard rules outside the model for thresholds like sanctions hits, residency constraints, or maximum exposure.
- •Prevents the LLM from making final decisions on disallowed cases.
Implementation
- •
Install CrewAI and define your payment tools
In TypeScript projects using CrewAI through the Node runtime wrapper you should keep all external checks as tools. The agent should never infer KYC or bureau data from text alone.
import { Agent } from "crewai";
import { Tool } from "@crewai/core";
type LoanApplication = {
applicantId: string;
amount: number;
currency: string;
country: string;
};
const fetchKycStatus = new Tool({
name: "fetch_kyc_status",
description: "Fetch KYC/AML status for an applicant",
func: async (applicantId: string) => {
// Replace with real API call
return JSON.stringify({
applicantId,
kycPassed: true,
amlFlagged: false,
residencyCountry: "KE",
});
},
});
const fetchRepaymentHistory = new Tool({
name: "fetch_repayment_history",
description: "Fetch repayment performance for an applicant",
func: async (applicantId: string) => {
return JSON.stringify({
applicantId,
onTimePayments30d: 12,
missedPayments90d: 0,
chargeOffs12m: 0,
});
},
});
- •
Create the loan approval agent with a strict role
Keep the prompt narrow. In payments workflows the agent should summarize evidence and recommend a decision; hard policy enforcement stays in code.
const loanApprovalAgent = new Agent({
role: "Loan Approval Analyst",
goal:
"Assess a loan application using KYC, repayment history, and policy constraints. Return a decision with concise reasons.",
backstory:
"You work inside a regulated payments company. You must be conservative on compliance risk and produce auditable reasoning.",
verbose: true,
allowDelegation: false,
tools: [fetchKycStatus, fetchRepaymentHistory],
});
- •
Build tasks that separate evidence gathering from decisioning
This pattern makes audits easier. You can inspect intermediate outputs before the final recommendation is returned to your lending system.
import { Task } from "crewai";
import { Crew } from "crewai";
const assessRiskTask = new Task({
description:
"Review KYC status and repayment history for applicant {applicantId}. Identify compliance issues and repayment risk.",
expectedOutput:
"A short risk summary including compliance flags, repayment quality, and whether manual review is required.",
agent: loanApprovalAgent,
});
const finalDecisionTask = new Task({
description:
"Using the risk summary and application details for {applicantId}, recommend approve, reject, or manual_review. Include reasons.",
expectedOutput:
"A JSON-like decision object with decision, rationale, and required_next_steps.",
agent: loanApprovalAgent,
});
const crew = new Crew({
agents: [loanApprovalAgent],
tasks: [assessRiskTask, finalDecisionTask],
});
- •
Execute the crew inside a service endpoint
The output should be validated before it reaches downstream payment orchestration. Treat the model response as advisory unless policy gates pass.
async function evaluateLoan(application: LoanApplication) {
if (application.country !== "KE") {
return {
decision: "manual_review",
rationale: "Data residency/policy requires local review for non-KE applications.",
};
}
const result = await crew.kickoff({
inputs: {
applicantId: application.applicantId,
amount: application.amount.toString(),
currency: application.currency,
country: application.country,
},
});
}
In practice you should parse result into a typed DTO before persisting it. If your CrewAI runtime returns a text payload instead of structured JSON in your setup, add a strict parser plus schema validation with zod.
Production Considerations
- •
Put compliance gates outside the LLM
- •Sanctions hits, age restrictions, country restrictions, and exposure caps must fail closed in code.
- •The agent can explain why a case was blocked; it should not override policy.
- •
Log everything needed for audit
- •Store prompt versions, tool inputs/outputs, model version, latency, decision outcome, and human override actions.
- •Payments auditors will ask why a customer was approved or rejected months later.
- •
Respect data residency
- •Keep PII in-region when regulations require it.
- •If you use hosted models or remote tool endpoints, confirm where data is processed and retained.
- •
Add monitoring on decision drift
- •Track approval rates by segment, manual review rate, false positives on fraud/compliance flags, and downstream delinquency.
Common Pitfalls
- •
Letting the model make policy decisions
Don’t ask the agent to decide on sanctions or residency exceptions by itself. Enforce those rules in deterministic code before
crew.kickoff()runs. - •
Passing raw PII into every prompt
Only send what is necessary for the task. Mask account numbers and national IDs unless a specific tool needs them for verification.
- •
Skipping schema validation on outputs
Never trust free-form text as a production decision object. Validate against a strict schema before writing to your ledger or triggering disbursement.
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