How to Build a claims processing Agent Using LangGraph in TypeScript for wealth management

By Cyprian AaronsUpdated 2026-04-21
claims-processinglanggraphtypescriptwealth-management

A claims processing agent for wealth management takes an incoming claim, validates the policy and client context, extracts the required facts, routes exceptions to a human reviewer, and produces an auditable decision trail. It matters because in wealth management, claims are not just operational events; they affect client trust, compliance posture, and downstream portfolio or custody actions.

Architecture

  • Ingress layer

    • Accepts claim payloads from CRM, case management, or document intake.
    • Normalizes fields like clientId, accountId, claimType, jurisdiction, and attachments.
  • State model

    • Keeps the full working state in a typed LangGraph state object.
    • Stores extracted facts, validation results, decision status, audit metadata, and escalation flags.
  • Validation node

    • Checks policy eligibility, KYC/AML constraints, account ownership, and jurisdiction rules.
    • Rejects or escalates incomplete claims early.
  • Extraction node

    • Pulls structured data from documents or free text using an LLM.
    • Converts unstructured evidence into deterministic fields for downstream rules.
  • Decision node

    • Applies business rules for approve / deny / escalate.
    • Produces a reasoned outcome with references to source data.
  • Audit and persistence layer

    • Writes every transition to an immutable audit log.
    • Persists final outcomes to a case system with retention controls.

Implementation

  1. Define the graph state and the core nodes

Use a typed state so your workflow stays explicit. In production systems, this is where you keep your compliance fields instead of letting them drift through ad hoc objects.

import { Annotation, StateGraph, START, END } from "@langchain/langgraph";
import { ChatOpenAI } from "@langchain/openai";

type ClaimStatus = "pending" | "approved" | "denied" | "escalated";

const ClaimState = Annotation.Root({
  claimId: Annotation<string>(),
  clientId: Annotation<string>(),
  accountId: Annotation<string>(),
  jurisdiction: Annotation<string>(),
  claimText: Annotation<string>(),
  extractedFacts: Annotation<Record<string, unknown>>(),
  validationErrors: Annotation<string[]>(),
  decision: Annotation<ClaimStatus>(),
  decisionReason: Annotation<string>(),
});

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

async function validateClaim(state: typeof ClaimState.State) {
  const errors: string[] = [];

  if (!state.clientId) errors.push("missing_client_id");
  if (!state.accountId) errors.push("missing_account_id");
  if (!state.jurisdiction) errors.push("missing_jurisdiction");

  return {
    validationErrors: errors,
    decision: errors.length > 0 ? "escalated" : "pending",
    decisionReason:
      errors.length > 0 ? "Claim failed required field validation" : "",
  };
}

async function extractFacts(state: typeof ClaimState.State) {
  const response = await llm.invoke([
    {
      role: "system",
      content:
        "Extract structured claim facts for wealth management operations. Return concise JSON only.",
    },
    { role: "user", content: state.claimText },
  ]);

  return {
    extractedFacts: { rawModelOutput: response.content },
  };
}
  1. Add deterministic routing for approval, denial, or escalation

Keep routing logic outside the model when possible. Wealth workflows need predictable decisions that can be explained to compliance teams and auditors.

function routeClaim(state: typeof ClaimState.State) {
  if (state.validationErrors.length > 0) return "escalate";
  
  const facts = state.extractedFacts as Record<string, unknown>;
  
  if (String(facts["fraudIndicator"]) === "true") return "escalate";
  if (String(facts["eligible"]) === "false") return "deny";
  
  return "approve";
}

async function approveClaim(state: typeof ClaimState.State) {
  return {
    decision: "approved" as const,
    decisionReason: "Policy validated and claim meets eligibility criteria",
  };
}

async function denyClaim(state: typeof ClaimState.State) {
  return {
    decision: "denied" as const,
    decisionReason: "Claim does not meet policy eligibility criteria",
  };
}

async function escalateClaim(state: typeof ClaimState.State) {
  return {
    decision: "escalated" as const,
    decisionReason:
      state.validationErrors.length > 0
        ? `Manual review required: ${state.validationErrors.join(", ")}`
        : "Manual review required due to risk signal",
  };
}
  1. Wire the graph with StateGraph, addNode, addEdge, and conditional routing

This is the actual workflow pattern you want in production. The graph stays small enough to reason about while still supporting controlled branching.

const graph = new StateGraph(ClaimState)
  .addNode("validate", validateClaim)
  .addNode("extract", extractFacts)
  
.addNode("approve", approveClaim)
.addNode("deny", denyClaim)
.addNode("escalate", escalateClaim)
  
.addEdge(START, "validate")
.addConditionalEdges("validate", routeClaim, {
    approve after? 
});

The snippet above shows the structure you want, but here is the complete working version:

const graph = new StateGraph(ClaimState)
 .addNode("validate", validateClaim)
 .addNode("extract", extractFacts)
 .addNode("approve", approveClaim)
 .addNode("deny", denyClaim)
 .addNode("escalate", escalateClaim)
 .addEdge(START, "validate")
 .addEdge("validate", "extract")
 .addConditionalEdges("extract", routeClaim, {
   approve:"approve",
   deny:"deny",
   escalate:"escalate",
 })
 .addEdge("approve", END)
 .addEdge("deny", END)
 .addEdge("escalate", END);

const app = graph.compile();

const result = await app.invoke({
 claimId:"CLM-1001",
 clientId:"C12345",
 accountId:"A99881",
 jurisdiction:"US-NY",
 claimText:"Client reports loss on managed account; attached statement indicates eligible event.",
 extractedFacts:{},
 validationErrors:[]
});
  1. Persist outcomes and emit audit events

Do not treat the graph result as the system of record. Write the final decision plus node-level metadata into your case store and audit pipeline.

  • Store:
    • input payload hash
    • model version
    • routing path taken
    • final outcome
    • reviewer override if present

Production Considerations

  • Data residency

    • Keep client data in-region.
    • If your wealth platform operates across jurisdictions, pin execution to approved cloud regions and avoid sending regulated data to external endpoints without contractual controls.
  • Auditability

    • Log every node transition with timestamps and correlation IDs.
    • Preserve prompt/version snapshots so a later review can reconstruct why a claim was escalated or denied.
  • Guardrails

    • Use deterministic checks for eligibility before any LLM-based reasoning.
    • Redact PII and account numbers before model calls unless your security posture explicitly allows it.
  • Monitoring

    • Track escalation rate, false denial rate, manual override rate, and average time-to-decision.
    • Alert when a model starts producing more malformed outputs or when specific jurisdictions spike in manual review.

Common Pitfalls

  1. Letting the LLM make final eligibility decisions

    • Fix this by keeping approval logic in code.
    • Use the model for extraction and summarization; use rules for final routing.
  2. Skipping audit metadata

    • Fix this by persisting node path, input hash, model version, and final reason.
    • In wealth management, “we don’t know how it decided” is not acceptable during review.
  3. Mixing sensitive client data into prompts without controls

    • Fix this by redacting unnecessary fields before invocation.
    • Apply residency-aware deployment and strict access controls around logs, traces, and stored transcripts.
  4. Building one generic workflow for all claim types

    • Fix this by splitting flows by product line or jurisdiction where rules differ materially.
    • Wealth claims often vary by account type, trust structure, tax treatment, and local regulation; one-size-fits-all graphs fail fast in production.

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