Coverage map
Click a state for its sources, access method, cadence, identifiers, matching and data.
Findings
- 44 jurisdictions publish a list; we hold 41 current copies. Seven states publish none. Older copies: West Virginia (its site was down today; a November edition is now posted) and Mississippi (site down after a vendor outage). Maine comes from OpenSanctions. New Mexico, Oklahoma, Rhode Island, South Dakota, Utah, Virginia and Wisconsin point providers to the federal LEIE and SAM lists; Utah and Virginia say so explicitly.
- Most states never say how often they update. In practice, about every 2–4 weeks. Only 12 of 49 lists state a schedule: 10 monthly, plus Pennsylvania and Arkansas (daily). From OpenSanctions' daily crawl over the last 12 months: 11 lists change every 2–3 weeks (AR, LA, MI, MT, NE, NV, NY, OH, PA, TX), 17 monthly, and 14 every few months or less (AZ, CO, HI, KY, MA, NH, TN, WA, WY…). A weekly resync covers every list.
- Most lists download with a simple script; 7 need a real browser. 39 lists download with a plain script. KS, NH, MN (2 lists), HI, MA and CT block scripts and come through CloudCruise. Tennessee came through a user's Chrome. Maine's portal opens only on weekdays 07–19 ET, and Mississippi has nothing to fetch today.
- No list publishes SSN; few publish DOB or NPI. NJ and PA ask for the last 4 digits of the SSN only to answer verification requests. DOB appears only on Louisiana, Ohio and Mississippi, plus 95% of LEIE. A valid NPI is on most records in 18 lists, but on only 21% of all state records. Large lists (CA, TX, NY, PA) carry license numbers instead.
- Better identifiers mean more automatic clears. Bare-name lists clear only 31%. Share of dry-run monitoring flags our rules dismissed, by the list's tier: B (license or DOB) 87%, A (NPI) 82%, C (name and profession) 73%, D (bare names: AR, DC, OR PIAU, TN, WA DSHS) 31%. On bare-name lists most hits go to a person, unless LEIE lends a DOB through merged identity.
- Our ingesters have a few gaps to fix. Fields the state publishes that we don't capture: Idaho exclusion dates; reinstatement dates for Iowa, Vermont and Mississippi; Nevada Medicaid IDs. URLs that moved: Michigan's file is now
MI_Sanctioned_Provider_List-XLSX.xlsx; Montana links a fixed asset name; the NJ Treasury directory is 404 (the files are now named per category). Oregon's PIAU page is retired, but its SharePoint list still answers. Pick up West Virginia's November file. - Some lists aren't quite Medicaid exclusions. DC's is a procurement debarment list (DC Medicaid publishes none). Florida's is mostly fines. Delaware mixes licensing-board actions and other states' actions. Arkansas spans every DHS division, child care included. Washington DSHS has a single row, from 2017. Indiana calls its list "not an active or ongoing exclusionary list".
- Some research is second-hand. Eight state sites block automated reads. Official pages for HI, KS, MA, MN, NH, NJ, CO and CT block automated reads, so their cadence, legal basis and contact details come from search snippets or archived copies. Each source card shows its confidence and links.
NPI lookup
Paste or type an NPI. We pull the provider from the NPPES registry and screen them with our rules against every state list plus LEIE and SAM.
Share of each list's records that carry the field after parsing. Marks show what the state publishes according to the web research: ● published, ○ not published, ◐ partial. A red outline means the state publishes it but we capture under 5% (an ingester gap, or a column that is mostly empty).
Stated: what the agency says on its own page (quote on hover). Observed: days on which OpenSanctions' daily crawl first saw new records in the last 12 months, and the median gap between them. Our fetches: distinct files among our own fetches since Oct 17. Activity: records by exclusion date per month, Nov 2025 – Nov 2026.
Medallion fields and the lists that can use them
Per state: which rules can fire, and what they did in the Oct 28 dry run
Dry run: 17,829 ongoing-monitoring flags in 44 orgs screened by our rules (default mode). "SLV override flags": flags in the Slack override set (1,080 providers) on that state's list.
Start here
The POC is a plain folder (no git) referred to below as <project root>. Python 3.12 via uv; every command runs from the project root. Read FINDINGS.md for the history of decisions, then this tab.
Folder map
| poc/ingest/ | one ingester per list (us-<st>-medicaid.py); shared helpers _pdfcommon.py, _sheetlib.py, _bigstates.py; SOURCES.md runbook |
| poc/service/ | server.py (FastAPI), resync.py (safe refresh), resync_cli.py, history.py, static/ (old screening form) |
| poc/match/ | matcher.py (rules), names.py (name keys, nicknames), holdout_safety.py (name-only safety test) |
| poc/common/ | schema.py (ExclusionRecord, save_raw), tls.py (incomplete TLS chains), nppes.py (local NPPES index) |
| poc/cloudcruise/ | cc_run.py: CloudCruise workflows for lists that block scripts |
| poc/eval/ | OpenSanctions supplement and comparison |
| poc/data/normalized/ | the lists we screen (jsonl + summary.json per source) |
| poc/data/raw/<source>/ | every fetched file plus a __meta.json (URL, time, sha256): the evidence |
| poc/data/nppes/nppes.sqlite | 3.2 GB local NPPES index built from the monthly CMS file |
| poc/report/ | builders for this page (state_explorer_data.py, build_state_explorer.py) |
| artifacts/scripts/ | outside poc: manual-fetch scripts for lists that need a real browser |
| FINDINGS.md | the running log of what was measured and decided |
Everyday commands
uv run --script poc/service/server.py # http://127.0.0.1:8791/explorer (settings under Deploy)
uv run -q python poc/service/resync_cli.py us-tx-oig # refresh one list with the safety checks
uv run -q python poc/service/resync_cli.py --all # refresh everything, then the OpenSanctions supplement
uv run -q python poc/report/state_explorer_data.py && uv run -q python poc/report/build_state_explorer.py # rebuild this pageKey code
Access you need
- US address (VPN with a US exit): most state sites refuse other countries.
- CloudCruise API key in
CLOUDCRUISE_API_KEY(or a .env file named byCLOUDCRUISE_ENV) for KS, NH, MN, HI, MA and CT. The API workflow ids are in SOURCES.md; they differ from the dashboard's. - NPPES: nothing, the registry API is public; the monthly full file feeds the local index.
Ground rules
- Anything with real provider data from internal systems stays local (directories 0700, files 0600), never committed or shared. Public list data is fine.
- Don't get around a block with proxies or captcha solving; use the routes in the runbook.
- Read-only everywhere: these scripts never write to another system or post anywhere.
Server settings
| Variable | Example | Effect |
|---|---|---|
| MEDEX_PORT | 8791 | port (127.0.0.1) |
| MEDEX_HOME | explorer | serve the explorer at / instead of the screening form |
| MEDEX_INTERNAL | 1 | serve the explorer with this POC tab (code, runbook) at / and /explorer |
| MEDEX_READONLY | 1 | 403 for resync and screening history (public deployments) |
| MEDEX_SKIP_SOURCES | us-fed-sam | lists left out of memory on small hosts (SAM is ~half the records) |
| MEDEX_AUTH | user:pass | HTTP basic auth for every route |
| MEDEX_HISTORY_DB | path | screening history sqlite |
| POC_LICENSE_ABSENCE | 0 | strict mode: missing licenses never dismiss |
| POC_RULES | all / list | rule switches |
A refresh copies the current list aside first and puts it back when the run fails, writes nothing, shrinks the list below half, or falls back to an Internet Archive copy for a list we had live.
Matcher rules
Candidates first: every record whose surname matches one of the provider's surnames (current, maiden, former) with a compatible first name (exact, nickname, spelling, initial), plus records sharing the NPI or a license number with the same first name. Then the rules, in this order; the first decisive one wins. Anything left is possible.
Counts: decisions on the 17,829 ongoing-monitoring flags (Oct 28 dry run, default / strict), and on the SLV records plus our own matches in the Slack override sets (Sep 15 – Nov 7, default). Strict = POC_LICENSE_ABSENCE=0: a license we don't see never dismisses. Rule switches: POC_RULES (the default set, all, all-<rule> or a comma list).
| Rule | Outcome | What it checks | Switch | Flags default | Flags strict | Override records |
|---|---|---|---|---|---|---|
| reinstated | dismiss | The list itself says the person was reinstated, so they are no longer excluded. Needs list: reinstatement date (past) · Medallion: – | always | 1,035 | 1,035 | 101 |
| npi_match | confirm | Same NPI on the record. Only NPIs that pass the check digit count. Needs list: valid NPI · Medallion: provider NPI | always | 44 | 44 | 3 |
| npi_mismatch | dismiss | The record publishes a different valid NPI. Needs list: valid NPI · Medallion: provider NPI | always | 2,732 | 2,732 | 15 |
| license_match | confirm | A record license number equals one of the provider's, in any state. Needs list: license number · Medallion: all license rows (+ NPPES licenses for the NPI) | always | 1 | 1 | 1 |
| dob_mismatch | dismiss | Different date of birth (partial dates compare on what they have). Needs list: DOB · Medallion: provider DOB | always | 1,066 | 1,066 | 6 |
| excluded_before_adulthood | dismiss | Excluded before the provider turned 16: a different person. Needs list: exclusion date · Medallion: provider DOB | age16 (on): 16th birthday, else 18th | 1,206 | 1,206 | 208 |
| nppes_license_match | confirm | NPPES lists the record's license under the provider's own NPI. Needs list: license + state · Medallion: provider NPI | license_owner (on) | 0 | 0 | 0 |
| license_owned_by_other | dismiss | NPPES lists the record's license under another NPI with the record's surname. Needs list: license + state · Medallion: provider NPI | license_owner (on) | 207 | 207 | 28 |
| license_state_mismatch | dismiss | Record license is in a state where the provider holds none. Since the safety test it also needs a profession contradiction or a different same-full-name person in NPPES for that state, and never fires in a state from the provider's history. Needs list: license + state · Medallion: license states, history states | off in strict (POC_LICENSE_ABSENCE=0); license_state_corroborated; history_guard | 3,508 | 0 | 583 |
| license_near_match | possible | One digit off, swapped digits or containment: a possible typo goes to a person, never a dismissal. Needs list: license + state · Medallion: same-state license | license_typo (on) | 0 | 0 | 0 |
| license_number_mismatch | dismiss | The provider holds a license in that state with a different number. Needs list: license + state · Medallion: same-state license | off in strict (POC_LICENSE_ABSENCE=0) | 640 | 0 | 62 |
| middle_name_mismatch | dismiss | Both middle names spelled out and different (initials only conflict on the letter). Needs list: middle name · Medallion: middle name, other names | always | 904 | 1,777 | 118 |
| provider_type_contradiction | dismiss | Record profession family contradicts the provider's (e.g. aide vs psychologist). Ignored in a state where the provider holds a license or has history, and when the exclusion predates their career. Needs list: profession · Medallion: profession, license states, history | type_needs_other_state, history_guard | 1,360 | 2,733 | 179 |
| merged_npi_match | confirm | The same person elsewhere carries the provider's NPI. Needs same person on another list (usually LEIE) · Medallion: provider NPI | use_merge | 0 | 0 | 0 |
| merged_npi_mismatch | dismiss | The same person elsewhere carries a different NPI. Needs same person on another list · Medallion: provider NPI | use_merge | 17 | 23 | 1 |
| merged_dob_mismatch | dismiss | The same person elsewhere has a different DOB. Needs same person on another list (LEIE has DOB on 95%) · Medallion: provider DOB | use_merge | 1,929 | 2,613 | 255 |
| nppes_other_person | dismiss | NPPES has exactly one matching clinician in that state and it is someone else. Needs list: name + state · Medallion: provider NPI | only with use_nppes=True | 0 | 0 | 0 |
| name_only (+ _nickname, _spelling, _initial, _alias_*) | possible | Name matches and nothing confirms or contradicts it: a person reviews it. Needs – · Medallion: – | fallback | 2,559 | 3,442 | 359 |
Provider-level rules
prior_confirmed: Once one hit is confirmed by an identifier, the provider's other soft dismissals are reopened.alias_full_name: Off by default: a hit through a published alias with the provider's exact name can't be dismissed by soft rules. Cost 94 providers, caught nothing.
Code
Source runbook
Order of attempts for any list: plain script (needs a US address for most states) → CloudCruise (KS, NH, MN ×2, HI, MA, CT) → the owner's Chrome over CDP (TN) → keep the previous copy. Every route ends in resync's safety checks. The text runbook is poc/ingest/SOURCES.md; update it on every resync.
AK us-ak-medicaid direct script, US VPNcurrent
| List | Alaska excluded provider list |
| Official page | https://health.alaska.gov/commissioner/pages/programintegrity/default.aspx |
| File we fetch | https://health.alaska.gov/media/5kedgesi/exclusion-list-august-2026.pdf (path is random per upload; the ingester discovers it from the landing page) |
| Route that works | direct script, US VPN |
| How | Reads the Program Integrity page for the newest `exclusion-list-<month>-<year>.pdf`, downloads and parses the PDF. Slow: ~4 min. |
| Watch out | Fails from non-US addresses. Latest published edition is still August (CloudCruise's browser got the identical file). |
| Edition held | August 2026 |
| Stated cadence | regularly / as needed (no fixed schedule) |
| Records | 304 (303 active), newest 2026-07-01 |
| Last resync | 304 records (+0) |
| Research notes | Reinstatement requires written request with 'clear and convincing evidence' to Program Integrity (post-conviction requests to Office of the Commissioner). Old copies of the list are mirrored on third-party sites (aapc.com) and an older stable path /media/h3ueo2kf/alaska-medical-assistance-excluded-provider-list.pdf still exists; the ingester must take the newest link from the landing page. |
Refresh
uv run -q python poc/service/resync_cli.py us-ak-medicaid
uv run --script poc/ingest/us-ak-medicaid.py # debug only: writes the list directly, no safety checksFields
Captured: provider_type 96%, middle_name 43%, aliases 2%, exclusion_date 98%, reinstatement_date 0%, first_last 91%. Other published columns: authority, reason, list_heading, pdf_page.
https://health.alaska.gov/media/5kedgesi/exclusion-list-august-2026.pdf; heading 'August 2026'; fetched via direct ; newest candidate: https://health.alaska.gov/media/5kedgesi/exclusion-list-august-2026.pdf
AL us-al-medicaid direct script, US VPNcurrent
| List | Alabama Provider Sanction List |
| Official page | https://medicaid.alabama.gov/content/8.0_Fraud/8.7_Suspended_Providers.aspx |
| File we fetch | https://medicaid.alabama.gov/content/8.0_Fraud/8.7_Suspended_Providers.aspx → `8.7_Provider_Sanction_List_<M-D-YY>.pdf/.xlsx` |
| Route that works | direct script, US VPN |
| How | Reads the page for the dated `8.7_Provider_Sanction_List_<M-D-YY>` link, takes the Excel file. Incomplete TLS chain handled by `common/tls.py`. |
| Watch out | ~4 min: discovery also queries the archive index. |
| Edition held | 10-8-26 |
| Stated cadence | monthly |
| Records | 2,086 (2,086 active), newest 2026-04-28 |
| Last resync | 2,086 records (+0) |
| Research notes | Landing page fetch hung/timed out from this network (curl and WebFetch TLS error); details come from the PDF and search snippets. Newly added names are highlighted yellow in the PDF. |
Refresh
uv run -q python poc/service/resync_cli.py us-al-medicaid
uv run --script poc/ingest/us-al-medicaid.py # debug only: writes the list directly, no safety checksFields
Captured: provider_type 100%, middle_name 85%, aliases 5%, exclusion_date 100%, first_last 95%. Other published columns: section, initiated_by, list_date, credentials, role, owners.
https://medicaid.alabama.gov/documents/8.0_Fraud_Abuse/8.7_Suspended_Providers/8.7_Provider_Sanction_List_10-8-26.xlsx (xlsx) list_date=2026-10-08; fetched via direct ; newest linked on site: 2026-10-08
AR us-ar-medicaid direct script, US VPNcurrent
| List | Arkansas DHS excluded providers |
| Official page | https://dhs.arkansas.gov/dhs/portal/exclusions/publicsearch |
| File we fetch | https://dhs.arkansas.gov/dhs/portal/exclusions/publicsearch/Download |
| Route that works | direct script, US VPN |
| How | Direct CSV download. |
| Watch out | US address needed. Name-only list. |
| Edition held | live export |
| Stated cadence | regularly; results 'may change daily' |
| Records | 2,866 (2,866 active), newest – |
| Last resync | 2,866 records (-1) |
| Research notes | Not Medicaid-only: divisions include DCCECE/child care, Special Nutrition, Aging, Youth Services etc. (DMS 846, DCCECE 482, OIG 358, OMIG 185, blank 110 rows). Filter on Division to isolate Medicaid exclusions. Duplicate name variants present. |
Refresh
uv run -q python poc/service/resync_cli.py us-ar-medicaid
uv run --script poc/ingest/us-ar-medicaid.py # debug only: writes the list directly, no safety checksFields
Captured: address 100%, provider_type 1%, middle_name 23%, aliases 5%, first_last 75%. Other published columns: division, facility_name, associated_person, name_credentials.
raw 20261107T003825Z__ar_exclusions_download.csv. Name-only list (no NPI/licence/dates). Division = excluding DHS division; Facility Name -> extra.facility_name.
AZ us-az-medicaid direct script, US VPNcurrent
| List | AHCCCS state exclusion list |
| Official page | https://www.azahcccs.gov/Fraud/Providers/StateExclusionList.html |
| File we fetch | https://www.azahcccs.gov/Fraud/Downloads/StateExclusionSpreadsheet.xlsx (linked from https://www.azahcccs.gov/Fraud/Providers/StateExclusionList.html as "Current Provider Exclusions") |
| Route that works | direct script, US VPN |
| How | Direct `StateExclusionSpreadsheet.xlsx`. The name changed twice in 2026; if it serves an HTML page, take the "Current Provider Exclusions" link. |
| Watch out | Byte-identical to CloudCruise's copy. |
| Edition held | Nov 6, 2026 |
| Stated cadence | not stated |
| Records | 827 (826 active), newest 2026-11-05 |
| Last resync | 827 records (+23) |
| Research notes | Exclusion reason is sent only to the provider in a Notice of Exclusion, not published. Reinstatement is not automatic. |
Refresh
uv run -q python poc/service/resync_cli.py us-az-medicaid
uv run --script poc/ingest/us-az-medicaid.py # debug only: writes the list directly, no safety checksFields
Captured: npi 53%, npi_valid 53%, middle_name 6%, aliases 2%, exclusion_date 100%, reinstatement_date 100%, first_last 55%. Other published columns: name_credentials, npis, Exclusion End Date (raw).
raw 20261107T003827Z__OGC_TerminationAndExclusionSpreadsheet.xlsx; generic header mapping
AZ us-az-medicaid-actions direct script, US VPNcurrent
| List | AHCCCS suspensions and terminations |
| Official page | https://www.azahcccs.gov/Fraud/Providers/actions.html |
| File we fetch | https://www.azahcccs.gov/Fraud/Downloads/ProviderSuspensionsTerminations.pdf |
| Route that works | direct script, US VPN |
| How | Direct PDF. First live copy: everything before was an Internet Archive snapshot. |
| Watch out | All rows differ because the old copy was archive-sourced; net −25. |
| Edition held | Oct 27, 2026 |
| Stated cadence | not stated |
| Records | 185 (185 active), newest 2026-09-02 |
| Last resync | 185 records (-25) |
| Research notes | Despite the title, the published document is effectively an active payment-suspension list, i.e. pending-investigation actions, not final exclusions. Some providers appear with multiple NPIs. |
Refresh
uv run -q python poc/service/resync_cli.py us-az-medicaid-actions
uv run --script poc/ingest/us-az-medicaid-actions.py # debug only: writes the list directly, no safety checksFields
Captured: npi 98%, npi_valid 98%, provider_type 2%, middle_name 1%, aliases 1%, exclusion_date 100%, first_last 9%. Other published columns: list_as_of, entity_type_inferred, pdf_page.
as of 2026-10-27; fetched via direct ; entity_type inferred from name (list mixes people and businesses, First Last order)
CA us-ca-medicaid direct script, US VPNcurrent
| List | Medi-Cal Suspended & Ineligible list |
| Official page | https://data.chhs.ca.gov/dataset/provider-suspended-and-ineligible-list-s-i-list (program page: http://files.medi-cal.ca.gov/pubsdoco/SandILanding.aspx) |
| File we fetch | https://data.chhs.ca.gov/datastore/dump/48630a37-b5ba-4d3d-af54-e82b30e658a0 |
| Route that works | direct script, US VPN |
| How | CHHS open-data CSV dump. |
| Watch out | Works from any network. |
| Edition held | live dataset |
| Stated cadence | monthly |
| Records | 23,526 (23,526 active), newest 2026-10-19 |
| Last resync | 23,526 records (+0) |
| Research notes | Suspensions are automatic (convictions, federal exclusions, license loss) with no APA hearing. Original program page files.medi-cal.ca.gov/pubsdoco/SandILanding.aspx timed out from this network. Other mirrors (data.ca.gov, catalog.data.gov) can lag. |
Refresh
uv run -q python poc/service/resync_cli.py us-ca-medicaid
uv run --script poc/ingest/us-ca-medicaid.py # debug only: writes the list directly, no safety checksFields
Captured: npi 14%, npi_valid 14%, license 75%, license_state 75%, medicaid_id 16%, address 100%, provider_type 100%, middle_name 72%, aliases 22%, exclusion_date 100%, first_last 95%. Other published columns: active_period, license_state_inferred, license_number_raw, addresses, npis, name_quirk.
live download; CHHS CSV dump, 23526 rows
CO us-co-medicaid direct script, US VPNcurrent
| List | Colorado HCPF terminations for cause |
| Official page | https://hcpf.colorado.gov/provider-termination |
| File we fetch | https://hcpf.colorado.gov/provider-termination → `Terminations for cause ef. <date>.xlsx` |
| Route that works | direct script, US VPN |
| How | Reads the page for the dated xlsx. |
| Watch out | Dated file name. |
| Edition held | ef. 11.3.26 |
| Stated cadence | not verified (page blocked) |
| Records | 321 (321 active), newest 2026-08-03 |
| Last resync | 321 records (+0) |
| Research notes | Landing page blocked (HTTP 403 CloudFront) for both curl and WebFetch; page text taken from search snippets and the file itself. OpenSanctions mirrors the file twice a month. |
Refresh
uv run -q python poc/service/resync_cli.py us-co-medicaid
uv run --script poc/ingest/us-co-medicaid.py # debug only: writes the list directly, no safety checksFields
Captured: npi 94%, npi_valid 94%, provider_type 18%, middle_name 29%, aliases 5%, exclusion_date 100%, first_last 75%. Other published columns: termination_authority, name_credentials, npis.
Mixed 'LAST CRED, FIRST M' and 'First Last' names; credential -> provider_type.
CT us-ct-medicaid CloudCruise hard-sources workflowcurrent
| List | Connecticut DSS administrative actions |
| Official page | https://portal.ct.gov/dss/quality-assurance/quality-assurance-administrative-actions-list |
| File we fetch | https://portaldir.ct.gov/dss/ASPApps/list/actiondb.asp |
| Route that works | CloudCruise hard-sources workflow |
| How | F5 challenge blocks scripts. The workflow opens the page in a real browser and extracts the 7-column table to JSON (`ct_rows`); `us-ct-cloudcruise.py` parses it. Runner: `cc_run.py hard`. |
| Watch out | Better than the saved-HTML route of Oct 28 (96 vs 92 records). |
| Edition held | live table |
| Stated cadence | not stated |
| Records | 96 (77 active), newest 2026-10-13 |
| Last resync | 96 records (+4) |
| Research notes | Mixed sanction types; dates use both MM/DD/YY and MM/DD/YYYY. Some business rows have no individual name. Same page backs us-ct-cloudcruise. |
Refresh
uv run -q python poc/service/resync_cli.py us-ct-medicaid
uv run python poc/cloudcruise/cc_run.py hard # loads CT; AK, SC, FL, AZ files are cross-checks
uv run --script poc/ingest/us-ct-medicaid.py # debug only: writes the list directly, no safety checksFields
Captured: address 100%, provider_type 90%, middle_name 20%, aliases 41%, exclusion_date 100%, reinstatement_date 30%, first_last 96%. Other published columns: period, reinstatement_is_period_end.
CloudCruise row extraction of the DSS administrative actions table; reinstatement_date = effective date + fixed period
DC us-dc-ocp direct script, US VPNcurrent
| List | DC excluded parties list |
| Official page | https://ocp.dc.gov/page/excluded-parties-list |
| File we fetch | https://ocp.dc.gov/page/excluded-parties-list |
| Route that works | direct script, US VPN |
| How | HTML table. |
| Watch out | HTML page. |
| Edition held | live page |
| Stated cadence | as needed |
| Records | 100 (25 active), newest 2026-05-08 |
| Last resync | 100 records (+0) |
| Research notes | NOT a Medicaid exclusion list. It covers procurement debarments of contractors. No DC DHCF Medicaid exclusion list was found; DC appears to rely on LEIE/SAM. Matching on name alone against this list will mostly produce noise. |
Refresh
uv run -q python poc/service/resync_cli.py us-dc-ocp
uv run --script poc/ingest/us-dc-ocp.py # debug only: writes the list directly, no safety checksFields
Captured: address 100%, middle_name 11%, aliases 3%, exclusion_date 100%, reinstatement_date 100%, first_last 44%. Other published columns: table, action_date_raw, principals, agency, reason.
https://ocp.dc.gov/page/excluded-parties-list; 4 tables (current/past individuals and companies)
DE us-de-medicaid direct script, US VPNcurrent
| List | Delaware Sanctioned Provider Report |
| Official page | https://medicaidpublications.dhss.delaware.gov/docs/search (DMAP document repository; entry 1671) |
| File we fetch | https://medicaidpublications.dhss.delaware.gov/docs/Search?Command=Core_Download&EntryId=1671 |
| Route that works | direct script, US VPN |
| How | Direct PDF by entry id. |
| Watch out | Mixes board discipline with exclusions; a matcher rule is still open. |
| Edition held | Oct 15, 2026 |
| Stated cadence | not stated |
| Records | 1,824 (1,623 active), newest 2026-09-17 |
| Last resync | 1,824 records (+0) |
| Research notes | Mixes board discipline and other-state actions (e.g. Pennsylvania DHS, Board of Medical Licensure monetary penalties) with Medicaid exclusions, so a match is not necessarily an exclusion. Repository UI is JS-rendered; no human-readable landing text found. |
Refresh
uv run -q python poc/service/resync_cli.py us-de-medicaid
uv run --script poc/ingest/us-de-medicaid.py # debug only: writes the list directly, no safety checksFields
Captured: npi 35%, npi_valid 35%, license 46%, license_state 46%, medicaid_id 7%, provider_type 54%, middle_name 61%, aliases 2%, exclusion_date 100%, reinstatement_date 30%, first_last 95%. Other published columns: year, comments, reinstated, taxonomy, name_credentials, promise_id_note, dea, npi_raw, effective_date_raw.
PDF table. Names 'First M Last, MD' with AKA; credential -> provider_type. Dates are as published (some typos like 7/20/014 stay in extra). License state assumed DE.
FED us-fed-leie direct script, US VPNcurrent
| List | OIG LEIE |
| Official page | https://oig.hhs.gov/exclusions/leie-database-supplement-downloads/ |
| File we fetch | https://oig.hhs.gov/exclusions/downloadables/UPDATED.csv |
| Route that works | direct script, US VPN |
| How | Direct CSV. |
| Watch out | Monthly; the November file was not out yet. |
| Edition held | Oct 2026 file |
| Stated cadence | monthly |
| Records | 84,093 (84,093 active), newest 2026-10-20 |
| Last resync | 84,093 records (+0) |
| Research notes | Use either the full monthly file or the supplements, not both ('If you download the LEIE database each month, do NOT use the Monthly Supplement Files'). Supplement older than 12 months are not available. The LEIE holds only OIG actions, not state Medicaid terminations. Reinstatement is not automatic when the exclusion period ends; the party must apply. |
Refresh
uv run -q python poc/service/resync_cli.py us-fed-leie
uv run --script poc/ingest/us-fed-leie.py # debug only: writes the list directly, no safety checksFields
Captured: npi 11%, npi_valid 11%, dob 95%, address 100%, provider_type 100%, middle_name 71%, exclusion_date 100%, first_last 96%. Other published columns: general, excltype, specialty, upin, waiver_state, waiver_date.
OIG LEIE UPDATED.csv, Last-Modified Fri, 09 Oct 2026 12:51:03 GMT. Federal list, used for enrichment (NPI, DOB). BUSNAME on an individual row is kept as an alias.
FED us-fed-sam direct script, US VPNcurrent
| List | SAM.gov exclusions |
| Official page | https://sam.gov/data-services/Exclusions/Public%20V2?privacy=Public |
| File we fetch | list: https://sam.gov/api/prod/fileextractservices/v1/api/listfiles?random=1&domain=Exclusions/Public%20V2&privacy=Public; file: `.../download/<key>?privacy=Public` |
| Route that works | direct script, US VPN |
| How | Lists extracts through the public file API, downloads the newest ZIP. No key. |
| Watch out | Daily. |
| Edition held | extract 26310 |
| Stated cadence | daily |
| Records | 169,210 (169,195 active), newest 2026-11-04 |
| Last resync | 169,210 records (+180) |
| Research notes | Wider than healthcare: about 25% of rows are OFAC 'Special Entity Designation' and some are vessels. About 70k rows are HHS (mostly LEIE reciprocals) and about 41k are OPM. The listfiles API returns S3 links (s3.amazonaws.com/falextracts/...). |
Refresh
uv run -q python poc/service/resync_cli.py us-fed-sam
uv run --script poc/ingest/us-fed-sam.py # debug only: writes the list directly, no safety checksFields
Captured: npi 12%, npi_valid 4%, address 89%, middle_name 49%, aliases 24%, exclusion_date 94%, reinstatement_date 6%, first_last 79%. Other published columns: classification, exclusion_program, termination_date, record_status, creation_date, country, excluding_agency, additional_comments, ct_code, uei, cage, prefix.
SAM_Exclusions_Public_Extract_V2_26310.ZIP (Nov 06,2026), public V2 extract, no API key needed. No DOB or provider type published; NPI on a minority of HHS rows. excluding_agency OPM = FEHBP debarments.
FL us-fl-medicaid direct script, US VPNcurrent
| List | Florida AHCA sanctioned providers |
| Official page | https://apps.ahca.myflorida.com/dm_web/ |
| File we fetch | https://apps.ahca.myflorida.com/dm_web/ |
| Route that works | direct script, US VPN |
| How | Posts back radio `rdlFOMedState$3`, presses `btnSearchFO`, exports the SSRS report with `Format=EXCEL`. |
| Watch out | Byte-identical to CloudCruise's export. Cloudflare 403 from non-US addresses. |
| Edition held | live report |
| Stated cadence | not stated |
| Records | 2,200 (2,200 active), newest 2026-09-11 |
| Last resync | 2,200 records (+64) |
| Research notes | Not an exclusion list. Most rows are fines (FINE/FINES about 4.5k) and corrective action plans. Only TERMINATION (1,294) and SUSPENSION (906), net of rescissions, are participation bars. Filter on Sanction Type before matching. |
Refresh
uv run -q python poc/service/resync_cli.py us-fl-medicaid
uv run --script poc/ingest/us-fl-medicaid.py # debug only: writes the list directly, no safety checksFields
Captured: npi 68%, npi_valid 67%, license 52%, license_state 52%, medicaid_id 100%, provider_type 100%, middle_name 29%, exclusion_date 100%, first_last 54%. Other published columns: violation_code, ahca_case, document_type, license_state_inferred.
SSRS Excel export; 2200 active terminations/suspensions of 7201 final orders
GA us-ga-medicaid direct script, US VPNcurrent
| List | Georgia DCH OIG exclusions |
| Official page | https://dch.georgia.gov/office-inspector-general/georgia-oig-exclusions-list |
| File we fetch | https://dch.georgia.gov/office-inspector-general/georgia-oig-exclusions-list → `/document/document/...-<month-day-year>/download` |
| Route that works | direct script, US VPN |
| How | Reads the page for the dated document link. |
| Watch out | The slug changed to `copy-department-community-health-...`. |
| Edition held | Nov 3, 2026 upload |
| Stated cadence | at least monthly |
| Records | 1,377 (1,377 active), newest 2026-08-28 |
| Last resync | 1,377 records (+0) |
| Research notes | Listed chronologically by sanction effective date; newly added rows highlighted. Workbook carries 3 empty extra sheets (Sheet2-4). |
Refresh
uv run -q python poc/service/resync_cli.py us-ga-medicaid
uv run --script poc/ingest/us-ga-medicaid.py # debug only: writes the list directly, no safety checksFields
Captured: npi 3%, npi_valid 3%, dob 0%, provider_type 93%, middle_name 14%, aliases 1%, exclusion_date 100%, first_last 93%. Other published columns: states, business_name.
Individuals have LAST/FIRST/MIDDLE; business-only rows are organizations. STATE kept in `state` when a single code, else extra.states. DOB column is new (Oct 2026) and nearly empty.
HI us-hi-medicaid CloudCruise multi-source downloadercurrent
| List | Hawaii Med-QUEST exclusion/reinstatement list |
| Official page | https://medquest.hawaii.gov/en/plans-providers/provider-exclusion-reinstatement-list.html |
| File we fetch | https://medquest.hawaii.gov/en/plans-providers/provider-exclusion-reinstatement-list.html → `/api/media/file/Med%20Prov%20Excl-Rein%20List-UPDATED-<MM.DD.YY>.pdf` |
| Route that works | CloudCruise multi-source downloader |
| How | Blocks scripts and headless browsers. The workflow's link finder opens the newest PDF; CloudCruise saves it as `ccpdf_*.pdf`. |
| Watch out | Confirmed the latest edition in the user's Chrome. Direct attempt wastes ~9 min on the archive; go straight to CloudCruise. |
| Edition held | 09/10/2026 |
| Stated cadence | not stated (could not load page) |
| Records | 213 (198 active), newest 2025-07-20 |
| Last resync | 213 records (+0) |
| Research notes | Cloudflare-blocked for scripted fetch; our fetcher must already cope with this. Most exclusions 3-5 years, some permanent (snippet). Archive page also exists at /en/archive/providers/ProviderExclusion_ReinstatementList.html. |
Refresh
uv run -q python poc/service/resync_cli.py us-hi-medicaid
uv run python poc/cloudcruise/cc_run.py multi us-hi-medicaid
uv run --script poc/ingest/us-hi-medicaid.py # debug only: writes the list directly, no safety checksFields
Captured: medicaid_id 24%, provider_type 100%, middle_name 60%, aliases 4%, exclusion_date 97%, reinstatement_date 7%, first_last 98%. Other published columns: reinstatement_raw, list_updated, pdf_page.
https://medquest.hawaii.gov/en/plans-providers/provider-exclusion-reinstatement-list.html; updated 2026-09-10; fetched via cloudcruise ; newest linked: None
IA us-ia-medicaid direct script, US VPNcurrent
| List | Iowa HHS sanctions list |
| Official page | https://hhs.iowa.gov/medicaid/how-report-medicaid-fraud/program-integrity (also linked from https://hhs.iowa.gov/medicaid/provider-services/excluded-individuals-and-entities) |
| File we fetch | https://hhs.iowa.gov/medicaid/provider-services/excluded-individuals-and-entities → `https://hhs.iowa.gov/media/<id>/download?inline` |
| Route that works | direct script, US VPN |
| How | Reads the page for `/media/<id>/download`. |
| Watch out | Media id changes per upload. |
| Edition held | Nov 2, 2026 |
| Stated cadence | not stated |
| Records | 1,329 (1,329 active), newest 2026-09-29 |
| Last resync | 1,329 records (+11) |
| Research notes | List covers involuntary termination, involuntary suspension, OIG exclusions, Medicare revocations and outstanding overpayments - broader than exclusions (includes overpayment suspensions). Informational Letter #1130 linked on page. |
Refresh
uv run -q python poc/service/resync_cli.py us-ia-medicaid
uv run --script poc/ingest/us-ia-medicaid.py # debug only: writes the list directly, no safety checksFields
Captured: npi 31%, npi_valid 31%, license 36%, license_state 36%, provider_type 99%, middle_name 59%, aliases 0%, exclusion_date 100%, first_last 81%. Other published columns: enrollment_type, authority, sanction_end, license_type, provider_id, sanction_end_date, eligible_to_reapply, affiliated_npi, effective_date_raw, legal_business_name.
One row per sanction (a person can repeat: state suspension + federal exclusion). Non-NPI values in the NPI column (X000..., atypical ids) -> extra.provider_id.
ID us-id-medicaid direct script, US VPNcurrent
| List | Idaho Medicaid exclusion list |
| Official page | https://healthandwelfare.idaho.gov/providers (link 'Medicaid Provider Exclusion List' -> publicdocuments.dhw.idaho.gov Laserfiche doc 6158) |
| File we fetch | https://publicdocuments.dhw.idaho.gov/WebLink/0/edoc/6158/Idaho-Medicaid-Exclusion-List.pdf |
| Route that works | direct script, US VPN |
| How | Direct PDF, stable Laserfiche document id. |
| Watch out | US address needed. |
| Edition held | live file |
| Stated cadence | irregular (on change) |
| Records | 171 (163 active), newest – |
| Last resync | 171 records (+0) |
| Research notes | Some names span multiple lines in the PDF table (parsing hazard). Old deep links (healthandwelfare.idaho.gov/providers/medicaid-providers/...) 404 after site redesign. |
Refresh
uv run -q python poc/service/resync_cli.py us-id-medicaid
uv run --script poc/ingest/us-id-medicaid.py # debug only: writes the list directly, no safety checksFields
Captured: middle_name 44%, reinstatement_date 14%, first_last 88%. Other published columns: Date, Reinstatement, Additional Information, pdf_page, parser.
generic header parser, headers=['Name', '', 'Date', '', '', 'Reinstatement', '', '', 'Reinstated', '', 'Additional Information']; fetched via direct
IL us-il-medicaid direct script, US VPNcurrent
| List | Illinois HFS OIG Active Sanctions |
| Official page | https://hfs.illinois.gov/oig/sanctionslist.html (search tool: https://ilhfspartner3.dynamics365portals.us/sanctions/) |
| File we fetch | https://ilhfspartner3.dynamics365portals.us (download-as-excel service; the key is minted per session) |
| Route that works | direct script, US VPN |
| How | Dynamics portal Excel export with a per-session key. |
| Edition held | live export |
| Stated cadence | 'regularly' (no fixed cadence) |
| Records | 3,273 (3,273 active), newest 2026-10-07 |
| Last resync | 3,273 records (+0) |
| Research notes | Also offers 'Provider Sanctions E-Mail Notifications' subscription (https://hfs.illinois.gov/oig/notify.html) and a removal page. Export saves only records currently displayed (must Reset filters first). |
Refresh
uv run -q python poc/service/resync_cli.py us-il-medicaid
uv run --script poc/ingest/us-il-medicaid.py # debug only: writes the list directly, no safety checksFields
Captured: npi 22%, npi_valid 22%, license 44%, license_state 44%, address 90%, provider_type 81%, middle_name 10%, exclusion_date 100%, first_last 84%. Other published columns: affiliation, name_credentials.
Names published 'LAST FIRST M' without a comma: first token = last name (particles DE/VAN/... merged). License state assumed IL (IDFPR numbers). Entity type inferred from name/provider type.
IN us-in-medicaid direct script, US VPNcurrent
| List | Indiana OMPP terminations |
| Official page | https://www.in.gov/fssa/ompp/provider-information/termination-of-provider-participation-in-medicaid-and-chip/ |
| File we fetch | https://www.in.gov/fssa/ompp/files/OMPP_Terminations.xlsx |
| Route that works | direct script, US VPN |
| How | Direct xlsx. |
| Edition held | Jul 27, 2026 |
| Stated cadence | not stated |
| Records | 112 (112 active), newest 2026-03-06 |
| Last resync | 112 records (+0) |
| Research notes | Separate 'Re-enrolled providers' PDF: https://www.in.gov/dA/e4ba7227b8/Re-enrollments.pdf - needed to net out re-enrolled names. OpenSanctions notes OMPP says Indiana has no 'exclusion' list. |
Refresh
uv run -q python poc/service/resync_cli.py us-in-medicaid
uv run --script poc/ingest/us-in-medicaid.py # debug only: writes the list directly, no safety checksFields
Captured: npi 94%, npi_valid 94%, address 100%, provider_type 58%, middle_name 23%, exclusion_date 100%, first_last 69%. Other published columns: name_credentials, service_locations, npis.
Names 'First M Last, MD'; credential suffix used as provider_type.
KS us-ks-medicaid CloudCruise multi-source downloadercurrent
| List | Kansas KDHE termination list |
| Official page | https://www.kdhe.ks.gov/1730/Medicaid-Program-Integrity |
| File we fetch | https://www.kdhe.ks.gov/DocumentCenter/View/517/Termination-List-PDF (serves an xlsx despite the name) |
| Route that works | CloudCruise multi-source downloader |
| How | Cloudflare blocks scripts even from a US address. The workflow opens the URL and captures the download (an xlsx despite the name). |
| Watch out | Same edition as Oct 28. Direct attempt wastes ~5 min; go straight to CloudCruise. |
| Edition held | 10/21/2026 |
| Stated cadence | as needed (from search snippet only) |
| Records | 213 (213 active), newest 2026-10-20 |
| Last resync | 213 records (+0) |
| Research notes | Cloudflare block from this network; mirror on coronavirus.kdheks.gov/DocumentCenter/View/517. List is for-cause terminations, entries reported as 2010-2021. |
Refresh
uv run -q python poc/service/resync_cli.py us-ks-medicaid
uv run python poc/cloudcruise/cc_run.py multi us-ks-medicaid
uv run --script poc/ingest/us-ks-medicaid.py # debug only: writes the list directly, no safety checksFields
Captured: npi 54%, npi_valid 54%, medicaid_id 100%, provider_type 100%, middle_name 58%, aliases 5%, exclusion_date 100%, first_last 84%. Other published columns: comments, npis.
KMAP termination list XLSX; fetched via cloudcruise
KY us-ky-medicaid direct script, US VPNcurrent
| List | Kentucky DMS termination list |
| Official page | https://www.chfs.ky.gov/agencies/dms/dpi/pe/Pages/terminated.aspx |
| File we fetch | https://www.chfs.ky.gov/agencies/dms/dpi/pe/Documents/KYMedicaidTerminationList.xlsx |
| Route that works | direct script, US VPN |
| How | Direct xlsx. |
| Watch out | US address needed. |
| Edition held | Nov 3, 2026 |
| Stated cadence | monthly |
| Records | 401 (401 active), newest 2026-07-17 |
| Last resync | 401 records (+0) |
| Research notes | Only KY-DMS actions; HHS-OIG excluded individuals not listed. |
Refresh
uv run -q python poc/service/resync_cli.py us-ky-medicaid
uv run --script poc/ingest/us-ky-medicaid.py # debug only: writes the list directly, no safety checksFields
Captured: npi 92%, npi_valid 92%, license 69%, license_state 69%, middle_name 13%, aliases 1%, exclusion_date 100%, first_last 66%. Other published columns: Timeframe of Term/Exclusion, reason, name_credentials, npis.
raw 20261107T005328Z__KYMedicaidTerminationList.xlsx; generic header mapping
LA us-la-medicaid direct script, US VPNcurrent
| List | Louisiana LDH exclusion database |
| Official page | https://adverseactions.ldh.la.gov/SelSearch |
| File we fetch | https://adverseactions.ldh.la.gov/SelSearch/SelSearch/GetCsv |
| Route that works | direct script, US VPN |
| How | Direct CSV. |
| Watch out | US address needed. |
| Edition held | live export |
| Stated cadence | continuous (live database) |
| Records | 6,001 (5,645 active), newest 2026-11-06 |
| Last resync | 6,001 records (+12) |
| Research notes | Mixes Medicaid PI exclusions and Health Standards (e.g. nurse aides, DSWs) actions; filter by Program Office if needed. |
Refresh
uv run -q python poc/service/resync_cli.py us-la-medicaid
uv run --script poc/ingest/us-la-medicaid.py # debug only: writes the list directly, no safety checksFields
Captured: npi 9%, npi_valid 9%, dob 71%, address 11%, provider_type 75%, middle_name 17%, aliases 0%, exclusion_date 97%, reinstatement_date 6%, first_last 94%. Other published columns: Program Office, Period of Exclusion, Reason for Exclusion, reinstate_raw, Affiliated Entity, Reason for Termination, Period of Enrollment Prohibition, npi_raw, birthdate_raw.
live download; list 'Document created on: 11/6/2026 6:53:30 PM'; 6001 rows
MA us-ma-medicaid CloudCruise multi-source downloadercurrent
| List | MassHealth suspended or excluded providers |
| Official page | https://www.mass.gov/info-details/learn-about-suspended-or-excluded-masshealth-providers |
| File we fetch | https://www.mass.gov/info-details/learn-about-suspended-or-excluded-masshealth-providers |
| Route that works | CloudCruise multi-source downloader |
| How | Akamai blocks scripts. The workflow finds the newest list link and captures the PDF (`ccpdf_*.pdf`). |
| Watch out | Keep the PDF: it adds the 9 reinstated people with dates that the XLSX omits. Direct attempt wastes ~9 min on the archive. |
| Edition held | 9/30/2026 |
| Stated cadence | monthly (from search snippets) |
| Records | 307 (298 active), newest 2026-07-31 |
| Last resync | 307 records (+9) |
| Research notes | Only actions effective on/after 2010-03-23. Monthly slug changes, so landing page must be scraped for the current link; landing page sometimes lags newest doc (snippet showed Feb 2026 link). |
Refresh
uv run -q python poc/service/resync_cli.py us-ma-medicaid
uv run python poc/cloudcruise/cc_run.py multi us-ma-medicaid
uv run --script poc/ingest/us-ma-medicaid.py # debug only: writes the list directly, no safety checksFields
Captured: npi 82%, npi_valid 82%, medicaid_id 11%, provider_type 100%, middle_name 40%, aliases 0%, exclusion_date 100%, reinstatement_date 3%, first_last 70%. Other published columns: reason, pdf_page, npi_raw, notes.
https://www.mass.gov/info-details/learn-about-suspended-or-excluded-masshealth-providers (pdf); effective through September 30, 2026; fetched via cloudcruise
MD us-md-medicaid direct script, US VPNcurrent
| List | Maryland MDH sanctioned providers |
| Official page | https://health.maryland.gov/mmcp/provider/Pages/sanctioned_list.aspx |
| File we fetch | https://health.maryland.gov/mmcp/provider/Documents/sanctioned-list/State_of_MD_Sanctioned_Providers.xlsx |
| Route that works | direct script, US VPN |
| How | Direct xlsx. |
| Edition held | Oct 9, 2026 |
| Stated cadence | monthly (if needed) |
| Records | 1,622 (1,622 active), newest 2026-10-09 |
| Last resync | 1,622 records (+0) |
| Research notes | Stable URL, file overwritten in place. Sanction-type codes undocumented on page (MFVVU likely Medicaid Fraud & Vulnerable Victims Unit). Older 2016 PDF still hosted at health.maryland.gov/oig/Documents/SanctionedProvidersUpdate11022016.pdf. |
Refresh
uv run -q python poc/service/resync_cli.py us-md-medicaid
uv run --script poc/ingest/us-md-medicaid.py # debug only: writes the list directly, no safety checksFields
Captured: npi 17%, npi_valid 17%, license 28%, license_state 28%, address 99%, provider_type 97%, middle_name 28%, aliases 0%, exclusion_date 100%, first_last 88%. Other published columns: sanction_type_meaning, name_credentials, npis.
Licence state assumed MD (MD board numbers). Org = no first name and business-type profession.
ME opensanctions-me current
| Records | 1,113 (1,108 active), newest 2026-10-01 |
Refresh
python3 poc/eval/opensanctions_supplement.py # rebuilds opensanctions-me / -ms (CC BY-NC data)Fields
Captured: middle_name 37%, aliases 28%, exclusion_date 100%, reinstatement_date 0%, first_last 99%. Other published columns: opensanctions_id, sanctions_raw, first_seen, last_change, schema.
us_me_med_exclusions 20261106130457-gtd: records missing from our copy; CC BY-NC
ME us-me-medicaid none yetnot refreshed
| List | MaineCare exclusion report |
| Official page | https://www.maine.gov/dhhs/oms/providers/program-integrity |
| File we fetch | https://mainecare.maine.gov/PrvExclRpt/Forms/AllItems.aspx |
| Route that works | none yet |
| How | Reads the SharePoint library JSON (`WPQ2ListData`), then downloads `<month folder>/PI0008-PM Monthly Exclusion Report.xlsx`. The ingester is written; it has never run in opening hours. |
| Watch out | Portal opens weekdays 07:00–19:00 ET only. Run on a weekday. Covered by OpenSanctions until then (non-commercial licence). |
| Edition held | none held |
| Stated cadence | monthly (1st of each month) |
| Records | 0 (0 active), newest – |
| Last resync | exit 1: WPQ2ListData not found on the library page; kept the previous copy |
| Research notes | Our known URL PrvExclRpt/Forms/AllItems.aspx redirected to https://mainecare.maine.gov/ today (Saturday). Portal home links /SPContent/DocumentLibrary/Monthly%20Provider%20Exclusion%20Report (rendered empty shell today) and /ProviderExclusion/ProviderExclusionSearch. Portal announcements list maintenance windows (Tue 19-22 ET, Sat 18:00-Sun 12:00 ET, ad hoc Nov 8 07-21 ET). |
Refresh
uv run -q python poc/service/resync_cli.py us-me-medicaid
uv run -q --with websockets python -I artifacts/scripts/cdp_page.py '<list page URL>' '<file URL>' /tmp/us-me-medicaid.file # the owner's Chrome (CDP 9222)
uv run -q python artifacts/scripts/ingest_manual.py us-me-medicaid /tmp/us-me-medicaid.file '<raw file name>' '<official URL>'
uv run --script poc/ingest/us-me-medicaid.py # debug only: writes the list directly, no safety checksFields
Captured: none. Other published columns: –.
MI us-mi-medicaid direct script, US VPNcurrent
| List | Michigan MDHHS sanctioned providers |
| Official page | https://www.michigan.gov/mdhhs/doing-business/providers/providers/billingreimbursement/list-of-sanctioned-providers |
| File we fetch | https://www.michigan.gov/mdhhs/-/media/Project/Websites/mdhhs/Assistance-Programs/Medicaid-BPHASA/MI-Sanctioned-Provider-List/MI_Sanctioned_Provider_List.xlsx |
| Route that works | direct script, US VPN |
| How | Direct xlsx. |
| Watch out | US address needed. |
| Edition held | live file |
| Stated cadence | not stated (changes published as made) |
| Records | 4,116 (4,116 active), newest 2026-11-02 |
| Last resync | 4,116 records (+4) |
| Research notes | URL CHANGED: our known URL .../MI_Sanctioned_Provider_List.xlsx now returns 404; current link is .../MI-Sanctioned-Provider-List/MI_Sanctioned_Provider_List-XLSX.xlsx (with ?rev=&hash= params; works without them) and ..._List-PDF.pdf. |
Refresh
uv run -q python poc/service/resync_cli.py us-mi-medicaid
uv run --script poc/ingest/us-mi-medicaid.py # debug only: writes the list directly, no safety checksFields
Captured: npi 29%, npi_valid 29%, license 24%, license_state 24%, address 100%, provider_type 100%, middle_name 21%, aliases 0%, exclusion_date 100%, first_last 93%. Other published columns: Sanction Source, license_state_inferred, Sanction Date2, Sanction Source2, entity_name, Sanction Date2_raw, ncpdp, sanction_date1_raw, license_annotations.
live download; sheet title 'Medicaid Michigan Sanction Provider List / November 2, 2026 / MDHHS-SanctionProviderList@michigan.gov'; 4116 rows
MN us-mn-medicaid CloudCruise multi-source downloadercurrent
| List | Minnesota excluded individuals |
| Official page | unverified (DHS site behind Radware captcha); DHS MHCP Provider Manual enrollment pages e.g. https://www.dhs.state.mn.us/id_008921/ |
| File we fetch | https://www.dhs.state.mn.us/main/idcplg?IdcService=GET_FILE&RevisionSelectionMethod=LatestReleased&Rendition=Primary&allowInterrupt=1&noSaveAs=1&dDocName=DHS16_177448 |
| Route that works | CloudCruise multi-source downloader |
| How | Radware captcha for scripts. The workflow opens the URL and captures the download; no captcha appeared in its browser. |
| Watch out | Radware captcha for scripts; none appeared in CloudCruise's browser. |
| Edition held | 11-04-26 |
| Stated cadence | not verified (official page blocked); LeadingAge MN says 'updated regularly' |
| Records | 1,103 (1,103 active), newest 2026-07-30 |
| Last resync | 1,103 records (+5) |
| Research notes | Separate individual and organization files. Today both direct fetches and WebFetch returned the Radware captcha page; did not attempt to solve it. |
Refresh
uv run -q python poc/service/resync_cli.py us-mn-medicaid
uv run python poc/cloudcruise/cc_run.py multi us-mn-medicaid
uv run --script poc/ingest/us-mn-medicaid.py # debug only: writes the list directly, no safety checksFields
Captured: address 5%, provider_type 100%, middle_name 88%, exclusion_date 100%, first_last 100%. Other published columns: –.
raw 20261107T011227Z__Excluded_Ind_Providers_11-04-26.xlsx; generic header mapping
MN us-mn-medicaid-org CloudCruise multi-source downloadercurrent
| List | Minnesota excluded organizations |
| Official page | unverified (DHS site behind Radware captcha); DHS MHCP Provider Manual enrollment pages e.g. https://www.dhs.state.mn.us/id_008921/ |
| File we fetch | same URL with `dDocName=DHS16_177447` |
| Route that works | CloudCruise multi-source downloader |
| How | As for individuals. |
| Watch out | As for MN individuals. |
| Edition held | 11-02-26 |
| Stated cadence | not verified (official page blocked); LeadingAge MN says 'updated regularly' |
| Records | 437 (437 active), newest 2026-09-20 |
| Last resync | 437 records (+4) |
| Research notes | Companion to us-mn-medicaid; same captcha block. Person-named practices (e.g. '... PCPO') are organization rows. |
Refresh
uv run -q python poc/service/resync_cli.py us-mn-medicaid-org
uv run python poc/cloudcruise/cc_run.py multi us-mn-medicaid-org
uv run --script poc/ingest/us-mn-medicaid-org.py # debug only: writes the list directly, no safety checksFields
Captured: address 100%, provider_type 100%, exclusion_date 100%. Other published columns: –.
raw 20261107T011230Z__Excluded_Org_Providers_11-02-26.xlsx; generic header mapping
MO us-mo-medicaid direct script, US VPNcurrent
| List | Missouri MMAC sanction list |
| Official page | https://mmac.mo.gov/providers/provider-sanctions/ |
| File we fetch | https://mmac.mo.gov/providers/provider-sanctions/ → `wp-content/uploads/sanction-list-<yyyy-mm-dd>.xlsx` |
| Route that works | direct script, US VPN |
| How | Reads the page for the dated xlsx. |
| Edition held | 2026-09-30 |
| Stated cadence | monthly (reviewed) |
| Records | 280 (280 active), newest 2026-05-07 |
| Last resync | 280 records (+0) |
| Research notes | Only for-cause terminations by MMAC since 2/3/2011; sanctions like suspension/prepayment review are not on the list. |
Refresh
uv run -q python poc/service/resync_cli.py us-mo-medicaid
uv run --script poc/ingest/us-mo-medicaid.py # debug only: writes the list directly, no safety checksFields
Captured: npi 100%, npi_valid 99%, license 28%, license_state 28%, provider_type 100%, middle_name 28%, exclusion_date 100%, first_last 37%. Other published columns: letter_date, termination_reason, name_credentials.
One row per provider x provider type (duplicates by design). License state MO unless prefixed (e.g. KS-209970).
MS opensanctions-ms current
| Records | 18 (18 active), newest 2026-08-13 |
Refresh
python3 poc/eval/opensanctions_supplement.py # rebuilds opensanctions-me / -ms (CC BY-NC data)Fields
Captured: npi 83%, npi_valid 83%, dob 44%, license 44%, address 94%, middle_name 22%, exclusion_date 100%, reinstatement_date 6%, first_last 56%. Other published columns: opensanctions_id, sanctions_raw, first_seen, last_change, schema.
us_ms_med_exclusions 20261006130142-ilm: records missing from our copy; CC BY-NC
MS us-ms-medicaid none availablenot refreshed
| List | Mississippi sanctioned providers |
| Official page | https://medicaid.ms.gov/providers/provider-terminations/ (currently 404 on temporary site) |
| File we fetch | **none**: the old pattern was `https://medicaid.ms.gov/wp-content/uploads/<yyyy>/<mm>/<MM.DD.YY>-Sanction(ed)-Providers*.xlsx` |
| Route that works | none available |
| How | The regular site is down: the state's temporary site says a web-hosting vendor outage is under way and links no list. Internet Archive has no newer capture. |
| Watch out | Check the site before each run. OpenSanctions adds newer records meanwhile (non-commercial licence). |
| Edition held | 06.08.26 file (archive) |
| Stated cadence | not stated for publication; providers told to search monthly |
| Records | 193 (193 active), newest 2026-04-20 |
| Last resync | exit 1: [fetch] falling back to the Internet Archive; kept the previous copy |
| Research notes | Site outage/rebuild: home page banner about web-hosting vendor outage; temporary site has no provider-terminations page (404). Only DOB-bearing list in this group. |
Refresh
uv run -q python poc/service/resync_cli.py us-ms-medicaid
uv run -q --with websockets python -I artifacts/scripts/cdp_page.py '<list page URL>' '<file URL>' /tmp/us-ms-medicaid.file # the owner's Chrome (CDP 9222)
uv run -q python artifacts/scripts/ingest_manual.py us-ms-medicaid /tmp/us-ms-medicaid.file '<raw file name>' '<official URL>'
uv run --script poc/ingest/us-ms-medicaid.py # debug only: writes the list directly, no safety checksFields
Captured: npi 72%, npi_valid 72%, dob 47%, medicaid_id 28%, address 100%, provider_type 77%, middle_name 29%, exclusion_date 99%, reinstatement_date 0%, first_last 64%. Other published columns: role, notes, exclusion_period, reason, name_credentials, organization_name.
raw 20261017T013724Z__Sanctioned-Providers-List.xlsx. Site down since Oct 2026; newest archived file is 06.08.26 (Internet Archive).
MT us-mt-medicaid direct script, US VPNcurrent
| List | Montana excluded or terminated providers |
| Official page | https://dphhs.mt.gov/MontanaHealthcarePrograms/TerminatedExcludedProviders |
| File we fetch | https://dphhs.mt.gov/MontanaHealthcarePrograms/TerminatedExcludedProviders → `/assets/ExcludedorTerminatedMontanaMedicaidProviders<M.DD.YY>.xlsx` |
| Route that works | direct script, US VPN |
| How | Reads the page for the xlsx. |
| Watch out | File name changed to `DownloadExcludedorTerminatedProviderlistinExcel.xlsx`. |
| Edition held | Nov 3, 2026 |
| Stated cadence | not stated |
| Records | 173 (173 active), newest 2026-10-22 |
| Last resync | 173 records (+0) |
| Research notes | URL CHANGED: page now links a stable ../assets/DownloadExcludedorTerminatedProviderlistinExcel.xlsx, not the dated ExcludedorTerminatedMontanaMedicaidProviders<M.DD.YY>.xlsx pattern we expect. Mostly OIG reciprocal exclusions. |
Refresh
uv run -q python poc/service/resync_cli.py us-mt-medicaid
uv run --script poc/ingest/us-mt-medicaid.py # debug only: writes the list directly, no safety checksFields
Captured: npi 27%, npi_valid 27%, provider_type 100%, middle_name 66%, aliases 4%, exclusion_date 100%, first_last 98%. Other published columns: –.
'a.k.a.' rows folded into the preceding record's aliases. Unlabelled 5th column (State Termination / OIG Exclusion) -> action_type.
NC us-nc-medicaid direct script, US VPNcurrent
| List | NC Medicaid excluded provider list |
| Official page | https://medicaid.ncdhhs.gov/providers/excluded-providers |
| File we fetch | https://medicaid.ncdhhs.gov/nc-medicaid-state-excluded-provider-list/download?attachment |
| Route that works | direct script, US VPN |
| How | Direct xlsx. |
| Edition held | Oct 30, 2026 |
| Stated cadence | monthly |
| Records | 183 (183 active), newest 2026-07-28 |
| Last resync | 183 records (+2) |
| Research notes | FAQ updated Sept. 25, 2026 at https://medicaid.ncdhhs.gov/providers/excluded-providers/north-carolina-excluded-provider-list-faqs. Removal requests need DOB, NPIs, address, signature (not published). |
Refresh
uv run -q python poc/service/resync_cli.py us-nc-medicaid
uv run --script poc/ingest/us-nc-medicaid.py # debug only: writes the list directly, no safety checksFields
Captured: npi 92%, npi_valid 91%, address 100%, middle_name 49%, aliases 4%, exclusion_date 100%, first_last 56%. Other published columns: reason, ownership_not_excluded, name_credentials, atypical_id.
Names 'FIRST MIDDLE LAST'; (DBA: ...) and (maiden) moved to aliases. OWNERSHIP names are explicitly NOT excluded -> extra.ownership_not_excluded.
ND us-nd-medicaid direct script, US VPNcurrent
| List | North Dakota provider exclusion list |
| Official page | https://www.hhs.nd.gov/healthcare/medicaid/provider/compliance/fraud-and-abuse |
| File we fetch | https://www.hhs.nd.gov/sites/default/files/documents/provider-exclusion-list.xlsx |
| Route that works | direct script, US VPN |
| How | Direct xlsx. |
| Edition held | Nov 2, 2026 |
| Stated cadence | not stated |
| Records | 191 (191 active), newest 2026-08-19 |
| Last resync | 191 records (-1) |
| Research notes | A guessed URL on hhs.nd.gov returned 403 'inaccessible due to geographical restrictions', so parts of the site may geo-block non-US clients; the list file itself downloaded fine. |
Refresh
uv run -q python poc/service/resync_cli.py us-nd-medicaid
uv run --script poc/ingest/us-nd-medicaid.py # debug only: writes the list directly, no safety checksFields
Captured: npi 26%, npi_valid 26%, license 28%, license_state 28%, address 100%, provider_type 97%, middle_name 7%, aliases 4%, exclusion_date 100%, first_last 93%. Other published columns: –.
License state ND unless the cell carries '(KY)' etc.
NE us-ne-medicaid direct script, US VPNcurrent
| List | Nebraska excluded providers |
| Official page | https://dhhs.ne.gov/Pages/Program-Integrity-Sanctioned-Providers.aspx |
| File we fetch | https://dhhs.ne.gov/Documents/Medicaid%20Excluded%20Providers.pdf |
| Route that works | direct script, US VPN |
| How | Direct PDF. |
| Watch out | US address needed. Every row shows as changed only because each stores the list date. |
| Edition held | 2026-11-03 |
| Stated cadence | not stated |
| Records | 1,435 (1,435 active), newest 2026-10-03 |
| Last resync | 1,435 records (-1) |
| Research notes | XLSX now offered alongside the PDF we fetch; prefer it. Includes terminations, not only exclusions. |
Refresh
uv run -q python poc/service/resync_cli.py us-ne-medicaid
uv run --script poc/ingest/us-ne-medicaid.py # debug only: writes the list directly, no safety checksFields
Captured: npi 21%, npi_valid 21%, provider_type 100%, middle_name 23%, aliases 1%, exclusion_date 100%, first_last 91%. Other published columns: reason, list_updated, pdf_page, date_added, npi_raw.
list updated 2026-11-03; fetched via direct
NH us-nh-medicaid CloudCruise multi-source downloadercurrent
| List | New Hampshire provider sanctions list |
| Official page | https://www.dhhs.nh.gov/programs-services/medicaid/medicaid-provider-relations (sanctions list page under it) |
| File we fetch | https://www.dhhs.nh.gov/sites/g/files/ehbemt476/files/documents2/provider-sanctions-list-update.xlsx |
| Route that works | CloudCruise multi-source downloader |
| How | "Access Denied" for scripts. The workflow opens the URL and captures the download. |
| Watch out | "Access Denied" for scripts, even from a US address. |
| Edition held | live file |
| Stated cadence | unknown (not verified) |
| Records | 77 (77 active), newest 2025-11-25 |
| Last resync | 77 records (+1) |
| Research notes | The known URL is a fixed filename that is overwritten each update. OpenSanctions describes the dataset as 'Providers who have been terminated for cause from New Hampshire's Medicaid program.' Reasons mix board actions, OIG LEIE exclusions and Medicaid fraud convictions. |
Refresh
uv run -q python poc/service/resync_cli.py us-nh-medicaid
uv run python poc/cloudcruise/cc_run.py multi us-nh-medicaid
uv run --script poc/ingest/us-nh-medicaid.py # debug only: writes the list directly, no safety checksFields
Captured: npi 68%, npi_valid 68%, provider_type 100%, middle_name 30%, exclusion_date 99%, first_last 83%. Other published columns: reason, business_name, Exclusion/Sanction Effective Date (raw).
raw 20261107T011225Z__provider-sanctions-list-update.xlsx; generic header mapping
NJ us-nj-medicaid direct script, US VPNcurrent
| List | NJ OSC Ineligible Provider List |
| Official page | https://nj.gov/comptroller/about/work/medicaid/ineligibleprovider.shtml |
| File we fetch | https://wwwdnet2-tre.nj.gov/OSC_IPS/Search/ExportResults (landing https://nj.gov/comptroller/about/work/medicaid/ineligibleprovider.shtml) |
| Route that works | direct script, US VPN |
| How | Rebuilt from the search app's XLSX export, one name fragment at a time. ~90 s. |
| Watch out | Slow (~2 min): exports by name fragment. |
| Edition held | live search |
| Stated cadence | not stated |
| Records | 4,113 (3,700 active), newest 2026-10-28 |
| Last resync | 4,113 records (+12) |
| Research notes | Exports are scoped to the search, so a full pull means many name searches. The site is behind Incapsula, and a plain curl to the export gets HTTP 500 or a bot page. Captcha appears on the SSN/TIN verification flow. The search page footer still says 'Copyright 1996-2025'. |
Refresh
uv run -q python poc/service/resync_cli.py us-nj-medicaid
uv run --script poc/ingest/us-nj-medicaid.py # debug only: writes the list directly, no safety checksFields
Captured: npi 30%, npi_valid 30%, address 100%, provider_type 76%, middle_name 28%, aliases 4%, exclusion_date 99%, reinstatement_date 16%, first_last 94%. Other published columns: other_npis, expiration_raw.
https://wwwdnet2-tre.nj.gov/OSC_IPS/Search/ExportResults?Names[0]=a..z, 26 exports merged; landing https://nj.gov/comptroller/about/work/medicaid/ineligibleprovider.shtml
NJ us-nj-treasury direct script, US VPNcurrent
| List | NJ Treasury debarment files |
| Official page | https://www.nj.gov/treasury/revenue/debarment/index.shtml (Medical: https://nj.gov/treasury/revenue/debarment/debarsearch-medical.shtml) |
| File we fetch | https://www.nj.gov/treasury/treasfiles/debarment/ |
| Route that works | direct script, US VPN |
| How | Direct text files. |
| Edition held | live files |
| Stated cadence | not stated |
| Records | 4,786 (3,842 active), newest 2026-10-28 |
| Last resync | 4,786 records (+12) |
| Research notes | There are 5 per-category files; only MEDICAL is health-specific, but Medicaid (agency 7540) actions can sit in other categories too. Two delimiter variants exist. The rows_D URL is a directory that 404s, so fetch the named Debarment-<CATEGORY>.txt files. This overlaps the OSC Ineligible Provider List. |
Refresh
uv run -q python poc/service/resync_cli.py us-nj-treasury
uv run --script poc/ingest/us-nj-treasury.py # debug only: writes the list directly, no safety checksFields
Captured: npi 25%, npi_valid 25%, address 94%, provider_type 64%, middle_name 27%, aliases 4%, exclusion_date 99%, reinstatement_date 23%, first_last 95%. Other published columns: category, department, agency, reason, permanent, firm, period, vendor_id.
https://www.nj.gov/treasury/treasfiles/debarment/Debarment-<category>.txt for MEDICAL, PROFESSIONAL, VENDOR, CONSTRUCTION, WASTE-Co, WASTE-Ind
NV us-nv-medicaid direct script, US VPNcurrent
| List | Nevada sanctions and exclusions |
| Official page | https://www.omig.nv.gov/provider-enrollment--termination/provider-exclusions-sanctions-and-press-releases/ |
| File we fetch | https://www.omig.nv.gov/provider-enrollment--termination/provider-exclusions-sanctions-and-press-releases/ → `/siteassets/press-releases/master-exclusions-<MM.DD.YYYY>.pdf` |
| Route that works | direct script, US VPN |
| How | Reads the page for `master-exclusions-<date>.pdf`. |
| Watch out | The parser once dropped the last table row per page (fixed). The sanction-period end date is the reinstatement date. |
| Edition held | 10.21.2026 |
| Stated cadence | periodically |
| Records | 1,333 (1,037 active), newest 2026-07-01 |
| Last resync | 1,333 records (+0) |
| Research notes | The list moved from dhcfp.nv.gov (MASTER Exclusions <date>.pdf) to omig.nv.gov/siteassets/press-releases/. Multi-line cells (several NPIs, dba names) make PDF parsing tricky. One row is repeated per controlling-interest person. |
Refresh
uv run -q python poc/service/resync_cli.py us-nv-medicaid
uv run --script poc/ingest/us-nv-medicaid.py # debug only: writes the list directly, no safety checksFields
Captured: npi 70%, npi_valid 70%, medicaid_id 3%, provider_type 62%, middle_name 20%, aliases 5%, exclusion_date 100%, reinstatement_date 59%, first_last 62%. Other published columns: pdf_page, sanction_period, medicaid_provider, sanction_period_end_date, controlling_persons_5pct, associated_legal_entity, oig_exclusion_date, invalid_npi_values, all_npis, other_ids.
https://www.omig.nv.gov/siteassets/press-releases/master-exclusions-10.21.2026.pdf; provider_type is the NV Medicaid provider-type CODE (e.g. 'NV PT 20'), not text. 9005xxxxxx IDs are NV Medicaid IDs, moved to medicaid_id.
NY us-ny-medicaid direct script, US VPNcurrent
| List | NY OMIG exclusions |
| Official page | https://omig.ny.gov/medicaid-fraud/medicaid-exclusions |
| File we fetch | https://apps.omig.ny.gov/exclusions/exporttoexcel.aspx |
| Route that works | direct script, US VPN |
| How | Direct Excel export. |
| Edition held | live export |
| Stated cadence | not stated |
| Records | 9,179 (9,179 active), newest 2026-11-04 |
| Last resync | 9,179 records (+18) |
| Research notes | The export is XLSX despite the .aspx URL; the old .xls naming misleads parsers. The short list holds only the last 30 days. No DOB or address, so matching relies on name plus NPI or license. |
Refresh
uv run -q python poc/service/resync_cli.py us-ny-medicaid
uv run --script poc/ingest/us-ny-medicaid.py # debug only: writes the list directly, no safety checksFields
Captured: npi 26%, npi_valid 26%, license 66%, license_state 66%, provider_type 100%, middle_name 41%, aliases 5%, exclusion_date 100%, first_last 85%. Other published columns: license_state_inferred, name_credentials, name_split_ambiguous, license_num_other_id, npi_raw.
live download; XLSX sheet 'Exclusions', 9179 rows
OH us-oh-medicaid direct script, US VPNcurrent
| List | Ohio exclusion and suspension list |
| Official page | https://medicaid.ohio.gov/resources-for-providers/enrollment-and-support/provider-enrollment/provider-exclusion-and-suspension-list |
| File we fetch | https://medicaid.ohio.gov/resources-for-providers/enrollment-and-support/provider-enrollment/provider-exclusion-and-suspension-list → `dam.assets.ohio.gov/.../ExclusionSuspensionList_<MM_DD_YYYY>-<n>.xlsx` |
| Route that works | direct script, US VPN |
| How | Reads the page for the dated workbook; also writes the organizations list. |
| Watch out | Also writes `us-oh-medicaid-org`. |
| Edition held | 10_30_2026 |
| Stated cadence | frequently (no fixed cadence) |
| Records | 1,867 (1,867 active), newest 2026-10-19 |
| Last resync | 1,867 records (+0) |
| Research notes | The page says 'the provider's last known address and date of birth are included', but the Individuals sheet has DOB only and addresses appear on the Organizations sheet. Some DOBs look like placeholders (e.g. 1990-01-01). Status values have trailing spaces and case variants. Providers terminated for license issues are excluded from the list. |
Refresh
uv run -q python poc/service/resync_cli.py us-oh-medicaid
uv run --script poc/ingest/us-oh-medicaid.py # debug only: writes the list directly, no safety checksFields
Captured: npi 32%, npi_valid 32%, dob 100%, medicaid_id 62%, provider_type 62%, middle_name 54%, aliases 2%, exclusion_date 100%, first_last 100%. Other published columns: date_added, provider_ids, npis.
Individuals sheet of 20261107T010716Z__ExclusionSuspensionList_10_30_2026.xlsx. Multiple NPIs/provider IDs per row kept in extra.
OH us-oh-medicaid-org direct script, US VPNcurrent
| List | Ohio organizations |
| Official page | https://medicaid.ohio.gov/resources-for-providers/enrollment-and-support/provider-enrollment/provider-exclusion-and-suspension-list |
| File we fetch | from the same workbook |
| Route that works | direct script, US VPN |
| How | Second sheet of the Ohio workbook. |
| Watch out | No download of its own. |
| Edition held | 10_30_2026 |
| Stated cadence | frequently (no fixed cadence) |
| Records | 255 (255 active), newest 2026-10-08 |
| Last resync | 255 records (+0) |
| Research notes | Same workbook as us-oh-medicaid. Column order differs from the Individuals sheet (NPI first). Provider ID mixes int and zero-padded strings. Expect typos in Status. |
Refresh
uv run -q python poc/service/resync_cli.py us-oh-medicaid-org
uv run --script poc/ingest/us-oh-medicaid-org.py # debug only: writes the list directly, no safety checksFields
Captured: npi 77%, npi_valid 77%, medicaid_id 99%, address 100%, provider_type 99%, exclusion_date 99%. Other published columns: date_added, provider_ids, npis.
Organizations sheet of 20261107T010716Z__ExclusionSuspensionList_10_30_2026.xlsx (same download as us-oh-medicaid).
OR us-or-medicaid direct script, US VPNcurrent
| List | Oregon OHA sanctions |
| Official page | https://www.oregon.gov/oha/HSD/OHP/Pages/Provider-Enroll.aspx ('Sanctioned Providers' section) |
| File we fetch | https://www.oregon.gov/oha/HSD/OHP/_api/web/lists/getbytitle('Sanctions')/items |
| Route that works | direct script, US VPN |
| How | SharePoint REST list. |
| Watch out | Only 3 records. |
| Edition held | live list |
| Stated cadence | not stated |
| Records | 3 (3 active), newest 2024-09-16 |
| Last resync | 3 records (+0) |
| Research notes | The list is tiny (3 rows) and has barely changed since 2021, so it is not a full exclusion list. List description: 'List of sanctioned providers posted at /Provider-Enroll.aspx'. Provider type is a lookup id that needs a second list to resolve. |
Refresh
uv run -q python poc/service/resync_cli.py us-or-medicaid
uv run --script poc/ingest/us-or-medicaid.py # debug only: writes the list directly, no safety checksFields
Captured: npi 100%, npi_valid 100%, middle_name 33%, exclusion_date 100%, first_last 33%. Other published columns: duration, Modified, Created, provider_type_lookup_id.
Persons 'Last, First M'; comma-less titles are organizations.
OR us-or-piau direct script, US VPNcurrent
| List | Oregon PIAU fraud convictions |
| Official page | https://www.oregon.gov/oha/FOD/PIAU/Pages/Convictions.aspx (now HTTP 404); PIAU home https://www.oregon.gov/oha/FOD/PIAU/Pages/Index.aspx |
| File we fetch | https://www.oregon.gov/oha/FOD/PIAU/_vti_bin/Lists.asmx (page https://www.oregon.gov/oha/FOD/PIAU/Pages/Convictions.aspx) |
| Route that works | direct script, US VPN |
| How | SharePoint `Lists.asmx` call. |
| Edition held | live list |
| Stated cadence | not stated |
| Records | 132 (132 active), newest – |
| Last resync | 132 records (+0) |
| Research notes | Probably retired: Convictions.aspx is 404 as of 2026-11-07 and the PIAU site's lists were rebuilt around 2026-09-27 with no convictions list. Check whether our Lists.asmx fetch still returns data or has gone stale or empty. Oregon DOJ MFCU press releases may be the replacement source. |
Refresh
uv run -q python poc/service/resync_cli.py us-or-piau
uv run --script poc/ingest/us-or-piau.py # debug only: writes the list directly, no safety checksFields
Captured: middle_name 5%, first_last 100%. Other published columns: notice_url, modified.
https://www.oregon.gov/oha/FOD/PIAU/_vti_bin/Lists.asmx GetListItems (Documents); page https://www.oregon.gov/oha/FOD/PIAU/Pages/Convictions.aspx
PA us-pa-medicheck direct script, US VPNcurrent
| List | PA Medicheck precluded providers |
| Official page | https://www.pa.gov/agencies/dhs/report-fraud/medicheck-list |
| File we fetch | https://www.humanservices.dhs.pa.gov/Medchk/MedchkSearch/Medchk |
| Route that works | direct script, US VPN |
| How | Direct CSV export. |
| Edition held | live export |
| Stated cadence | daily |
| Records | 6,765 (4,919 active), newest 2026-09-20 |
| Last resync | 6,765 records (+10) |
| Research notes | Statuses include non-exclusion states (Reinstated, Voluntary Withdrawal, blank), so filter on Status plus EndDate. Formerly mailed monthly as 88-series MA Bulletins (hard copy ended Jan 2002). FEIN is present for some businesses. |
Refresh
uv run -q python poc/service/resync_cli.py us-pa-medicheck
uv run --script poc/ingest/us-pa-medicheck.py # debug only: writes the list directly, no safety checksFields
Captured: npi 23%, npi_valid 23%, license 65%, license_state 63%, provider_type 81%, middle_name 66%, aliases 4%, exclusion_date 100%, reinstatement_date 34%, first_last 95%. Other published columns: IND_CHGD, ListDate, CAO, DTE_CHANGE_LAST, LicenseNumber, NBR_FEIN.
Full CSV from a plain GET of the Medchk search URL. license_state inferred: '(XX)' suffix, else PA board format.
SC us-sc-medicaid direct script, US VPNcurrent
| List | South Carolina excluded/terminated providers |
| Official page | https://www.scdhhs.gov/fraud-waste-and-abuse (old URL /site-page/excluded-providers-list redirects here) |
| File we fetch | https://www.scdhhs.gov/fraud-waste-and-abuse → `/sites/dhhs/files/<MM DD YYYY> SC Medicaid Sanctioned Individuals_<name>.xlsx` |
| Route that works | direct script, US VPN |
| How | Reads the Fraud, Waste and Abuse page for the dated xlsx. |
| Watch out | Byte-identical to CloudCruise's copy. |
| Edition held | 10/30/2026 |
| Stated cadence | not stated |
| Records | 1,372 (1,372 active), newest 2026-10-28 |
| Last resync | 1,372 records (+5) |
| Research notes | The filename changes with each update (date plus a staff name); the current one is '10 30 2026 SC Medicaid Sanctioned Individuals_Patricia K Godley.xlsx'. The page also links LEIE and SAM. NPI column uses the string 'Not Found'. |
Refresh
uv run -q python poc/service/resync_cli.py us-sc-medicaid
uv run --script poc/ingest/us-sc-medicaid.py # debug only: writes the list directly, no safety checksFields
Captured: npi 39%, npi_valid 39%, address 100%, provider_type 100%, middle_name 55%, aliases 2%, exclusion_date 100%, first_last 82%. Other published columns: npis, name_credentials.
raw 20261107T010724Z__10_30_2026_SC_Medicaid_Sanctioned_Individuals_Patricia_K_Godley.xlsx
TN us-tn-medicaid user's Chromecurrent
| List | TennCare terminated providers |
| Official page | https://www.tn.gov/tenncare/fraud-and-abuse/program-integrity.html |
| File we fetch | https://www.tn.gov/tenncare/fraud-and-abuse/program-integrity.html → `.../tn_complex_datatable.tablejson.json` |
| Route that works | user's Chrome |
| How | The JSON behind the page's table returned 403 to scripts on this VPN address (it worked from the non-US network on Oct 28). Fetched inside the page in the user's Chrome with `cdp_page.py`, loaded with `ingest_manual.py`. |
| Watch out | Try direct first: the block looks specific to the VPN exit. Discovery regex fixed for the entity-escaped URL. |
| Edition held | live table |
| Stated cadence | as needed |
| Records | 21 (21 active), newest 2026-01-05 |
| Last resync | 21 records (+0) |
| Research notes | Covers providers whose TennCare provider agreement was terminated. Names only, no business-name column (entities appear in name fields). Small list. |
Refresh
uv run -q python poc/service/resync_cli.py us-tn-medicaid
uv run -q --with websockets python -I artifacts/scripts/cdp_page.py '<list page URL>' '<file URL>' /tmp/us-tn-medicaid.file # the owner's Chrome (CDP 9222)
uv run -q python artifacts/scripts/ingest_manual.py us-tn-medicaid /tmp/us-tn-medicaid.file '<raw file name>' '<official URL>'
uv run --script poc/ingest/us-tn-medicaid.py # debug only: writes the list directly, no safety checksFields
Captured: npi 43%, npi_valid 43%, middle_name 24%, aliases 5%, exclusion_date 100%, first_last 71%. Other published columns: reason.
Org rows have the name in 'Last Name' and an empty first name.
TX us-tx-oig direct script, US VPNcurrent
| List | Texas HHSC OIG exclusions |
| Official page | https://oig.hhs.texas.gov/exclusions (portal: https://oig.hhsc.state.tx.us/oigportal2/Exclusions) |
| File we fetch | https://oig.hhsc.state.tx.us/oigportal2/Exclusions/ctl/DOW/mid/384 |
| Route that works | direct script, US VPN |
| How | Replays the page's download postback for the TEXT file. |
| Watch out | US address needed. |
| Edition held | live file |
| Stated cadence | not stated |
| Records | 13,459 (11,993 active), newest 2026-11-01 |
| Last resync | 13,459 records (+7) |
| Research notes | Filter on ReinstatedDate to get active exclusions. Occupation is sometimes a numeric code (e.g. '31', '100'). There is a 'Waiver' flag column. The download is a POST with VIEWSTATE and EVENTVALIDATION, so a fresh GET is needed first. |
Refresh
uv run -q python poc/service/resync_cli.py us-tx-oig
uv run --script poc/ingest/us-tx-oig.py # debug only: writes the list directly, no safety checksFields
Captured: npi 4%, npi_valid 4%, license 75%, license_state 75%, provider_type 94%, middle_name 80%, exclusion_date 100%, reinstatement_date 11%, first_last 96%. Other published columns: Waiver, AddDate, WebComments, license_state_inferred, EligibleToReapplyDate, company_name.
live download; header ['CompanyName', 'LastName', 'FirstName', 'MidInitial', 'Occupation', 'LicenseNumber', 'NPI', 'StartDate', 'AddDate', 'ReinstatedDate', 'EligibleToReapplyDate', 'Waiver', 'WebComments']; column map {'company': 'CompanyName', 'last': 'LastName', 'first': 'FirstName', 'middle': 'MidInitial', 'ptype': 'Occupation', 'license': 'LicenseNumber', 'npi': 'NPI', 'start': 'StartDate', 'reinstated': 'ReinstatedDate'}
VT us-vt-medicaid direct script, US VPNcurrent
| List | Vermont for-cause exclusions |
| Official page | https://www.vtmedicaid.com/#/provEnrollExcluded |
| File we fetch | https://www.vtmedicaid.com/assets/provEnroll/excludedProvidersList/ExcludedProvidersList.xlsx |
| Route that works | direct script, US VPN |
| How | Direct xlsx. |
| Edition held | Oct 8, 2026 |
| Stated cadence | monthly (implied by the file title; no explicit statement) |
| Records | 69 (69 active), newest 2026-05-28 |
| Last resync | 69 records (+0) |
| Research notes | Small list of for-cause terminations only. The duplicate 'State' header hides the reason code. The fixed filename is overwritten each month. dvha.vermont.gov/providers/medicaid-excluded-providers links to the portal page. |
Refresh
uv run -q python poc/service/resync_cli.py us-vt-medicaid
uv run --script poc/ingest/us-vt-medicaid.py # debug only: writes the list directly, no safety checksFields
Captured: npi 77%, npi_valid 77%, medicaid_id 100%, address 100%, provider_type 100%, middle_name 54%, exclusion_date 100%, first_last 80%. Other published columns: State#2, name_credentials.
Names 'LAST,FIRST M CRED'. End date 2382-12-31 = indefinite (dropped). Second 'State' column (2-digit code) kept in extra as 'State#2'.
WA us-wa-dshs direct script, US VPNcurrent
| List | Washington DSHS terminations |
| Official page | https://www.hca.wa.gov/billers-providers-partners/become-apple-health-provider/provider-termination-and-exclusion-list |
| File we fetch | https://www.hca.wa.gov/assets/billers-and-providers/termination-exclusion-dshs.xlsx |
| Route that works | direct script, US VPN |
| How | Direct xlsx. |
| Watch out | One record; rarely changes. |
| Edition held | Feb 12, 2025 |
| Stated cadence | not stated (no fixed cadence; the page shows a shared 'updated' date) |
| Records | 1 (1 active), newest 2017-07-05 |
| Last resync | 1 records (+0) |
| Research notes | Effectively a 1-record list that is stale since 2017. It covers DSHS social-services providers such as home care, not medical providers. |
Refresh
uv run -q python poc/service/resync_cli.py us-wa-dshs
uv run --script poc/ingest/us-wa-dshs.py # debug only: writes the list directly, no safety checksFields
Captured: medicaid_id 100%, address 100%, exclusion_date 100%, first_last 100%. Other published columns: –.
Tiny list (1 row). P1 ID = WA ProviderOne id.
WA us-wa-hca direct script, US VPNcurrent
| List | Washington HCA terminations |
| Official page | https://www.hca.wa.gov/billers-providers-partners/become-apple-health-provider/provider-termination-and-exclusion-list |
| File we fetch | https://www.hca.wa.gov/assets/billers-and-providers/termination-exclusion.xlsx |
| Route that works | direct script, US VPN |
| How | Direct xlsx. |
| Edition held | Oct 13, 2026 |
| Stated cadence | not stated (no fixed cadence; the page and the file show the update date) |
| Records | 234 (234 active), newest 2025-11-06 |
| Last resync | 234 records (+0) |
| Research notes | Many rows are license actions, not Medicaid-only exclusions. Multi-value cells need splitting. No address column. |
Refresh
uv run -q python poc/service/resync_cli.py us-wa-hca
uv run --script poc/ingest/us-wa-hca.py # debug only: writes the list directly, no safety checksFields
Captured: npi 86%, npi_valid 77%, license 99%, license_state 99%, medicaid_id 14%, provider_type 90%, middle_name 65%, exclusion_date 100%, first_last 97%. Other published columns: name_credentials, business_names, npis.
'Last, First M CRED'; credential -> provider_type; business names glued to the person -> extra.business_names. Non-NPI ids in 'NPI # or P1 #' -> medicaid_id (ProviderOne).
WV us-wv-medicaid none todaynot refreshed
| List | West Virginia exclusions and terminations |
| Official page | https://www.wvmmis.com/SitePages/Medicaid%20Provider%20SanctionedExclusion |
| File we fetch | https://www.wvmmis.com/SitePages/Medicaid%20Provider%20SanctionedExclusion → `SharepointDownload.aspx?parent=...&docname=...` |
| Route that works | none today |
| How | Reads the SharePoint list for the monthly PDF, then `SharepointDownload.aspx` (route last worked Oct 28). |
| Watch out | Site in scheduled maintenance until 10 pm EST Nov 6, so not refreshed. Rerun the ingester once it is back. |
| Edition held | October 2026 |
| Stated cadence | monthly (implied by the monthly file names; no explicit statement) |
| Records | 166 (166 active), newest 2026-05-18 |
| Last resync | exit 1: requests.exceptions.HTTPError: 404 Client Error: Not Found for url: https://www.wvmmis.com/SitePages/Medicaid%20Provider%20SanctionedExclusion; kept the previous copy |
| Research notes | Organizations appear in the Last/First name columns. Multi-line cells need careful PDF table parsing. A new file is posted early each month, and the newest is chosen by the month in the file name. |
Refresh
uv run -q python poc/service/resync_cli.py us-wv-medicaid
uv run -q --with websockets python -I artifacts/scripts/cdp_page.py '<list page URL>' '<file URL>' /tmp/us-wv-medicaid.file # the owner's Chrome (CDP 9222)
uv run -q python artifacts/scripts/ingest_manual.py us-wv-medicaid /tmp/us-wv-medicaid.file '<raw file name>' '<official URL>'
uv run --script poc/ingest/us-wv-medicaid.py # debug only: writes the list directly, no safety checksFields
Captured: npi 95%, npi_valid 95%, address 100%, middle_name 7%, exclusion_date 100%, first_last 92%. Other published columns: reason, pdf_page, npi_raw.
https://www.wvmmis.com/SharepointDownload.aspx?parent=Medicaid+Provider+SanctionedExclusion&docname=WV%20Provider%20Exclusions%20and%20Terminations%20October%202026.pdf; fetched via direct
WY us-wy-medicaid direct script, US VPNcurrent
| List | Wyoming exclusion list |
| Official page | https://health.wyo.gov/healthcarefin/program-integrity/ |
| File we fetch | `https://health.wyo.gov/wp-content/uploads/<yyyy>/<mm>/<yyyy_mm_dd>_-Wyoming-Medicaid-Exclusion-List.pdf` |
| Route that works | direct script, US VPN |
| How | Probes the monthly WordPress upload names, newest first. |
| Watch out | Checked: no Oct or Nov file exists yet. |
| Edition held | 2026_09_01 |
| Stated cadence | not stated (the reissue cadence is irregular) |
| Records | 127 (127 active), newest 2025-03-20 |
| Last resync | 127 records (+0) |
| Research notes | Name aliases ('a.k.a', maiden names in parentheses) and multi-license cells. Business rows have blank first names. No stable URL, so discovery depends on upload-path name patterns or search. |
Refresh
uv run -q python poc/service/resync_cli.py us-wy-medicaid
uv run --script poc/ingest/us-wy-medicaid.py # debug only: writes the list directly, no safety checksFields
Captured: npi 9%, npi_valid 9%, license 39%, license_state 39%, medicaid_id 28%, address 100%, provider_type 100%, middle_name 54%, aliases 16%, exclusion_date 100%, first_last 91%. Other published columns: pdf_page, provider_number_raw, licenses, business_name, associated_person, derived_from, all_medicaid_ids.
https://health.wyo.gov/wp-content/uploads/2026/09/2026_09_01_-Wyoming-Medicaid-Exclusion-List.pdf; fetched via direct; business names also emitted as organizations
Code
Read-only view of the POC source, as of this build. Paths and names that would identify a person or machine are replaced with placeholders.
Evaluation
Baselines to compare against after any rule or ingester change. The provider sets behind the first three rows are internal data and are not part of this hand-over; the last two run on public data only.
| Set | What it measures | Baseline (Nov 7) |
|---|---|---|
| Override requests (Sep 15 – Nov 7) | Name matches the current vendor raised and ops cleared by hand: how many our rules clear, and agreement with ops | 783 of 1172 cleared (66.8%), strict 54.5%; the 3 real exclusions confirmed |
| Ongoing-monitoring flags | 17,829 flags in 44 orgs: dismiss rate, and the 702 a person resolved | Unreviewed: 79.8% dismissed (strict 72.2%), 19 confirmed |
| Real exclusions | 90 real exclusions re-screened with the record's NPI hidden: any dismissal is a miss | 0 of 90 dismissed (12 before the license-state fix) |
| Holdout, name only | 2 × 1,000 list records rebuilt as the real NPPES person and stripped to a name | 3 / 2 wrongly dismissed per 1,000 · uv run --with nicknames python poc/match/holdout_safety.py |
| OpenSanctions | Our lists vs OpenSanctions' copies, record by record | see the comparison report · uv run python poc/eval/compare_opensanctions_1107.py --fetch |
Known issues
Ingesters
- Idaho: exclusion dates published but not captured.
- Iowa, Vermont, Mississippi: reinstatement dates published but not captured.
- Nevada: Medicaid IDs published but not captured.
- Maryland: 6 PDF legend rows ("A = Abuse of…", "10.08.2026") loaded as records.
- Alaska: 3 rows at a page boundary have the date glued into the name.
- Michigan: companies kept in parentheses inside person names.
Moved or dead sources
- Michigan file is now MI_Sanctioned_Provider_List-XLSX.xlsx.
- Montana links a fixed asset name instead of a dated file.
- NJ Treasury directory is 404; files are named per category (Debarment-MEDICAL.txt).
- Oregon PIAU page retired; its SharePoint list still answers.
- Washington DSHS: one row, from 2017.
- West Virginia: November edition posted; the Nov 7 run got a 404 (maintenance).
- Mississippi: no list since the vendor outage; we hold the June archive + OpenSanctions.
- Maine: portal only weekdays 07–19 ET; we use the OpenSanctions copy.
Data and rules
- 22 state NPIs fail the check digit (Delaware's PDF prints them wrong); OpenSanctions has the right ones. Repair via NPPES.
- Delaware mixes licensing-board penalties with exclusions: a monetary penalty gets confirmed by license.
- Bare-name lists (AR, ME, parts of DE/IL/NE) clear poorly (23–53%) and their recall can't be measured.
- DC's list is procurement debarment, not Medicaid. Florida's is mostly fines.
- Nobody has reviewed a sample of the dismissals by hand yet; ~100 stratified by rule is the next check.
Platform
- SAM takes ~half the memory; on small hosts skip it with MEDEX_SKIP_SOURCES (the process needs ~1.6 GB on Linux with it).
- OpenSanctions data (ME, part of MS) is CC BY-NC: production needs a commercial license or our own copies.
- Most state sites refuse non-US addresses; KS, NH, MN, HI, MA, CT refuse scripts entirely (CloudCruise).
- The local NPPES index is the Oct 17 monthly file; the lookup uses the live API and falls back to it.