Skip to main content
The @openinsure/x12 package provides a pure TypeScript parser and builder for X12 EDI transaction sets used in healthcare, insurance, and transportation. No external EDI libraries or services are required — all processing runs in-process on Cloudflare Workers.

Supported Transaction Sets

SetNameDirectionUse case
834Benefit Enrollment & MaintenanceInboundGroup health member enrollment from employer
835Healthcare Claim Payment/AdviceInboundEOB from carrier to provider / plan
837PHealthcare Claim — ProfessionalOutboundStop-loss claim submission to reinsurer
210Motor Carrier Freight InvoiceInboundFreight billing for transportation lines
211Motor Carrier Bill of LadingInboundShipment manifest for cargo insurance

Parsing

import { parseX12 } from '@openinsure/x12';

const raw = `ISA*00*          *00*          *ZZ*SENDER         *ZZ*RECEIVER       *230601*1200*^*00501*000000001*0*P*:~
GS*BE*SENDER*RECEIVER*20230601*1200*1*X*005010X220A1~
ST*834*0001~
...`;

const result = parseX12(raw);
// result.transactionSets[0].type  → '834'
// result.transactionSets[0].loops → parsed loop structure
// result.valid                    → true | false
// result.errors                   → validation error details

Member Enrollment (834)

import { parse834, type MemberEnrollment } from '@openinsure/x12';

const enrollments: MemberEnrollment[] = parse834(raw834String);

enrollments.forEach((member) => {
  console.log(member.memberId); // '12345'
  console.log(member.firstName); // 'Jane'
  console.log(member.lastName); // 'Smith'
  console.log(member.birthDate); // '1985-03-15'
  console.log(member.coverageType); // 'HMO' | 'PPO' | 'HDHP'
  console.log(member.effectiveDate); // '2025-01-01'
  console.log(member.terminationDate); // null (active)
});

Claim Payment (835)

import { parse835, type ClaimPayment } from '@openinsure/x12';
import { toDollars } from '@openinsure/rating';

const payments: ClaimPayment[] = parse835(raw835String);

payments.forEach((payment) => {
  console.log(payment.claimNumber); // carrier's claim control number
  console.log(payment.paymentAmount); // { cents: 2750000, currency: 'USD' }
  console.log(toDollars(payment.paymentAmount)); // 27500
  console.log(payment.checkNumber); // '00198734'
  console.log(payment.payerName); // 'Acme Health Plan'
  payment.serviceLines.forEach((line) => {
    console.log(line.procedure); // '99213'
    console.log(line.submitted); // Money — submitted charge
    console.log(line.paid); // Money — paid amount
  });
});

Building

import { build837P, type ProfessionalClaim } from '@openinsure/x12';
import { money } from '@openinsure/rating';

const claim: ProfessionalClaim = {
  claimNumber: 'CLM-2025-001',
  patientName: 'Jane Smith',
  patientDob: '19850315',
  patientGender: 'F',
  subscriberId: 'SUB-00123',
  payerName: 'Acme Health Plan',
  diagnosisCodes: ['J06.9'], // Upper respiratory infection
  totalCharge: money(185.0), // { cents: 18500, currency: 'USD' }
  serviceLines: [
    {
      procedure: '99213', // Office visit, established patient
      serviceDate: '20250615',
      units: 1,
      charge: money(185.0),
      placeOfService: '11', // Office
      diagnosis: '1',
    },
  ],
};

const edi = build837P([claim], {
  senderId: 'OPENINSURE',
  receiverId: 'REINSURER',
});

// edi → valid X12 837P EDI string ready for transmission

Transportation (210 / 211)

For commercial transportation insurance programs:
import { parse210, parse211 } from '@openinsure/x12';

// 210 — Freight Invoice (auto-generate invoice from carrier's EDI)
const invoice = parse210(raw210);
// invoice.proNumber, invoice.shipDate, invoice.weight, invoice.charges[]

// 211 — Bill of Lading (manifest for cargo insurance underwriting)
const bol = parse211(raw211);
// bol.shipmentId, bol.origin, bol.destination, bol.commodities[]

Validation

The parser validates each transaction set against the relevant HIPAA or X12 implementation guide:
CheckExample
ISA/GS/GE/IEA envelopeSegment counts must match
Required elementsMissing NM1 segment → error
Element formatDate must be YYYYMMDD
Code valuesOnly valid X12 qualifier codes accepted
const result = parseX12(rawEdi);
if (!result.valid) {
  result.errors.forEach((err) => {
    console.error(`${err.segmentId}/${err.elementPosition}: ${err.message}`);
  });
}

Production Considerations

Caution: ISA envelope setup — Production X12 transmissions require the correct ISA sender/receiver IDs and qualifiers agreed with your trading partner. Test with ISA*00*...*T*:~ (test indicator T) before switching to P (production).
  • Money type: All monetary fields (paymentAmount, submitted, paid, charge, totalCharge, etc.) return Money objects from @openinsure/rating with integer-cent precision. Use toDollars(m) for display formatting.
  • Character encoding: X12 uses ASCII. Characters outside the basic ASCII set in insured names or addresses must be transliterated before building.
  • Segment terminator: The package defaults to ~. Some trading partners use \n or \r\n. Configurable in build*() functions.
  • Acknowledgment (999): The package can parse 999 functional acknowledgments to confirm your 837P was accepted.

Integration Points

  • Member enrollment (834) → populates the members table for group health captives
  • Claim payment (835) → auto-reconciles claim payments against open reserves in the TigerBeetle ledger
  • Professional claim (837P) → submits stop-loss claims to the reinsurer
  • BOL (211) → pre-populates cargo submission fields for transportation risks