Generate X12 EDI from Java

The EDI Parser for Java can generate X12 EDI directly from Java business objects. The generation API provides the same functionality as the EDI Generation API, but runs inside your Java application without an HTTP request or JSON serialization.

EDI generation is currently supported for:

  • 835 healthcare payment and remittance advice transactions
  • 837P professional claim transactions
  • 837I institutional claim transactions

Generation uses the same Claim, Payment, ServiceLine, PatientSubscriber, OrgOrPerson, and related objects returned by the parser. See the Java parser object model and Javadoc API for field details.

Before using the examples, add the parser library to your project and configure a license key.

Generation Flow

Use EdiWriter to write the EDI envelope, transaction, and business objects in order:

  1. Create an EdiWriter around a Java Writer.
  2. Write the ISA interchange and GS functional group.
  3. Write an EdiTransaction for the ST transaction.
  4. Write one or more Claim objects for an 837, or Payment objects for an 835.
  5. Review the validation issues returned while writing.
  6. Close EdiWriter; it writes the required closing segments automatically.
File ediFile = new File("837p.edi");
try (var fileWriter = new FileWriter(ediFile);
     var ediWriter = new EdiWriter(fileWriter)) {

    var isa = new InterchangeControl("ZZ", "123", "ZZ", "456");
    var gs = new FunctionalGroup(TransactionType.PROF, "1", "2");
    ediWriter.writeIsa(isa);
    ediWriter.writeFunctionalGroup(gs);

    EdiTransaction transaction = create837Transaction(TransactionType.PROF);
    ediWriter.writeTransaction(transaction);

    Claim claim = createProfessionalClaim();
    var validationIssues = ediWriter.writeClaim(claim);
    validationIssues.forEach(System.out::println);
}

EdiWriter assigns unique interchange and group control numbers when they are not provided. It can also assign the transaction’s originator application ID. Closing the writer completes the transaction, functional group, and interchange envelopes.

The shared envelope setup is available in GenerateEdiExampleHelper.java.

Generate an 837P Professional Claim

Use TransactionType.PROF for both the functional group and transaction. Create the claim with Claim.createProfClaim, then populate its providers, subscriber, diagnoses, and professional service lines.

var transaction = new EdiTransaction(TransactionType.PROF);
transaction.sender(createSubmitter());
transaction.receiver(createReceiver());
ediWriter.writeTransaction(transaction);

var claim = Claim.createProfClaim("1234567890", "11");
claim.billingProvider(createBillingProvider());
claim.subscriber(createSubscriber());
claim.addDiagCodes(List.of("J0300", "Z1159"));

var line = ServiceLine.createProfLine(
        "99213",
        new BigDecimal("100.00"),
        BigDecimal.ONE,
        LocalDate.of(2025, 1, 1),
        List.of(1, 2));
line.procedure().addModifier("25");
claim.addLine(line);

var validationIssues = ediWriter.writeClaim(claim);

The submitter and receiver are required at the transaction level. The example also shows required billing-provider and subscriber data, including the payer associated with the subscriber.

View the complete 837P and 837I generation example in GitHub.

Generate an 837I Institutional Claim

Use TransactionType.INST and create the claim with Claim.createInstClaim. Institutional claims use revenue-code service lines and can include occurrence, value, and other institutional codes.

var claim = Claim.createInstClaim(
        "1234567890",
        "11",
        "1",
        "01",
        LocalDate.of(2025, 1, 1),
        LocalDate.of(2025, 1, 31));

claim.addDiagCodes(List.of("M24562", "E8359", "Z1159"));
claim.diags().get(0).isPresentOnAdmission(true);
claim.addCodeEntity(new CodeEntity(UbCodeType.OCCURRENCE, "01")
        .occurrenceDate(LocalDate.of(2025, 1, 1)));

var line = ServiceLine.createInstLine(
        "300", new BigDecimal("100"), new BigDecimal("5"));
line.unitType(UnitType.DAYS);
line.serviceDateFrom(LocalDate.of(2025, 1, 1));
line.serviceDateTo(LocalDate.of(2025, 1, 6));
claim.addLine(line);

var validationIssues = ediWriter.writeClaim(claim);

The complete Generate837EdiExample contains runnable methods for both professional and institutional claims.

Generate an 835 Payment

Use TransactionType.PAYMENT for the functional group and transaction. The transaction contains payment-level data and payer/payee information. Each Payment represents an adjudicated claim and contains its service lines and adjustments.

var transaction = new EdiTransaction(TransactionType.PAYMENT);
transaction.transactionHandlingType(TransactionHandlingType.PAYMENT_AND_ADVICE);
transaction.totalPaymentAmount(new BigDecimal("1000.00"));
transaction.creditOrDebitFlagCode("C");
transaction.paymentMethodType(PaymentMethodType.CHECK);
transaction.paymentDate(LocalDate.of(2026, 6, 1));
transaction.checkOrEftTraceNumber("12345");
transaction.sender(createPayer());
transaction.receiver(createPayee());
ediWriter.writeTransaction(transaction);

var payment = Payment.createPayment(
        "5554555444",
        "94060555410000",
        AdjudicatedClaimStatus.PRIMARY,
        InsurancePlanType.PPO);
payment.patient(createPatient());
payment.patientResponsibilityAmount(new BigDecimal("300.00"));
payment.addLine(createServiceLine());

var validationIssues = ediWriter.writePayment(payment);

The full example builds the payer and payee, a patient, a service line, supplemental amounts, and a claim adjustment.

View the complete 835 generation example in GitHub.

Validation

EdiWriter validates transactions, claims, and payments while writing them. Capture and review the validation issues returned by writeTransaction, writeClaim, and writePayment rather than assuming that generated EDI is valid.

var transactionIssues = ediWriter.writeTransaction(transaction);
transactionIssues.forEach(System.out::println);

var claimIssues = ediWriter.writeClaim(claim);
claimIssues.forEach(System.out::println);

Validation checks required data, transaction structure, balancing, data types, and supported healthcare code sets. Correct reported issues before sending generated EDI to a trading partner.

Parse, Modify, and Generate EDI

Because parsing and generation use the same object model, you can parse an existing transaction, update its objects, and write a new EDI file. This example increases each 837P service-line charge by 10 percent and recalculates the claim total:

try (var parser = new EdiParser(inputFile);
     var fileWriter = new FileWriter(outputFile);
     var ediWriter = new EdiWriter(fileWriter)) {

    EdiParsingResults results = parser.parse(100);
    writeIsaAndGs(ediWriter, TransactionType.PROF);

    for (Claim claim : results.claims()) {
        EdiTransaction transaction = claim.transaction();
        transaction.creationDate(LocalDate.now());
        transaction.creationTime(LocalTime.now());
        ediWriter.writeTransaction(transaction);

        BigDecimal total = BigDecimal.ZERO;
        for (ServiceLine line : claim.lines()) {
            line.chargeAmount(line.chargeAmount().multiply(BigDecimal.valueOf(1.1)));
            total = total.add(line.chargeAmount());
        }
        claim.chargeAmount(total);
        var validationIssues = ediWriter.writeClaim(claim);
        validationIssues.forEach(System.out::println);
    }
}

For files with multiple parsing chunks or transactions, follow the complete example’s loop and preserve the correct envelope and transaction boundaries.

View the complete parse-modify-generate example in GitHub.

Run the Examples

The complete examples are JUnit tests in the hdi.edi.gen package. Clone the repository and run the Java parser test suite from the java-parser directory:

./gradlew test

The suite writes generated files to the repository’s out_edi_files directory. TransformClaimExample is an opt-in example and can be run directly from an IDE.