healthcare.dev docs

Verify a provider

Before you schedule, refer or pay: does the NPI exist, is it active, is it enrolled in Medicare, has it opted out, does OIG list an exclusion, and do the sources disagree.

PlanFree for each check. Pro for the one-call answer with source conflicts and possible exclusion matches (Joined answers)
DatasetsNPI, Medicare enrollment, Medicare opt-out, OIG exclusions
Calls per answer4 on Free (validate, enrollment, opt-out, exclusions), 1 on Pro

Free: four checks

NPI=1003926940
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
{"npi":"1003926940","valid_format":true,"valid_check_digit":true,"exists":true,"status":"active","deactivation_history":[]}
{"npi":"1003926940","enrolled":false,"note":"Matched by NPI (the enrollment's NPI or one of its additional NPIs) in CMS's Medicare Fee-For-Service Public Provider Enrollment file, ..."}
{"npi":"1003926940","opted_out":true,"note":"..."}
{"npi":"1003926940","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

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

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

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

from healthcare_dev import HealthcareDev

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

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:

curl "https://api.healthcare.dev/v1/exclusions?q=shelburne&state=VA" \
  -H "Authorization: Bearer $HDEV_API_KEY"
const byName = await hdev.exclusions.search({ q: "shelburne", state: "VA" });
by_name = hdev.exclusions.search(q="shelburne", state="VA")

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.

curl "https://api.healthcare.dev/v1/providers/1003926940/full?view=compact" \
  -H "Authorization: Bearer $HDEV_API_KEY"
{
  "data": {
    "npi": "1003926940",
    "name": "ROY S SHELBURNE, DDS",
    "entity_type": "individual",
    "status": "active",
    "flags": { "medicare_enrolled": false, "opted_out": true, "exclusion_recorded": true },
    "exclusion_note": "Matched by NPI as listed in the OIG file (LEIE). ...",
    "missing": [{ "component": "enrollment", "status": "not_listed", "reason": "..." }],
    "conflicts": [],
    "conflicts_checked": []
  },
  "meta": { "data_version": "nppes@2026-10,medicare-enrollment@2026-10-01,...", "sources": ["..."] }
}
const { data } = await hdev.providers.full("1003926940", { view: "compact" });
console.log(data.flags, data.exclusion_note, data.conflicts);
full = hdev.providers.full("1003926940", view="compact")["data"]
print(full["flags"], full["exclusion_note"], full["conflicts"])

Ask an agent

With the MCP server connected:

Verify NPI 1003926940 before I schedule with 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 before acting on it, and check enrollment with your Medicare Administrative Contractor when it matters for payment.

On this page