# Texas Pharmacy License Lookup Scraper (`automation-lab/texas-pharmacy-license-lookup`) Actor

Search official Texas pharmacist, pharmacy, intern, and technician license records and export status, dates, public location, and disciplinary indicators.

- **URL**: https://apify.com/automation-lab/texas-pharmacy-license-lookup.md
- **Developed by:** [Stas Persiianenko](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

Pay per event

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/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Texas Pharmacy License Lookup Scraper

Search and export official Texas State Board of Pharmacy (TSBP) records for pharmacists, pharmacy facilities, pharmacist interns, pharmacy technicians, and technician trainees.

The Actor turns the four public daily TSBP license tables into consistent JSON records for credential verification, compliance review, recruiting, and scheduled status checks. A **texas pharmacy license lookup** can target an exact license number, a city, a name, a status, an expiration cutoff, or the public disciplinary-action indicator.

### What does this Texas pharmacy license lookup extract?

Each run downloads only the official license categories you select, processes records as a stream, applies your filters, and saves matching records to the default Apify dataset.

You can use it to:

- verify one pharmacy or individual license;
- find active pharmacy facilities in a city;
- review licenses approaching an expiration cutoff;
- identify records whose TSBP disposition field indicates action;
- build scheduled credential refreshes in Apify;
- export current public records to JSON, CSV, Excel, or an API client.

The source files are updated by TSBP on business days. This Actor reports the `Last-Modified` value returned by each file, so consumers can see the source snapshot timestamp.

### Who is this Actor for?

- **Credentialing teams** checking staff or facility authorization.
- **Pharmacy operators** reviewing license status and expiry dates.
- **Recruiters** finding active pharmacists or technicians in a Texas market.
- **Compliance teams** screening public status and disposition indicators.
- **Insurers and auditors** refreshing public license evidence.
- **Data engineers** loading normalized TSBP records into a warehouse or CRM.

### Why use this Actor?

TSBP publishes separate CSV layouts for pharmacists, pharmacies, interns, and technicians. Their column names and category-specific fields differ.

This Actor provides:

- one normalized output shape across all four categories;
- streaming parsing instead of loading all large files into memory;
- exact and combined filters before records are saved;
- ISO-formatted issue and expiration dates;
- explicit active/inactive normalization while preserving the source status;
- public-address privacy handling for values marked `PRIVATE`;
- bounded retries for transient download failures;
- direct HTTPS access with no browser, proxy, login, or API key.

### Official data sources

| License type | Official TSBP file | Typical contents |
| --- | --- | --- |
| `pharmacist` | `phtdsk.csv` | Pharmacist identity, license status, dates, location, education, and disposition indicator |
| `pharmacy` | `phydsk.csv` | Facility identity, status, dates, address, phone, class, type, ownership, and responsible pharmacist |
| `intern` | `intdsk.csv` | Intern identity, rank, status, hours, dates, location, and disposition indicator |
| `technician` | `techdsk.csv` | Technician or trainee identity, rank, status, dates, location, and disposition indicator |

The Actor uses the public downloads linked by the TSBP “Download Tables for License Verifications” page. It does not bypass authentication or access private Board systems.

### Getting started

1. Open the Actor input page.
2. Select one or more license types.
3. Add an exact license number, city, state, name keyword, or compliance filter.
4. Set `maxItems` to the maximum number of matching records you need.
5. Click **Start**.
6. Open the **License records** dataset view.
7. Export the results or connect through the Apify API.

A useful first run is:

```json
{
  "licenseTypes": ["pharmacy"],
  "cities": ["Austin"],
  "status": "active",
  "maxItems": 25
}
```

### Input parameters

| Field | Type | Default | Description |
| --- | --- | --- | --- |
| `licenseTypes` | array | all four | Categories to search: `pharmacist`, `pharmacy`, `intern`, `technician` |
| `search` | string | empty | Words matched against name, license number, city, and county |
| `licenseNumbers` | array | empty | Exact TSBP license numbers or intern file numbers |
| `cities` | array | empty | Exact city names, case-insensitive |
| `states` | array | empty | Exact state abbreviations; useful for non-resident facilities |
| `status` | string | `all` | `all`, `active`, or `inactive` |
| `disciplinary` | string | `all` | `all`, `clean`, or `disciplined` based on the public disposition field |
| `expiringBefore` | string | empty | Inclusive expiration cutoff in `YYYY-MM-DD` format |
| `maxItems` | integer | `100` | Maximum records saved across selected categories, from 1 to 10,000 |

All supplied filters are combined with AND logic. Values within `cities`, `states`, or `licenseNumbers` are alternatives.

### Search examples

#### Verify one pharmacy license

```json
{
  "licenseTypes": ["pharmacy"],
  "licenseNumbers": ["33239"],
  "maxItems": 1
}
```

#### Find active technicians in Houston

```json
{
  "licenseTypes": ["technician"],
  "cities": ["Houston"],
  "status": "active",
  "maxItems": 100
}
```

#### Review pharmacist discipline and expiry indicators

```json
{
  "licenseTypes": ["pharmacist"],
  "disciplinary": "disciplined",
  "expiringBefore": "2027-12-31",
  "maxItems": 25
}
```

### Output fields

| Field | Meaning |
| --- | --- |
| `licenseNumber` | TSBP license number or intern file number |
| `entityNumber` | Public TSBP entity identifier |
| `licenseType` | Normalized category |
| `rank` | Intern, technician, or trainee rank when supplied |
| `fullName` | Combined person name or pharmacy name |
| `firstName`, `middleName`, `lastName`, `suffix` | Person-name components |
| `formerLastName` | Former name when the source publishes it |
| `pharmacyName` | Facility name for pharmacy records |
| `status` | Status exactly as TSBP publishes it |
| `statusCategory` | Normalized `active` or `inactive` category |
| `issueDate`, `expirationDate` | ISO date values |
| `disciplinaryAction` | Boolean derived from the public disposition-action indicator |
| `address1`, `address2`, `city`, `state`, `zip` | Public location fields |
| `county`, `country`, `phone` | Additional public location/contact fields |
| `pharmacyClass`, `ownership`, `pharmacyType` | Pharmacy facility classifications |
| **pharmacistInCharge** | Published responsible-pharmacist name |
| **pharmacistInChargeLicenseNumber** | Published responsible pharmacist's license number |
| `sourceFile`, `sourceUrl` | Official file provenance |
| `sourceUpdatedAt` | Official source `Last-Modified` timestamp |
| `retrievedAt` | Actor retrieval timestamp |

Fields that do not apply to a category are `null`.

### Example output

This abbreviated record reflects the current output shape:

```json
{
  "licenseNumber": "33239",
  "entityNumber": "1098834",
  "licenseType": "pharmacy",
  "fullName": "CHRISTUS MOTHER FRANCES HOSPITAL - CANTON",
  "pharmacyName": "CHRISTUS MOTHER FRANCES HOSPITAL - CANTON",
  "status": "Active",
  "statusCategory": "active",
  "issueDate": "2020-05-12",
  "expirationDate": "2028-05-31",
  "disciplinaryAction": false,
  "city": "CANTON",
  "state": "TX",
  "zip": "75103",
  "sourceFile": "phydsk.csv",
  "sourceUrl": "https://www.pharmacy.texas.gov/downloads/phydsk.csv"
}
```

### How much does it cost to look up Texas pharmacy licenses?

The Actor uses pay-per-event pricing:

- the one-time `start` event is **$0.00005** per run;
- at the BRONZE tier, the `item` event is **$0.002** per matching license record;
- item rates decrease at higher usage tiers, from **$0.0023** at FREE through **$0.00056** at DIAMOND.

A one-record verification emits one start event and one item event. A 25-record compliance review emits one start event and 25 item events. A 100-record market export emits one start event and 100 item events. No item event is emitted for source rows rejected by filters, duplicate output, failed downloads, or empty results.

For cost control, set `maxItems` to the records you actually need and select only relevant license categories. The Apify pricing panel applies your current usage tier and is the source of truth.

### Scheduled credential verification

Create an Apify schedule with the same exact-license input to refresh credential evidence daily, weekly, or monthly.

A downstream automation can:

1. fetch the newest dataset;
2. match on `licenseType` plus `licenseNumber`;
3. compare `status`, `expirationDate`, and `disciplinaryAction` with the prior snapshot;
4. notify a reviewer when those values change;
5. retain run and source timestamps for an audit trail.

The Actor returns current snapshots. It does not itself store historical comparisons or send alerts.

### Data pipeline integration

Use Apify integrations to send results to Google Sheets, Zapier, Make, webhooks, or cloud storage.

Recommended stable key:

```text
licenseType + ":" + licenseNumber
```

Do not key only on `entityNumber` unless your own testing confirms that it fits your retention model.

### Run with the Apify API using cURL

```bash
curl -X POST \
  "https://api.apify.com/v2/acts/automation-lab~texas-pharmacy-license-lookup/runs?token=$APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "licenseTypes": ["pharmacy"],
    "cities": ["Austin"],
    "status": "active",
    "maxItems": 25
  }'
```

For a synchronous response, use the `run-sync-get-dataset-items` endpoint when the requested timeout fits your client.

### Run with JavaScript

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

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('automation-lab/texas-pharmacy-license-lookup').call({
    licenseTypes: ['pharmacy'],
    licenseNumbers: ['33239'],
    maxItems: 1,
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items[0]);
```

### Run with Python

```python
from apify_client import ApifyClient

client = ApifyClient(token="YOUR_APIFY_TOKEN")
run = client.actor("automation-lab/texas-pharmacy-license-lookup").call(run_input={
    "licenseTypes": ["pharmacist"],
    "status": "active",
    "cities": ["Dallas"],
    "maxItems": 50,
})

for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item["licenseNumber"], item["status"])
```

### Use with MCP and AI agents

Add this Actor to Claude Code through Apify MCP:

```bash
claude mcp add --transport http apify \
  "https://mcp.apify.com?tools=automation-lab/texas-pharmacy-license-lookup"
```

#### Claude Desktop, Cursor, and VS Code setup

Use this equivalent JSON configuration in Claude Desktop, Cursor, or VS Code:

```json
{
  "mcpServers": {
    "apify": {
      "url": "https://mcp.apify.com?tools=automation-lab/texas-pharmacy-license-lookup"
    }
  }
}
```

Example prompts:

- “Verify Texas pharmacy license 33239 and summarize its current status and expiration.”
- “Find up to 50 active pharmacy facilities in Austin from the official TSBP data.”
- “Return pharmacist records with a public disciplinary indicator expiring through 2027.”

### Performance and limits

- TSBP files are large; a narrow filter may still require scanning an entire selected file.
- The Actor downloads selected files sequentially to stay within its conservative memory allocation.
- `maxItems` stops output once enough matching records are found.
- TSBP controls source availability, layout, content, and update timing.
- A no-result run is successful when no current source row matches all filters.
- A malformed input or unavailable/invalid source response fails the run rather than returning misleading empty data.
- Direct downloads are used; proxy configuration is neither needed nor exposed.

### Troubleshooting

#### Why did my run return no records?

Check that all filters can be true at the same time. City and state matches are exact except for letter case. Try removing one filter or using `status: "all"`.

#### Why does a record have null address fields?

Some categories omit a field, and TSBP marks some individual addresses as `PRIVATE`. The Actor converts that marker to `null` instead of publishing it as an address.

#### Why did a run fail during download?

The Actor retries transient network errors, HTTP 429, and temporary server errors. A persistent source failure is surfaced as a failed run so scheduled workflows can retry or alert correctly.

#### Does the disciplinary flag describe the order?

No. It reflects only the disposition-action indicator in the public table. Consult official TSBP records for order details and legal interpretation.

### Responsible use and legal notes

The Actor processes public licensing tables supplied by the Texas State Board of Pharmacy. Use the data for lawful verification, compliance, research, and operational purposes.

- Follow TSBP terms, notices, and applicable law.
- Verify material decisions against the current official record.
- Do not treat the disposition indicator as a complete disciplinary history.
- Do not infer protected characteristics or use public personal data for harassment.
- Apply appropriate access controls and retention rules to exported datasets.

This Actor is an independent automation tool and is not affiliated with or endorsed by TSBP.

### FAQ

#### Does the Actor cover all four TSBP license tables?

Yes: pharmacists, pharmacy facilities, pharmacist interns, and pharmacy technicians/trainees.

#### Can it look up one license number?

Yes. Set `licenseNumbers` and select the relevant `licenseTypes` value.

#### Can it search several categories in one run?

Yes. Results share one normalized schema in the default dataset.

#### Is a browser or proxy required?

No. The official public CSV files are downloaded directly over HTTPS.

#### Are source records real-time?

No. TSBP controls publication and says its verification databases are updated on business days. Inspect `sourceUpdatedAt` for the file timestamp returned during your run.

#### Does the Actor monitor changes automatically?

Use an Apify schedule and compare successive datasets in your workflow. The Actor produces the current snapshot but does not retain or compare prior runs.

#### Can I export to CSV or Excel?

Yes. Apify datasets support JSON, CSV, Excel, XML, and other export formats.

### Related automation-lab Actors

- [Texas Insurance License Lookup](https://apify.com/automation-lab/texas-insurance-license-lookup) for Texas producer and agency verification.
- [Texas TREC License Holder Search Scraper](https://apify.com/automation-lab/texas-trec-license-holder-search-scraper) for Texas real-estate and inspector license records.
- [Florida DBPR License Verification Scraper](https://apify.com/automation-lab/florida-dbpr-license-verification-scraper) for Florida professional and business credentials.

Use separate Actors when the regulator, record type, or required compliance fields differ. This Actor is intentionally specific to official Texas pharmacy licensing data.

# Actor input Schema

## `licenseTypes` (type: `array`):

TSBP record categories to search. Leave all selected to search every official table.

## `search` (type: `string`):

Case-insensitive words matched against licensee or pharmacy name, license number, city, and county.

## `licenseNumbers` (type: `array`):

Optional exact TSBP license or intern file numbers.

## `cities` (type: `array`):

Optional exact city names, matched without regard to case.

## `states` (type: `array`):

Optional exact state abbreviations, such as TX. Useful for filtering non-resident pharmacies.

## `status` (type: `string`):

Return all records, active licenses only, or all non-active statuses.

## `disciplinary` (type: `string`):

Filter on the public TSBP disposition-action indicator. This flag does not include order details.

## `expiringBefore` (type: `string`):

Optional inclusive license expiration cutoff in YYYY-MM-DD format.

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

Maximum matching records saved across all selected license types.

## Actor input object example

```json
{
  "licenseTypes": [
    "pharmacy"
  ],
  "cities": [
    "Austin"
  ],
  "status": "active",
  "disciplinary": "all",
  "maxItems": 20
}
```

# Actor output Schema

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

Dataset containing all matching normalized license records.

# 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 = {
    "licenseTypes": [
        "pharmacy"
    ],
    "cities": [
        "Austin"
    ],
    "status": "active",
    "maxItems": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("automation-lab/texas-pharmacy-license-lookup").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 = {
    "licenseTypes": ["pharmacy"],
    "cities": ["Austin"],
    "status": "active",
    "maxItems": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("automation-lab/texas-pharmacy-license-lookup").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 '{
  "licenseTypes": [
    "pharmacy"
  ],
  "cities": [
    "Austin"
  ],
  "status": "active",
  "maxItems": 20
}' |
apify call automation-lab/texas-pharmacy-license-lookup --silent --output-dataset

```

## MCP server setup

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

```

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/Wdjjm43emjzFFWryS/builds/CHWHIvb3AVM3DPo93/openapi.json
