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.

ingest() in lib/pipeline/ingest.ts accepts a PNG image as a Uint8Array and calls GPT-5.6 Sol via the OpenAI Responses API to extract structured remittance data. The image is base64-encoded and sent as an input_image content block with detail: "original". The model response is parsed and validated against IngestOutputSchema before the function returns. To avoid redundant API calls during development and testing, results are cached to disk by a SHA-256 content hash combined with the active schema version.

Function signature

export async function ingest(
  imageBytes: Uint8Array,
  dependencies: IngestDependencies = {},
): Promise<IngestOutput>
imageBytes is the raw binary content of the PNG file — the same bytes produced by file.arrayBuffer() in the route handler. dependencies is an optional bag of injectable collaborators; when omitted, the function uses the real filesystem cache and the live OpenAI vision client.

Caching

Before making a model call, ingest() computes a cache key by SHA-256 hashing the image bytes and prepending the schema version constant "v2":
const CACHE_SCHEMA_VERSION = "v2";

function cacheKey(imageBytes: Uint8Array): string {
  const imageHash = createHash("sha256").update(imageBytes).digest("hex");
  return `${CACHE_SCHEMA_VERSION}-${imageHash}`;
}
The key is used to look up a JSON file under samples/parsed/. On a cache hit the file is parsed through IngestOutputSchema and returned immediately. On a cache miss the model is called, the result is written to disk, and the validated output is returned. The v2 prefix ensures that a schema change automatically invalidates all existing cache entries without touching the files.

Output schema

IngestOutput is z.array(ClaimSchema).min(1) — an array with at least one Claim object per claim shown on the remittance. Each Claim has three top-level fields: remittance — header fields shared across every claim on the same remittance:
FieldTypeDescription
payerstringPayer name as printed
providerstringProvider name as printed
provider_npistringNational Provider Identifier
notice_datestring (ISO 8601)Date the remittance was issued
payment_datestring (ISO 8601)Date payment was made
eft_tracestringEFT trace number
code_legendCodeLegendEntry[]Every CARC and RARC entry from the printed legend
claim — claim-level identifiers:
FieldTypeDescription
claim_idstringPayer claim identifier
patient_namestringPatient name as printed
service_datestring (ISO 8601)Date of service
claim_received_datestring (ISO 8601)Date claim was received
lines — one entry per service line (ServiceLine[], minimum one):
FieldTypeDescription
line_numbernumberPositive integer line identifier
service_datestring (ISO 8601)Service date for this line
procedure_codestringCPT or HCPCS code
descriptionstringService description
billed_amountnumberAmount billed (nonnegative)
allowed_amountnumberAmount allowed (nonnegative)
paid_amountnumberAmount paid (nonnegative)
patient_responsibilitynumberPatient’s share (nonnegative)
group_codestringClaim adjustment group code
carcstringClaim Adjustment Reason Code
rarcstring | nullRemittance Advice Remark Code, or null if absent
notesstring | nullClaim remark or line-level note, or null if absent

Dependency injection

export interface IngestCache {
  read(key: string): Promise<unknown | null>;
  write(key: string, value: IngestOutput): Promise<void>;
}

export interface IngestVisionClient {
  extract(imageBytes: Uint8Array, prompt: string): Promise<IngestResponse>;
}

export interface IngestDependencies {
  cache?: IngestCache;
  visionClient?: IngestVisionClient;
}
Replacing cache with an in-memory implementation lets tests skip filesystem I/O entirely. Replacing visionClient with a fixture that returns a pre-built response lets tests run without an OpenAI API key. Both substitutions are independent — you can inject only the one you need.

Prompt design

The ingest prompt at prompts/ingest.md gives the model a strictly bounded transcription role. The key constraints are:
  • Transcribe only — copy values visible on the page; never infer, normalize, or complete a code from context or model knowledge.
  • Exact code strings — CARC and RARC are strings, not numbers; preserve leading zeroes and alphanumeric codes exactly as printed.
  • Verbatim legend definitions — transcribe every code_legend entry verbatim from the printed legend; never use the model’s internal knowledge of what a code means.
  • Always emit rarc and notes — use null when the page provides no value for either field.
  • ISO 8601 dates — convert page dates only when all date components are visible.
  • Nonnegative amounts — no currency symbols or thousand separators.
The ingest prompt explicitly forbids inferring missing values. If a required schema value is absent or illegible on the image, the model must omit the affected claim or line entirely rather than guessing. Similarly, if a printed legend entry or definition is illegible, extraction fails rather than completing it from the model’s memory. This means IngestOutput reflects only what is actually visible on the remittance.
The reasoning effort level is "high", set in the responseWithImageSchema() call inside ingest.ts. This gives the model maximum deliberation time to transcribe complex multi-claim remittance layouts accurately.

Build docs developers (and LLMs) love