Converting a Spreadsheet to an 837P Claim File

October 26, 2026 · EDI Paisan Team
edi 837p healthcare billing claims x12 hipaa revenue cycle

Converting a Spreadsheet to an 837P Claim File

Many smaller practices, billing companies, and health IT vendors still manage claim data in spreadsheets — Excel files, CSV exports from an EHR, or hand-maintained Google Sheets. At some point, that data needs to move into the payer ecosystem, and that means producing a valid HIPAA X12 837P file.

This guide walks through exactly how to do that: mapping your spreadsheet columns to X12 segments, understanding what order they go in, handling loops and envelopes correctly, and avoiding the most common mistakes that cause claim rejections.


What Is an 837P File, Really?

The 837P (Professional) transaction set is the HIPAA-standard electronic format for submitting medical claims from physicians, outpatient facilities, labs, and other non-institutional providers. It’s built on the X12 EDI standard and follows a rigid hierarchical structure of loops, segments, and elements.

Every 837P file is essentially a batch — it can contain one claim or thousands. Each claim is nested inside loops that identify the submitter, the receiver, the billing provider, and the patient, before getting to the actual service lines.

Understanding that hierarchy is the first step before you can map a flat spreadsheet to it.


The Anatomy of an 837P File

Before mapping columns, you need to understand the segment structure. Here’s a simplified view:

ISA — Interchange Control Header
  GS  — Functional Group Header
    ST  — Transaction Set Header
    BPR — not used in 837P; BHT is
    BHT — Beginning of Hierarchical Transaction
      Loop 1000A — Submitter
        NM1*41  — Submitter Name
        PER     — Submitter Contact
      Loop 1000B — Receiver
        NM1*40  — Receiver Name
      Loop 2000A — Billing Provider Hierarchical Level
        HL*1**20*1
        Loop 2010AA — Billing Provider Name/Address
          NM1*85
          N3, N4
          REF*EI  — Tax ID
        Loop 2000B — Subscriber (Patient) Hierarchical Level
          HL*2*1*22*0
          SBR — Subscriber Information
          Loop 2010BA — Subscriber Name
            NM1*IL
          Loop 2010BB — Payer Name
            NM1*PR
          Loop 2300 — Claim Information
            CLM — Claim Details
            DTP*435  — Admission Date
            REF — Claim Ref Numbers
            HI  — Diagnosis Codes
            Loop 2310B — Rendering Provider
              NM1*82
            Loop 2400 — Service Line
              LX  — Line Counter
              SV1 — Service Line Detail
              DTP*472 — Date of Service
    SE  — Transaction Set Trailer
  GE  — Functional Group Trailer
IEA — Interchange Control Trailer

Your spreadsheet rows will primarily feed Loop 2300 (claim level) and Loop 2400 (service line level), with shared data from the billing provider and subscriber loops.


Step 1 — Audit Your Spreadsheet Columns

Start by inventorying what data you have. A typical billing spreadsheet has columns like:

ColumnMaps To
Patient First/Last NameNM1QC (or NM1IL for subscriber)
Member ID / Insurance IDNM1*IL — NM109
Date of ServiceDTP*472
CPT / Procedure CodeSV1-01-02
Diagnosis Code (ICD-10)HIABK / HIABF
Charge AmountSV1-02
UnitsSV1-04
Place of ServiceCLM-05-01
Provider NPINM1*82 — NM109
Payer IDNM1*PR — NM109
Group / Policy NumberSBR-03
Claim Reference NumberREF*D9

Common gaps in spreadsheets:

  • Rendering provider NPI vs. billing provider NPI (you need both if different)
  • Taxonomy code for the billing provider (PRV*BI*PXC*<taxonomy>)
  • Patient relationship to subscriber (SBR-02)
  • Claim filing indicator code (SBR-09)

Identify these gaps before you start building the file — missing required elements will cause rejections at the clearinghouse level.


Step 2 — Establish Your Envelope Values

Every 837P file starts with an ISA envelope. Most of these values come from your trading partner agreement with your clearinghouse, not from your spreadsheet.

ISA*00*          *00*          *ZZ*SENDERID       *ZZ*RECEIVERID     *261026*1700*^*00501*000000001*0*P*:~
GS*HC*SENDERID*RECEIVERID*20261026*1700*1*X*005010X222A1~
ST*837*0001*005010X222A1~
BHT*0019*00*BATCH001*20261026*1700*CH~

Key fields:

  • ISA06 — Your interchange sender ID (from clearinghouse)
  • ISA08 — Receiver ID (clearinghouse or payer)
  • ISA15 — P for production, T for test
  • BHT06 — CH for claims, RP for repriced claims

These values are static across all claims in the batch. If you’re building a conversion script, they become constants or config values.


Step 3 — Build the Provider and Submitter Loops

Loop 1000A identifies who is sending the file (the submitter). Loop 1000B identifies the receiver. These are typically your billing company or practice management system and the clearinghouse, respectively.

NM1*41*2*ACME BILLING COMPANY*****46*12345678~
PER*IC*EDI CONTACT*TE*8005550100~
NM1*40*2*CHANGE HEALTHCARE*****46*030240928~

Loop 2010AA is the billing provider — the entity getting paid:

NM1*85*2*MAIN STREET FAMILY PRACTICE*****XX*1234567890~
N3*123 MAIN ST~
N4*SPRINGFIELD*MA*01103~
REF*EI*123456789~
  • NM108 = XX for NPI
  • NM109 = 10-digit NPI
  • REF*EI = Federal Tax ID (EIN)

If your spreadsheet has per-claim billing provider variations (e.g., multi-group setups), you’ll need to handle this at the 2000A loop level. Most single-practice conversions can treat this as a constant.


Step 4 — Map Each Row to a Claim (Loop 2300)

Each claim in your spreadsheet — typically a unique combination of patient, date of service, and payer — maps to one Loop 2300 block.

CLM*CLAIM001*150.00**11:B:1*Y*A*Y*I~
DTP*472*D8*20261015~
REF*D9*1234567890~
HI*ABK:Z38.00*ABF:Z00.129~

Breaking this down:

  • CLM01 — Your claim number / patient account number
  • CLM02 — Total billed amount (sum of all service lines)
  • CLM05-01 — Place of service code (11 = office, 21 = inpatient, etc.)
  • CLM05-03 — Claim frequency code (1 = original, 7 = replacement)
  • CLM06 — Provider signature on file (Y/N)
  • CLM07 — Provider accept assignment (A = assigned)
  • CLM08 — Benefits assignment
  • CLM09 — Release of information (I = informed consent)

HI Segment — Diagnosis Codes:

HI*ABK:Z38.00*ABF:Z00.129*ABF:R10.9~
  • ABK = Principal/primary diagnosis (ICD-10)
  • ABF = Additional diagnoses
  • Each code goes in its own element, colon-delimited with the qualifier

If your spreadsheet has diagnosis codes in separate columns (DX1, DX2, DX3), concatenate them into one HI segment with up to 12 diagnosis positions.


Step 5 — Map Service Lines (Loop 2400)

Each service line in your spreadsheet (a CPT code + date + charge) maps to one Loop 2400 block.

LX*1~
SV1*HC:99213:25**150.00*UN*1***1~
DTP*472*D8*20261015~

Breaking down SV1:

  • SV1-01 — Composite: HC (HCPCS/CPT) + procedure code + modifier(s)
  • SV1-02 — Charge amount for this line
  • SV1-03 — Unit or basis for measurement (usually UN)
  • SV1-04 — Quantity (units)
  • SV1-07 — Diagnosis code pointers (which HI positions apply to this line)

Modifiers go in additional sub-elements of SV1-01:

SV1*HC:99213:25:GT**175.00*UN*1***1~

Here 25 and GT are modifier 1 and modifier 2.

Diagnosis pointers (SV1-07) reference the position of the diagnosis in the HI segment — 1 for the first code, 2 for the second, etc. If your spreadsheet has a column linking each CPT to a diagnosis, map those relationships here.


Step 6 — Close Out the Transaction

After all claims, close the loops in reverse order:

SE*42*0001~
GE*1*1~
IEA*1*000000001~
  • SE01 — Segment count (count every segment from ST to SE inclusive)
  • SE02 — Must match ST02
  • GE02 — Must match GS06
  • IEA02 — Must match ISA13

Getting these counts wrong is one of the most common causes of 999 Functional Acknowledgment rejections. If you’re generating programmatically, count segments as you emit them.


Practical Tips for Scripted Conversions

If you’re building a spreadsheet-to-837P converter (in Python, Node.js, or another language), keep these principles in mind:

Group rows before writing

Sort and group your spreadsheet rows by: Payer → Patient → Date of Service → Claim. This determines your loop hierarchy before you emit a single segment.

Use a segment counter

Maintain a running count of every segment emitted. SE01 must be accurate or the file will fail.

Validate before submitting

Run the output through a HIPAA 837P validator before sending to a clearinghouse. Most clearinghouses offer a test environment — use it.

Handle multiple service lines per claim

If your spreadsheet has multiple CPT rows per claim, aggregate them under a single CLM segment with multiple LX/SV1 loops.

Watch for required vs. situational elements

The 005010X222A1 implementation guide marks elements as Required (R), Situational (S), or Not Used (N). Situational elements must be included when the data exists — for example, REF*D9 (original reference number) is required on replacement claims.


Common Conversion Errors and How to Avoid Them

ErrorCauseFix
ISA segment length errorISA must be exactly 106 charactersPad sender/receiver IDs to required length
Invalid loop structureSegments emitted outside their loopFollow the loop order strictly
SE count mismatchWrong segment count in SE01Count dynamically, not statically
Missing NM1*85No billing provider name loopAlways include Loop 2010AA
HI qualifier invalidUsing wrong ICD qualifierUse ABK for principal, ABF for others in 5010
SV1 diagnosis pointer blankSV1-07 not mappedMap each service line to at least one DX pointer
CLM05-03 missingClaim frequency code absentDefault to 1 for new claims

When to Use a Tool vs. Build Your Own

Building a custom converter makes sense if:

  • You have a high-volume, repeating conversion process
  • Your source data has unique quirks or non-standard columns
  • You’re integrating into a larger workflow (API, batch job, etc.)

But for ad-hoc conversions, spot checks, or one-time file work, a browser-based EDI tool lets you inspect, parse, and validate 837P files without writing any code. You can paste in a raw X12 file, see the segment tree, and verify your output is structurally correct before it hits a clearinghouse.


Summary

Converting a spreadsheet to an 837P file is a well-defined mapping problem — but it demands precision. The X12 format is unforgiving about segment order, element counts, and required fields. Before you write your first ISA segment:

  1. Audit your spreadsheet for all required 837P fields
  2. Identify your envelope values from your clearinghouse setup
  3. Group rows into claims and service lines
  4. Follow the loop hierarchy: 2000A → 2000B → 2300 → 2400
  5. Validate the output before submitting

Once you’ve done it once and have a working template, the process becomes repeatable and automatable.


Ready to work with EDI files in your browser? Try EDI Paisan free — no install required.