mrfkit
mrfkit reads US hospital and insurer price transparency files and turns them into clean, normalized tables.
Every US hospital must publish its prices in a machine-readable file (MRF). The files are huge, and no two look alike. Columns get renamed, payers sit in rows or in columns, codes come glued to modifiers, and plenty of JSON files are not valid JSON. mrfkit handles that mess, so you get the same tables from any file.
It was extracted from a production system that parsed files from about 3,000 hospitals. Its parsing tests, and the fixes behind them, came along.
Install
pip install mrfkit
For Parquet output:
pip install "mrfkit[parquet]"
Python 3.11 or newer.
Command line
mrfkit hospital_standardcharges.csv -o out/
This writes one CSV per table into out/. Use -f parquet for Parquet. Give several files and each one gets its own subdirectory. Plain, gzip and zip files all work, and the format is detected from the content.
Python
import mrfkit
stats = mrfkit.ParseStats()
for record in mrfkit.iter_records("hospital_standardcharges.json", stats=stats):
if isinstance(record, mrfkit.PayerRate):
print(record.code, record.payer_name, record.plan_name, record.negotiated_rate)
print(stats.rows_read, stats.rejected_codes, stats.warnings)
Records stream one at a time, so memory stays flat for multi-gigabyte files. To write them to disk:
with mrfkit.open_sink("out/", "parquet") as sink:
for record in mrfkit.iter_records("hospital_standardcharges.csv"):
sink.write(record)
Output
| Table | One row per | Main columns |
|---|---|---|
charge_items |
billable item (code, type, billing class, setting, modifiers) | code, code_type, description, billing_class, setting, modifiers, drug units |
standard_charges |
item price row | gross_charge, discounted_cash_price, min_negotiated_rate, max_negotiated_rate |
payer_rates |
negotiated rate for one payer and plan | payer_name, raw_payer_name, plan_name, plan_category, negotiated_rate, negotiated_percentage, methodology_type, estimated_amount, median_amount |
unmapped_cells |
value in a column mrfkit could not map | source_column, value |
file_metadata |
file | hospital name, locations, license, NPI, last updated, version, attestation |
header_mappings |
source column | what the column was read as |
modifiers |
modifier definition (CMS 3.0 JSON) | code, description, payer-specific notes |
Every data row carries its item key (code, code_type, billing_class, setting, modifiers), so the tables join without a database.
Insurer files (Transparency in Coverage)
Insurers publish their negotiated rates as Transparency in Coverage (TiC) JSON files. mrfkit and iter_records recognize them by their root keys and read two kinds:
- In-network rates files (
provider_referencesandin_network), into two main tables.tic_provider_groupshas one row per provider group (a TIN and its NPIs) behind each of the file's provider references.tic_rateshas one row per distinct price for a billing code: identical prices are merged, andprovider_group_idslists every group that has the price, so a code priced the same for 5,000 providers is one row, not 5,000.tic_file_metadataholds the reporting entity, last-updated date, version and network name. - Tables of contents (
reporting_structure), intotic_index: one row per plan and in-network file, with the file's URL.mrfkit.group_tic_networksgroups those rows into networks, one per in-network file name.
Both stream: memory holds one item or plan structure at a time, plus the provider groups' ids, never the whole file. Item names and descriptions are never read into a row, and a key mrfkit does not know is counted by its JSON path only (ParseStats.unmapped_paths, or mrfkit -v), never with its value.
for record in mrfkit.iter_records("2026-09-01_network_in-network-rates.json.gz"):
if isinstance(record, mrfkit.TicRate):
print(record.billing_code, record.negotiated_rate, record.provider_group_ids)
Allowed-amount and prescription-drug files are not supported, and provider groups kept in a separate file behind a URL are reported but not fetched.
What it handles
- CMS templates, versions 2 and 3, as CSV (tall and wide) and JSON
- Older and vendor layouts: one column per payer, payer and setting packed into column names, separate inpatient and outpatient price columns
- More than 130 header spellings, plus your own (
extra_synonyms) - Metadata rows with the data header glued on,
Key: Valuepreambles, several tables stacked in one CSV - Pipe- and tab-delimited files, stray quotes that would fuse rows
- Deflate64 zips, gzip, UTF-16, Windows-1252 bytes, byte-order marks
- Broken JSON: double and trailing commas, control characters
- Codes: CPT, HCPCS, NDC, revenue codes, MS-DRG, APR-DRG; modifiers baked into codes (
73721TC); corrupt codes are dropped and counted - Payer and plan names: about 1,200 known payer spellings, normalized to a canonical payer, a plan category and a network
- Self-pay rows: read as the cash price, not as a payer
What it does not do
- Download files. Point it at files you already have.
- Fix hospital errors. mrfkit reports what the file says.
- Insurer allowed-amount and prescription-drug files.
Disclaimer
The output is for information only. It is not medical, legal or financial advice. Hospitals publish mistakes, and a price in a file is not a quote.
CPT codes are numbers published by hospitals under the federal price transparency rule. mrfkit ships no CPT descriptions.
License
Metadata
Release files for mrfkit 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| mrfkit-0.1.0.tar.gz | 321.6 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| mrfkit-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 441.9 kB
Release files / mrfkit-0.1.0.tar.gz
| Download URL | mrfkit-0.1.0.tar.gz |
|---|---|
| Size | 321.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
32904602bbf4c60bc90d298284b32a2e51447eda56d353a4c58e867e3df65104
|
|
BLAKE2b-256 checksum How to use checksums |
2ad4e80107755ce8910412ae23849f78b50b4ee18fe99edaeecaeaf1ff21ce05
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 9, 2026.
Transparency logRelease files / mrfkit-0.1.0-py3-none-any.whl
| Download URL | mrfkit-0.1.0-py3-none-any.whl |
|---|---|
| Size | 120.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
352ddcb01fb7b124be4003abbb9106ba32e0d7038648c9999119171325d36567
|
|
BLAKE2b-256 checksum How to use checksums |
54a7113bd6b14fbae3177acb212acb60a9ab0f101358aa5fa3f83fda2a149a7a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 9, 2026.
Transparency log