# Verify a provider

URL: https://docs.healthcare.dev/recipes/verify-a-provider

|                  |                                                                                                                                                                                                |
| ---------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Plan             | **Free** for each check. **Pro** (or a preview on Free and Builder) for the one-call answer with source conflicts and possible exclusion matches ([Joined answers](/joined-answers#providers)) |
| Datasets         | [NPI](/datasets/npi), [Medicare enrollment](/datasets/medicare-enrollment), [Medicare opt-out](/datasets/medicare-opt-out), [OIG exclusions](/datasets/oig-exclusions)                         |
| Calls per answer | 4 on Free (validate, enrollment, opt-out, exclusions), 1 on Pro                                                                                                                                |

## Free: four checks

```sh
NPI=1922348218
for check in validate enrollment opt-out exclusions; do
  curl -s "https://api.healthcare.dev/v1/providers/$NPI/$check" \
    -H "Authorization: Bearer $HDEV_API_KEY" | jq -c '.data | del(.enrollments, .affidavits, .exclusions)'
done
```

Each check prints one line: `validate` gives `exists` and `status`, `enrollment` gives
`enrolled`, `opt-out` gives `opted_out`, and each has a `note`. The exclusion check for this NPI:

```json
{
  "npi": "1922348218",
  "exclusion_recorded": true,
  "matched_by": "npi_as_listed",
  "note": "Matched by NPI as listed in the OIG file (LEIE). Most LEIE records carry no NPI, ..."
}
```

**TypeScript**

```ts
import { HealthcareDev } from "@healthcare.dev/sdk";

const hdev = new HealthcareDev(); // reads HDEV_API_KEY
const npi = "1922348218";

const [id, enrollment, optOut, exclusions] = await Promise.all([
  hdev.providers.validate(npi),
  hdev.providers.enrollment(npi),
  hdev.providers.optOut(npi),
  hdev.providers.exclusions(npi),
]);

console.log({
  exists: id.data.exists,
  status: id.data.status, // "active" | "deactivated" | null
  medicare_enrolled: enrollment.data.enrolled,
  opted_out: optOut.data.opted_out,
  exclusion_recorded: exclusions.data.exclusion_recorded,
  exclusion_note: exclusions.data.note, // show this with the answer
});
```

**Python**

```python
from healthcare_dev import HealthcareDev

hdev = HealthcareDev()  # reads HDEV_API_KEY
npi = "1922348218"

checks = {
    "id": hdev.providers.validate(npi)["data"],
    "enrollment": hdev.providers.enrollment(npi)["data"],
    "opt_out": hdev.providers.opt_out(npi)["data"],
    "exclusions": hdev.providers.exclusions(npi)["data"],
}
print(checks["id"]["exists"], checks["id"]["status"])
print(checks["enrollment"]["enrolled"], checks["opt_out"]["opted_out"])
print(checks["exclusions"]["exclusion_recorded"], checks["exclusions"]["note"])
```

### Also search exclusions by name

Most OIG exclusion records carry no NPI, so `exclusion_recorded: false` means "no exclusion
recorded **with this NPI**", never "not excluded". Search by name and state as well:

```sh
curl "https://api.healthcare.dev/v1/exclusions?q=184th+street+pharmacy&state=NY" \
  -H "Authorization: Bearer $HDEV_API_KEY"
```

```ts
const byName = await hdev.exclusions.search({ q: "184th street pharmacy", state: "NY" });
```

```python
by_name = hdev.exclusions.search(q="184th street pharmacy", state="NY")
```

A name match is not an identity match: confirm with OIG's online search, which checks SSN or EIN.

## Pro: one call, with conflicts

`GET /v1/providers/{npi}/full` runs every check above in one billed call and adds what the
separate checks can't: where NPPES and Medicare enrollment (PECOS) disagree, and OIG records
without an NPI that may be this provider.

<Callout title="Try it before you upgrade">
  Free and Builder keys can call it as a preview: 50 preview calls a month on Free, 200 on Builder,
  per feature. A preview answer is the real answer, with `meta.preview` (calls `remaining` this
  month and the plan that `unlocks` it) and `links.upgrade`. Preview calls count toward your
  included calls. Once they're used up, the `403` `plan-upgrade-required` adds `upgrade_url` and a
  sample answer for a fixed demo subject. See [Plans](/plans#previews).
</Callout>

```sh
curl "https://api.healthcare.dev/v1/providers/1922348218/full?view=compact" \
  -H "Authorization: Bearer $HDEV_API_KEY"
```

```json
{
  "data": {
    "npi": "1922348218",
    "name": "184TH STREET PHARMACY CORP",
    "entity_type": "organization",
    "flags": { "exclusion_recorded": true, "...": "..." },
    "exclusion_note": "Matched by NPI as listed in the OIG file (LEIE). ...",
    "missing": [{ "component": "...", "status": "not_listed", "reason": "..." }],
    "conflicts": [],
    "conflicts_checked": ["..."]
  },
  "meta": { "data_version": "...,oig-exclusions@2026-10-09", "sources": ["..."] }
}
```

```ts
const { data } = await hdev.providers.full("1922348218", { view: "compact" });
console.log(data.flags, data.exclusion_note, data.conflicts);
```

```python
full = hdev.providers.full("1922348218", view="compact")["data"]
print(full["flags"], full["exclusion_note"], full["conflicts"])
```

## Ask an agent

With the [MCP server](/mcp) connected:

> Verify NPI 1922348218 before we pay them: is the NPI active, are they enrolled in Medicare or
> opted out, and does the OIG list an exclusion? Show each answer's note and cite the
> source and data version.

The agent uses `validate_npi`, `check_medicare_enrollment`, `check_medicare_opt_out` and
`check_provider_exclusion`, or `get_provider_full` on Pro.

## Read the answer

- **`not_listed` is not "no".** A check whose file doesn't list the NPI says so in its `note`.
  Show the note next to the answer.
- **A flag of `null`** (Pro) means the dataset to answer isn't available, never `false`.
- **Conflicts are shown, never settled.** `conflicts` lists the fact with every source's value,
  `as_of` and page; we don't pick a winner. An empty `conflicts` means the facts in
  `conflicts_checked` agree; a fact not in `conflicts_checked` wasn't compared.
- **Possible exclusion matches** (`exclusion_matches`, Pro) are OIG records without an NPI with
  the same name in the same state, scored on middle name, address and specialty. Each says how it
  was reached: `derivation: "derived"` means fixed matching rules published it on their own (one
  candidate, strong evidence); `"reviewed"` means a person checked it first. `confidence` (0 to 1)
  is how strong the evidence is. A possible match is never a finding that the provider is
  excluded.

## What it is not

Reference data, not a credentialing or enrollment determination. Confirm an exclusion's identity
with [OIG's online search](https://exclusions.oig.hhs.gov) before acting on it, and check
enrollment with your Medicare Administrative Contractor when it matters for payment.
