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

By Cyprian AaronsUpdated 2026-04-21
claims-processingllamaindextypescriptpayments

A claims processing agent for payments takes an incoming claim, pulls the right policy and transaction context, checks eligibility rules, drafts a decision, and routes anything ambiguous to a human. In payments, that matters because claims are not just text classification — they affect money movement, dispute handling, compliance evidence, and customer trust.

Architecture

  • Claim intake API

    • Receives claim payloads from your payment app or ops workflow.
    • Normalizes fields like transactionId, merchantId, amount, reasonCode, and attachments.
  • Retrieval layer

    • Uses LlamaIndex to fetch policy docs, dispute rules, chargeback guidelines, and internal SOPs.
    • Keeps the agent grounded in current payment policy instead of model memory.
  • Decision engine

    • Applies deterministic checks first: amount thresholds, time windows, duplicate claims, KYC status.
    • Uses the LLM only for interpretation and summarization where rules are ambiguous.
  • Audit trail store

    • Persists inputs, retrieved context, model output, and final decision.
    • Required for compliance review, dispute traceability, and post-incident analysis.
  • Human review queue

    • Handles low-confidence claims or cases that fail guardrails.
    • Prevents automated payout decisions when evidence is incomplete.

Implementation

1) Install the TypeScript dependencies

Use LlamaIndex TS with a real OpenAI-backed LLM and embeddings setup.

npm install llamaindex zod dotenv

Set your environment variables:

export OPENAI_API_KEY="your-key"

2) Index your payment policy documents

You want one index for claims policy docs, chargeback procedures, and payment exception handling. Use VectorStoreIndex plus a simple file loader pattern.

import "dotenv/config";
import { SimpleDirectoryReader, VectorStoreIndex } from "llamaindex";

async function buildPolicyIndex() {
  const documents = await new SimpleDirectoryReader("./policy-docs").loadData();
  const index = await VectorStoreIndex.fromDocuments(documents);
  return index;
}

buildPolicyIndex().then(() => {
  console.log("Policy index ready");
});

This is the core retrieval layer. In production you would persist the vector store instead of rebuilding on every boot.

3) Create a claims agent with structured output

For payments work, free-form text is not enough. Force the model into a schema so downstream systems can route decisions safely.

import "dotenv/config";
import { z } from "zod";
import {
  SimpleDirectoryReader,
  VectorStoreIndex,
} from "llamaindex";

const ClaimDecisionSchema = z.object({
  decision: z.enum(["approve", "deny", "manual_review"]),
  reason: z.string(),
  confidence: z.number().min(0).max(1),
  citedPolicyRefs: z.array(z.string()).default([]),
});

async function runClaimAgent(claimText: string) {
  const documents = await new SimpleDirectoryReader("./policy-docs").loadData();
  const index = await VectorStoreIndex.fromDocuments(documents);

  const queryEngine = index.asQueryEngine({
    similarityTopK: 4,
    responseMode: "compact",
  });

  const response = await queryEngine.query({
    query: `
You are a payments claims processor.
Review this claim against policy docs and return JSON only matching:
${ClaimDecisionSchema.toString()}

Claim:
${claimText}
`,
  });

  const parsed = ClaimDecisionSchema.parse(JSON.parse(response.response));

  return parsed;
}

runClaimAgent(
  "Transaction TXN-88321 was charged twice on the same merchant within 2 minutes."
).then(console.log);

That pattern gives you three things:

  • grounded retrieval over policy content
  • structured output for workflow automation
  • validation before any payout or denial is emitted

4) Add deterministic gates before model output becomes action

Do not let the model be the first line of defense. Put hard rules in front of it for compliance-sensitive payment cases.

type ClaimInput = {
  transactionId: string;
  amount: number;
  daysSinceTransaction: number;
  kycVerified: boolean;
};

function precheck(claim: ClaimInput) {
  if (!claim.kycVerified) return { allowed: false, reason: "KYC not verified" };
  if (claim.amount > 5000) return { allowed: false, reason: "Manual review threshold" };
  if (claim.daysSinceTransaction > 120) return { allowed: false, reason: "Outside dispute window" };
  return { allowed: true };
}

Use this gate before calling LlamaIndex. If allowed is false, route straight to manual review and log the reason.

Production Considerations

  • Persist everything needed for audit

    • Store original claim payloads, retrieved chunks, model response, schema validation errors, and final disposition.
    • For payments teams, this is non-negotiable when regulators or scheme rules ask why a claim was approved or denied.
  • Control data residency

    • Keep policy indexes and claim data in-region if your payment stack has residency requirements.
    • Do not send raw PANs, bank account numbers, or sensitive identity fields into prompts unless they are tokenized or redacted first.
  • Add confidence-based routing

    • Low confidence should mean manual review by default.
    • A bad auto-denial is worse than slower throughput in claims operations because it creates reversals, complaints, and reconciliation noise.
  • Monitor retrieval quality

SignalWhy it matters
Top-k similarity scoresDetects weak policy grounding
Manual review rateShows whether rules are too strict or retrieval is poor
Schema validation failuresCatches malformed model output early
Dispute reversal rateMeasures whether automated decisions are actually correct

Common Pitfalls

  • Letting the LLM decide without hard rules

If you skip deterministic checks for KYC status, dispute windows, fraud flags, or amount thresholds, you will eventually approve something that should have been blocked. Put business logic outside the model.

  • Using raw claim data in prompts

Payment claims often include sensitive identifiers. Redact PANs, CVVs, bank details, and personal data before prompt construction; keep only tokens or masked values in the LLM path.

  • Treating retrieval as optional

A claims agent without current policy context becomes a generic chatbot with payment vocabulary. Rebuild or refresh indexes when policies change, and version your documents so every decision can be tied back to the exact rule set used.


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