# NPI Registry & Healthcare Provider Leads Scraper (NPPES) (`mystique-lab/npi-registry-scraper`) Actor

Scrape US healthcare providers, doctors (NPI-1), dental clinics & medical practices (NPI-2) from the official CMS NPPES NPI Registry API. Exports clinic Authorized Official (owner/CEO/medical director) names & phones, practice addresses, phone, fax, NUCC specialty codes & state licenses.

- **URL**: https://apify.com/mystique-lab/npi-registry-scraper.md
- **Developed by:** [Mystique Lab](https://apify.com/mystique-lab) (community)
- **Categories:** Lead generation, Business
- **Stats:** 2 total users, 1 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$1.00 / 1,000 healthcare provider / practice leads

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## NPI Registry & Healthcare Provider Leads Scraper (NPPES)

Extract verified US healthcare providers, medical practices, dental clinics, mental health groups, pharmacies, and individual doctors/practitioners (`NPI-1` and `NPI-2`) directly from the official **CMS National Plan and Provider Enumeration System (NPPES) NPI Registry API v2.1**.

Built for **healthcare B2B sales teams, medical/dental device reps, healthcare SaaS founders, medical billing & RCM agencies, healthcare recruiters, and credentialing/KYB workflows**.

***

### Why Use This NPI Registry Scraper Over Raw API Calls?

1. **Direct Decision-Maker Contacts (`Authorized Official` on `NPI-2` Practices):** Every `NPI-2` organization record (dental clinics, medical groups, urgent care centers, dermatology practices, surgical centers, behavioral health clinics) includes the clinic's registered **Authorized Official** (`authorizedOfficialName`, `authorizedOfficialTitle` such as *Owner, President, CEO, Medical Director, Managing Partner*, and `authorizedOfficialPhone`).
2. **Multi-Specialty & Multi-State Fan-Out with Automatic Deduplication:** The raw CMS NPPES API only accepts a single `state` and a single `taxonomy_description` per request, and fails with `Error 07` if you query a `state` without an additional criterion. This actor accepts arrays of `specialties`, `states`, `cities`, and `postalCodes`, fans out across all combinations automatically, handles state-only queries via ZIP-prefix slicing, and deduplicates by 10-digit NPI number.
3. **Flattened, CRM-Ready Lead Schema:** Raw NPPES responses nest practice locations, mailing addresses, primary vs. secondary NUCC taxonomy codes, state medical/dental licenses, DBA trade names, and endpoints across 7 separate sub-arrays. This actor flattens every record into clean top-level columns ready for HubSpot, Salesforce, Clay, Apollo, or CSV export while preserving the full arrays.
4. **Built-In B2B Lead Quality Filters:** Filter with `requirePhone: true` (skip records missing telephone numbers), `requireAuthorizedOfficial: true` (only return clinics with a named executive/owner), and `activeOnly: true`.

***

### Extracted Fields

| Field | Type | Description |
| :--- | :--- | :--- |
| `npi` | `string` | 10-digit National Provider Identifier (`"1063828648"`) |
| `entityType` | `string` | `"Organization (NPI-2)"` or `"Individual (NPI-1)"` |
| `displayName` | `string` | Cleaned practice/organization name or practitioner full name + credential |
| `organizationName` | `string` | Legal organization name (`NPI-2`) |
| `dbaName` | `string` | Doing-Business-As / trade name (`other_names`) when registered |
| `firstName` / `lastName` / `credential` | `string` | Practitioner name and credentials (`MD`, `DO`, `DDS`, `DMD`, `NP`, `PA-C`, etc.) |
| `primarySpecialty` | `string` | Primary NUCC specialty description (e.g., `"Clinic/Center, Dental"`, `"Dermatology"`) |
| `primaryTaxonomyCode` | `string` | Primary 10-character NUCC taxonomy code (e.g., `"261QD0000X"`) |
| `primaryLicenseNumber` / `primaryLicenseState` | `string` | Primary state professional license number and state |
| `authorizedOfficialName` | `string` | Clinic decision-maker full name + credential (`NPI-2`) |
| `authorizedOfficialTitle` | `string` | Decision-maker role (`"President"`, `"Owner"`, `"CEO"`, `"Medical Director"`, `"Dentist"`) |
| `authorizedOfficialPhone` | `string` | Direct phone number for the Authorized Official |
| `practicePhone` / `practiceFax` | `string` | Primary clinical practice location phone and fax numbers (`XXX-XXX-XXXX`) |
| `practiceStreet1` / `practiceCity` / `practiceState` / `practiceZip` | `string` | Physical practice street address (`LOCATION`) |
| `mailingStreet1` / `mailingCity` / `mailingState` / `mailingZip` | `string` | Billing / mailing office address (`MAILING`) |
| `secondaryLocationsCount` / `secondaryLocations` | `array` | Additional branch/clinic locations registered under this NPI |
| `allSpecialties` / `allTaxonomies` | `array` | Complete list of all specialties, NUCC codes, and state licenses |
| `enumerationDate` / `lastUpdated` | `string` | Initial NPI registration date and most recent NPPES update (`YYYY-MM-DD`) |
| `npiRegistryUrl` | `string` | Direct link to the official CMS NPPES profile (`https://npiregistry.cms.hhs.gov/provider-view/<npi>`) |

***

### Example Input

```json
{
  "specialties": ["Dental", "Dentist"],
  "states": ["TX", "FL"],
  "enumerationType": "NPI-2",
  "requirePhone": true,
  "requireAuthorizedOfficial": true,
  "activeOnly": true,
  "maxItems": 100
}
```

### Example Output Record

```json
{
  "npi": "1063828648",
  "entityType": "Organization (NPI-2)",
  "enumerationType": "NPI-2",
  "status": "Active",
  "displayName": "ROBERT F. BENNINGFIELD D.D.S. INC.",
  "organizationName": "ROBERT F. BENNINGFIELD D.D.S. INC.",
  "dbaName": null,
  "primarySpecialty": "Clinic/Center, Dental",
  "primaryTaxonomyCode": "261QD0000X",
  "authorizedOfficialName": "Dr. ROBERT FAULKNER BENNINGFIELD, DDS",
  "authorizedOfficialTitle": "Dentist",
  "authorizedOfficialPhone": "817-249-4150",
  "practicePhone": "817-249-4150",
  "practiceFax": "817-249-4153",
  "practiceStreet1": "111 SPROLES DR",
  "practiceCity": "BENBROOK",
  "practiceState": "TX",
  "practiceZip": "76126-3213",
  "enumerationDate": "2014-07-03",
  "lastUpdated": "2014-07-03",
  "npiRegistryUrl": "https://npiregistry.cms.hhs.gov/provider-view/1063828648"
}
```

***

### Copy-Paste Scheduled Automation (Python / n8n / cURL)

Automate daily or weekly data feeds into your CRM (HubSpot, Salesforce, Clay, Google Sheets, or Slack) in under 60 seconds:

#### 1. cURL (REST API — Instant JSON / CSV Export)

```bash
curl -X POST "https://api.apify.com/v2/acts/mystique-lab~npi-registry-scraper/run-sync-get-dataset-items?token=YOUR_APIFY_TOKEN&format=json" \
  -H "Content-Type: application/json" \
  -d '{"states": ["TX", "FL", "CA"], "taxonomyDescription": "Dentist", "entityType": "Organization (NPI-2)", "requireAuthorizedOfficial": true, "maxItems": 200}'
```

*(Tip: Change `format=json` to `format=csv` or `format=xlsx` to download a spreadsheet directly.)*

#### 2. Python (`apify-client`)

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("mystique-lab/npi-registry-scraper").call(
    run_input={"states": ["TX", "FL", "CA"], "taxonomyDescription": "Dentist", "entityType": "Organization (NPI-2)", "requireAuthorizedOfficial": true, "maxItems": 200}
)

for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)
```

#### 3. n8n / Make.com / Zapier (Daily Cron Webhook)

1. Add a **Schedule Trigger** node (e.g., every morning at `07:00 AM`).
2. Add an **HTTP Request** node:
   - **Method:** `POST`
   - **URL:** `https://api.apify.com/v2/acts/mystique-lab~npi-registry-scraper/run-sync-get-dataset-items?token=YOUR_APIFY_TOKEN`
   - **Body (JSON):** `{"states": ["TX", "FL", "CA"], "taxonomyDescription": "Dentist", "entityType": "Organization (NPI-2)", "requireAuthorizedOfficial": true, "maxItems": 200}`
3. Pipe the returned JSON array directly into **HubSpot**, **Clay**, **Instantly.ai**, **Smartlead**, **Airtable**, or **Google Sheets**.

***

> **Want a Done-For-You Excel/CSV Lead Export without coding?**
>
> - **[$14 Ready-to-Open 2026 YC Startups & SEC Form D Funded B2B Lead Pack (.XLSX + .CSV — 720 Verified Leads)](https://mystiquelabshop.gumroad.com/l/free-starter-pack)** *(360 active YC 2025–2026 startups & 795 founders with LinkedIn/X + 360 newly funded SEC Form D operating companies with executive contacts & phones)*
> - **[$39 Done-For-You Custom B2B Lead Export (24-Hour Delivery)](https://mystiquelabshop.gumroad.com/l/free-starter-pack)** — tell us your exact niche, state, industry, or filters and receive a clean, verified `.XLSX` + `.CSV` spreadsheet in 24 hours (also available via our [Client Proposal & Scope Kit](https://mystiquelabshop.gumroad.com/l/client-proposal-scope-kit) and [BFCM Promo & Margin Kit](https://mystiquelabshop.gumroad.com/l/bfcm-promo-margin-kit)).
> - **Promo Code:** Use code **`LAUNCH2`** at checkout for **$2 OFF** on **[MYSTIQUE LAB Gumroad](https://mystiquelabshop.gumroad.com/l/free-starter-pack)** ([storefront](https://mystiquelabshop.gumroad.com)).

# Actor input Schema

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

One or more specialty keywords (e.g. "Dental", "Dentist", "Dermatology", "Chiropractor", "Family Medicine", "Mental Health", "Physical Therapist", "Pharmacy", "Optometrist", "Podiatrist", "Internal Medicine"). Multiple values are queried and deduplicated automatically.

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

Optional list of 2-letter US state or territory codes (e.g. \["TX", "FL", "CA", "NY"]). Leave empty to search nationwide.

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

Optional city names to filter by (e.g. \["Austin", "Dallas", "Miami"]). Leave empty for all cities.

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

Optional 5-digit ZIP codes or prefixes with trailing \* wildcard (e.g. \["750\*", "90210"]).

## `enumerationType` (type: `string`):

Choose NPI-2 for B2B clinic/practice leads (which include Authorized Official owner/president/medical director name, title & phone), NPI-1 for individual practitioners, or All.

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

Optional organization or clinic name filter (e.g. "Aspen Dental\*", "*Dermatology*").

## `firstName` (type: `string`):

Optional individual provider first name filter.

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

Optional individual provider last name filter.

## `npiNumbers` (type: `array`):

Optional list of specific 10-digit NPI numbers to enrich directly (e.g. \["1063828648"]).

## `requirePhone` (type: `boolean`):

Only return providers/practices that have a non-empty practice phone or authorized official phone number.

## `requireAuthorizedOfficial` (type: `boolean`):

When enabled, only returns records that include a named Authorized Official (Owner, President, CEO, Medical Director, Partner, etc.).

## `activeOnly` (type: `boolean`):

Only include active NPI records (status = 'A').

## `maxItems` (type: `integer`):

Maximum number of unique NPI provider records to export.

## Actor input object example

```json
{
  "specialties": [
    "Dental",
    "Dentist"
  ],
  "states": [
    "TX",
    "FL"
  ],
  "cities": [],
  "postalCodes": [],
  "enumerationType": "NPI-2",
  "organizationName": "",
  "firstName": "",
  "lastName": "",
  "npiNumbers": [],
  "requirePhone": true,
  "requireAuthorizedOfficial": false,
  "activeOnly": true,
  "maxItems": 50
}
```

# Actor output Schema

## `providers` (type: `string`):

No description

## `summary` (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 = {};

// Run the Actor and wait for it to finish
const run = await client.actor("mystique-lab/npi-registry-scraper").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 = {}

# Run the Actor and wait for it to finish
run = client.actor("mystique-lab/npi-registry-scraper").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 '{}' |
apify call mystique-lab/npi-registry-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,mystique-lab/npi-registry-scraper"
        }
    }
}
```

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/KGRTMJXhWXR8ykrw0/builds/kyAgnmoZ8uDLlOXBy/openapi.json
