A dependency-free Medicare fee-schedule pricer with a service-ZIP → MAC-locality / CBSA crosswalk. Given a claim line and its date of service, it returns the Medicare reference allowed amount computed from published CMS methodology — the stable, public, per-code number a repricing analysis is built on.
Runs on synthetic / public claims only — no PHI, no cloud, no database, no
web framework. Money is integer cents throughout; the RVU/weight math runs in
Decimal and rounds to cents exactly once, at the boundary.
service_zip ──crosswalk──▶ PFS locality (GPCI) + CBSA (wage index)
claim line + date of service ──price()──▶ Medicare allowed amount
claims-extract CSV ──build_report()──▶ footing repricing report
| claim type | schedule | formula | vintage |
|---|---|---|---|
professional |
PFS | (Σ RVU × GPCI) × conversion factor | calendar year |
outpatient |
OPPS | APC relative weight × conversion factor × wage adj | calendar year |
inpatient |
IPPS | billed MS-DRG relative weight × operating base × wage | federal FY (Oct 1) |
Each line is priced against the fee schedule effective on its date of service
(PFS/OPPS by calendar year, IPPS by federal fiscal year), and the reference is
pinned to that vintage's published release — the version a report cites.
Unknown codes / vintages return a non-priceable reference (never $0, which
would falsely inflate an overpayment total).
A real extract carries a service ZIP, not the carrier locality that selects GPCI nor the CBSA that selects the OPPS/IPPS wage index. The ZIP crosswalk turns one into both — the two geographic adjustments that make a repriced number defensible (a Manhattan office visit and an Alabama one are different Medicare allowed amounts). An unmapped ZIP is not silently nationalized; it is rejected, because substituting the national 1.000 index mis-states the reference in either direction.
Reference data is APPROXIMATE curated seed data, marked with a
DATA_VERSION(andGEO_DATA_VERSIONfor the crosswalk) and guarded by tests and a golden-file oracle gate. It exists to exercise the pricing math and its seams (locality/GPCI, CBSA/wage-index, service-date vintage). Refresh against the primary CMS sources — the PFS look-up tool, GPCI Addendum E, OPPS Addendum A/B, IPPS Table 5 + final-rule base rates — before relying on the figures.
Requires Python 3.12+ and uv.
uv syncThe package installs a medicare-pricer console command with three subcommands.
# ZIP → MAC locality / CBSA crosswalk
uv run medicare-pricer crosswalk 10022
# ZIP 10022
# PFS locality : NY-MANHATTAN
# CBSA : 35614
# Price a single claim line at its date of service
uv run medicare-pricer price-line --type professional --code 99214 \
--date 2025-03-01 --zip 10022
# Reprice a whole claims-extract CSV into a footing report
uv run medicare-pricer price extract.csvfrom datetime import date
from medicare_pricer import ClaimLine, ClaimType, price, resolve_zip
resolve_zip("10022") # ZipGeography(pfs_locality="NY-MANHATTAN", cbsa="35614")
ref = price(ClaimLine(ClaimType.PROFESSIONAL, "99214", locality="NY-MANHATTAN"),
date(2025, 3, 1))
ref.allowed_cents # int cents, or None if unpriceable
ref.provenance # "CMS PFS 2025, published 2024-11-01"parse_claims_csv() turns an employer claims extract into canonical
ClaimRecords; build_report() reprices every row at its own date of service
into a report whose total foots:
from medicare_pricer import parse_claims_csv, build_report
result = parse_claims_csv(open("extract.csv", "rb").read())
report = build_report(result.records)
report.total_overpayment_cents # Σ(paid − Medicare) over priceable lines
report.excluded # unpriceable lines — disclosed, kept out of the total
report.excluded_paid_cents # plan spend that could not be repriced
report.percent_of_medicare # headline ratio (read with the framing caveat)
report.schedule_provenance # e.g. ["CMS OPPS 2025, published 2024-11-27", ...]
for bad in result.rejects: # rejected source rows, kept with a reason
print(bad.line_number, bad.reason)CSV columns — required: claim_id, claim_type, code, service_date, npi, paid_amount; optional: units, service_zip, locality, cbsa, modifiers.
claim_type is professional | outpatient | inpatient; service_date is ISO
YYYY-MM-DD; paid_amount is dollars ($ and thousands commas tolerated).
File-level problems (empty input, missing required column) raise
ClaimIngestError; row-level problems (bad NPI check digit, unrecognized ZIP,
malformed amount, …) are collected in result.rejects so one bad row never
crashes the run. NPIs are validated by their CMS Luhn check digit.
- The total foots.
total_overpayment_centsis the exact integer sum of the per-line signed deltas and equalstotal_paid_cents − total_allowed_cents. - Unpriceable is disclosed, not zeroed. Unknown codes/vintages land in
report.excludedwith a reason and their spend inreport.excluded_paid_cents. - Commercial-reasonableness framing.
percent_of_medicareis paired with a caveat (COMMERCIAL_REASONABLENESS_FRAMING): paying above Medicare is expected, not a finding — the question is how far above. - Modifiers. PFS 26/TC (professional/technical split) and 50 (bilateral) are applied; every other modifier is carried and disclosed as unadjusted, never silently absorbed.
uv run pytest # unit + golden-file oracle gate
uv run mypy src # strict type checkThe golden file (tests/golden/pricing_golden.json) freezes known-correct
reference prices as absolute integer cents, each with a documented oracle, so CI
goes red on any priced-value drift — a code change or a silent edit to a
reference constant.
Licensed under the GNU Affero General Public License, version 3.0 (AGPL-3.0-only) — see LICENSE. Contributions are accepted under the Contributor License Agreement.
A hosted version is in the works from Receipts Health. Join the waitlist at receiptshealth.com.