# Medicare Opt-Out Providers List (CMS Affidavits) Scraper (`jserle/medicare-opt-out-physicians`) Actor

Medicare opt-out providers list from the CMS Opt Out Affidavits dataset: every physician and practitioner who opted out of Medicare, with NPI, specialty, practice address and opt-out effective and end dates. Filter by state, specialty, ZIP, date, name or NPI. About 57,500 records. $0.008/record.

- **URL**: https://apify.com/jserle/medicare-opt-out-physicians.md
- **Developed by:** [JS Tech Solutions](https://apify.com/jserle) (community)
- **Categories:** Lead generation, Other
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$8.00 / 1,000 opt-out provider records

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?

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

## Medicare Opt-Out Providers List (CMS Affidavits) Scraper

Pulls the CMS Opt Out Affidavits dataset, every physician and practitioner who has opted out of Medicare, into clean JSON records: NPI, name, specialty, practice address, and the exact opt-out effective and end dates. Filter by state, specialty, ZIP prefix, effective date, name or NPI, or keep only providers whose opt-out is still in force.

About **57,500 records** in the current release, refreshed monthly by CMS. A provider who opts out files an affidavit, stops billing Medicare entirely, and contracts privately with patients who pay out of pocket. This Actor turns that publication into records you can drop into a CRM, a territory model, or a spreadsheet.

### Who uses this data

- **Concierge medicine, direct primary care (DPC) and physician recruiters.** A physician who has already opted out of Medicare has made the hard decision you are usually selling. Filter by state and specialty and you have a pre-qualified list.
- **Private-pay and cash-pay networks** building provider directories, especially in behavioural health: Clinical Psychologist, Mental Health Counselor, Clinical Social Worker and Marriage And Family Therapist are the four largest specialties in the file.
- **Payer network teams** who need to know which providers in a market are unavailable to a Medicare Advantage or fee-for-service network, and when each opt-out period ends.
- **Compliance, credentialing and claims teams** checking opt-out status against a date, and whether the provider is still eligible to order and refer.
- **Health-economics researchers** studying opt-out patterns by specialty, geography and time.

### What you get

One dataset item per affidavit record.

```json
{
  "source": "https://data.cms.gov/data-api/v1/dataset/9887a515-7552-4693-bf58-735c77af46d7/data",
  "attribution": "Centers for Medicare & Medicaid Services (CMS)",
  "recordKey": "abeab2dbc1ed6e26",
  "npi": "1720444581",
  "firstName": "Jonathan",
  "lastName": "Raines",
  "fullName": "Jonathan Raines",
  "specialty": "Psychiatry",
  "optoutEffectiveDate": "1998-01-30",
  "optoutEndDate": "2028-01-30",
  "currentlyOptedOut": true,
  "addressLine1": "1629 MONK RD",
  "addressLine2": "P O BOX 470",
  "city": "GLADWYNE",
  "state": "PA",
  "zipCode": "19035-1349",
  "zip5": "19035",
  "eligibleToOrderAndRefer": false,
  "lastUpdated": "2026-02-16",
  "fetchedAt": "2026-08-23T11:41:07.512Z"
}
```

Dates are ISO 8601 calendar dates; CMS publishes no time of day, so none is invented. Missing values are `null`, never an empty string. `eligibleToOrderAndRefer` is a real boolean, not `"Y"`. Nine-digit ZIPs are hyphenated and `zip5` is split out for joining. `currentlyOptedOut` is computed from `optoutEndDate` against the UTC date the run starts.

`recordKey` is a stable 16-character hash of every source column except CMS's `Last updated` stamp, so the same record produces the same key on every run and across monthly refreshes. Use it as an upsert key.

Records are delivered in the CMS API's own order and stop at `maxResults`. They are not re-sorted: a global sort would mean downloading all 57,500 rows on every run, which at the crawl delay this Actor honours takes about two minutes even for a hundred records. Every item carries its dates, so any ordering you want is one sort away.

A run summary is written to the key-value store under `OUTPUT`: source URL, the dataset size CMS reports, rows scanned, HTTP requests made, duplicates folded, records delivered and records charged, and whether the charge limit stopped the run.

### Input

Everything is optional. Run it with no input and you get the first 100 records of the current release.

| Field | Type | Default | Notes |
| --- | --- | --- | --- |
| `state` | string\[] | - | US state, district or territory codes, e.g. `["NY", "NJ"]`. Applied by the CMS API itself, so this is the fast filter. Several states share the record budget evenly. |
| `specialty` | string | - | Case-insensitive substring, so `psych` matches Psychiatry and Clinical Psychologist. |
| `keyword` | string | - | Case-insensitive substring across the provider's full name and NPI. |
| `zipPrefix` | string | - | 1-9 digits matched against the start of the ZIP, e.g. `100` or `90210`. |
| `effectiveFrom` | ISO date | - | Keep opt-outs effective on or after this date. This is how you find recent opt-outs. |
| `effectiveTo` | ISO date | - | Keep opt-outs effective on or before this date. |
| `currentlyOptedOutOnly` | boolean | false | Keep only records whose end date has not passed, as of the day the run starts. |
| `maxResults` | integer | 100 | 1 to 20000. This is your cost cap: you pay per delivered record. |
| `includeRaw` | boolean | false | Attach a `raw` object with the CMS columns under their published names. |

Filters combine with AND. Only `state` can be pushed to the CMS API; the rest are applied here, which means a run that uses them reads more of the dataset and takes longer. A `state` filter in front of them cuts that work down sharply.

#### Example inputs

**Opted-out physicians in one state and specialty, still opted out** (DPC and concierge recruiting):

```json
{
  "state": ["TX"],
  "specialty": "Family",
  "currentlyOptedOutOnly": true,
  "maxResults": 1000
}
```

**Recent opt-outs in your states** (new-decision prospecting):

```json
{
  "state": ["FL", "GA"],
  "effectiveFrom": "2026-01-01",
  "maxResults": 500
}
```

**Check one provider's opt-out status** (credentialing, claims):

```json
{
  "keyword": "1720444581",
  "maxResults": 10
}
```

### Pricing

**$0.008 per record; you pay only for records delivered.** One charge per dataset item, nothing else. Set `maxResults` and you have set your bill: 100 records is $0.80, 5,000 is $40.00. Filters are applied before delivery, so a narrow search costs less than a broad one, and a filter that matches nothing costs nothing.

### Data source, refresh and licence

Records come from the **Centers for Medicare & Medicaid Services (CMS)**, dataset **Opt Out Affidavits**, read through the public data.cms.gov data-api:

- Landing page: <https://data.cms.gov/provider-characteristics/medicare-provider-supplier-enrollment/opt-out-affidavits>
- API endpoint: `https://data.cms.gov/data-api/v1/dataset/9887a515-7552-4693-bf58-735c77af46d7/data`
- Data dictionary: <https://data.cms.gov/resources/opt-out-affidavits-data-dictionary> ([PDF](https://data.cms.gov/sites/default/files/2020-06/OptOut_DD.pdf))
- Methodology: <https://data.cms.gov/sites/default/files/2020-07/OptOut_Methods.pdf>

**Refresh:** CMS lists this dataset as monthly (`accrualPeriodicity: R/P1M`) and publishes it as a dated release; the July 2026 release was posted on 2026-08-20. Run this Actor monthly and you track CMS's own cadence. Each item also carries CMS's own `lastUpdated` stamp for that record.

**Licence:** CMS publishes this dataset in its open-data catalogue (`https://data.cms.gov/data.json`) with `accessLevel: public`, `accessRights: Open`, and the licence **<https://www.usa.gov/government-works>**.

**Attribution:** Centers for Medicare & Medicaid Services (CMS). This Actor is **not affiliated with or endorsed by the Centers for Medicare & Medicaid Services or any US government agency.** No login, API key or account is involved.

The data.cms.gov `robots.txt` allows `/data-api/v1/dataset/*` (only `/data-api/v1/download-request` and the view tracker are disallowed) and publishes `crawl-delay: 10`; this Actor waits ten seconds between requests, keeps one request in flight, sends a descriptive User-Agent, and caches nothing between runs.

### Limitations

- **This is the opt-out file, not a full provider directory.** It covers only providers who filed an opt-out affidavit. There is no phone number, email, licence number or practice name in the source, and none is invented here.
- **Recently expired affidavits stay in the file.** 1,096 of 57,530 records had an end date in the past on 2026-08-23. Set `currentlyOptedOutOnly` if you only want live opt-outs.
- **One provider can appear several times.** An NPI with practice addresses in three states is three records, and a provider listed under two specialties at one address is two records. That is the source's structure, not a duplication bug. Deduplicate on `npi` yourself if you want one row per person. True duplicates, meaning byte-identical repeats, are folded away: 125 of 57,530 rows on 2026-08-23.
- **Addresses are as CMS publishes them,** upper case and unstandardised. They are not geocoded or validated.
- **A local filter reads more of the dataset.** A nationwide `specialty`, `keyword`, `zipPrefix` or date filter scans until it has enough records, up to about two minutes for the whole file. A `state` filter runs on the CMS API and is fast.
- **Ordering is CMS's own.** See the note above.
- **The run fails rather than delivering a wrong answer.** If CMS drops a column on any row of any page, serves a stub, or stops paginating before the row count its own stats endpoint reports, the run stops with an error and pushes nothing, so a broken source costs you nothing instead of quietly returning fewer records. That check covers state filters too: a `state` pass is compared against CMS's own count for that state, not just against the national total.

### FAQ

#### How do I find doctors who have opted out of Medicare in my state?

Set `state` to the two-letter code (the one filter the CMS API applies itself, so it is fast) and optionally `specialty`. Add `currentlyOptedOutOnly: true` to drop providers whose opt-out period has ended.

#### How do I check whether a specific provider has opted out of Medicare?

Put the NPI or name in `keyword`. Each matching record carries `optoutEffectiveDate`, `optoutEndDate` and the computed `currentlyOptedOut` flag.

#### What does "opted out of Medicare" mean?

The provider filed an affidavit with CMS, does not bill Medicare for any service, and enters private contracts with Medicare patients who pay out of pocket. The opt-out runs for a fixed period from the effective date; `optoutEndDate` is when the current period ends.

#### Which specialties opt out of Medicare most?

In this file the four largest specialties are Clinical Psychologist, Mental Health Counselor, Clinical Social Worker and Marriage And Family Therapist. Use `specialty` as a substring filter (`psych` matches Psychiatry and Clinical Psychologist).

#### How often is the Medicare opt-out list updated?

Monthly. CMS publishes dated releases; the July 2026 release was posted on 2026-08-20, and every record carries CMS's own `lastUpdated` stamp.

#### Does the list include phone numbers or emails?

No. The source carries the practice address only. Join on `npi` against the NPPES registry for contact details.

### Related datasets

Other datasets by the same author, all pay-per-record with source, refresh cadence and licence stated on each listing:

**Nursing home and long-term care data**

- [Nursing Home Deficiency Citations (CMS) Scraper](https://apify.com/jserle/nursing-home-deficiency-citations)
- [Nursing Home Fines & Civil Money Penalties (CMS) Scraper](https://apify.com/jserle/nursing-home-penalties-fines)
- [Nursing Home Directory & Ownership (CMS Form 671) Scraper](https://apify.com/jserle/ltc-facility-characteristics)
- [Nursing Home Daily Nurse Staffing (CMS PBJ) Scraper](https://apify.com/jserle/cms-nursing-home-staffing-daily)
- [Nursing Home Change of Ownership (CMS SNF CHOW) Scraper](https://apify.com/jserle/snf-change-of-ownership-tracker)
- [New York Nursing Home Bed Availability (NYSDOH) Scraper](https://apify.com/jserle/ny-nursing-home-bed-census)

**Medicare provider enrollment data**

- [Medicare Revoked Providers List (CMS Revocations) Scraper](https://apify.com/jserle/medicare-revoked-providers)
- [Medicare Revalidation Due Date List (CMS) Scraper](https://apify.com/jserle/medicare-revalidation-due-leads)

**Public procurement and RFP feeds**

- [E-Rate Form 470 RFP Scraper (USAC School & Library Bids)](https://apify.com/jserle/erate-form-470-rfp-feed)
- [NYC PASSPort Procurement Scraper (RFPs, Bids & Contracts)](https://apify.com/jserle/nyc-passport-procurement)

**Developer and AI test data**

- [Synthetic Invoice OCR Ground Truth Dataset Generator](https://apify.com/jserle/ocr-ground-truth-document-factory)

# Actor input Schema

## `state` (type: `array`):

US state, district or territory codes, for example \["NY", "NJ", "CT"]. Matched exactly against the provider's practice address; an unrecognised code is rejected rather than quietly returning nothing. This filter runs on the CMS API, so a single state is much faster than scanning nationwide. With several states the record budget is shared evenly between them, so one large state cannot crowd the others out.

## `specialty` (type: `string`):

Case-insensitive substring matched against the provider's specialty, so "psych" matches both Psychiatry and Clinical Psychologist. Common values: Clinical Psychologist, Mental Health Counselor, Clinical Social Worker, Marriage And Family Therapist, Psychiatry, Dentist, Oral Surgery, Family Practice, Nurse Practitioner, Internal Medicine.

## `keyword` (type: `string`):

Case-insensitive substring matched against the provider's full name and NPI. Example: Raines, or 1720444581.

## `zipPrefix` (type: `string`):

1 to 9 digits matched against the start of the provider's ZIP code, so "100" covers all of the 100xx range and "90210" pins one ZIP. Digits only, no dash.

## `effectiveFrom` (type: `string`):

ISO date, for example 2026-01-01. Keeps records whose opt-out effective date is on or after this date, which is how you find providers who opted out recently. Records with no readable effective date are excluded.

## `effectiveTo` (type: `string`):

ISO date, for example 2026-06-30. Keeps records whose opt-out effective date is on or before this date. Records with no readable effective date are excluded.

## `currentlyOptedOutOnly` (type: `boolean`):

Keep only records whose opt-out end date has not passed, evaluated against the day the run starts. CMS keeps recently expired affidavits in the file: 1,096 of 57,530 records had already expired on 2026-08-23.

## `maxResults` (type: `integer`):

How many records to deliver. You are charged per delivered record, so this is also your cost cap.

## `includeRaw` (type: `boolean`):

Attach a `raw` object holding the CMS columns under their published names, whitespace-trimmed. Useful for auditing the normalization; roughly doubles item size.

## Actor input object example

```json
{
  "state": [],
  "currentlyOptedOutOnly": false,
  "maxResults": 100,
  "includeRaw": false
}
```

# Actor output Schema

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

One item per physician or practitioner opt-out record delivered by this run.

## `summary` (type: `string`):

Source URL, dataset size, rows scanned, HTTP requests made, delivered records and whether the charge limit stopped the run.

# 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 = {
    "state": [],
    "maxResults": 100
};

// Run the Actor and wait for it to finish
const run = await client.actor("jserle/medicare-opt-out-physicians").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 = {
    "state": [],
    "maxResults": 100,
}

# Run the Actor and wait for it to finish
run = client.actor("jserle/medicare-opt-out-physicians").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 '{
  "state": [],
  "maxResults": 100
}' |
apify call jserle/medicare-opt-out-physicians --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,jserle/medicare-opt-out-physicians"
        }
    }
}

```

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/uvmgjOFkNmueos4xr/builds/McMyCcH5Z4qVrnctY/openapi.json
