Skip to main content

The problem

Your claim extraction prompt returns this:
{
  "npi": "12345",
  "providerName": "Dr. Sarah Chen",
  "patientDob": "1990-13-01",
  "procedureCode": "99213",
  "diagnosisCode": "J06.9",
  "amount": 150,
  "lineItems": [
    { "code": "99213", "amount": 85 },
    { "code": "36415", "amount": 65 }
  ]
}
The JSON is valid. The values are not. 12345 is not a valid NPI, and 1990-13-01 is not a real date. Those errors usually show up later, after a payer or downstream system rejects the claim. Boundary does not replace clinical, billing, or compliance review. It gives you a deterministic gate for the data checks you can express in code.

The contract

import { z } from "zod";
import { defineContract } from "@withboundary/contract";

const lineItemSchema = z.object({
  code: z.string(),
  amount: z.number().positive(),
});

export const claimSchema = z.object({
  npi: z.string(),
  providerName: z.string(),
  patientDob: z.string(),
  procedureCode: z.string(),
  diagnosisCode: z.string(),
  amount: z.number().positive(),
  lineItems: z.array(lineItemSchema).min(1),
});

function isValidIsoDate(value: string) {
  const match = /^(\d{4})-(\d{2})-(\d{2})$/.exec(value);
  if (!match) return false;

  const [, yearText, monthText, dayText] = match;
  const year = Number(yearText);
  const month = Number(monthText);
  const day = Number(dayText);
  const date = new Date(Date.UTC(year, month - 1, day));

  return (
    date.getUTCFullYear() === year &&
    date.getUTCMonth() === month - 1 &&
    date.getUTCDate() === day
  );
}

export const claimContract = defineContract({
  name: "healthcare-claim",
  schema: claimSchema,
  rules: [
    {
      name: "npi_is_ten_digits",
      description: "NPI is a 10-digit National Provider Identifier",
      fields: ["npi"],
      check: (claim) =>
        /^\d{10}$/.test(claim.npi)
          || `npi "${claim.npi}" must be exactly 10 digits`,
    },
    {
      name: "diagnosis_is_icd10",
      description: "Diagnosis code matches ICD-10 format",
      fields: ["diagnosisCode"],
      check: (claim) =>
        /^[A-Z]\d{2}(\.\d{1,4})?$/.test(claim.diagnosisCode)
          || `diagnosisCode "${claim.diagnosisCode}" does not match ICD-10 format`,
    },
    {
      name: "procedure_is_cpt",
      description: "Procedure code is a 5-digit CPT code",
      fields: ["procedureCode"],
      check: (claim) =>
        /^\d{5}$/.test(claim.procedureCode)
          || `procedureCode "${claim.procedureCode}" must be a 5-digit CPT code`,
    },
    {
      name: "patient_dob_is_valid",
      description: "Patient date of birth is a real ISO date",
      fields: ["patientDob"],
      check: (claim) =>
        isValidIsoDate(claim.patientDob)
          || `patientDob "${claim.patientDob}" must be a real date in YYYY-MM-DD format`,
    },
    {
      name: "line_items_sum_to_amount",
      description: "Line item amounts sum to the claim total",
      fields: ["lineItems", "amount"],
      check: (claim) => {
        const lineTotal = claim.lineItems.reduce((sum, item) => sum + item.amount, 0);
        return Math.abs(lineTotal - claim.amount) < 0.01
          || `line items total ${lineTotal.toFixed(2)}, but claim amount is ${claim.amount.toFixed(2)}`;
      },
    },
    {
      name: "procedure_in_line_items",
      description: "Primary procedure code appears in the line items",
      fields: ["procedureCode", "lineItems"],
      check: (claim) =>
        claim.lineItems.some((item) => item.code === claim.procedureCode)
          || `procedureCode "${claim.procedureCode}" must appear in lineItems`,
    },
  ],
});
Regex rules are useful here because many healthcare identifiers look plausible even when they are malformed. A schema can say “string”; rules can say “10 digits”, “valid ISO date”, or “primary code appears in the line items.”

Run the model

const result = await claimContract.accept(async (attempt) => {
  const response = await callYourLLM({
    messages: [
      {
        role: "user",
        content: [
          "Extract claim data as JSON.",
          attempt.instructions,
          documentText,
        ].join("\n\n"),
      },
      ...attempt.repairs,
    ],
  });

  return response.text;
});

Accept or reject

if (result.ok) {
  await claimsSystem.stageForSubmission({
    documentId,
    claim: result.data,
  });

  return { status: "accepted" };
}

await claimReviewQueue.add({
  documentId,
  reason: result.error.message,
  attempts: result.error.attempts,
});

return { status: "needs_review" };
Only accepted claim data enters the submission workflow. Rejected data keeps the rule failures and raw attempts for review.

When to use this pattern

  • Medical claims extraction and validation
  • Insurance document parsing
  • Provider credentialing extraction
  • Patient record structured data extraction
  • Lab report parsing with code validation
  • Any healthcare pipeline with regulated identifier formats