Healthcare Discipline Watch — Multi-State & Federal Actions
Pricing
$2.00 / 1,000 normalized records
Healthcare Discipline Watch — Multi-State & Federal Actions
Normalized public disciplinary actions from CA, FL, MD, WA, KY and the federal OIG exclusion list. Stable IDs, action taxonomy, delta mode, provenance, optional possible-match flags.
Pricing
$2.00 / 1,000 normalized records
Rating
0.0
(0)
Developer
Pranava Kumar I
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
4 days ago
Last modified
Categories
Security
Limited permissionsShare
Summary: Normalized public disciplinary actions for healthcare providers from five state agencies and the federal OIG exclusion list, delivered as typed JSON records with stable IDs, an action taxonomy, provenance, delta mode, and optional possible-match flags.
Last verified live: 2026-11-03. Default 90-day run: 1,579 records, about 75–100 seconds, about 0.4–0.5 GB RSS. Ten consecutive runs passed with all six sources healthy.
Why this actor exists
Healthcare compliance teams, credentialing staff, journalists, and researchers need to know when a provider is disciplined or federally excluded. That currently means checking five state websites, each with a different format: a filtered CSV download, an Excel workbook, an HTML table, a news archive, and monthly PDFs. Teams reconcile the results by hand.
This actor does the reconciliation on each run and emits one canonical record per action:
- Six sources, one schema. Every record uses the same field names and types regardless of origin.
- Stable record identity.
recordIdis the source plus a SHA-256 of the source's own record key. It stays the same unless the source changes that key. - Action taxonomy. Free-text sanctions map to a fixed
actionTypeandstage. - Delta mode. Emit only records never seen before, or new and changed records, using a named Key-Value Store that persists across runs.
- Provenance. Every record carries
sourceUrl,sourceRecordId,retrievedAt, anddocumentUrlorprofileUrlwhere the source publishes one. - Conservative federal matching. Exact normalized first name, last name, and state, reported in a separate
possibleFederalMatchfield and never merged into the state record. - Isolated failures. One broken source is marked
failedorpartialinSOURCE_STATUS; the other sources still complete.
The six sources require no login, CAPTCHA, paywall, or API key. The actor uses no paid proxies or third-party paid APIs; the only costs are your own Apify run compute and the per-record event price described below.
Sources
| Key | Source | Format | Extracted fields |
|---|---|---|---|
fl_mqa | Florida Department of Health — MQA Enforcement Actions | Server-side date-filtered CSV export | Name, license, profession, action, action date, case number, city, county, state |
ca_mbc | Medical Board of California — Enforcement Actions / License Alerts | Annual Excel workbooks linked from the alerts page | Name, license, physician label, city/state, action, action date, posted date, profile link |
md_mbp | Maryland Board of Physicians — Disciplinary Alerts | HTML table with linked order PDFs | Name, action, order date, summary, document URL |
wa_doh | Washington State Department of Health — Disciplinary News Releases | Prose newsroom articles | Name, credential number, action, action month, release date, summary |
ky_kbml | Kentucky Board of Medical Licensure — Board Action Reports | Monthly PDF reports | Name, license number, city/state, action, action date, document URL |
oig_leie | HHS OIG List of Excluded Individuals/Entities | Full CSV download | Name or business name, exclusion type, exclusion date, reinstatement date, NPI, state, specialty |
Each source publishes these records on a public government website. For CA and WA, the date filter also accepts the official posting or release date, because those sources publish later than the action date. The other four sources filter on the action date.
Use cases
- Credentialing research — assemble a practitioner's public discipline history for a credentialing file. The reviewer makes the decision.
- Ongoing sanctions monitoring — schedule a daily or weekly run with
emitMode: "new"and route new records to an alert queue. - Compliance risk dashboards — join records to internal provider data on
npi,licenseNumber, ornameNormalized. - Journalism — track board-action patterns by state, profession, or sanction type.
- Legal and regulatory review — pull the underlying order PDF through
documentUrl. - Provider-directory hygiene — flag directory entries that need verification against the board.
- Academic and policy research — measure discipline rates and sanction mix across states.
- Agent workflows — feed typed JSON into retrieval, classification, or summarization pipelines without HTML cleanup.
Use restriction: do not use the output as the sole basis for hiring, credit, insurance underwriting, or tenant-screening decisions. See Legal and compliance.
Quick start
Apify Console
- Open the actor and click Start.
- Leave the defaults: all six sources, last 90 days, up to 2,000 records.
- Results appear in the dataset. Run metadata is in the Key-Value Store records
SUMMARY,SOURCE_STATUS, andDISCLAIMER.
API
Replace YOUR_USERNAME with your Apify username and YOUR_TOKEN with a token from https://console.apify.com/account#/integrations.
curl -X POST "https://api.apify.com/v2/acts/YOUR_USERNAME~healthcare-discipline-watch/runs?token=YOUR_TOKEN" \-H "Content-Type: application/json" \-d '{"sources": ["fl_mqa", "ca_mbc", "md_mbp", "wa_doh", "ky_kbml", "oig_leie"],"sinceDate": "2026-08-05","untilDate": "2026-11-03","emitMode": "all","maxRecords": 2000}'
Sample input
{"sources": ["fl_mqa", "ca_mbc", "md_mbp", "wa_doh", "ky_kbml", "oig_leie"],"sinceDate": "2026-08-05","untilDate": "2026-11-03","states": [],"emitMode": "all","stateStoreName": "healthcare-discipline-watch-state","maxRecords": 2000,"includeSummaries": true,"matchFederalExclusions": true,"requestDelayMs": 750}
Input reference
| Field | Type | Default | Description |
|---|---|---|---|
sources | array of enum | all six | Which sources to fetch. |
sinceDate | YYYY-MM-DD | 90 days ago | Action date lower bound. CA and WA also match their posting or release date. |
untilDate | YYYY-MM-DD | today | Action date upper bound. CA and WA also match their posting or release date. |
states | string array | [] | Two-letter jurisdiction filter for state records. OIG records are kept when their state is blank or in the list. |
emitMode | all | new | changed | all | new emits first-seen records; changed also emits records whose content hash changed. |
stateStoreName | string | healthcare-discipline-watch-state | Named Key-Value Store for delta state. Created on first use and reused across runs. |
maxRecords | integer, 1–20,000 | 2000 | Output cap applied after sorting newest-first and before delta comparison. |
includeSummaries | boolean | true | Include sanction text or news-release paragraphs. |
matchFederalExclusions | boolean | true | Flag exact name-and-state matches against the full OIG LEIE. Requires oig_leie in sources. |
requestDelayMs | integer, 250–10,000 | 750 | Minimum delay between outbound requests. |
Unknown fields are ignored. Invalid dates and inverted date ranges fail the run with a clear error.
Output reference
Each dataset item is one JSON object. The only nested objects are federalExclusion, possibleFederalMatch, and dataQuality.
| Field | Type | Notes |
|---|---|---|
recordId | string | source: plus SHA-256 of sourceRecordId. |
source | enum | fl_mqa, ca_mbc, md_mbp, wa_doh, ky_kbml, oig_leie. |
sourceName | string | Human-readable source name. |
sourceUrl | string | Page the record was published on. |
sourceRecordId | string | The source's own identity, such as license, case, date, credential, or document. |
jurisdiction | string | Two-letter state, or US for federal records. |
jurisdictionName | string | State name, or United States (federal). |
providerType | individual | entity | unknown | Entity detection is pattern-based for state sources and source-declared for OIG. |
providerName | string | Name as published, whitespace-normalized. |
entityName | string | null | Business name when providerType is entity. |
firstName, middleName, lastName | string | null | Parsed uppercase name parts. Null for entities. |
nameNormalized | string | Lowercase family given key; middle names are excluded. Entity records use the normalized business name; unparsed names are empty. |
npi | string | null | National Provider Identifier, OIG records only. |
licenseNumber | string | null | License or credential number when published. |
licenseType, profession | string | null | Source label, sometimes normalized. |
city, county, state | string | null | Practice location as published. |
caseNumber | string | null | Board case number when published. |
actionRaw | string | Sanction text as published, or a concise label for prose sources. |
actionType | enum | revocation, suspension, probation, reprimand, fine, surrender, denial, restriction, reinstatement, stay, cease_and_desist, complaint_filed, decision, federal_exclusion, other. |
actionCategory | enum | license_revoked, license_surrendered, license_restriction, license_denied, license_restoration, public_reprimand, monetary_penalty, pending_charge, procedural, decision, cease_and_desist, federal_exclusion, other. |
stage | enum | charge, decision, final_order, exclusion, unknown. |
actionType names the sanction, actionCategory names its effect on the license, and stage names where the action sits in the process.
| actionDate | string | null | ISO YYYY-MM-DD. WA uses the first day of the month when only a month is published. |
| postedDate | string | null | Official posting or release date when the source publishes one. |
| summary | string | null | Sanction text or news-release paragraph. |
| documentUrl | string | null | Link to the official order or PDF. |
| profileUrl | string | null | Link to the official provider profile. |
| federalExclusion | object | null | On OIG records: { source, recordId, exclusionType, exclusionDate, reinstatementDate, sourceUrl }. |
| possibleFederalMatch | object | null | On state records: { source, recordId, exclusionType, exclusionDate, confidence: 0.75, method: "exact_name_state", isConfirmed: false }. |
| isNew, isChanged | boolean | Delta flags relative to the named state store. |
| firstSeenAt, lastSeenAt | string | null | ISO timestamps maintained by the actor. |
| retrievedAt | string | ISO timestamp for this run. |
| dataQuality.confidence | number | 0–1. Starts at 1.0 (0.9 for KY PDFs, 0.75 for WA prose) and is reduced for unknown names (−0.4), missing action dates (−0.2), missing license numbers (−0.1), single-token names (−0.1), unparsed names (−0.2), and future dates (−0.1). |
| dataQuality.issues | string[] | For example missing_license_number, prose_parse_uncertain, future_date. |
Sample output
{"recordId": "fl_mqa:9f1c0d7b2e6a4c8f5d3a1b0e9c7f6a2d4b8e1c3a5f7d9b2e4c6a8f0d1b3e5c7a","source": "fl_mqa","sourceName": "Florida Department of Health — MQA Enforcement Actions","sourceUrl": "https://mqa-internet.doh.state.fl.us/MQASearchServices/EnforcementActionsPractitioner","sourceRecordId": "ME00000|2026-000000|08/21/2026|Suspension","jurisdiction": "FL","jurisdictionName": "Florida","providerType": "individual","providerName": "DOE, JANE Q","entityName": null,"firstName": "JANE","middleName": "Q","lastName": "DOE","nameNormalized": "doe jane","npi": null,"licenseNumber": "ME00000","licenseType": "Medical Doctor","profession": "Medical Doctor","city": "ORLANDO","county": "ORANGE","state": "FL","caseNumber": "2026-000000","actionRaw": "Suspension","actionType": "suspension","actionCategory": "license_restriction","stage": "final_order","actionDate": "2026-08-21","postedDate": null,"summary": null,"documentUrl": null,"profileUrl": null,"federalExclusion": null,"possibleFederalMatch": null,"isNew": true,"isChanged": false,"firstSeenAt": "2026-11-03T03:12:00.000Z","lastSeenAt": "2026-11-03T03:12:00.000Z","retrievedAt": "2026-11-03T03:11:58.000Z","dataQuality": { "confidence": 1, "issues": [] }}
A federal record carries "federalExclusion" with its exclusion type and date. A state record with a possible match carries:
"possibleFederalMatch": {"source": "oig_leie","recordId": "oig_leie:2b7e...","exclusionType": "1128a1","exclusionDate": "2024-03-14","confidence": 0.75,"method": "exact_name_state","isConfirmed": false}
Run summary and source status
The actor writes three records to the default Key-Value Store:
SUMMARY— totals, per-source status, timing, and the disclaimer. Totals are undertotals:recordsPushed,recordsSkipped,chargeEvents,chargeLimitReached,sourcesOk,sourcesPartial,sourcesFailed,sourcesSkipped.SOURCE_STATUS— one entry per source withok,partial,failed, orskipped, a record count, elapsed time, and an error message when applicable.DISCLAIMER— the legal notice shown below.
recordsSkipped is the number of collected records that were not pushed. It combines records removed by maxRecords, delta filtering, and any charge-limit stop.
If every selected source fails, the run fails with All selected sources failed instead of producing an empty dataset.
Delta mode
emitMode: "new" compares each record ID against the named state store and pushes only IDs never seen before. emitMode: "changed" also pushes records whose content hash changed.
The store is a named Key-Value Store created on first use. Later runs with the same stateStoreName reuse it, on the platform and locally with apify run --no-purge. The state is persisted under the KV record key state. Changing the name starts a new baseline.
Entries that have not been seen for 400 days are pruned, and the store is capped at 30,000 entries to stay within the Key-Value Store's single-value size limit (about 9.5 MB). A pruned record can reappear as new if the source still publishes it. This covers the default 2,000-record cap with room to spare; if you raise maxRecords close to 20,000 across a long window, narrow the date range so the state does not rotate.
maxRecords is applied before delta comparison. If a window contains more records than the cap, the oldest records beyond the cap are not pushed and are not marked as seen. Raise maxRecords when you need complete coverage.
Federal matching
Matching is deliberately narrow. The actor builds an index from the full current OIG LEIE snapshot, not just the date window, then checks each state record:
- Only exact normalized first name, last name, and state qualify.
- Entities are skipped because they have no first or last name.
- A match is attached in
possibleFederalMatchwithconfidence: 0.75andmethod: "exact_name_state". - Records are never merged,
recordIdis never changed, andisConfirmedis alwaysfalse.
Matching requires oig_leie in sources. If building the full index fails, the run logs a warning and falls back to matching only against exclusions collected in the date window. Common names can produce false positives; treat the flag as a lead to verify, not a conclusion.
Pricing
Pay-per-event:
- Event:
record— one normalized record pushed to the dataset. - Price: $0.002 per record ($2.00 per 1,000 records).
- Max-total-charge floor: $0.01. The actor sets
minimalMaxTotalChargeUsd: 0.01, which means a caller may set the run optionmaxTotalChargeUsdas low as $0.01. The run stops charging and pushing records when that limit is reached. - No charge for records filtered out by delta mode, removed by
maxRecords, or stopped by a charge limit.
Cost is records pushed × $0.002. The default 90-day run measured on 2026-11-03 pushed 1,579 records, about $3.16. Counts change with source publication cadence. Platform compute usage is billed separately by Apify and deducted from the payout side, not added to the per-record price.
For AI agents
The output needs no HTML cleanup. Callers still filter on actionType, jurisdiction, dataQuality.confidence, and possibleFederalMatch.
- Input is a small typed JSON object; unknown fields are ignored and dates are validated.
- One JSON object per record, with all fields documented above. The only nested objects are
federalExclusion,possibleFederalMatch, anddataQuality. recordIdis stable, so an agent can cache, diff, and deduplicate results across runs.actionType,actionCategory,stage,providerType, andjurisdictionare enums suitable for filtering.dataQuality.confidenceanddataQuality.issuesidentify low-confidence parses.possibleFederalMatchis a lead, not an identity confirmation.
Suggested loop: call with emitMode: "new" and a persistent stateStoreName, fetch dataset items, filter on actionType and jurisdiction, then escalate records with confidence < 0.9 or a non-null possibleFederalMatch for human review.
Legal and compliance
- Public records only. The actor collects only fields that the source publishes on a public government page.
- No access-control bypass. The actor submits no credentials, solves no CAPTCHAs, circumvents no paywalls, and uses no proxies or browser-fingerprint spoofing.
- Robots rules. Before requesting a host, the actor fetches that host's
robots.txtand enforces its rules. A disallowed path fails the request, so the source is markedfailedorpartialrather than bypassing the rule. A 401 or 403 response forrobots.txtis treated as disallow-all; an unreachablerobots.txtis treated as allow-all. Requests are throttled byrequestDelayMsand retried after a short wait. - Attribution and provenance. Every record carries
sourceUrl,sourceRecordId, andretrievedAt, plusdocumentUrlorprofileUrlwhere the source publishes one. - Use restriction. Do not use the output as the sole basis for hiring, credit, insurance underwriting, or tenant-screening decisions. The actor republishes source records without scoring or evaluating them.
- No legal advice. Output is informational. Verify against the official source before acting.
- Data minimization. The actor collects only professional disciplinary and exclusion information published by the source; no contact details, patient data, or non-public information.
- Corrections. Records are regenerated from the source on each run. A source correction appears on the next run; datasets already delivered to buyers are immutable. If a source requests removal, update or disable its adapter and publish a new version.
Full disclaimer text is written to the DISCLAIMER Key-Value Store record and included in SUMMARY.
Limitations
- Five states, not fifty. Coverage is CA, FL, MD, WA, KY, and the federal OIG list. Other states are not supported.
- Publication lag. State agencies post actions weeks or months after the action date. CA and WA records are matched on the posting date as a fallback; FL, MD, KY, and OIG are not.
- Prose parsing. Washington publishes disciplinary actions as news releases. Its parser applies fixed rules, not a model. Those records carry
confidence: 0.75andprose_parse_uncertain. - Missing identifiers. Maryland does not publish license numbers, and OIG records have no license number. Those records carry
missing_license_numberandconfidence: 0.9. - Name matching is exact. Nicknames and maiden names are not reconciled, and transliterations are not matched. Credentials, generational suffixes, and diacritics are normalized before comparison. Federal matches are possible matches only.
- Federal list is a snapshot. The OIG CSV is downloaded in full on each run. Records removed from the source do not appear again.
- No historical archive. The actor reports what the sources currently publish within the requested window; it is not a complete historical database.
- Truncation. Four caps can hide older records:
maxRecordsin a busy window, the single current listing page on MD's site, the 10-page limit on WA's newsroom archive, and a fixed 200,000-record ceiling on records collected per run. OnlymaxRecordsand the date range are adjustable; narrow the window when complete coverage matters.
Maintenance and breakage response
A source failure does not stop the run or produce an empty dataset. The source is marked failed or partial in SOURCE_STATUS, and the rest of the run completes.
When a source breaks:
- Run
npm run smoke -- 90 <source_key>and capture the error and sample output. - Save a trimmed live sample into
test/fixtures/. - Update the adapter and its fixture test.
- Run
npx vitest runandnpx tsc --noEmit. - Bump
versionin.actor/actor.json, rebuild, and republish.
Recommended cadence: run the smoke test monthly, or when a scheduled run reports the same source as failed twice in a row.
Development
npm installnpx tsc --noEmit # type checknpx vitest run # 85 unit and adapter testsnpm run smoke -- 90 # live smoke test across all sourcesnpx apify run # local end-to-end run
Node.js 22 or newer is required. The actor needs no environment variables or secrets.
Support
Open an issue on the actor's Apify Store page for questions, source breakage, or data corrections. Include the run ID and the affected source key.
License and attribution
Source data remains the property of the respective agencies and is used under their public-record terms. The actor code is provided as-is for lawful use with public records. See the official source for the authoritative version of any record.