Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/sputhenofficial/claimjumper/llms.txt

Use this file to discover all available pages before exploring further.

The POST /api/triage route in app/api/triage/route.ts is the single server-side endpoint in ClaimJumper. It accepts a multipart form upload containing a PNG EOB screenshot, runs the full five-stage pipeline (ingest → triage → invariants → prioritize → draft), and returns a TriageResponse JSON object containing every denial line ranked by priority with lane decisions, deadlines, urgency scores, and—where applicable—ready-to-review draft artifacts.

Request

The endpoint expects a multipart/form-data POST with a single file field named eob.
Content-Type
multipart/form-data
required
Must be multipart/form-data. The request body is parsed with the standard Web Request.formData() API.
eob
File
required
A PNG EOB or remittance advice screenshot. The file must be a valid PNG — the server validates the PNG magic bytes before making any model call. Maximum image size is limited only by what the OpenAI vision API can process.
curl -X POST http://localhost:3000/api/triage \
  -F "eob=@samples/eob-001.png"

Response: 200 OK

A successful response is a TriageResponse JSON object. All denial lines from the remittance are present in items, sorted by descending priority_score.
interface TriageResponse {
  items: QueueItem[];       // prioritized, sorted denial lines
  remittance: RemittanceMeta; // header from the first parsed claim
}
The remittance field contains the payer and provider header data extracted from the first claim on the remittance. Individual QueueItem entries carry the full claim context for each service line.

QueueItem

Each element of items represents one actionable service-line denial.
interface QueueItem {
  claim: Claim;                  // full parsed claim (remittance + claim meta + all lines)
  serviceLine: ServiceLine;      // the specific service line being worked
  prioritized: PrioritizedLine;  // triage decision + deadline + urgency + priority_score
  artifact?: DraftArtifact;      // present for appeal, corrected_claim, and human_review lanes
}
claim
Claim
required
The complete parsed claim containing the remittance header, claim metadata (claim ID, patient name, service date, received date), and the full lines array for that claim.
serviceLine
ServiceLine
required
The specific service line this queue item represents, including procedure code, billed/allowed/paid amounts, patient responsibility, and the denial codes (group_code, carc, rarc).
prioritized
PrioritizedLine
required
Triage output merged with scheduling data. Contains the DenialTriage decision (lane, root cause, rationale, evidence needed, confidence, recovery probability, overrides), the calculated appeal deadline (ISO date string), a 0–1 urgency score, and a finite priority_score used to sort the queue.
artifact
DraftArtifact
Present when prioritized.triage.lane is "appeal", "corrected_claim", or "human_review". Contains the generated draft title, body content, lane tag, and a citations array pointing back to specific fields in the parsed claim. Omitted for patient_bill and write_off lanes. A draft failure does not fail the line — artifact will simply be absent.

Error responses

error
string
A human-readable description of the failure, suitable for display in the UI.
kind
"bad_file" | "server_error"
A stable machine-readable error category. Use this to distinguish between client-correctable errors and server-side failures.
StatuskindCause
400"bad_file"The eob field is missing from the form, or the uploaded bytes do not start with the PNG magic bytes.
500"server_error"Any unhandled pipeline failure — model errors, schema validation failures, claim mapping errors.
// 400 — missing or non-PNG file
{
  "error": "That file is not a PNG EOB screenshot. Choose a .png image and try again.",
  "kind": "bad_file"
}

// 500 — pipeline failure
{
  "error": "The remittance could not be triaged: No claims could be mapped from this remittance. Retry the upload.",
  "kind": "server_error"
}

PNG validation

Before any model call is made, the server reads the first 8 bytes of the uploaded file and compares them against the canonical PNG magic byte sequence. This prevents the pipeline from spending model tokens on non-image files and returns a clear 400 immediately. The PNG magic bytes are [137, 80, 78, 71, 13, 10, 26, 10] — the standard \x89PNG\r\n\x1a\n signature defined in the PNG specification.
function isPng(bytes: Uint8Array): boolean {
  return bytes.length >= 8 && [137, 80, 78, 71, 13, 10, 26, 10].every((value, index) => bytes[index] === value);
}
If isPng() returns false, the route immediately returns a 400 with kind: "bad_file" and does not call OpenAI.

runTriagePipeline()

The route handler delegates all pipeline logic to the exported runTriagePipeline() function. Separating the function from the Next.js handler makes every pipeline stage independently testable without a running HTTP server.
export async function runTriagePipeline(
  imageBytes: Uint8Array,
  dependencies: PipelineDependencies = {},
): Promise<TriageResponse>

PipelineDependencies

All external collaborators can be replaced for testing via the optional second argument:
interface PipelineDependencies {
  ingest?: (imageBytes: Uint8Array) => Promise<IngestOutput>;
  triage?: typeof triage;
  draft?: DraftModelClient;
  today?: () => string;
}
FieldDefaultPurpose
ingestingest from lib/pipeline/ingestExtracts structured claims from the image via the OpenAI vision API.
triagetriage from lib/pipeline/triageClassifies each denial line into a lane with rationale and confidence.
draftresponseWithTextSchema from lib/openaiThe model client used to generate appeal and corrected-claim drafts.
today() => new Date().toISOString().slice(0, 10)Returns today’s UTC date string; override in tests for deterministic deadlines.
When dependencies is omitted (as in the live route handler), all four defaults use the real OpenAI Responses API.
All model calls — ingest, triage, prioritize, and draft — are executed server-side inside runTriagePipeline(). The browser sends only the PNG file in a multipart/form-data POST and receives a single TriageResponse JSON object in return. No OpenAI API key or model output is ever exposed to the client.

Build docs developers (and LLMs) love