# Healthcare Provider Intel: NPI, Pharma Payments, Rx (`themineworks/healthcare-provider-intelligence`) Actor

One row per US provider joined across three federal sources: NPPES identity, licence, address and phone, plus CMS Open Payments industry money received and Medicare Part D prescribing volume. 8M+ NPIs. No API key, no proxy.

- **URL**: https://apify.com/themineworks/healthcare-provider-intelligence.md
- **Developed by:** [The Mine Works](https://apify.com/themineworks) (community)
- **Categories:** Business, Lead generation, MCP servers
- **Stats:** 1 total users, 0 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per usage

This Actor is paid per platform usage. The Actor is free to use, and you only pay for the Apify platform usage, which gets cheaper the higher subscription plan you have.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-usage

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## 🩺 Healthcare Provider Intel: NPI, Pharma Payments, Rx

> ⚡ Three public federal APIs joined into one row. No API key, no proxy, no browser, no login.

> 💸 You are charged only for a provider row that lands in your dataset. The run summary is free.

### Overview

There are dozens of NPI scrapers on this Store. All of them return the same thing: a copy of the NPPES registry. Name, address, taxonomy, done. That tells you a dermatologist exists in Palo Alto. It does not tell you whether Regeneron paid her $8,414 last year, or whether she writes 147 Medicare prescriptions.

This actor answers those questions in the same row, because it joins three separate federal datasets that the government publishes independently and nobody publishes together:

1. **NPPES NPI Registry** for identity, specialty, state licence number, practice address and phone.
2. **CMS Open Payments** for every dollar of pharma and medical device money the provider received, who paid it, and what it was for.
3. **CMS Medicare Part D Prescriber** for prescribing volume, drug cost, beneficiary count and cost per claim.

The result is one row that a commercial team can actually act on: who the provider is, how to reach them, which manufacturers already have a relationship with them, and how much they prescribe.

✅ 8M+ NPIs · ✅ Industry payments by payer · ✅ Medicare prescribing volume · ✅ State licence and direct phone · ✅ MCP ready for AI agents

### What makes a row

```json
{
  "npi": "1780675181",
  "provider_name": "SUMAIRA ZAREEN AASI",
  "credential": "MD",
  "primary_specialty": "Dermatology, MOHS-Micrographic Surgery",
  "license_number": "C54709",
  "license_state": "CA",
  "practice_address": "300 PASTEUR DR",
  "practice_city": "STANFORD",
  "practice_state": "CA",
  "practice_postal_code": "94305",
  "phone": "650-723-4000",

  "payment_year": "2024",
  "payment_count": 10,
  "payments_total_usd": 9173.64,
  "top_payer": "Regeneron Pharmaceuticals, Inc.",
  "top_payer_usd": 8414.83,
  "payers_count": 2,
  "top_payers": ["Regeneron Pharmaceuticals, Inc.: $8414.83", "MIMEDX Group, Inc.: $758.81"],
  "top_payment_natures": ["Consulting Fee", "Travel and Lodging", "Food and Beverage"],

  "medicare_claims": 147,
  "medicare_drug_cost_usd": 2707.55,
  "medicare_beneficiaries": 117,
  "medicare_cost_per_claim_usd": 18.42,
  "medicare_provider_type": "Dermatology",

  "has_industry_payments": true,
  "is_medicare_prescriber": true,
  "commercial_priority": "high",
  "sources": ["NPPES", "CMS Open Payments", "CMS Part D Prescriber"]
}
```

`commercial_priority` is deliberately simple and explainable rather than a black box score. A provider who both takes industry money and writes Medicare volume is `high`. One or the other is `medium`. Neither is `low`. You can rebuild it from the raw fields yourself if you disagree with the rule.

### Input

```json
{
  "specialties": ["Dermatology"],
  "states": ["CA"],
  "providerType": "individual",
  "includePayments": true,
  "paymentYear": 2024,
  "includePrescribing": true,
  "industryPaidOnly": false,
  "maxProviders": 200
}
```

| Field | What it takes |
| --- | --- |
| `specialties` | NPPES taxonomy descriptions. Matching is partial, so `Cardiology` also returns `Cardiovascular Disease`. |
| `states` | Two letter state codes. Needs a specialty, name, city or postal code alongside it, because NPPES rejects a bare state. |
| `cities` | Practice cities. Crossed with the specialty list to form the search plan. |
| `postalCodes` | Five digit ZIPs for tight territory targeting. |
| `npis` | Ten digit NPIs to enrich directly. Use this to bulk enrich a list you already have. |
| `lastName` | Provider last name. Trailing asterisk works as a wildcard. |
| `organizationName` | Organisation name. Add a trailing asterisk for prefix matching. |
| `providerType` | `individual`, `organization` or `both`. |
| `includePayments` | Join Open Payments. One extra request per provider. |
| `paymentYear` | Open Payments programme year. |
| `includePrescribing` | Join Part D Prescriber. One extra request per provider. |
| `industryPaidOnly` | Keep only providers who received at least one industry payment. |
| `maxProviders` | Hard cap for the run, and your main cost control. |

### Two upstream traps this actor handles for you

**NPPES silently repeats its last page.** The API clamps `limit` to 200 and `skip` to 1000. Asking for `skip=2000` does not error and does not return an empty page. It returns the `skip=1000` page again, byte for byte, forever. A pager that waits for the API to run out will loop and re-deliver the same 200 providers indefinitely, and you would pay for every duplicate. This actor knows the ceiling is 1200 per query, stops there, and gets past it by crossing your specialty list with your geography list into many independent queries instead of one long one.

**The Open Payments dataset id changes every year.** Actors that hardcode the UUID quietly return zero payments for every provider the January after CMS publishes a new programme year. This one resolves the id from the live CMS metastore at the start of each run, and if the year you asked for is not published yet it falls back to the newest available year and tells you which one it used in the summary row.

### Common use cases

**Pharma and medical device targeting.** Find every dermatologist in a territory, see which manufacturers already pay them, and prioritise the ones with prescribing volume but no existing relationship with your competitor.

**Key opinion leader identification.** Rank a specialty by total consulting and speaking fees received to find who the industry already treats as an authority.

**Healthcare recruiting.** Specialty plus state plus licence number plus direct practice phone, in one export.

**Medical practice sales.** Target group practices and clinics as organisations, with authorised official name, title and phone.

**Compliance and transparency research.** Reconstruct the industry payment picture for a specialty or a region without downloading a 15 million row bulk file.

**Journalism and academic research.** All three sources are official government releases, so every figure is citable back to the agency that published it.

**AI agents.** Point an agent at it through MCP and ask which cardiologists in Ohio received more than $10,000 from a named manufacturer last year.

### Cost control built in

1. **Run level spend cap.** Enrichment costs two extra requests per provider, so a per provider budget bounds nothing while the provider count grows. The ceiling applies to the whole run.
2. **Zero yield abort.** Two consecutive pages that add no new provider and the query is dropped. One productive page resets it, so a healthy run never trips it.
3. **No transport escalation.** A source that does not answer degrades that one group of fields and is reported in `sources`. There is no retry through a paid proxy or a browser.

### Pricing

| Event | Price | You pay when |
| --- | --- | --- |
| Provider enriched | $0.003 | An enriched provider row lands in your dataset |

**$3.00 per 1,000 providers**, whether the row carries one source or all three. Empty runs cost nothing.

### Run it on a schedule

1. Run once with the specialty and territory you want, then click **Save as a task**.
2. In the Apify Console go to **Schedules → Create new**.
3. Pick a frequency and attach the saved task.
4. Wire the dataset to Sheets, Salesforce, HubSpot or a webhook from the **Integrations** tab.

Deduplicate on `npi`. NPPES updates continuously, Open Payments publishes annually, and Part D publishes annually, so a monthly refresh is usually enough.

### FAQ

**Is this data public?**
Yes. NPPES, Open Payments and Part D Prescriber are all official public releases from CMS, published for reuse. No login, no key, nothing scraped from behind a paywall.

**Why do some providers have no payments or no prescribing?**
Because they genuinely have none in that year. Open Payments only covers physicians, dentists, podiatrists, optometrists, chiropractors and, since 2021, several non physician practitioner types. Part D only covers Medicare Part D prescribing. A zero is reported as zero, not left blank, so you can tell "checked and none" apart from "not checked".

**What does `payments_truncated` mean?**
A small number of providers have more industry payment records than the API returns in one call, which is capped at 500. When that happens the row carries the true `payment_count` from the API alongside `payments_summed`, and flags the total as partial. Publishing a quietly incomplete sum would be worse than saying so.

**Can I enrich a list of NPIs I already have?**
Yes. Put them in `npis` and the search is skipped entirely.

**Why does a state on its own return nothing?**
Because NPPES refuses it: "Field state requires additional search criteria". Add a specialty, a city, a postal code or a name.

**Which Part D year is used?**
The most recent one CMS publishes on its "by Provider" endpoint. CMS keeps that endpoint pointed at the latest year.

### Use from Claude, ChatGPT and any MCP agent

```
https://mcp.apify.com/?tools=themineworks/healthcare-provider-intelligence
```

Or call it programmatically:

```js
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: 'YOUR_APIFY_TOKEN' });

const run = await client.actor('themineworks/healthcare-provider-intelligence').call({
  specialties: ['Cardiovascular Disease'],
  states: ['OH'],
  includePayments: true,
  paymentYear: 2024,
  industryPaidOnly: true,
  maxProviders: 500,
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
```

Questions, or need a federal source we do not join yet? Reach out through the Apify profile.

# Actor input Schema

## `specialties` (type: `array`):

NPPES taxonomy descriptions, for example Cardiovascular Disease, Dermatology, Orthopaedic Surgery, Internal Medicine, Nurse Practitioner. Matching is partial, so Cardiology also returns Cardiovascular Disease.

## `states` (type: `array`):

Two letter state codes. NPPES rejects a bare state, so this needs a specialty, name, city or postal code alongside it.

## `cities` (type: `array`):

Practice city names. Combined with the specialty list to form the search plan.

## `postalCodes` (type: `array`):

Five digit ZIP codes for tight territory targeting.

## `npis` (type: `array`):

Ten digit NPI numbers to enrich directly. Use this to bulk enrich a list you already have. Bypasses the search entirely.

## `lastName` (type: `string`):

Provider last name. Wildcards are supported by NPPES, so smit\* works.

## `organizationName` (type: `string`):

Organisation name for group practices, hospitals and clinics. Add a trailing asterisk for prefix matching, for example boston medical\*, because an exact string matches only an exact name. NPPES also searches former and doing business as names, so some results will look unrelated until you check their other names. Set Provider type to organization when using this.

## `providerType` (type: `string`):

Individual providers, organisations, or both.

## `includePayments` (type: `boolean`):

Join CMS Open Payments to get how much pharma and device money each provider received, from whom, and for what. Adds one request per provider.

## `paymentYear` (type: `integer`):

Which Open Payments programme year to join. The dataset id is resolved live, so if the year is not published yet the newest available year is used and reported in the summary.

## `includePrescribing` (type: `boolean`):

Join CMS Part D Prescriber to get Medicare claim counts, drug cost and beneficiary counts. Adds one request per provider.

## `industryPaidOnly` (type: `boolean`):

Keep only providers with at least one Open Payments record. Turn this on to build a list of prescribers already engaged with industry.

## `maxProviders` (type: `integer`):

Hard cap on providers for the whole run. This is your main cost and runtime control.

## Actor input object example

```json
{
  "specialties": [
    "Dermatology"
  ],
  "states": [
    "CA"
  ],
  "cities": [],
  "postalCodes": [],
  "npis": [],
  "providerType": "individual",
  "includePayments": true,
  "paymentYear": 2024,
  "includePrescribing": true,
  "industryPaidOnly": false,
  "maxProviders": 25
}
```

# Actor output Schema

## `results` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "specialties": [
        "Dermatology"
    ],
    "states": [
        "CA"
    ],
    "cities": [],
    "postalCodes": [],
    "npis": [],
    "lastName": "",
    "organizationName": "",
    "providerType": "individual",
    "includePayments": true,
    "paymentYear": 2024,
    "includePrescribing": true,
    "industryPaidOnly": false,
    "maxProviders": 25
};

// Run the Actor and wait for it to finish
const run = await client.actor("themineworks/healthcare-provider-intelligence").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "specialties": ["Dermatology"],
    "states": ["CA"],
    "cities": [],
    "postalCodes": [],
    "npis": [],
    "lastName": "",
    "organizationName": "",
    "providerType": "individual",
    "includePayments": True,
    "paymentYear": 2024,
    "includePrescribing": True,
    "industryPaidOnly": False,
    "maxProviders": 25,
}

# Run the Actor and wait for it to finish
run = client.actor("themineworks/healthcare-provider-intelligence").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "specialties": [
    "Dermatology"
  ],
  "states": [
    "CA"
  ],
  "cities": [],
  "postalCodes": [],
  "npis": [],
  "lastName": "",
  "organizationName": "",
  "providerType": "individual",
  "includePayments": true,
  "paymentYear": 2024,
  "includePrescribing": true,
  "industryPaidOnly": false,
  "maxProviders": 25
}' |
apify call themineworks/healthcare-provider-intelligence --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,themineworks/healthcare-provider-intelligence"
        }
    }
}

```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/qpKPOMmyGJSrlmi5G/builds/NmVah1XzBSgDgqdF8/openapi.json
