Skip to content

X12 EDI

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.


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

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
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)
});
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
});
});

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

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[]

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}`);
});
}

  • 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.

  • 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