CMS Open Payments API — Physician Roll-up (Sunshine Act) avatar

CMS Open Payments API — Physician Roll-up (Sunshine Act)

Pricing

from $4.40 / 1,000 results

Go to Apify Store
CMS Open Payments API — Physician Roll-up (Sunshine Act)

CMS Open Payments API — Physician Roll-up (Sunshine Act)

CMS Open Payments (Sunshine Act) API: look up physician or manufacturer general payments by name, NPI or manufacturer, rolled up per physician × manufacturer — total USD, payment count, date range and payment-type mix. Pharma-compliance ready. Keyless, official CMS.

Pricing

from $4.40 / 1,000 results

Rating

0.0

(0)

Developer

Kyle Maloney

Kyle Maloney

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

0

Monthly active users

2 days ago

Last modified

Share

CMS Open Payments API - Physician x Manufacturer Roll-up (Sunshine Act)

A CMS Open Payments (Sunshine Act) API: look up physician or manufacturer general payments by name, NPI, profile ID or manufacturer, and roll them up per recipient x manufacturer - total USD, payment count, date range, product mix and payment-type mix. Turn millions of disclosure rows into a compliance-ready summary. Keyless, official CMS source.

Every row states its own completeness. CMS returns an exact match count for your query; this Actor reports it as matching_rows_total alongside rows_fetched, rows_coverage_pct and a totals_are_partial flag, so a capped pull can never be mistaken for a relationship total.

Who it's for

  • Pharma / medtech compliance teams auditing physician payment exposure.
  • Investigative and policy researchers analysing industry-to-physician money.
  • Healthcare due-diligence teams and journalists profiling a physician, teaching hospital or manufacturer.
  • AI agents needing a "look up Open Payments" tool.

What it does

Resolves the correct CMS General Payment detailed dataset from the live CMS catalogue (program years 2019-2025 as of 2026-08-01), runs four live drift assertions, queries the datastore, and aggregates each recipient x manufacturer pair into one row: total dollars, payment count, first/last payment dates, natures of payment, products and NDC codes, and CMS compliance indicators (dispute status, third-party payment, physician ownership, delayed publication). Optional NPPES specialty enrichment.

Example input

{
"lastName": "smith",
"firstName": "john",
"programYear": "2025",
"includeSpecialty": true,
"maxResults": 500
}

Look up one physician precisely (the recommended mode):

{ "npi": "1659344299" }

Profile a manufacturer:

{ "manufacturer": "Genentech", "maxResults": 500 }

Inputs

InputTypeNotes
lastNamestringCovered-recipient last name. Substring match - Smith also matches Goldsmith, Nesmith, Smithers.
firstNamestringCovered-recipient first name, substring match.
npistringExact 10-digit NPI. The most precise lookup.
profileIdstringExact CMS covered-recipient profile ID.
manufacturerstringManufacturer / GPO name, substring match.
programYearstringe.g. 2025. Blank = most recent published year. A year CMS does not publish now fails the run and lists the available years instead of silently answering about a different year.
includeSpecialtybooleanBest-effort NPPES specialty enrichment. Reported in nppes_status.
maxResultsintegerCap on raw CMS rows pulled before roll-up. CMS pages via SQL OFFSET, which slows sharply past a few thousand rows.

At least one filter is required. An unfiltered run fails immediately - nothing is emitted and nothing is billed.

Output fields

One row per (recipient x manufacturer) relationship. 70 declared fields.

Recipient

FieldDescription
recipient_namePhysician full name, or the teaching hospital name when the recipient is a hospital.
recipient_npi10-digit NPI, if disclosed.
recipient_profile_idCMS covered-recipient profile ID.
recipient_typee.g. Covered Recipient Physician, Covered Recipient Teaching Hospital.
recipient_key_basisHow the recipient was identified for grouping: npi, profile_id, teaching_hospital_id, teaching_hospital_name, person_name, unidentified.
recipient_city / recipient_state / recipient_zip_code / recipient_countryPrimary business address.
recipient_specialtySpecialty from CMS slot 1, optionally NPPES-enriched.
recipient_specialties_allAll six CMS specialty slots, deduped.
teaching_hospital_name / teaching_hospital_ccn / teaching_hospital_idPopulated when the recipient is a teaching hospital. Verified populating input: {"manufacturer":"Genentech","maxResults":500}.

Payer

FieldDescription
manufacturer_nameManufacturer or GPO that made the payments.
manufacturer_idCMS payer ID.
manufacturer_state / manufacturer_countryPayer location.
submitting_manufacturer_nameThe entity that submitted the record - frequently different from the payer.

Money

FieldDescription
total_amount_usdSum of published payment amounts in the relationship.
payment_countNumber of CMS rows aggregated.
payments_included_totalSum of CMS number_of_payments_included_in_total_amount - the payments those rows represent.
largest_single_payment_usdLargest individual payment.
mean_payment_usdMean across rows with a published amount.
amount_rows_unparseableRows where CMS published no usable amount. Excluded from the sum, never counted as $0.
first_payment_date / last_payment_dateDate range, YYYY-MM-DD.
intensityHuman-readable "$X across N payment(s)".

Payment character

FieldDescription
natures_of_payment / distinct_natures_countConsulting fee, food and beverage, travel, royalty, etc.
forms_of_paymentCash or cash equivalent, in-kind items and services, etc.
productsProduct names from CMS slot 1 (legacy field, unchanged).
products_all / distinct_products_countProduct names across all five CMS slots.
product_typesDrug, Biological, Device, Medical Supply.
product_therapeutic_areasCMS product category / therapeutic area.
product_ndc_codesNDC codes CMS associates with the products.
covered_product_payment_count / noncovered_product_payment_countCovered vs non-covered product rows.
related_product_payment_countRows CMS ties to at least one covered product.
contextual_information_samplesUp to five free-text notes the manufacturer attached.
record_ids_sampleUp to 25 CMS record_id values so any figure can be traced to source rows.
change_typesCMS change_type: NEW, CHANGED, UNCHANGED.

Compliance indicators

FieldDescription
disputed_payment_count / any_payment_disputedPayments the recipient disputed with CMS.
delayed_publication_countRows CMS flagged for delayed publication.
physician_ownership_payment_countRows with the CMS physician-ownership indicator.
third_party_payment_count / third_party_entitiesPayments routed to a third party.
charity_payment_countRows with the CMS charity indicator.

Completeness, provenance and per-source status

FieldDescription
matching_rows_totalThe exact number of CMS rows matching your query.
rows_fetchedRows actually retrieved and aggregated.
rows_coverage_pctrows_fetched as a percentage of the match count. Null when unknown - never 0 as a stand-in.
totals_are_partialTrue when fewer rows were retrieved than CMS reports matching, so the money figures are lower bounds.
result_completenesscomplete or partial.
completeness_notePlain-language statement of what the row does and does not cover.
query_stopped_byexhausted, max_results, time_budget or page_error.
name_match_modeexact_key (NPI / profile ID) vs substring (name) vs manufacturer_substring.
cms_datastore_statusok, partial, partial_error. Never blank.
cms_datastore_errorError text when a page failed mid-run. Null on a healthy run - that is good news, not a dead column.
nppes_statusnot_requested, ok, partial, unavailable. A dead NPPES is reported here, never rendered as "no specialty".
dataset_identifier / dataset_titleThe CMS dataset that answered the query.
program_year_requested / program_year_resolvedWhat you asked for vs what was queried.
program_yearReporting year from the CMS rows.
payment_publication_dateLatest CMS publication date across the rows - the data vintage.
retrieved_atUTC timestamp of the query.
source_system / source_urlProvenance.

Reliability - what this Actor asserts live, on every run

An offline test cannot see a silently degraded upstream. Before any billable row is emitted, this Actor fails the run if any of these regress. Every measured value is logged.

  1. Column presence - all 91 CMS columns it reads must still exist. A CMS rename returns HTTP 400 Column not found., which previously became zero rows.
  2. Dataset size - the national file must be in a plausible band (measured 2026-08-01: 2025 = 16,131,856 rows; 2024 = 15,498,687).
  3. Negative control - an impossible NPI must match exactly 0 rows. If CMS ever starts dropping unsatisfied filters, every roll-up would silently become a slice of the whole national file.
  4. Positive canary - last_name LIKE %SMITH% must match a plausible band (measured 2026-08-01: 89,441).

If the CMS datastore never answers, the run fails with an explicit message - it never emits "no payments found", which is not the same fact.

Limits you should know

  • CMS pages via SQL OFFSET, which is O(n). Deep pulls are slow; a wall-clock budget stops very deep paging and flags the result partial.
  • The datastore rejects limit > 500 (HTTP 400), so pages are 500 rows.
  • A name search is a substring sweep. Use npi or profileId for a single-physician answer.
  • These are CMS general payments. Research payments and ownership/investment interest are separate CMS files and are not included.

Use as an MCP tool

Available to AI agents through Apify's MCP server. Field-level descriptions are written for tool selection: an agent can read result_completeness and matching_rows_total to decide whether to re-query with a narrower filter.

Pricing

Pay per result: one event per emitted (recipient x manufacturer) relationship row. A run that fails a drift assertion or never reaches CMS emits nothing and bills nothing.

FAQ

Why did my NPI lookup return nothing before? Until v1.1 the input schema carried a server-side default of lastName: "Smith", which Apify injected into every run - so an NPI-only lookup executed as

npi = X AND last_name LIKE %SMITH%
. That default is gone.

Are these totals complete? Only when result_completeness is complete. Check totals_are_partial before quoting a figure.

Is a payment here evidence of wrongdoing? No. Open Payments is a transparency disclosure. This is a screening and research tool, not a determination about any individual.

  • CMS Part D Prescriber Delta - year-over-year Medicare Part D drug spending.
  • License Verifier - multi-state clinician licence and OIG-exclusion checks.
  • CMS NADAC Price Movers - drug acquisition-cost movement.