# US Contractor License Leads Scraper (Multi-State) (`memo23/us-contractor-license-leads-scraper`) Actor

License-verified contractor leads across every US state board on the ARLS platform in one run — NC electrical, NC plumbing/HVAC, NC general contractors, and LA contractors (with board-published emails). Company, license #, class, status, expiry, address, phone. Full-state sweep or targeted search.

- **URL**: https://apify.com/memo23/us-contractor-license-leads-scraper.md
- **Developed by:** [Muhamed Didovic](https://apify.com/memo23) (community)
- **Categories:** Lead generation, Agents, MCP servers
- **Stats:** 1 total users, 0 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $4.00 / 1,000 license-verified contractor leads

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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.

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

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

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python/docs.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/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

## US Contractor License Leads Scraper (Multi-State)

**Every US state licensing board on the ARLS platform, in one run.** Pull license-verified contractor leads across four state boards — NC electrical, NC plumbing/HVAC/fire-sprinkler, NC general contractors, and Louisiana contractors — from a single actor. Each row carries company, license number, classification, status, expiration, mailing address, phone, and (for Louisiana) the contractor's board-published email, tagged with the board it came from. Pick the boards you want or run all four; sweep whole states or target a city, classification, company, name, or license number. JSON or CSV out, billed per lead.

#### How it works

![How US Contractor License Leads Scraper works](https://raw.githubusercontent.com/muhamed-didovic/muhamed-didovic.github.io/main/assets/how-it-works-us-contractor-leads.png)

#### ✨ Why use this scraper?

- **Four boards, one job** — instead of running four separate actors and stitching the output, pick any combination (or all) and get one merged, `boardId`-tagged dataset. Perfect for agencies and multi-state outreach.
- **License-verified, not directory-scraped** — every lead comes from the board's own registry, so license number, classification, status, and expiry are authoritative at scrape time.
- **Louisiana emails come standard** — LSLBC publishes each contractor's contact email on the record; those rows arrive outreach-ready with no enrichment. Optional `enrichEmails` recovers emails for the other boards.
- **One shared budget** — `maxItems` is total across boards, so "give me 500 leads across NC + LA" just works; boards run biggest-roster-first until the budget is spent.
- **Active-only by default** — Expired / Terminated / Not Active records are dropped before you pay for them.
- **Everything the per-state actors do** — full-state sweeps, classification filters, company/name/license/phone search, qualifier & classification-holder people, technician→employer links (plumbing), and new-license monitoring — all through one engine.
- **Zero setup** — US residential proxy is built in; every board is a public registry, no login or CAPTCHA.

#### 🗺 Boards covered

| `boardId` | Board | State | Notable |
|---|---|---|---|
| `ncbeec` | Board of Examiners of Electrical Contractors | NC | Qualifier decision-makers |
| `ncphfsc` | Plumbing, Heating & Fire Sprinkler Contractors | NC | 24 classifications; technician→employer links |
| `nclbgc` | Licensing Board for General Contractors | NC | 31 classifications; big roster |
| `lslbc` | State Licensing Board for Contractors | LA | **Board-published emails** |

*This is the complete current ARLS-platform contractor roster. New boards are added as configs the moment they appear.*

#### 🎯 Use cases

| Who | What they do with it |
|---|---|
| **Suppliers & distributors** | One call/email list of active licensed contractors across every covered state and trade |
| **SaaS & fintech selling to trades** | Feed license-verified accounts into outbound; `qualifyByPayment` flags who transacts online |
| **Insurance, bonding & lending** | Bulk-verify license status + expiration before quoting, across states |
| **Agencies & data resellers** | One run → a multi-state, board-labeled dataset to segment and deliver |
| **GCs & developers** | Verify subs' licenses in bulk from a license-number list against every board at once |

#### 📥 Supported inputs

| Mode | Input | Behaviour |
|---|---|---|
| **Board selection** | `boards: ["ncbeec", "lslbc"]` | boardId, state code (`NC` → all NC boards), or trade fragment (`electrical`). Empty = all four |
| **Full sweep** (default) | *(empty)* | Each selected board sweeps its own state's city list |
| **City sweep** | `cities: ["Charlotte", "New Orleans"]` | Exact mailing-city match, applied to every selected board |
| **Classification filter** | `classifications: ["residential"]` | Resolved per board — matches whichever boards have it |
| **Company / Name / License / Phone** | `companyNames`, `lastName`, `licenseNumbers`, `phoneNumber` | Tried on every selected board |

#### 🔄 How it works

1. **Resolves the board list** from your `boards` selection (or all four).
2. **Runs each board through one shared engine** — the engine adapts per board (different form fields, active-detection, classification slicing, native-email parsing) from a single config, so all four run the same code path.
3. **Filters** inactive licenses and duplicates per board before any detail fetch.
4. **Fetches each license's detail** — company, address, phone, status, expiry, classifications, qualifiers/holders, and (LA) the board email.
5. **Optionally enriches** rows without a board email (website + contact-email discovery).
6. **Pushes one merged dataset** — one row per license, each tagged with `boardId`, `stateCode`, and `trade`, sharing one `maxItems` budget.

#### ⚙️ Input parameters

| Field | Type | Default | Description |
|---|---|---|---|
| `boards` | array | `[]` → all | Which boards to run (boardId / state / trade) |
| `cities` | array | `[]` → full sweep | Mailing-address cities, applied to every board |
| `classifications` | array | `[]` → all | Per-board classification filter (label / fragment / code) |
| `activeOnly` | boolean | `true` | Drop licenses not in good standing before fetching |
| `companyNames` / `lastName` / `firstName` / `licenseNumbers` / `phoneNumber` | — | — | Targeted searches, tried on every selected board |
| `enrichEmails` | boolean | `false` | Website + email discovery for rows lacking a board email |
| `qualifyByPayment` | boolean | `false` | Payment-processor detection (needs `enrichEmails`) |
| `monitoringMode` | boolean | `false` | Only licenses not delivered on previous runs (tracked per board) |
| `maxItems` | integer | `500` | Total lead cap, shared across boards |
| `maxConcurrency` / `searchConcurrency` | integer | `10` / `3` | Parallel detail fetches / roster searches |

#### 📊 Output overview

One row per license, merged into a single dataset regardless of how many boards ran. Every row carries `boardId`, `stateCode`, and `trade` so you can split or filter downstream. Fields that only some boards expose (`boardEmail`, `parentLicensees`, `classificationHolders`, `qualifiers`, `activeClassifications`) are present where the board provides them and null/empty elsewhere.

#### 📦 Output sample

Real trimmed row from a live run (Louisiana — note the native `boardEmail`):

```json
{
    "type": "license-lead",
    "boardId": "lslbc",
    "stateCode": "LA",
    "trade": "contractor",
    "boardName": "Louisiana State Licensing Board for Contractors",
    "licenseNumber": "CL.00689",
    "classification": "Commercial License Certificate",
    "businessName": "CAMUS ELECTRIC CO., INC.",
    "licenseStatus": "Active",
    "isActive": true,
    "expirationDate": "2028-03-31",
    "phone": "(318) 687-1420",
    "boardEmail": "jwallace@camuselectric.com",
    "contactEmail": "jwallace@camuselectric.com",
    "address": { "street": "…", "city": "Shreveport", "state": "LA", "zip": "…", "raw": "…" },
    "qualifiers": [],
    "classificationHolders": [],
    "searchCity": "Shreveport",
    "sourceUrl": "https://arlspublic.lslbc.louisiana.gov/Public/Search",
    "scrapedAt": "2026-07-24T…"
}
````

An NC general-contractor row instead carries `qualifiers[]` and `activeClassifications[]` (e.g. `["Building", "Residential"]`); an NC plumbing row carries `classificationHolders[]` and, for technicians, `parentLicensees[]`.

#### 🗂 Key output fields

| Group | Fields |
|---|---|
| **Provenance** | `boardId`, `boardName`, `stateCode`, `trade`, `searchCity`, `sourceUrl`, `scrapedAt` |
| **License** | `licenseNumber`, `classification`, `activeClassifications[]`, `classificationCode`, `accountType`, `licenseStatus`, `statusNote`, `isActive`, `expirationDate` |
| **Business** | `businessName`, `contactName`, `dbaName`, `phone`, `boardEmail`, `contactEmail`, `address.{street,city,state,zip,raw}` |
| **People** | `qualifiers[]`, `classificationHolders[]`, `parentLicensees[]` |
| **Enrichment** (opt-in) | `contactWebsite`, `emailEnrichment`, `takesPayments`, `paymentProcessors`, `stripeLiveKey`, `paymentConfidence` |

#### ❓ FAQ

**How is `maxItems` split across boards?**
It's a single total budget. Boards run in registry order (NC electrical → NC plumbing → NC general → LA) until the budget is spent, so a small `maxItems` may not reach every board — raise it, or select specific `boards`, to guarantee coverage of the ones you care about.

**Do all rows have an email?**
Louisiana rows almost always do (`boardEmail`, published by the board). The other three boards don't publish emails — turn on `enrichEmails` to try to recover one from the business's website. `contactEmail` is always the best available (board email first, enriched second).

**Should I use this or the single-state actors?**
Use this when you want multiple boards in one run or one dataset. If you only ever want one board, the dedicated per-state actors ([NC Electrical](https://apify.com/memo23/north-carolina-electrical-contractor-leads-scraper), [NC Plumbing & HVAC](https://apify.com/memo23/north-carolina-plumbing-hvac-contractor-leads-scraper), [Louisiana](https://apify.com/memo23/louisiana-contractor-leads-scraper)) are simpler.

**Is this legal to scrape?**
Every board is a public government licensing registry intended for verification by the public. The actor accesses only those public pages, politely. See the Disclaimer.

#### 💬 Support

- 🐛 **Issues:** [the actor's Issues tab](https://apify.com/memo23/us-contractor-license-leads-scraper/issues)
- 💡 **Feature requests:** same place — new boards, states, and fields usually ship fast
- 📧 **Direct:** message via [my Apify profile](https://apify.com/memo23)

#### 🛠 Additional services

Need another state or trade board added, a custom export, or a managed feed into your CRM? New ARLS boards drop in as configs. Reach out via my Apify profile.

#### 🔎 Explore more scrapers

Single-board versions: [NC Electrical](https://apify.com/memo23/north-carolina-electrical-contractor-leads-scraper) · [NC Plumbing & HVAC](https://apify.com/memo23/north-carolina-plumbing-hvac-contractor-leads-scraper) · [Louisiana](https://apify.com/memo23/louisiana-contractor-leads-scraper). More lead-gen & directory actors: **[apify.com/memo23](https://apify.com/memo23)**.

#### 🤖 For AI Agents & LLM Apps

MCP-ready via the [Apify MCP server](https://mcp.apify.com), or hit it with one API call and read clean JSON. The row schema is stable and flat where it matters (`boardId`, `licenseNumber`, `businessName`, `phone`, `contactEmail`, `address.city`, `isActive`), so it drops into RAG pipelines, lead-qualification agents, and compliance checks. Agent patterns: *"verify this contractor's license across NC and LA"* (pass `licenseNumbers`), *"active residential contractors in Charlotte and New Orleans with emails"* (`boards` + `cities` + `classifications` + `enrichEmails`), or a scheduled *"alert me on newly licensed contractors in any state"* loop (`monitoringMode`).

***

### ⚠️ Disclaimer

This Actor is an independent tool and is not affiliated with, endorsed by, or sponsored by the North Carolina State Board of Examiners of Electrical Contractors, the North Carolina State Board of Examiners of Plumbing, Heating & Fire Sprinkler Contractors, the North Carolina Licensing Board for General Contractors, the Louisiana State Licensing Board for Contractors, the States of North Carolina or Louisiana, or any of their agencies or affiliates. All trademarks are the property of their respective owners.

The scraper accesses only each board's publicly available license-verification pages — no authenticated endpoints and no content behind a login. License data, including any contact email a board publishes, is a public record provided for verification purposes. Users are responsible for ensuring their use complies with applicable law and regulation — including data-protection rules (GDPR, CCPA), telemarketing/e-mail regulations (TCPA, CAN-SPAM) when contacting leads, and any obligations of their own organisation.

***

### SEO Keywords

us contractor license leads, multi-state contractor leads, contractor license lookup api, nc electrical contractor leads, nc plumbing hvac contractor leads, nc general contractor leads, louisiana contractor leads, contractor leads with email, state licensing board scraper, arls license verification, licensed contractor database, contractor license verify bulk, home services leads scraper, multi-board license scraper, newly licensed contractors alerts, contractor license monitoring, b2b construction leads, charlotte contractors, new orleans contractors, apify contractor leads

# Actor input Schema

## `boards` (type: `array`):

Empty = all boards. Each row is one board.

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

Cities to sweep, matched EXACTLY against each licensee's mailing-address city (e.g. `Charlotte`, `New Orleans`). Applied to every selected board. Empty = each board's bundled full-state place list, biggest cities first.

## `classifications` (type: `array`):

Keep only these classifications. Resolved per board, so a fragment like `residential` matches on whichever boards have it. Accepts a full label or the board's numeric code too. Empty = all classifications on each board.

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

Keep only licenses in good standing — Expired / Terminated / Not Active / Not Valid records are dropped before any detail fetch. Turn off for historical or compliance research.

## `companyNames` (type: `array`):

Company-name searches (each board substring-matches, so `electric` finds every company containing the word). Overrides the city sweep. Applied to every selected board.

## `lastName` (type: `string`):

Search by the license holder's last name. Overrides the city sweep.

## `firstName` (type: `string`):

Optional, only used together with the last name.

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

Direct license lookups — accepts full numbers (`U.00025`, `CL.13827`, `L.00007`) or bare digits. Tried on every selected board. Overrides every other mode.

## `phoneNumber` (type: `string`):

Search by the phone number on record. Overrides the city sweep.

## `enrichEmails` (type: `boolean`):

For rows without a board-published email (all boards except LA), discover the business website and harvest a contact email. Adds `contactEmail`, `contactWebsite`, `emailEnrichment`. Best-effort — no charge on misses, and skipped entirely when the board already gave an email.

## `qualifyByPayment` (type: `boolean`):

Piggybacks on email enrichment (only runs when that's on): detects Stripe/Square/e-commerce signals on the business site. Adds `takesPayments`, `paymentProcessors`, `stripeLiveKey`, `paymentConfidence`. Free.

## `monitoringMode` (type: `boolean`):

Skip licenses already delivered to you on previous runs (tracked per board) — ideal on a schedule for catching newly licensed contractors. The first run seeds the baseline and returns everything.

## `resetMonitoringState` (type: `boolean`):

One-shot: forget every previously delivered license at run start, so this run returns everything again.

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

Hard cap on leads pushed to the dataset, shared across all selected boards (boards run in order until the budget is spent).

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

Parallel per-licensee detail fetches.

## `searchConcurrency` (type: `integer`):

Parallel roster searches per board. Keep modest to stay polite to the boards.

## Actor input object example

```json
{
  "boards": [],
  "cities": [
    "Charlotte",
    "New Orleans"
  ],
  "activeOnly": true,
  "enrichEmails": false,
  "qualifyByPayment": false,
  "monitoringMode": false,
  "resetMonitoringState": false,
  "maxItems": 500,
  "maxConcurrency": 10,
  "searchConcurrency": 3
}
```

# 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 = {
    "cities": [
        "Charlotte",
        "New Orleans"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("memo23/us-contractor-license-leads-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 = { "cities": [
        "Charlotte",
        "New Orleans",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("memo23/us-contractor-license-leads-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 '{
  "cities": [
    "Charlotte",
    "New Orleans"
  ]
}' |
apify call memo23/us-contractor-license-leads-scraper --silent --output-dataset

```

## MCP server setup

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

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "US Contractor License Leads Scraper (Multi-State)",
        "description": "License-verified contractor leads across every US state board on the ARLS platform in one run — NC electrical, NC plumbing/HVAC, NC general contractors, and LA contractors (with board-published emails). Company, license #, class, status, expiry, address, phone. Full-state sweep or targeted search.",
        "version": "0.0",
        "x-build-id": "lJFClbqbui2Ij0tvI"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/memo23~us-contractor-license-leads-scraper/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-memo23-us-contractor-license-leads-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/memo23~us-contractor-license-leads-scraper/runs": {
            "post": {
                "operationId": "runs-sync-memo23-us-contractor-license-leads-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/memo23~us-contractor-license-leads-scraper/run-sync": {
            "post": {
                "operationId": "run-sync-memo23-us-contractor-license-leads-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": {
                    "boards": {
                        "title": "Boards to run",
                        "type": "array",
                        "description": "Empty = all boards. Each row is one board.",
                        "items": {
                            "type": "string",
                            "enum": [
                                "ncbeec",
                                "ncphfsc",
                                "nclbgc",
                                "lslbc"
                            ],
                            "enumTitles": [
                                "NC — Electrical Contractors (NCBEEC)",
                                "NC — Plumbing, Heating & Fire Sprinkler (NCPHFSC)",
                                "NC — General Contractors (NCLBGC)",
                                "LA — Contractors (LSLBC, with emails)"
                            ]
                        },
                        "default": []
                    },
                    "cities": {
                        "title": "Cities (mailing address)",
                        "type": "array",
                        "description": "Cities to sweep, matched EXACTLY against each licensee's mailing-address city (e.g. `Charlotte`, `New Orleans`). Applied to every selected board. Empty = each board's bundled full-state place list, biggest cities first.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "classifications": {
                        "title": "License classifications",
                        "type": "array",
                        "description": "Keep only these classifications. Resolved per board, so a fragment like `residential` matches on whichever boards have it. Accepts a full label or the board's numeric code too. Empty = all classifications on each board.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "activeOnly": {
                        "title": "Active licenses only",
                        "type": "boolean",
                        "description": "Keep only licenses in good standing — Expired / Terminated / Not Active / Not Valid records are dropped before any detail fetch. Turn off for historical or compliance research.",
                        "default": true
                    },
                    "companyNames": {
                        "title": "Company names",
                        "type": "array",
                        "description": "Company-name searches (each board substring-matches, so `electric` finds every company containing the word). Overrides the city sweep. Applied to every selected board.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "lastName": {
                        "title": "Licensee last name",
                        "type": "string",
                        "description": "Search by the license holder's last name. Overrides the city sweep."
                    },
                    "firstName": {
                        "title": "Licensee first name",
                        "type": "string",
                        "description": "Optional, only used together with the last name."
                    },
                    "licenseNumbers": {
                        "title": "License numbers",
                        "type": "array",
                        "description": "Direct license lookups — accepts full numbers (`U.00025`, `CL.13827`, `L.00007`) or bare digits. Tried on every selected board. Overrides every other mode.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "phoneNumber": {
                        "title": "Phone number",
                        "type": "string",
                        "description": "Search by the phone number on record. Overrides the city sweep."
                    },
                    "enrichEmails": {
                        "title": "Find contact emails (opt-in)",
                        "type": "boolean",
                        "description": "For rows without a board-published email (all boards except LA), discover the business website and harvest a contact email. Adds `contactEmail`, `contactWebsite`, `emailEnrichment`. Best-effort — no charge on misses, and skipped entirely when the board already gave an email.",
                        "default": false
                    },
                    "qualifyByPayment": {
                        "title": "Detect payment processors",
                        "type": "boolean",
                        "description": "Piggybacks on email enrichment (only runs when that's on): detects Stripe/Square/e-commerce signals on the business site. Adds `takesPayments`, `paymentProcessors`, `stripeLiveKey`, `paymentConfidence`. Free.",
                        "default": false
                    },
                    "monitoringMode": {
                        "title": "Only new licenses since last run",
                        "type": "boolean",
                        "description": "Skip licenses already delivered to you on previous runs (tracked per board) — ideal on a schedule for catching newly licensed contractors. The first run seeds the baseline and returns everything.",
                        "default": false
                    },
                    "resetMonitoringState": {
                        "title": "Reset monitoring baseline",
                        "type": "boolean",
                        "description": "One-shot: forget every previously delivered license at run start, so this run returns everything again.",
                        "default": false
                    },
                    "maxItems": {
                        "title": "Maximum leads (total across boards)",
                        "minimum": 1,
                        "type": "integer",
                        "description": "Hard cap on leads pushed to the dataset, shared across all selected boards (boards run in order until the budget is spent).",
                        "default": 500
                    },
                    "maxConcurrency": {
                        "title": "Detail concurrency",
                        "minimum": 1,
                        "type": "integer",
                        "description": "Parallel per-licensee detail fetches.",
                        "default": 10
                    },
                    "searchConcurrency": {
                        "title": "Search concurrency",
                        "minimum": 1,
                        "type": "integer",
                        "description": "Parallel roster searches per board. Keep modest to stay polite to the boards.",
                        "default": 3
                    }
                }
            },
            "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
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
