# Michigan Medical License Lookup Scraper (`automation-lab/michigan-medical-license-records`) Actor

Search Michigan MiPLUS Medical Doctor licenses by surname or exact license number. Export physician identity, license status, expiration and provenance for recurring credential verification.

- **URL**: https://apify.com/automation-lab/michigan-medical-license-records.md
- **Developed by:** [Automation Lab](https://apify.com/automation-lab) (community)
- **Categories:** Business
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 item extracteds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Michigan Medical License Lookup Scraper

Use this Michigan medical license lookup to retrieve public **Medical Doctor** license records from Michigan LARA's anonymous MiPLUS search. Search by surname or exact license number, then export physician identity, regulator status, expiration date and retrieval provenance.

### Who is it for?

Credentialing teams, provider-network analysts and compliance operations can refresh known physician licenses and compare regulator snapshots. This Actor returns public licensing facts, not medical advice or a certified verification document.

### Why use this Actor?

- Restricts every search to Medical Doctor instead of mixing professional categories.
- Preserves license numbers as strings and regulator status verbatim.
- Follows source pagination and deduplicates by license number across queries.
- Includes the search context, official source URL and UTC retrieval time.
- Requires no source login, paid external API key or user-managed proxy.

### Getting started

1. Open Input and provide one or more surname or license-number queries.
2. Choose a global maximum of unique licenses.
3. Start the Actor and inspect the default dataset.
4. Export JSON, CSV, Excel or another Apify dataset format.
5. For recurring checks, save a Task and configure an Apify schedule. Compare datasets in your own workflow; the Actor itself does not retain a history or send alerts.

```json
{"queries":[{"lastName":"Smith"}],"maxItems":20}
```

For a precise known license, use:

```json
{"queries":[{"licenseNumber":"4301010722"}],"maxItems":1}
```

### Input parameters

| Field | Behavior |
| --- | --- |
| `queries` | Required array of 1–25 objects, each containing exactly one `lastName` or `licenseNumber`. |
| `lastName` | Nonempty surname, trimmed before submission. Matching is performed by MiPLUS; no separate case-sensitive or substring filtering is applied by the Actor. |
| `licenseNumber` | Exact ten-digit regulator number. The returned number is checked for equality. |
| `maxItems` | Global unique-license limit, default 20, range 1–1000. Zero/unlimited are unsupported. |

Queries run in order. Duplicate licenses from later searches are not emitted or charged again.

The earliest query producing a license supplies its `query` field. When the maximum is reached, remaining queries/pages are not fetched.

### Extracted data

| Field | Meaning |
| --- | --- |
| `licenseType` | Always Medical Doctor. |
| `licenseNumber` | Regulator license identifier. |
| `firstName`, `middleInitial`, `lastName` | Separate grid name components when shown. |
| `fullName` | Practitioner name shown by the source. |
| `licenseStatus` | Verbatim regulator status, including inactive statuses. |
| `expirationDate` | Source date in MM/DD/YYYY, or null when blank. |
| `sourceUrl` | Official search or single-result detail page. |
| `query` | Normalized query first returning this license. |
| `scrapedAt` | UTC retrieval timestamp. |

MiPLUS automatically redirects single-result searches to a detail page. Those pages provide a full name but not reliable separate name components, so components remain null rather than being guessed. No active/inactive status is inferred from dates.

### Output example

A real source record retrieved by surname search:

```json
{
  "licenseType": "Medical Doctor",
  "licenseNumber": "4301010722",
  "firstName": "Donald",
  "middleInitial": "R",
  "lastName": "Smith",
  "fullName": "Donald R Smith",
  "licenseStatus": "Deceased",
  "expirationDate": "01/31/1991",
  "sourceUrl": "https://aca-prod.accela.com/MILARA/GeneralProperty/PropertyLookUp.aspx?isLicensee=Y",
  "query": {"lastName": "Smith"},
  "scrapedAt": "2026-10-01T06:07:28.965Z"
}
```

### How much does it cost to look up Michigan medical licenses?

The Actor charges a one-time **$0.005 start fee** plus a fee for each unique license delivered. BRONZE pricing is **$0.003332 per license**; FREE is $0.0038318, SILVER $0.002599, and GOLD/PLATINUM/DIAMOND $0.0019992.

At BRONZE prices, estimated Actor event charges are $0.008332 for 1 result, $0.03832 for 10 results and $0.1716 for 50 results. A valid no-result search incurs only the start fee. Apify spend tiers depend on qualifying monthly Store spend, not the number of licenses in this Actor's run. See the platform pricing panel for applicable charges and usage treatment.

### Limits and coverage

This product covers the Medical Doctor category only. It excludes osteopathic physicians, educational/limited medical licenses, other professions, disciplinary history, addresses and certified license verification documents. It is a bounded query tool, not a guaranteed complete Michigan physician roster.

Upstream result coverage/order may change. A broad surname can return old or deceased licensees alongside active physicians. Review the status field rather than treating every returned record as authorized to practice. The Actor stops at a safe 100-page query ceiling and fails if the source exposes more results without a usable next-page link.

### Failure behavior and troubleshooting

Malformed query combinations fail before extraction. A recognized no-result response succeeds with zero records. Unexpected HTML, changed column structures, wrong profession, wrong license number, login/challenge pages and repeated pagination fail rather than silently producing misleading data.

Transient network errors, 429 and selected 5xx responses receive at most two retries per request. No automatic residential proxy or browser fallback is enabled. A failed run can contain records delivered before the failure; inspect run status before relying on completeness.

### Integrations

- Export snapshots to a spreadsheet for credentialing review.
- Join `licenseNumber` to your internal provider roster; never join by name alone when identities may collide.
- Use an Apify webhook after a successful scheduled Task to download results into your warehouse.
- Compare `licenseStatus` and `expirationDate` between snapshots in your own pipeline. The Actor does not implement historical storage or notifications.

### API access

Set your own `APIFY_TOKEN` securely and run:

```bash
curl -X POST -H "Authorization: Bearer $APIFY_TOKEN" \
  -H 'Content-Type: application/json' \
  'https://api.apify.com/v2/acts/automation-lab~michigan-medical-license-records/run-sync-get-dataset-items' \
  -d '{"queries":[{"lastName":"Smith"}],"maxItems":10}'
```

JavaScript:

```javascript
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('automation-lab/michigan-medical-license-records')
  .call({ queries: [{ lastName: 'Smith' }], maxItems: 10 });
const { items } = await client.dataset(run.defaultDatasetId).listItems();
```

Python:

```python
import os
from apify_client import ApifyClient
client = ApifyClient(os.environ['APIFY_TOKEN'])
run = client.actor('automation-lab/michigan-medical-license-records').call(
    run_input={'queries': [{'lastName': 'Smith'}], 'maxItems': 10})
items = client.dataset(run['defaultDatasetId']).list_items().items
```

### MCP setup

For Claude Code:

```bash
claude mcp add --transport http apify \
  "https://mcp.apify.com?tools=automation-lab/michigan-medical-license-records"
```

Claude Desktop, Cursor, and VS Code clients supporting HTTP MCP can use this endpoint configuration, with authentication configured securely in their client:

```json
{
  "mcpServers": {
    "apify": {
      "url": "https://mcp.apify.com?tools=automation-lab/michigan-medical-license-records"
    }
  }
}
```

Example prompts: “Find up to 10 Michigan Medical Doctor licenses with surname Smith” or “Look up Michigan license 4301010722 and return its regulator status and expiration.” Availability through hosted MCP depends on platform exposure and authentication.

### Legality, responsible use and data handling

This independent Actor is not affiliated with or endorsed by Michigan LARA, MiPLUS or Apify. Source names are used to identify the records. Apify's standard terms apply; no additional custom end-user terms are imposed.

The Actor processes publicly accessible practitioner names, license identifiers, status and dates. Use records for lawful credential verification; do not treat public availability as permission for discriminatory use or unsolicited marketing. Verify consequential decisions against the official regulator and obtain certified verification when required.

No AI is used during extraction, and no input or record is sent to an AI provider. The only external source requests go to Michigan's Accela portal. Execution, logs and results use Apify infrastructure. Session cookies remain in memory only and are discarded at run termination. The Actor writes no persistent cross-run cache.

Results remain in your run's Apify storage under your account's retention settings until expired or deleted; this Actor does not set a custom retention period. Delete datasets, run storage and logs through Apify when no longer needed. Names and license identifiers are intentional dataset fields, not log content. Do not publish datasets unnecessarily.

### FAQ

**Does this verify every physician in Michigan?** No. It queries the regulator's Medical Doctor category and returns a limited snapshot of the requested searches.

**Why are the name components null for an exact number?** The single-result detail page supplies only a full name. The Actor does not infer how that name should be split.

**Does an empty expiration imply an active license?** No. Null means the regulator did not display that date.

**Can I monitor changes?** Schedule recurring Apify Tasks and compare their outputs externally; alerts and historical diffs are not built in.

**Where can I report an issue?** Use the Actor's Apify Store Issues tab and include the input and run link, without secrets.

### Related Actors

For complementary identity data, use [NPPES NPI Registry Provider Search](https://apify.com/automation-lab/npi-registry-provider-search). NPI taxonomy license identifiers do not replace Michigan regulator status. For a different jurisdiction's official roster, see [West Virginia Physician License Roster](https://apify.com/automation-lab/west-virginia-physician-license-roster).

# Changelog

This Actor's version history is a separate document: https://apify.com/automation-lab/michigan-medical-license-records/changelog.md

# Actor input Schema

## `queries` (type: `array`):

Provide 1–25 objects containing exactly one lastName or licenseNumber. Names are trimmed and sent to the regulator's surname search; matching semantics are controlled by MiPLUS, not an Actor substring filter. License numbers must be exactly 10 digits and returned numbers are verified for equality. Searches run in order; duplicate licenses are emitted once across the run. All queries are restricted to Medical Doctor, excluding limited/educational categories and osteopathic physicians.

## `maxItems` (type: `integer`):

Global maximum of unique Medical Doctor licenses across all queries, after deduplication. Defaults to 20; accepts 1–1000. Zero and unlimited are unsupported. Pagination stops once the limit is reached or the upstream result set ends; the source may impose its own coverage limits.

## Actor input object example

```json
{
  "queries": [
    {
      "lastName": "Smith"
    }
  ],
  "maxItems": 20
}
```

# Actor output Schema

## `dataset` (type: `string`):

Default dataset containing normalized licenses, provenance and query context.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "queries": [
        {
            "lastName": "Smith"
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("automation-lab/michigan-medical-license-records").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "queries": [{ "lastName": "Smith" }] }

# Run the Actor and wait for it to finish
run = client.actor("automation-lab/michigan-medical-license-records").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "queries": [
    {
      "lastName": "Smith"
    }
  ]
}' |
apify call automation-lab/michigan-medical-license-records --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,automation-lab/michigan-medical-license-records"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/GcOTiYY9k7vrHhGNd/builds/VaQ3qFkXt318lbkJL/openapi.json
