# OIG Exclusion Check & Medicare Opt-Out Screen - Bulk NPI LEIE (`infocomp/oig-exclusion-optout-screen`) Actor

Screen NPIs in bulk against the HHS-OIG exclusion list (LEIE) and the CMS Medicare opt-out list, matched by NPI, from official bulk files. Optional name check flags possible matches to verify. $3 per 1,000 screened entries.

- **URL**: https://apify.com/infocomp/oig-exclusion-optout-screen.md
- **Developed by:** [InfoComp Data](https://apify.com/infocomp) (community)
- **Categories:** Developer tools, Other
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$3.00 / 1,000 provider checks

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

## OIG Exclusion Check & Medicare Opt-Out Screen - Bulk NPI LEIE

**Screen a list of NPIs against the HHS-OIG List of Excluded Individuals/Entities (LEIE) and the CMS Medicare opt-out list in one run.** Matching is by NPI, using the official bulk files downloaded fresh each run. You can also add provider names: a name that equals an LEIE entry without an NPI is flagged in a **separate "possible match - verify" field**. It is never reported as a confirmed exclusion.

- ✅ **Exact NPI matching** against the full current LEIE (84,093 exclusions in the October 2026 file, 8,924 of them with an NPI) and the Medicare Opt Out Affidavits file (58,286 NPIs).
- 🔎 **Optional name check** for the many LEIE entries that have no NPI. Results are labeled *possible match - verify*.
- 🧮 **Offline NPI format check** (check digit). Invalid NPIs are flagged and **free**.
- ⚡ Fast and light: 100,000 NPIs screened in about 37 s in a local test, with no per-record API calls.
- 💲 **$3.00 per 1,000 screened entries** ($0.003 each). No start fee.

> ⚠️ **Not an official verification.** This is a screening aid built from public government files. **Confirm any match with OIG's own LEIE online search: https://exclusions.oig.hhs.gov/** (it can verify identity by SSN/EIN, which the public file does not contain). This Actor is **not affiliated with or endorsed by HHS, the HHS Office of Inspector General (OIG), or CMS.** Not legal advice.

### What does it do?

1. Downloads the current **OIG LEIE `UPDATED.csv`** and the current **CMS Medicare Opt Out Affidavits** CSV, once per run, with retries.
2. Cleans and de-duplicates your NPIs and checks each NPI's check digit offline.
3. For each valid NPI: looks it up **by NPI** in both files.
4. For each name you supply (person or organization, ideally with a state): looks for LEIE entries **without an NPI** with the same name. Persons match on last name + first name (+ state). If both records have a middle initial, they must agree. Organizations match on the name with suffixes such as LLC/INC removed (+ state).
5. Saves one row per unique NPI or name, with a plain-language `screen_result`.

It does **not** call the NPPES NPI Registry API, and it does not return provider addresses, phones or taxonomies from NPPES. It only screens against the two lists.

### Who is it for?

Credentialing and compliance teams, billing companies, staffing agencies, pharmacies, home-health and DME suppliers, and health-tech platforms that need a monthly or on-hire screen of many NPIs, before confirming hits at OIG.

### Input

| Field | Type | Description |
|---|---|---|
| `npis` | list of strings | 10-digit NPIs, one per line. Spaces and dashes are removed, and duplicates are screened once. |
| `providers` | JSON array (optional) | Name checks: `{"firstName","middleName","lastName","state","npi"}` for a person or `{"organizationName","state","npi"}` for an organization. `npi` attaches the name to that NPI's row. `state` is strongly recommended (without it, the check covers all states). |
| `npiListUrl` | string (optional) | URL of a CSV or text file. Every 10-digit number in it is screened (up to 100,000 per run; the first 30 MB are read). |
| `checkMedicareOptOut` | boolean, default true | Also check the Medicare opt-out list. |
| `includeInvalid` | boolean, default true | Keep free rows for invalid NPIs so you can clean your list. |
| `maxEntries` | integer, default 0 | Cap on unique entries (0 = up to 100,000). |

Example:

```json
{
  "npis": [
    "1972902351",
    "1588302186",
    "1447580105",
    "1003000126",
    "1234567890"
  ],
  "providers": [
    {
      "organizationName": "1 Best Care, Inc.",
      "state": "MN"
    }
  ]
}
```

### Output

One row per unique NPI or name. Main fields:

- `npi`, `valid_format`, `input_name`, `input_entity_type`, `input_state`
- **OIG by NPI (confirmed NPI match in the file):** `oig_excluded`, `oig_excluded_name`, `oig_excluded_general`, `oig_excluded_specialty`, `oig_excluded_city`, `oig_excluded_state`, `oig_exclusion_type` (e.g. `1128b8`), `oig_exclusion_type_description`, `oig_exclusion_date`, `oig_reinstatement_date`, `oig_waiver_date`, `oig_waiver_state`, `oig_verify_url`
- **OIG by name only (never confirmed):** `oig_name_possible_match` and `oig_name_possible_matches[]` (each with `match_basis` and `verdict: "possible match - verify"`)
- **Medicare opt-out by NPI:** `medicare_opted_out`, `opt_out_active_today`, `opt_out_effective_date`, `opt_out_end_date`, `opt_out_specialty`, `opt_out_state`, `opt_out_eligible_to_order_and_refer`
- `screen_result`, `charged`, `duplicate_count_in_input`, `checked_at`, `source_dates` (file names and dates actually used), `disclaimer`, `attribution`

A run summary (counts, source file dates, invalid NPIs, charged rows) is saved to the key-value store as `RUN_SUMMARY`.

#### Real output sample

From a local run of the default input on 2026-10-27 at 10:20 AM CT (LEIE file dated 2026-10-09, opt-out file `Opt_Out_List_September.csv` dated 2026-10-23):

| NPI | Name (input) | screen_result | Billed |
|---|---|---|---|
| `1972902351` |  | ON OIG LEIE by NPI - confirm at OIG online search | yes |
| `1588302186` |  | ON OIG LEIE by NPI - confirm at OIG online search | yes |
| `1447580105` |  | Medicare opt-out active | yes |
| `1003000126` |  | not found on OIG LEIE or Medicare opt-out list | yes |
| `1234567890` |  | invalid NPI format (not screened, not charged) | no |
| `-` | 1 Best Care, Inc. | POSSIBLE NAME MATCH on OIG LEIE - verify, not confirmed | yes |

Selected fields from 4 of those rows:

```json
[
  {
    "npi": "1972902351",
    "valid_format": true,
    "oig_excluded": true,
    "oig_excluded_name": "101 FIRST CARE PHARMACY INC",
    "oig_excluded_general": "OTHER BUSINESS",
    "oig_excluded_specialty": "PHARMACY",
    "oig_excluded_state": "NY",
    "oig_exclusion_type": "1128b8",
    "oig_exclusion_type_description": "Entities controlled by a sanctioned individual",
    "oig_exclusion_date": "2022-03-20",
    "oig_reinstatement_date": null,
    "oig_name_possible_match": null,
    "oig_verify_url": "https://exclusions.oig.hhs.gov/",
    "medicare_opted_out": false,
    "screen_result": "ON OIG LEIE by NPI - confirm at OIG online search",
    "charged": true,
    "checked_at": "2026-10-27T15:20:59Z",
    "source_dates": {
      "oig_leie": {
        "file": "UPDATED.csv",
        "file_last_modified": "2026-10-09",
        "rows": 84093
      },
      "medicare_opt_out": {
        "file": "Opt_Out_List_September.csv",
        "file_last_modified": "2026-10-23",
        "npis": 58286
      }
    }
  },
  {
    "npi": "1447580105",
    "valid_format": true,
    "oig_excluded": false,
    "medicare_opted_out": true,
    "opt_out_active_today": true,
    "opt_out_effective_date": "2016-10-01",
    "opt_out_end_date": "2028-10-01",
    "opt_out_specialty": "Clinical Psychologist",
    "opt_out_state": "CA",
    "opt_out_eligible_to_order_and_refer": "Y",
    "screen_result": "Medicare opt-out active",
    "charged": true
  },
  {
    "npi": null,
    "input_name": "1 Best Care, Inc.",
    "input_entity_type": "organization",
    "input_state": "MN",
    "oig_excluded": null,
    "oig_name_possible_match": true,
    "oig_name_possible_matches": [
      {
        "name": "1 BEST CARE, INC",
        "middle_name": null,
        "general": "OTHER BUSINESS",
        "specialty": "HOME HEALTH AGENCY",
        "city": "SAINT PAUL",
        "state": "MN",
        "exclusion_type": "1128b5",
        "exclusion_type_description": "Exclusion or suspension under a federal or state health care program",
        "exclusion_date": "2023-05-18",
        "reinstatement_date": null,
        "waiver_date": null,
        "waiver_state": null,
        "match_basis": "name + state; LEIE entry has no NPI",
        "verdict": "possible match - verify"
      }
    ],
    "screen_result": "POSSIBLE NAME MATCH on OIG LEIE - verify, not confirmed",
    "charged": true
  },
  {
    "npi": "1234567890",
    "valid_format": false,
    "oig_excluded": null,
    "medicare_opted_out": null,
    "screen_result": "invalid NPI format (not screened, not charged)",
    "charged": false
  }
]
```

### Pricing

**$3.00 per 1,000 screened entries** ($0.003 per row, pay-per-event `npi-screened`, no start fee).

- **Charged:** every row for a valid NPI or a supplied name, **including clean results** ("not found on OIG LEIE or Medicare opt-out list"). A clean screen is a real, useful result.
- **Free:** rows for NPIs that fail the format/check-digit test (`charged: false`).
- If a source file can't be downloaded after retries, the run fails **before anything is charged**.
- Your **maximum cost per run** is respected. The Actor stops when the next billable row would exceed it.

Examples: 1,000 NPIs is $3.00, and 10,000 NPIs is $30.00.

### Data sources and credits

- **U.S. Department of Health and Human Services, Office of Inspector General: List of Excluded Individuals/Entities (LEIE), downloadable database** (https://oig.hhs.gov/exclusions/exclusions_list.asp). Updated monthly. Contains active exclusions only (reinstated parties are removed).
- **Centers for Medicare & Medicaid Services: Medicare Opt Out Affidavits** (data.cms.gov) (https://data.cms.gov/provider-characteristics/medicare-provider-supplier-enrollment/opt-out-affidavits). Updated monthly.

Both are U.S. Government works. Credit is given on every row (`attribution`). OIG's own pages place no license restriction on the downloadable LEIE and recommend downloading it for checking many names. data.cms.gov states its data is public domain with attribution appreciated and no implied endorsement. Quotes are in `TERMS.md`.

### Limitations

- **Not an official verification.** OIG requires final identity verification by SSN/EIN in its online search, and the public file has no SSNs or EINs.
- **Name-only matches are weak.** Common names produce false positives, and a missing state widens the search to all states. Treat them only as leads to check at OIG.
- **The file lags.** LEIE is updated monthly (it holds actions through the prior month), and the opt-out file is monthly. Recent exclusions or reinstatements may not appear yet. `source_dates` shows the files used.
- **Exclusions only.** This does not cover state Medicaid exclusion lists, the SAM.gov debarment list, licensure, or NPPES status.
- **A valid format doesn't mean the NPI is real or active.** NPIs are not looked up in NPPES.
- Up to 100,000 entries per run.

### FAQ

**Why not also return NPPES details?** NPPES asks that bulk NPI Registry queries use its downloadable file rather than the API, so this Actor makes no NPPES calls.
**Is a `possible match - verify` an exclusion?** No. It means an LEIE entry with no NPI has the same name (and state). Verify it at https://exclusions.oig.hhs.gov/.

# Actor input Schema

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

One 10-digit NPI per line. Each is matched by NPI against the OIG LEIE and the CMS Medicare opt-out list. Duplicates are screened once. NPIs that fail the check-digit test are flagged and not charged.

## `providers` (type: `array`):

Optional name checks against LEIE entries that have no NPI. One object per provider: {"firstName", "middleName", "lastName"} for a person or {"organizationName"} for an organization, plus optional "state" (2 letters, strongly recommended) and "npi" (to attach the name to that NPI's row). Name hits are reported only as 'possible match - verify', never as confirmed exclusions.

## `npiListUrl` (type: `string`):

Public URL of a CSV or text file. Every 10-digit number in it is screened as an NPI (up to 100,000 per run).

## `checkMedicareOptOut` (type: `boolean`):

Also match each NPI against the current CMS Medicare Opt Out Affidavits file.

## `includeInvalid` (type: `boolean`):

Keep a free row (valid_format = false, charged = false) for inputs that fail the NPI check digit, so you can clean your list.

## `maxEntries` (type: `integer`):

Stop after this many unique entries (0 = no limit, up to 100,000 per run).

## Actor input object example

```json
{
  "npis": [
    "1972902351",
    "1588302186",
    "1447580105",
    "1003000126",
    "1234567890"
  ],
  "providers": [
    {
      "organizationName": "1 Best Care, Inc.",
      "state": "MN"
    }
  ],
  "checkMedicareOptOut": true,
  "includeInvalid": true,
  "maxEntries": 0
}
```

# Actor output Schema

## `results` (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 = {
    "npis": [
        "1972902351",
        "1588302186",
        "1447580105",
        "1003000126",
        "1234567890"
    ],
    "providers": [
        {
            "organizationName": "1 Best Care, Inc.",
            "state": "MN"
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("infocomp/oig-exclusion-optout-screen").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 = {
    "npis": [
        "1972902351",
        "1588302186",
        "1447580105",
        "1003000126",
        "1234567890",
    ],
    "providers": [{
            "organizationName": "1 Best Care, Inc.",
            "state": "MN",
        }],
}

# Run the Actor and wait for it to finish
run = client.actor("infocomp/oig-exclusion-optout-screen").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 '{
  "npis": [
    "1972902351",
    "1588302186",
    "1447580105",
    "1003000126",
    "1234567890"
  ],
  "providers": [
    {
      "organizationName": "1 Best Care, Inc.",
      "state": "MN"
    }
  ]
}' |
apify call infocomp/oig-exclusion-optout-screen --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,infocomp/oig-exclusion-optout-screen"
        }
    }
}
```

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/11ezNYjQFZ8vuwBTo/builds/C37svqJsbop0tspJO/openapi.json
