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.
Supported Transaction Sets
| Set | Name | Direction | Use case |
|---|---|---|---|
| 834 | Benefit Enrollment & Maintenance | Inbound | Group health member enrollment from employer |
| 835 | Healthcare Claim Payment/Advice | Inbound | EOB from carrier to provider / plan |
| 837P | Healthcare Claim — Professional | Outbound | Stop-loss claim submission to reinsurer |
| 210 | Motor Carrier Freight Invoice | Inbound | Freight billing for transportation lines |
| 211 | Motor Carrier Bill of Lading | Inbound | Shipment 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:
| Check | Example |
|---|---|
| ISA/GS/GE/IEA envelope | Segment counts must match |
| Required elements | Missing NM1 segment → error |
| Element format | Date must be YYYYMMDD |
| Code values | Only 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.) returnMoneyobjects from@openinsure/ratingwith integer-cent precision. UsetoDollars(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\nor\r\n. Configurable inbuild*()functions. - Acknowledgment (999): The package can parse 999 functional acknowledgments to confirm your 837P was accepted.
Integration Points
- Member enrollment (834) → populates the
memberstable 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