Every number on this site is an API call. Here is how to make them yourself.
Project Crossfoot publishes two read-only JSON APIs — one per analysis. They are the same endpoints the site's own pages and charts run on: when a chart drills down to its underlying rows, the panel that opens is one of these URLs, rendered. There is no separate "API product" that can drift from what the pages show.
No key, no registration, no rate card. The data is publicly funded and legislatively mandated; the API is how it stays public in a form machines can use.
How every endpoint behaves
Both APIs follow the same contract, so anything learned on one carries to the other. Everything is a GET request returning application/json; nothing on this site writes, so there is nothing to authenticate.
Requests
Every endpoint answers GET and sends Access-Control-Allow-Origin: *, so calls work from a browser page on any origin as well as from curl, Python or a spreadsheet. Every value that reaches SQL is a bound parameter, and identifiers such as sort columns and set names are looked up in fixed lists — an unrecognised value falls back to a default or returns a 400, it is never passed through.
Pagination
List responses take &per= (rows per page; up to 500 on the prior-auth API, up to 2,000 on the prices API) and &page=. The meta object echoes the page, the page size, the total row count and the page count, so a client can walk the whole set without guessing.
Errors
A bad request is a 400 and a missing record a 404, each with a machine-readable error code and a human-readable message naming the accepted values. Queries that would return the bulk of a 150,000-row table without a filter answer 400 too_broad and say which filters would narrow them.
Responses
Numeric columns arrive as JSON numbers, not strings — counts as integers, rates and dollars as floats. Code-like fields that merely look numeric (CCNs, FIPS codes, ZIP codes, CPT and DRG codes) stay strings, because leading zeros are part of the identifier.
null never means zero
A null means the publisher printed nothing for that field. "This payer denied nothing" and "this payer published nothing" are different claims, and the API keeps them apart. Every list response carries this note in its meta, so the rule travels with the data.
Provenance
Every dataset traces to the bytes its publisher served: source URL, fetch time, size and SHA-256. The prices API exposes this directly (set=source for the central files, set=mrf for each hospital's own price file), so a figure can be audited back to the original document without asking anyone's permission.
Courtesy
The site runs on ordinary shared hosting. Page through large sets rather than requesting them in one call, and cache what you fetch — the underlying data changes on the cadence of regulatory publishing, not by the minute. For bulk work, the full CSVs in the repository are the better tool.
api.php — the CY2025 prior authorization filings
One row per plan-level disclosure under CMS-0057-F: requests received, approved and denied, appeal outcomes and turnaround times, alongside the payer's own printed denial rate and the rate recomputed from its counts. The API takes exactly the filters the explorer takes — any explorer URL becomes an API call by swapping explorer.php for api.php.
List filings
GET api.php GET api.php?coverage=Medicare%20Advantage&minvol=1000&sort=rateReturns meta (pagination, sort, reporting year, the null rule) and filings, an array of full filing rows.
| Parameter | Accepts | What it filters |
|---|---|---|
| q | free text | Payer, plan and contract-ID search. |
| coverage | exact coverage type | e.g. Medicare Advantage, Marketplace QHP — the distinct values are in any list response. |
| state | two-letter code | Filing state. |
| org | exact parent organization | One payer's filings. |
| quality | clean · error · warn · flagged | Validation status: no findings, has errors, has warnings, has either. |
| counts | yes · no | Whether the filing published raw counts, or only percentages. |
| minvol / maxvol | integer | Standard-request volume band, [minvol, maxvol). |
| minrate / maxrate | percent | Standard denial-rate band — how the histogram bars drill down. |
| appeals | yes | Only filings that reported appeal outcomes. |
| sort | rate · vol · org · findings · plan · coverage · state · overturn · expdenial · tat | Sort key; text keys default ascending, numeric keys descending. |
| dir | asc · desc | Override the sort direction. |
| per / page | 1–500 · 1+ | Page size and page number. |
One filing, with its findings
GET api.php?id=f0042The full filing row plus every validation finding recorded against it — the rule that fired, its severity, and the numbers that triggered it. 404 with error: not_found if the id is unknown.
The same rows as CSV
GET export.php?coverage=Marketplace%20QHP&quality=errorexport.php takes the same filters and streams the filtered set as a CSV download — the portable subset of the same table.
costs_api.php — prices, price files, debt and county profiles
The pricing analysis is many datasets — Medicare's inpatient, outpatient and physician files, a 3,109-hospital sample of the price files hospitals must publish under 45 CFR 180, county-level medical debt and health outcomes, a code dictionary, and the validation findings over all of it. One endpoint serves them all: set= selects the dataset, and each set takes its own filters. Called with no set, it returns an index of every set, current row counts, and the provenance of every source file.
The index. Everything below paginates with &per= (max 2,000) and &page=, and most sets accept &state=NY.
| Set | Filters | What comes back |
|---|---|---|
| basket | state · code + type | The 49-service comparison basket by state (state=US for the national row): Medicare charge and payment beside the sampled files' gross, cash and negotiated medians. |
| county | fips · state · by + lo/hi | County profiles: medical debt in collections, uninsured share, health outcomes, price ratios. by= cuts a band of one whitelisted column — how the debt page's quartile bars drill down. |
| hospital | ccn · state · county · system | Every hospital in the Medicare files, with location, system membership and its price-file status where sampled. |
| system | id · state | Health systems (AHRQ linkage) with Medicare charges summed across member hospitals. |
| inpatient | ccn · drg · state (one required) | Medicare inpatient rows: one hospital's every DRG, or one DRG across hospitals — discharges, average covered charge, average total payment. |
| outpatient | ccn · apc · state (one required) | Medicare outpatient rows by APC. |
| physician | code · state | The physician fee file, every HCPCS code, state by state, office and facility. |
| mrf | seed · state | The sampled hospital price files. With seed=NY-04: the full file record (URL, bytes, SHA-256, outcome), every coded charge aggregated across payers, and the file's findings. |
| finding | scope · severity · ref · rule | Validation findings over the pricing data — every place a published file contradicts itself. |
| model | target · feature | The county models: fit quality, permutation importance, partial dependence. Descriptive, not causal — the run's own note fields say so. |
| hospital_model | seed · state | The hospital fair-price index: every scored file with its index, interval and unexplained premium. With seed=: that file's card plus its model-estimated prices for unpublished basket items — model output, never published prices. |
| code | code · q · status · type | The code dictionary: 85,000+ CPT/HCPCS and MS-DRG codes with ranked, synonym-widened full-text search over descriptors and hospital wordings. |
| suggest | q | The same search, top 8 — built for a typeahead. |
| code_state | code + type · state | The catalog: one non-basket code, every state where any source prices it. |
| source | key | Provenance of every central source file: URL fetched, when, bytes, SHA-256, license. |
| map | code + type | Everything the price map draws in one round trip: state medians, Medicare hospital pins (MS-DRG), and each sampled file's published prices, all with canvas coordinates. |
| zip / near | zip · lat + lon | ZCTA centroids on the map canvas — one ZIP, or the nearest to a coordinate. |
Worked examples
GET costs_api.php?set=basket&state=NYWhat the basket costs in New York, service by service.
GET costs_api.php?set=inpatient&drg=470&state=TXKnee and hip replacement (MS-DRG 470) at every Texas hospital in the Medicare file.
GET costs_api.php?set=mrf&seed=NY-04Bellevue's own published price file: the document record, every coded charge, and its findings.
GET costs_api.php?set=county&by=medical_debt_pct&lo=20Every county where more than a fifth of people with credit records have medical debt in collections.
GET costs_api.php?set=code&q=knee%20replacementRanked code search — the same lookup behind the codes page.
Three-line recipes
The API needs nothing but an HTTP client. These use curl and jq; the same calls work from Python, R, JavaScript or a spreadsheet's "from web" import.
# The ten highest computed denial rates among high-volume Medicare Advantage plans curl -s 'https://ryangomez.nyc/crossfoot/api.php?coverage=Medicare%20Advantage&minvol=10000&sort=rate&per=10' \ | jq -r '.filings[] | [.parent_org, .plan_name, .std_denial_rate] | @tsv' # Walk every page of a filtered set pages=$(curl -s 'https://ryangomez.nyc/crossfoot/api.php?quality=error&per=100' | jq .meta.pages) for p in $(seq 1 "$pages"); do curl -s "https://ryangomez.nyc/crossfoot/api.php?quality=error&per=100&page=$p" | jq -c '.filings[]' done # What one hospital publishes for one code, straight from its mandated file curl -s 'https://ryangomez.nyc/crossfoot/costs_api.php?set=mrf&seed=IL-03' \ | jq '.charges[] | select(.code == "470")' # Verify a source file is the one the pipeline read: compare the SHA-256 curl -s 'https://ryangomez.nyc/crossfoot/costs_api.php?set=source&key=inpatient' | jq -r '.rows[0].sha256'
Questions the API doesn't answer, or a field that doesn't behave as documented here? Open an issue — the documentation is part of the product, and a wrong page is a bug.