How to Build a claims processing Agent Using LlamaIndex in TypeScript for fintech

By Cyprian AaronsUpdated 2026-04-21
claims-processingllamaindextypescriptfintech

A claims processing agent automates the first pass on incoming claims: it extracts the claim details, checks them against policy and transaction data, flags missing evidence, and routes the case for approval or investigation. For fintech, this matters because claim volume is high, manual review is expensive, and every decision needs to be auditable, policy-aligned, and defensible under compliance review.

Architecture

  • Claim intake layer

    • Receives claim emails, PDFs, JSON payloads, or webhook events.
    • Normalizes input into a single claim schema before LLM processing.
  • Document ingestion and retrieval

    • Uses VectorStoreIndex to index policy docs, KYC rules, chargeback procedures, and historical claim templates.
    • Supports retrieval over internal knowledge without stuffing everything into the prompt.
  • Claim reasoning agent

    • Uses LlamaIndex chat/agent primitives to classify claim type, extract entities, and decide next action.
    • Produces structured output for downstream workflow systems.
  • Policy and compliance guardrails

    • Enforces data minimization, redaction, and jurisdiction-aware routing.
    • Keeps PII handling separate from model prompts where possible.
  • Audit trail store

    • Persists inputs, retrieved sources, outputs, confidence scores, and human overrides.
    • Required for dispute handling and regulatory review.
  • Case management integration

    • Pushes approved actions into CRM or claims systems.
    • Escalates low-confidence or high-risk cases to human reviewers.

Implementation

1. Install dependencies and define your claim schema

Use the TypeScript LlamaIndex package plus a validator like zod for strict output control. In fintech workflows, untyped model output is how you end up with broken case routing and bad audit records.

npm install llamaindex zod dotenv
import "dotenv/config";
import { z } from "zod";

export const ClaimInputSchema = z.object({
  claimId: z.string(),
  customerId: z.string(),
  amount: z.number(),
  currency: z.string().default("USD"),
  category: z.enum(["fraud", "chargeback", "dispute", "refund"]),
  description: z.string(),
});

export type ClaimInput = z.infer<typeof ClaimInputSchema>;

export const ClaimDecisionSchema = z.object({
  decision: z.enum(["approve", "reject", "needs_review"]),
  reason: z.string(),
  missingEvidence: z.array(z.string()).default([]),
});

2. Build a retrieval index over policy documents

This example uses VectorStoreIndex with SimpleDirectoryReader. Put your policy PDFs or text files in a controlled directory after preprocessing them for residency requirements.

import {
  SimpleDirectoryReader,
  VectorStoreIndex,
} from "llamaindex";

async function buildPolicyIndex() {
  const documents = await new SimpleDirectoryReader({
    inputDir: "./data/policies",
    recursive: true,
  }).loadData();

  return await VectorStoreIndex.fromDocuments(documents);
}

export async function getPolicyRetriever() {
  const index = await buildPolicyIndex();
  return index.asRetriever({ similarityTopK: 4 });
}

3. Create the claims agent with structured output

For production claims handling, I prefer a retrieve-then-reason pattern. The agent pulls relevant policy context first, then produces a constrained decision object that your workflow engine can trust.

import {
  Settings,
  OpenAI,
} from "llamaindex";
import { getPolicyRetriever } from "./policy-index";
import { ClaimInputSchema, ClaimDecisionSchema } from "./schemas";

Settings.llm = new OpenAI({
  model: "gpt-4o-mini",
});

export async function processClaim(rawClaim: unknown) {
  const claim = ClaimInputSchema.parse(rawClaim);
  const retriever = await getPolicyRetriever();

  const query = `
    Review this fintech claim:
    ${JSON.stringify(claim)}

    Return only a decision based on policy context.
    If evidence is missing or risk is unclear, choose needs_review.
    `;

  const nodes = await retriever.retrieve({ query });
  const context = nodes.map((n) => n.node.getContent()).join("\n\n");

  const response = await Settings.llm.complete({
    prompt: `
You are a claims triage assistant for a fintech company.
Use only the provided policy context.

Policy Context:
${context}

Claim:
${JSON.stringify(claim)}

Return JSON with keys: decision, reason, missingEvidence
`,
  });

  const parsed = JSON.parse(response.text);
  return ClaimDecisionSchema.parse(parsed);
}

4. Add an audit record before sending to case management

This is where most teams get sloppy. Store the claim payload version, retrieved document IDs if available, model response, and final human action so compliance can reconstruct the decision path later.

type AuditRecord = {
  claimId: string;
};

export async function handleClaim(rawClaim: unknown) {
  const decision = await processClaim(rawClaim);

   // persist to your DB here
   // include timestamps, model name, prompt hash,
   // retrieved sources, and reviewer override if any

   return {
     ...decision,
     routedTo:
       decision.decision === "needs_review" ? "human_queue" : "case_system",
   };
}

Production Considerations

  • Keep PII out of prompts where possible

    • Mask account numbers, SSNs/national IDs, card PANs, and sensitive free-text fields before sending content to the model.
    • If you must include identifiers for matching, use tokenized internal references.
  • Enforce data residency

    • Store policies and case data in-region if your regulator or contract requires it.
    • Make sure your embedding store and model provider deployment match jurisdictional constraints.
  • Log every retrieval and decision

    • Persist retrieved chunks or document IDs alongside the final answer.
    • Track model version, prompt template version, confidence proxy, reviewer overrides, and SLA timing.
  • Add hard failover paths

    • If retrieval fails or the model returns invalid JSON twice, route directly to manual review.
    • Never auto-close claims on low-confidence outputs.

Common Pitfalls

  • Letting the model decide without policy grounding

    • This creates inconsistent decisions across similar cases.
    • Fix it by forcing retrieval from approved policy documents before every triage call.
  • Accepting free-form text as final output

    • Claims workflows need deterministic fields like decision, reason, and missingEvidence.
const parsed = ClaimDecisionSchema.safeParse(JSON.parse(response.text));
if (!parsed.success) throw new Error("Invalid agent output");
  • Ignoring jurisdiction-specific controls
A US-only deployment pattern will fail if your claims data includes EU customers or local banking secrecy rules.
  • Skipping human review thresholds
Any fraud-adjacent claim with incomplete evidence should go to review instead of auto-decision.

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