From 9fe41b72690e959b49ebc056592fc03473f390bc Mon Sep 17 00:00:00 2001 From: Tyler Date: Fri, 19 Jun 2026 19:49:02 -0600 Subject: [PATCH] docs: add 837p reference note --- docs/reference/837p.md | 78 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 docs/reference/837p.md diff --git a/docs/reference/837p.md b/docs/reference/837p.md new file mode 100644 index 0000000..6bd0a99 --- /dev/null +++ b/docs/reference/837p.md @@ -0,0 +1,78 @@ +# 837P — Professional Claims (005010X222A1) + +The 837P transaction set carries professional (outpatient) healthcare claims +from a billing provider to a payer. Cyclone parses the segments it needs to +produce a structured `ClaimOutput` and validates against CO Medicaid rules. + +## File format + +- Extension: `.txt` +- Encoding: ASCII (UTF-8 also accepted) +- Delimiters (declared in `ISA`): `*` element, `:` component, `~` segment, `^` repetition + +## Envelope + +| Segment | Purpose | +|---|---| +| `ISA` / `IEA` | Interchange envelope (sender ↔ receiver) | +| `GS` / `GE` | Functional group envelope | +| `ST` / `SE` | Transaction set envelope (837) | + +## Loops + +| Loop | Contents | +|---|---| +| 2000A | Billing provider hierarchy (NM1*85) | +| 2000B | Subscriber hierarchy (NM1*IL) | +| 2300 | Claim (CLM, HI, NM1, DTP, REF…) | +| 2400 | Service line (LX, SV1, DTP) | + +## Segments Cyclone parses + +- `NM1`, `N3`, `N4` — names and addresses +- `REF` — prior auth (`REF*G1`), provider taxonomy, etc. +- `CLM` — claim header; `CLM01` = patient control number, `CLM02` = total claim charge +- `HI` — diagnoses (qualifier `ABK` = ICD-10 principal) +- `LX`, `SV1` — service line + procedure code +- `DTP` — service date (`DTP*472`) +- `BHT` — beginning of hierarchical transaction + +## Segments preserved but not modeled + +All other segments are kept in `raw_segments` for audit but are not extracted +into the structured `ClaimOutput`. See `cyclone/parsers/parse_837.py` for the +full walker. + +## CO Medicaid specifics + +- Trading partner: `SKCO0` (sender) ↔ `COHCPF` (receiver) on `NM1*PR` / `NM1*40` +- `CLM05` is a composite of three components: place of service, facility code + qualifier, and frequency code (in that order) + - `CLM05-1` = place of service (any valid CMS POS code) + - `CLM05-2` = facility code qualifier (`B` for CMS POS) + - `CLM05-3` = frequency code; must be one of `{1, 7, 8}` (1 = original, + 7 = replacement, 8 = void) +- `REF*G1` carries prior-authorization number when applicable +- No 2010BA/2010CA patient loop — subscriber is the patient +- `CLM06` (provider signature on file) and `CLM07` (assignment of benefits) are + typically `Y` + +## Validation rules Cyclone enforces + +Rules are defined in `cyclone/parsers/validator.py` and registered on the +`PayerConfig` for the active payer. The default `co_medicaid()` factory uses +`allowed_claim_frequencies={1, 7, 8}` and the full CMS POS set. + +| Rule | Severity | Description | +|---|---|---| +| `R010_clm01_present` | error | `CLM01` (patient control number) is empty | +| `R011_total_charge_positive` | error | `CLM02` (total charge) must be `> 0` | +| `R020_npi_format` | error | Billing provider NPI must be 10 digits | +| `R030_frequency_allowed` | error | `CLM05-3` ∈ `allowed_claim_frequencies` | +| `R031_ref_g1_optional` | — | `REF*G1` is informational in v1; no issues yielded | +| `R032_clm05_2_facility_qualifier` | error | `CLM05-2` ∈ `allowed_facility_qualifiers` (e.g. `B`) | +| `R033_clm05_1_place_of_service_code` | error | `CLM05-1` ∈ `allowed_place_of_service_codes` (CMS POS) | +| `R050_diagnosis_present` | error | At least one diagnosis on the `HI` segment | +| `R060_service_dates_present` | error | Every service line has a `DTP*472` service date | +| `R070_charges_sum` | warning | Sum of service-line charges matches `CLM02` (±$0.01) | +| `R100_payer_id_matches` | warning | `NM1*PR N104` matches the configured `payer_id` |