# TDLR Texas Contractor & Trade License Scraper (`ws_tony/tdlr-texas-contractor-license-scraper`) Actor

Search TDLR Texas contractor and trade licenses — electrician, elevator, A/C, mold remediation, water well, cosmetology, and 80+ other types. Returns full business address, phone, owner contact, and live Active/Expired/Revoked status.

- **URL**: https://apify.com/ws\_tony/tdlr-texas-contractor-license-scraper.md
- **Developed by:** [Tony](https://apify.com/ws_tony) (community)
- **Categories:** Lead generation
- **Stats:** 2 total users, 1 monthly users, 50.0% runs succeeded, NaN bookmarks
- **User rating**: No ratings yet

## Pricing

from $19.00 / 1,000 results

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

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

## What's an Apify Actor?

Actors are a software tools running on the Apify platform, for all kinds of web data extraction and automation use cases.
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.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/platform/integrations/mcp.md).

If your project is in a different language, use 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

## TDLR Texas Contractor & Trade License Scraper

Pull licensed Texas Department of Licensing and Regulation (TDLR) contractor and trade businesses — **Electrical Contractors, Elevator Contractors, Appliance Installation Contractors, Electrical Sign Contractors, Water Well Drillers, Service Contract Providers, cosmetology establishments, and more** — with **full business address, phone, owner contact, and live Active / Expired / Revoked status**.

Other TDLR actors scrape the public search form and return a thin record (name, county, license #). This one combines the **state's own Open Data API** (full address, phone, mailing contact, geocoded lat/lon — for the ~108k business-entity licenses where the state publishes contact info) with a **live lookup against tdlr.texas.gov** for the current license status the API doesn't expose. You get the rich business dataset *and* a current status check on every record.

---

### Who this is for

**Sales teams selling to Texas contractors.** HVAC equipment vendors, electrical supply distributors, software vendors, marketing agencies — every business-entity license ships with line-1 address, county, and phone. Filter to a county or ZIP prefix and you have a clean, deduplicated territory list ready for the CRM.

**Underwriters and verification services.** Insurance carriers, lien-search providers, and procurement teams who need to confirm a contractor's license is currently active before a deal closes. Pass a list of license numbers in `licenseNumbers` and get back live status from `tdlr.texas.gov` for each — much cheaper than building and maintaining your own scraper.

**Renewal-monitoring services.** Schedule a weekly run with `expirationDateTo` set to today + 60 days to catch every license about to lapse. Powers renewal-reminder businesses, supplier-compliance teams, and trade-association membership programs.

**Recruiters and staffing firms.** Filter by license type and county to surface every Master Electrician, Journeyman, A/C Technician, or other licensed tradesperson in a target metro.

**Researchers and analysts.** The county / city / ZIP filters and the structured output make Texas trade-license demographics, regional density studies, and competitive analysis trivial.

---

### What you get

One JSON object per license, pushed to the Apify dataset. A sample of four records covering an Electrical Contractor, Appliance Installation Contractor, Elevator Contractor (non-enrichable — `source: "socrata"`), and a cosmetology Full Service Establishment with a DBA is in [`example_output.json`](example_output.json). Single-record preview (Appliance Installation Contractor, enriched mode):

```json
{
  "license_number": "641",
  "license_type_code": "AIRREF",
  "license_type": "Appliance Installation Contractor",
  "license_subtype": "RAIC",
  "license_status": "Active",
  "license_status_raw": "Active",
  "expiration_date": "2026-04-19",
  "original_issue_date": "2015-03-17",
  "continuing_education_flag": false,
  "business_name": "POOL CARE SPECIALISTS",
  "dba": null,
  "owner_name": "POOL CARE SPECIALISTS",
  "business_address": {
    "line1": "STE 107123",
    "line2": "2201 LONG PRAIRIE RD",
    "city": "FLOWER MOUND",
    "state": "TX",
    "zip": "75022",
    "county": "DENTON"
  },
  "business_phone": "+1-972-829-8485",
  "mailing_address": {
    "line1": "STE 107123",
    "line2": "2201 LONG PRAIRIE RD",
    "city": "FLOWER MOUND",
    "state": "TX",
    "zip": "75022-4832",
    "county": "DENTON"
  },
  "owner_phone": "+1-972-829-8485",
  "endorsement": null,
  "location": { "latitude": 33.0264, "longitude": -97.0811 },
  "location_precision": "address",
  "source": "socrata+live",
  "source_url": "https://www.tdlr.texas.gov/LicenseSearch/SearchResultDetail.asp?1=ACTELE00000641&2=RAIC",
  "scraped_at": "2026-04-22T21:40:00.000Z"
}
````

#### Field reference

| Field | Type | Notes |
|---|---|---|
| `license_number` | string | Primary key (composite with `license_type_code`) |
| `license_type_code` | string | null | Canonical TDLR short code (e.g. `ELCTRC`) |
| `license_type` | string | Spelled-out name (e.g. `Electrical Contractor`) |
| `license_subtype` | string | null | Subtype code (distinguishes Master/Journeyman/etc. on same type\_code) |
| `license_status` | enum | null | `Active` / `Expired` / `Canceled` / `Revoked` / `Suspended` / `Other`. Verified live from tdlr.texas.gov when possible; otherwise inferred from `expiration_date` (Active / Expired only). Check `source` to tell which |
| `license_status_raw` | string | null | Raw status text from the live lookup. `null` when status was inferred from expiration date |
| `expiration_date` | ISO date | `YYYY-MM-DD`. Verified live from tdlr.texas.gov in enriched mode; falls back to the Socrata value (refreshed weekly) when the live page can't be parsed. In `api_only` mode always uses the Socrata value, which can lag the live site by up to 7 days for recently-renewed licenses |
| `original_issue_date` | ISO date | null | Enriched mode only |
| `continuing_education_flag` | boolean | |
| `business_name` / `owner_name` | string | |
| `business_address` / `mailing_address` | object | fields null | `{ line1, line2, city, state, zip, county }` |
| `business_phone` / `owner_phone` | string | null | E.164 where possible |
| `endorsement` | string | null | For license types that have endorsements |
| `location` | object | `{ latitude, longitude }` from the state's geocoded business address; both fields `null` if not published |
| `location_precision` | string | null | `"address"` (real geocode), `"city"` (state's geocoder fell back to a city centroid — every record in that city shares the same coords), or `null`. Filter on `"address"` for radius-search use cases |
| `source` | `"socrata"` | `"socrata+live"` | Which data sources contributed |
| `source_url` | string | null | Direct deep-link to tdlr.texas.gov |
| `scraped_at` | ISO timestamp | |

***

### Coverage: which license types come back with full contact info?

The state's Open Data dataset publishes **business addresses for business-entity license types** and leaves **individual licenses** with just name + county + license #. Use `requireBusinessAddress: true` to filter to only the rich rows.

**Business entities with full address + phone** (~108k records total):

| License type | Records with full contact |
|---|---|
| Full Service Establishment (cosmetology) | 35,399 |
| Mini Establishment (cosmetology) | 21,883 |
| Electrical Contractor | 13,796 |
| Devices (motor fuel) | 13,384 |
| Manicurist/Esthetician Establishment | 7,721 |
| Esthetician Establishment | 4,681 |
| Water Well Driller/Pump Installer | 1,170 |
| Manicurist Establishment | 868 |
| Appliance Installation Contractor | 828 |
| Used Auto Parts Recycler | 731 |
| Eyelash Extension Establishment | 668 |
| Cosmetology Private School | 648 |
| Electrical Sign Contractor | 646 |
| Registered Accessibility Specialist | 633 |
| Service Contract Provider | 572 |
| Professional Employer Organization | 428 |
| Elevator Contractor | 360 |
| …and others |  |

**Individual licenses** (thin records — name, county, license #, live status only): A/C Contractor (20,167), A/C Technician (58,095), Journeyman Electrician (44,155), Master Electrician (19,572), Apprentice Electrician, Residential Wireman, cosmetologists, barbers, combative sports contestants, athletic trainers, midwives, dietitians, massage therapists, dyslexia practitioners, and most other person-held licenses.

This is a Texas-side regulatory choice — TDLR publishes business addresses but not individuals' home addresses. When you need contact info, filter on `requireBusinessAddress: true`.

***

### Quick start — three common jobs

#### 1. Every active Electrical Contractor business in the Houston area (full contact)

```json
{
  "licenseTypes": ["Electrical Contractor"],
  "counties": ["HARRIS", "FORT BEND", "MONTGOMERY"],
  "activeOnly": true,
  "requireBusinessAddress": true,
  "searchMode": "enriched",
  "maxResults": 5000
}
```

#### 2. Every licensed contractor business in Texas expiring in the next 90 days

```json
{
  "licenseTypes": [
    "Electrical Contractor",
    "Electrical Sign Contractor",
    "Elevator Contractor",
    "Appliance Installation Contractor",
    "Water Well Driller/Pump Installer",
    "Service Contract Provider"
  ],
  "expirationDateFrom": "2026-04-22",
  "expirationDateTo": "2026-07-22",
  "activeOnly": true,
  "requireBusinessAddress": true,
  "searchMode": "enriched",
  "maxResults": 10000
}
```

#### 3. Every individual Master Electrician (thin records, live status)

```json
{
  "licenseTypes": ["Master Electrician", "Journeyman Electrician"],
  "activeOnly": true,
  "requireBusinessAddress": false,
  "searchMode": "enriched",
  "maxResults": 5000
}
```

***

### Input reference

See the run-form descriptions on each field; highlights:

- **`searchMode`** — `enriched` (default) adds a live tdlr.texas.gov lookup per result for current status, original issue date, and endorsement. `api_only` skips enrichment (cheaper, faster, no live status).
- **`licenseTypes`** — exact Socrata license type names. Leave empty for all 85+ types. See the coverage table above.
- **`requireBusinessAddress`** — set `true` to get only records with full address/phone; `false` (default) to include everything.
- **`businessNameContains` / `ownerNameContains`** — case-insensitive substring filters.
- **`activeOnly`** — drop Expired/Canceled/Revoked/Suspended. In enriched mode uses the live status; in API-only uses `expiration_date >= today`.
- **`maxResults`** — hard cap; every record pushed is billable.
- **`maxConcurrency`** — only matters in enriched mode. Default 10 is polite.

***

### How the data is sourced

1. **Bulk data:** [`data.texas.gov/resource/7358-krk7.json`](https://data.texas.gov/resource/7358-krk7.json) — the state's own open-data publication, *"TDLR - All Licenses"*, ~962k rows total (~108k with full business contact info), updated weekly.
2. **Live status:** `https://www.tdlr.texas.gov/LicenseSearch/SearchResultDetail.asp` — the public license detail page. The correct URL prefix is subtype-specific (e.g. Electrical Contractor → `EECELE`, Appliance Installation Contractor → `ACTELE`, Full Service Establishment → `COSSHP`). The actor resolves the URL per record by POSTing to the site's own search form and following the redirect, so new license subtypes keep working without maintenance. Source of `license_status`, `expiration_date`, `original_issue_date`, and `endorsement` in enriched mode — using the live page for these fields keeps the output current with the site (Socrata refreshes weekly and can lag real-world renewals).

Both sources are public. No authentication bypass. Live-status requests are rate-limited by the `maxConcurrency` input.

***

### Data freshness and accuracy

**Bulk data refreshes weekly.** Socrata syncs from TDLR's authoritative database every ~7 days. A license that renewed yesterday may show its old expiration date in `api_only` mode. In `enriched` mode the live `tdlr.texas.gov` lookup overrides the Socrata value, so you always get the current expiration and status as of the moment the actor ran.

**Geolocation precision is mixed.** The state geocoder occasionally falls back to a city centroid when it can't resolve a specific street address — e.g. Houston's centroid (29.76078, -95.36952) shows up on every record where the geocoder couldn't pin a Houston street. The `location_precision` field tells you which is which: `"address"` for real geocodes, `"city"` for centroid fallbacks, `null` when no location was published. **Filter on `location_precision === "address"` for any use case that depends on per-record coordinates** — radius search, mapping, distance ranking. City-precision records still have signal for city-level mapping.

**Out-of-Texas geocodes are dropped.** A few licensee records geocode to the wrong state (Pasadena, CA instead of Pasadena, TX is the classic). Those are nulled out rather than shipped as bad data.

***

### FAQ

**How do I export to Excel or CSV?**
Apify ships every dataset as JSON, CSV, Excel, RSS, or HTML directly from the run page — no extra step. The actor comes pre-configured with an `Overview` view that surfaces the most useful columns for spreadsheet work.

**Can I run this on a schedule?**
Yes. Apify Schedules can run this actor daily, weekly, or monthly with the same inputs. A common pattern: a weekly run with `expirationDateTo` set to today + 60 days, feeding a renewal-watch list. Pair it with the `Notify on finish` setting to get an email or webhook when each run completes.

**Can I use this data for marketing outreach?**
TDLR licensee data is **public record** under the Texas Public Information Act (Government Code Chapter 552), and this actor accesses only public state endpoints. When using the data for outreach, you remain responsible for honoring federal TCPA rules and Texas's own Telephone Solicitation Act — DNC compliance, written-consent requirements, and call-time-of-day limits are on you.

**Does this include bonds, insurance, or complaint/enforcement history?**
No. TDLR doesn't publish bond, insurance, or complaint data in a machine-readable form on its license search or Open Data portal — that information is only available by Texas Public Information Act request.

**Why two direct TDLR competitors on the Apify Store?**
They scrape the public search form only, so they return the thin fields the form exposes (name, county, license #, status, expiration). They miss the full address, phone, mailing info, owner contact, and geocoded lat/lon that the state's Open Data API publishes for business-entity licenses.

**Does `license_number` uniquely identify a license?**
No — the same license number can recur across (and within) license types. For example, Service Contract Provider #109 belongs to two separate businesses under subtypes `PROVIDER` and `ADMIN`. The unique composite key is `(license_type_code, license_number, license_subtype)`. Buyers deduplicating across runs should key on all three.

**Pricing?**
Per-result. Every fully-formed record pushed to the dataset counts.

***

### Changelog

**0.1.1** — Added `location_precision` field (`"address"` / `"city"` / `null`) so buyers can distinguish real geocodes from the state geocoder's city-centroid fallbacks. Stopped routing Socrata calls through Apify Proxy (the public Open Data API throttles shared datacenter IPs); proxy is still used for live `tdlr.texas.gov` enrichment. Hardened got-scraping retries against transient upstream 5xx.

**0.1.0** — Initial release. Hybrid Socrata + live-status enrichment. 85+ license types supported; 17 business-entity types carry full contact info.

# Actor input Schema

## `searchMode` (type: `string`):

Enriched adds the live Active / Expired / Revoked status from tdlr.texas.gov for every result — slower and more expensive but gives you fields the state's bulk data doesn't include. API-only is pure bulk data: cheapest, fastest, no live status.

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

Only return licenses matching these types. Leave empty to include every TDLR license type. Use exact Socrata names. Types with full business address + phone: 'Electrical Contractor', 'Electrical Sign Contractor', 'Elevator Contractor', 'Appliance Installation Contractor', 'Service Contract Provider', 'Water Well Driller/Pump Installer', 'Full Service Establishment', 'Mini Establishment', 'Manicurist/Esthetician Establishment', 'Esthetician Establishment'. Types with thin records (name + county only): 'A/C Contractor', 'A/C Technician', 'Journeyman Electrician', 'Master Electrician', 'Residential Wireman'.

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

Look up specific license numbers directly. When provided, filters above still apply — use this together with a licenseTypes entry to disambiguate (the same number can exist across different license types).

## `businessNameContains` (type: `string`):

Case-insensitive substring filter on the business name. Example: 'HVAC'. Note: the state search also matches owner/personnel names — a hit on 'SMITH' can surface business 'Acme Inc.' with owner John Smith.

## `ownerNameContains` (type: `string`):

Case-insensitive substring filter on the owner's name (last, first). Example: 'MURPHY, DAVID'.

## `counties` (type: `array`):

Filter by business county. Use full uppercase names: HARRIS, BEXAR, TRAVIS, DALLAS, TARRANT, etc.

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

Filter by business city (case-insensitive). Matches the city portion of 'CITY, STATE ZIP'.

## `zipPrefix` (type: `string`):

Business ZIP code prefix. '77' returns all Houston-area ZIPs; '78704' matches one specific ZIP. Max 5 digits.

## `requireBusinessAddress` (type: `boolean`):

When true, drops all records that don't have a business address in the state's open-data dataset. That filters to ~108k business-entity licenses (Electrical Contractor, Elevator Contractor, Appliance Installation Contractor, cosmetology establishments, etc.) — every returned record has full address + phone. Keep off to also include individual licenses (A/C Contractor, journeymen, technicians) which only have name + county.

## `expirationDateFrom` (type: `string`):

Earliest license expiration date (inclusive). Format: YYYY-MM-DD.

## `expirationDateTo` (type: `string`):

Latest license expiration date (inclusive). Format: YYYY-MM-DD.

## `activeOnly` (type: `boolean`):

Drop licenses that are Expired, Canceled, Revoked or Suspended. In enriched mode this uses the live site status; in API-only mode it uses expiration\_date >= today as an approximation.

## `continuingEducationFlag` (type: `string`):

Filter by whether the license has a continuing-education flag set in the bulk data.

## `maxResults` (type: `integer`):

Hard cap on records pushed to the dataset. Protects your account from runaway costs. Every returned record is a billable result under the per-result pricing model.

## `proxyConfiguration` (type: `object`):

Apify Proxy (datacenter) is fine for TDLR. Only enable residential if you see a block rate.

## `maxConcurrency` (type: `integer`):

Parallel enrichment requests to tdlr.texas.gov. Higher = faster but more likely to trigger rate limiting.

## Actor input object example

```json
{
  "searchMode": "enriched",
  "licenseTypes": [],
  "licenseNumbers": [],
  "counties": [],
  "cities": [],
  "requireBusinessAddress": false,
  "activeOnly": true,
  "continuingEducationFlag": "any",
  "maxResults": 1000,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": []
  },
  "maxConcurrency": 10
}
```

# 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": [],
    "licenseNumbers": [],
    "counties": [],
    "cities": [],
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": []
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("ws_tony/tdlr-texas-contractor-license-scraper").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": [],
    "licenseNumbers": [],
    "counties": [],
    "cities": [],
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": [],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("ws_tony/tdlr-texas-contractor-license-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).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": [],
  "licenseNumbers": [],
  "counties": [],
  "cities": [],
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": []
  }
}' |
apify call ws_tony/tdlr-texas-contractor-license-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=ws_tony/tdlr-texas-contractor-license-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "TDLR Texas Contractor & Trade License Scraper",
        "description": "Search TDLR Texas contractor and trade licenses — electrician, elevator, A/C, mold remediation, water well, cosmetology, and 80+ other types. Returns full business address, phone, owner contact, and live Active/Expired/Revoked status.",
        "version": "0.1",
        "x-build-id": "J8KI6xgYlVDOGCKbz"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/ws_tony~tdlr-texas-contractor-license-scraper/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-ws_tony-tdlr-texas-contractor-license-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/ws_tony~tdlr-texas-contractor-license-scraper/runs": {
            "post": {
                "operationId": "runs-sync-ws_tony-tdlr-texas-contractor-license-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/ws_tony~tdlr-texas-contractor-license-scraper/run-sync": {
            "post": {
                "operationId": "run-sync-ws_tony-tdlr-texas-contractor-license-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "properties": {
                    "searchMode": {
                        "title": "Search mode",
                        "enum": [
                            "enriched",
                            "api_only"
                        ],
                        "type": "string",
                        "description": "Enriched adds the live Active / Expired / Revoked status from tdlr.texas.gov for every result — slower and more expensive but gives you fields the state's bulk data doesn't include. API-only is pure bulk data: cheapest, fastest, no live status.",
                        "default": "enriched"
                    },
                    "licenseTypes": {
                        "title": "License types",
                        "uniqueItems": true,
                        "type": "array",
                        "description": "Only return licenses matching these types. Leave empty to include every TDLR license type. Use exact Socrata names. Types with full business address + phone: 'Electrical Contractor', 'Electrical Sign Contractor', 'Elevator Contractor', 'Appliance Installation Contractor', 'Service Contract Provider', 'Water Well Driller/Pump Installer', 'Full Service Establishment', 'Mini Establishment', 'Manicurist/Esthetician Establishment', 'Esthetician Establishment'. Types with thin records (name + county only): 'A/C Contractor', 'A/C Technician', 'Journeyman Electrician', 'Master Electrician', 'Residential Wireman'.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "licenseNumbers": {
                        "title": "Specific license numbers",
                        "uniqueItems": true,
                        "type": "array",
                        "description": "Look up specific license numbers directly. When provided, filters above still apply — use this together with a licenseTypes entry to disambiguate (the same number can exist across different license types).",
                        "items": {
                            "type": "string"
                        }
                    },
                    "businessNameContains": {
                        "title": "Business name contains",
                        "type": "string",
                        "description": "Case-insensitive substring filter on the business name. Example: 'HVAC'. Note: the state search also matches owner/personnel names — a hit on 'SMITH' can surface business 'Acme Inc.' with owner John Smith."
                    },
                    "ownerNameContains": {
                        "title": "Owner name contains",
                        "type": "string",
                        "description": "Case-insensitive substring filter on the owner's name (last, first). Example: 'MURPHY, DAVID'."
                    },
                    "counties": {
                        "title": "Counties",
                        "uniqueItems": true,
                        "type": "array",
                        "description": "Filter by business county. Use full uppercase names: HARRIS, BEXAR, TRAVIS, DALLAS, TARRANT, etc.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "cities": {
                        "title": "Cities",
                        "uniqueItems": true,
                        "type": "array",
                        "description": "Filter by business city (case-insensitive). Matches the city portion of 'CITY, STATE ZIP'.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "zipPrefix": {
                        "title": "ZIP prefix",
                        "pattern": "^[0-9]{0,5}$",
                        "type": "string",
                        "description": "Business ZIP code prefix. '77' returns all Houston-area ZIPs; '78704' matches one specific ZIP. Max 5 digits."
                    },
                    "requireBusinessAddress": {
                        "title": "Only return licenses with a business address (recommended for lead-gen)",
                        "type": "boolean",
                        "description": "When true, drops all records that don't have a business address in the state's open-data dataset. That filters to ~108k business-entity licenses (Electrical Contractor, Elevator Contractor, Appliance Installation Contractor, cosmetology establishments, etc.) — every returned record has full address + phone. Keep off to also include individual licenses (A/C Contractor, journeymen, technicians) which only have name + county.",
                        "default": false
                    },
                    "expirationDateFrom": {
                        "title": "Expiration date from",
                        "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}$",
                        "type": "string",
                        "description": "Earliest license expiration date (inclusive). Format: YYYY-MM-DD."
                    },
                    "expirationDateTo": {
                        "title": "Expiration date to",
                        "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}$",
                        "type": "string",
                        "description": "Latest license expiration date (inclusive). Format: YYYY-MM-DD."
                    },
                    "activeOnly": {
                        "title": "Active licenses only",
                        "type": "boolean",
                        "description": "Drop licenses that are Expired, Canceled, Revoked or Suspended. In enriched mode this uses the live site status; in API-only mode it uses expiration_date >= today as an approximation.",
                        "default": true
                    },
                    "continuingEducationFlag": {
                        "title": "Continuing-education filter",
                        "enum": [
                            "any",
                            "Y",
                            "N"
                        ],
                        "type": "string",
                        "description": "Filter by whether the license has a continuing-education flag set in the bulk data.",
                        "default": "any"
                    },
                    "maxResults": {
                        "title": "Max results",
                        "minimum": 1,
                        "maximum": 100000,
                        "type": "integer",
                        "description": "Hard cap on records pushed to the dataset. Protects your account from runaway costs. Every returned record is a billable result under the per-result pricing model.",
                        "default": 1000
                    },
                    "proxyConfiguration": {
                        "title": "Proxy configuration",
                        "type": "object",
                        "description": "Apify Proxy (datacenter) is fine for TDLR. Only enable residential if you see a block rate."
                    },
                    "maxConcurrency": {
                        "title": "Max concurrency",
                        "minimum": 1,
                        "maximum": 50,
                        "type": "integer",
                        "description": "Parallel enrichment requests to tdlr.texas.gov. Higher = faster but more likely to trigger rate limiting.",
                        "default": 10
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
