Skip to content

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

x12-835-parser

Parses X12 835 healthcare remittance files into structured JSON, with CARC-level denial rollups. TypeScript, zero dependencies, runs in the browser.

Running in the browser is the point. An 835 is full of PHI: member names, member IDs, claim numbers, dates of service. Parsing it client-side means it never has to reach a server, which changes what you are under HIPAA. You become a file processor rather than a data custodian.

Try it

No install required. Node 22+ strips the types natively.

node --experimental-strip-types examples/demo.ts
Payer        SYNTHETIC HEALTH PLAN
Check date   20260805
Claims       5  (3 denied)

Billed       $  1350.00
Paid         $   480.00
Denied       $   825.00

Denials by reason code
────────────────────────────────────────────────────────────────────────
CARC    Claims      Denied  Reason
────────────────────────────────────────────────────────────────────────
29           1  $   400.00  Timely filing limit exceeded
197          1  $   220.00  Precertification/authorization/notification absent
96           1  $   180.00  Non-covered charge
45           1  $    25.00  Charge exceeds fee schedule or contracted/legislated fee
────────────────────────────────────────────────────────────────────────

The sample in examples/ is synthetic. Every name, member ID, claim number and dollar amount in it is invented.

Usage

import { parse835 } from './src/index.ts';

const result = parse835(rawFileContents);

result.totalBilled        // 1350
result.totalPaid          // 480, taken from the BPR check amount
result.totalDenied        // 825
result.payerName          // 'SYNTHETIC HEALTH PLAN'
result.checkDate          // '20260805'
result.claimCount         // 5
result.deniedClaimCount   // 3
result.claims             // Claim[], each with adjustments and service lines
result.byCARC             // CARCSummary[], rolled up denial reasons
result.parseErrors        // string[], non-fatal problems worth surfacing

In a browser, read the file with the File API and hand the text straight in:

const text = await file.text();
const result = parse835(text);
// No upload. No fetch. Nothing leaves the page.

What it handles

Delimiters are read from the envelope, not assumed. X12 declares its own element delimiter at byte 3 and its segment terminator at byte 105 of the ISA segment. Plenty of parsers hardcode * and ~ and then break on the first payer who uses something else. This one reads them.

Adjustment groups are distinguished. CO (contractual obligation) and OA (other adjustment) roll into the denial summary. PR (patient responsibility) does not, because a copay is not a denial and counting it as one inflates every number a billing manager cares about.

Claims carry their service lines. SVC segments attach to the CLP they belong to, with their own adjustments, so you can see which procedure inside a claim got denied rather than only that the claim did.

Unknown reason codes degrade instead of throwing. A code with no label returns Reason code X (contact payer for details). Payers add codes; a parser that crashes on an unrecognized one is useless in production.

Malformed input fails with a message a human can act on, not a stack trace.

CARC labels

src/carc.ts maps Claim Adjustment Reason Codes to plain-language descriptions, weighted toward the codes that actually appear in behavioral health remittances rather than the full published set.

import { getCARCLabel } from './src/carc.ts';

getCARCLabel('29');    // 'Timely filing limit exceeded'
getCARCLabel('ZZ99');  // 'Reason code ZZ99 (contact payer for details)'

Tests

node --experimental-strip-types tests/parse835.test.ts

Eleven tests covering envelope delimiter detection, claim and total reconciliation, denied-claim identification, CARC rollup correctness, the patient-responsibility exclusion, service line attachment, and graceful handling of unknown codes and malformed input.

Scope

This parses 835s. It does not do denial workflow, appeal generation, payer submission, or claim scrubbing.

It was extracted from a larger denial-management tool built for Pennsylvania behavioral health agencies. The parser is the reusable half and it is the half worth sharing.

Background

I spent twelve years inside a HIPAA-regulated behavioral health provider, three of them as Director of IT, processing 835 remittances across Medicaid, Medicare and managed-care payers. I ran the 4010 to 5010 transition. I can read X12 by eye, which is mostly what made writing this tractable.

License

MIT. See LICENSE.

About

Zero-dependency X12 835 healthcare remittance parser with CARC denial rollups. Runs in the browser so PHI never leaves the client.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages