Contractor License Lookup and Leads avatar

Contractor License Lookup and Leads

Pricing

from $2.40 / 1,000 license records

Go to Apify Store
Contractor License Lookup and Leads

Contractor License Lookup and Leads

Verify US contractor licenses and find licensed contractors by trade and area. Get a clear status verdict, board classifications, dates, published bonds and insurance, source freshness and scheduled change monitoring.

Pricing

from $2.40 / 1,000 license records

Rating

0.0

(0)

Developer

Zaiq

Zaiq

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

16 hours ago

Last modified

Categories

Share

Contractor License Lookup and Leads: Verify US contractor licenses and find licensed contractors by trade and area

Get one sourced verdict per US contractor licence: the published status, trade, expiry date, and available bond or insurance information. Verify licence numbers or business names, find contractors by trade and area, and schedule checks that return new or changed records.

$0.003 per delivered licence record ($3 per 1,000), the same price on every Apify plan. Failure notes and unchanged monitored records have no licence-record charge. Start with {"states":["WA"],"city":"Seattle","trades":["general-building"],"maxResults":10}.

Coverage is specific to each official source. California, Washington, Oregon, Connecticut and Virginia cover broad contractor categories. Colorado covers electrical and plumbing contractor registrations; New York covers statewide mold assessment and remediation contractor licences. This is not an all-state or all-trade directory.

StateRecords availableImportant limits
CaliforniaCSLB master: current and expired but renewable licences, classifications, bonds and workers’ compensationCancelled, revoked and expired non-renewable licences are excluded. Bulk snapshot; a download can be incomplete.
WashingtonL&I construction, electrical and plumbing registrations; separate bond and liability-insurance feedsOriginal issue date, county, workers’ compensation and discipline are not published in these feeds.
OregonActive CCB licences, endorsements, bonds, insurance and workers’ compensation exemption classificationActive only; broad endorsements do not identify every specialty trade.
ConnecticutConstruction-related contractor credentials, including inactive statusesNo bond, insurance or county fields in this source.
ColoradoElectrical and plumbing contractor registrations and published disciplinary actionsNo general-contractor coverage, street address, county, bonds or insurance.
New YorkStatewide mold assessment and remediation contractor licencesNo general-contractor or local home-improvement coverage.
VirginiaCurrent Class A, B and C contractor rosters plus legacy Class ANo suspended, revoked or inactive records, bonds, insurance or county.

What you get

FieldWhat it holds
Verdict firstA readable line such as active licence, classification, published bond information and expiry date. riskFlags highlight date contradictions, stale sources and other published concerns.
Identity and statusstate, licenseNumber, businessName, licenseeName where published, status, statusRaw, statusReason and matchType.
TradesNormalized trades plus each board’s original classifications code and description. Multiple endorsements are combined into one licence row.
DatesissuedOn, effectiveOn, expiresOn and recordUpdatedOn where the source identifies them. Missing dates remain null.
Bond and insurance evidencePublished bonds, insurance and workersComp, including company, amount, policy dates and exemption classification where available. Washington join availability is explicit.
DisciplineColorado’s published action rows and California’s disciplinary-bond fields. An empty list is not proof of a clean disciplinary history.
Published address and phoneBusiness or mailing address, city, ZIP, county and phone where the board publishes them. No external personal-contact enrichment.
Evidence and freshnessrecordUrl, evidenceUrl, sourceUrl, sourceUpdatedAt, checkedAt, freshness and sourceAgeDays.
Monitoring changeschangeType is baseline, new or changed. changes gives before/after values. Unchanged records are omitted.
SUMMARYPer-state source, scope, freshness, scanned and delivered counts, completeness, skipped malformed records, route failures and charged events.

What people use it for

  • Contractor lead lists: Find licensed businesses in a published trade and mailing area for suppliers or home-service marketing.
  • Marketplace and property-management checks: Look up a supplied licence number and retain its source record and dated status.
  • Bond and insurance review: Collect the policy information a board publishes, including expiry or cancellation dates, for further review.
  • Recurring portfolio monitoring: Schedule the same watchlist and receive changed statuses and new matching licences without paying again for unchanged records.

How to use it

  1. Run the prefilled Washington leads query to see ten real records. Open the Licenses table for verdicts and the Summary link for coverage.
  2. For verification, set mode to verify and enter licence numbers as STATE:number. Business-name searches return candidates; compare their identifiers before selecting a business.
  3. For leads, choose states, trades or original classification codes, and optional city, county or ZIP filters. Raise maxResults to collect a larger list.
  4. For scheduled comparisons, add a named monitorStore, keep the same filters, and schedule one run at a time. The first successful deliveries form the baseline.
  5. Export the dataset or read it by API. Use kind=license for licence records and kind=note for free explanations. Check SUMMARY.coverage[].complete before treating a scan as exhaustive.

Input

FieldExampleNotes
modeleads or verifyDefault: leads. Verification returns the actual status regardless of the leads status filter.
states["WA", "OR"]CA, WA, OR, CT, CO, NY or VA; omitted or empty defaults to WA.
licenseNumbers["CA:123456"]Verify mode; prefix required when more than one state is selected. Keep board prefixes and leading zeros. Up to 500 entries.
businessNames["WA:Example Building Company"]Verify mode. With no state prefix, searches the selected states. Up to 500 entries.
nameMatchcontainsOr exact, ignoring case. A matching name is a candidate, not proof of identity.
trades["roofing", "electrical"]Any selected normalized trade. Empty means all; classifications come from the board, never from a business-name guess.
classifications["CA:C-39", "VA:ELE"]Any selected original classification. If trades are also supplied, both filters must match.
city / county / zipSeattle / empty / emptyExact city or county ignoring case; ZIP or ZIP+4. County is supported in CA and OR only. Addresses do not establish a service area.
statusactiveAlso all, expired, suspended, revoked, inactive, cancelled, pending or unknown. Active-only sources cannot answer other statuses.
newlyLicensedDays30Uses the published original issue date. Zero disables the filter; unavailable in WA.
maxResults10Total delivered records across selected states in input order; maximum 250,000. Unchanged records do not consume this limit.
includeInsuranceonJoins Washington bond and liability-insurance feeds. Other states retain policy fields already in their primary record.
monitorStorecontractor-watchlistOptional named key-value store. Same name and filters reuse the baseline. Different filters create a separate scope.

Output

Each result is one row in the run's dataset (download it as JSON, CSV, Excel, XML or HTML, or read it through the API). An example row (values shortened):

{
"verdict": "Active WA licence · 01 GENERAL · bond $30,000 on file · insurance $1,000,000 on file · expires 15 Aug 2027",
"kind": "license",
"state": "WA",
"status": "active",
"statusRaw": "ACTIVE",
"classifications": [
{
"code": "01",
"description": "GENERAL",
"trade": "general-building"
}
],
"trades": [
"general-building"
],
"effectiveOn": "2025-08-15",
"expiresOn": "2027-08-15",
"workersComp": {
"status": "not_published"
},
"freshness": "recent",
"sourceUpdatedAt": "2026-10-26",
"licenseNumber": "EXAMPLE123AB",
"businessName": "Example Building Company",
"address": "100 Example Street",
"city": "Example City",
"zip": "00000",
"phone": "000-555-0100",
"recordUrl": "https://example.invalid/official-license/EXAMPLE123AB",
"bonds": [
{
"status": "on_file",
"company": "Example Surety",
"amountUsd": 30000.0,
"number": "EXAMPLE-BOND",
"effectiveOn": "2026-08-20",
"expiresOn": null,
"cancelsOn": null,
"expirationText": "Until Canceled"
}
],
"insurance": [
{
"status": "on_file",
"company": "Example Insurer",
"amountUsd": 1000000.0,
"number": "EXAMPLE-POLICY",
"effectiveOn": "2026-06-12",
"expiresOn": "2027-06-12",
"cancelsOn": null,
"expirationText": "2027-06-12T00:00:00.000"
}
]
}

This example is shortened from a real test on 26 October 2026. Business and insurer names, licence and policy identifiers, phone, address, city, ZIP and site addresses have been replaced. Status, classifications, policy amounts and dates retain the test values. The SUMMARY record in the run’s key-value store carries the coverage and completeness table, source freshness and charges.

Pricing

  • $0.003 per delivered licence record. The same price on every Apify plan.
  • Only a record that arrives is charged. Missing results, unsupported inputs and failure notes have no licence-record charge.
  • Monitoring charges the first baseline and then only new or changed licence records. Unchanged records are omitted.
  • Apify’s $0.00005 start charge counts towards Maximum cost per run, including runs with no delivered licence records.
  • No AI model or separate AI fee is used.

What typical jobs cost at the list price:

JobCost
1 delivered licence$0.00305 including start
10 delivered licences$0.03005 including start
1,000 delivered licences$3.00005 including start
50,000 delivered licences$150.00005 including start
Unchanged monitoring run$0.00005 start charge; no licence-record charge

Set Maximum cost per run before starting. A limit of $0.00605 covers two licence records and the start charge. The Actor checks available room before requesting paid results, stops when the next record cannot fit, and still writes free notes. A result limit or spending limit can leave a state scan incomplete.

Tips

  • Use exact licence numbers for a known watchlist. Use trade and area filters for discovery, then retain the state and licence number as the identity.
  • For Washington, turn off includeInsurance when only the licence status and classification are needed. This avoids two supplemental API lookups per batch.
  • For Oregon, search a broad endorsement or original classification. Do not infer a roofing or electrical specialty from a general CCB registration.
  • For recurring checks, keep one named store per watchlist, maintain the same filters, and avoid overlapping runs.
  • Use the official record URL and source date when reviewing a result. The source’s omissions and incomplete flags are part of the result.

Use it through the API

Python

from apify_client import ApifyClient
client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("zaiq/contractor-license-lookup").call(run_input={"states": ["WA"], "city": "Seattle", "trades": ["general-building"], "maxResults": 10})
for row in client.dataset(run.default_dataset_id).iterate_items():
print(row)

JavaScript

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });
const run = await client.actor('zaiq/contractor-license-lookup').call({"states": ["WA"], "city": "Seattle", "trades": ["general-building"], "maxResults": 10});
const { items } = await client.dataset(run.defaultDatasetId).listItems();

HTTP (one call, results back)

curl -X POST 'https://api.apify.com/v2/acts/zaiq~contractor-license-lookup/run-sync-get-dataset-items?token=<YOUR_APIFY_TOKEN>' \
-H 'Content-Type: application/json' \
-d '{"states": ["WA"], "city": "Seattle", "trades": ["general-building"], "maxResults": 10}'

Integrations and schedules

  • Schedules: run it every hour, day or week from the Apify Console (Schedules) and keep a history of results.
  • Make, Zapier, n8n, Google Sheets, Slack, Airtable: connect it through Apify's integrations, or send each finished run to a webhook.
  • Datasets: results stay in the run's dataset; export them or read them by API whenever you need them.

Use it with AI agents (MCP)

Add Apify's MCP server (https://mcp.apify.com) to Claude, ChatGPT, Cursor, VS Code or any MCP client. The agent can find this Actor and run it for you: ask it for "find active roofing contractor licences in this state and city, with their official record links". AI agents can also pay for runs directly through Apify's agentic payments.

Limits

  • Only the seven sources described above are supported. Statewide coverage does not imply every trade or every historical status.
  • California and Virginia require bulk downloads even for a small query. They can take several minutes. California can return a truncated file; received rows remain useful, but coverage is marked incomplete and absent records are not interpreted.
  • Bulk files use direct or datacenter connections. Large residential downloads are refused to keep a small query from consuming disproportionate resources. API calls can try direct, datacenter and fresh residential routes when available; failures are recorded.
  • Official data can lag a live board record. The verdict reflects the source snapshot, not a guarantee of present eligibility, insurance coverage or permission for a particular job. Sources older than 14 days receive a review flag.
  • “On file” describes dated published policy evidence, not confirmation from an insurer. Oregon’s nonexempt workers’ compensation classification does not establish current coverage.
  • No record does not establish that a contractor is unlicensed. A missing record in an active-only source is reported as unknown, never as a guessed suspension or revocation.
  • Licence holders may be people or businesses. Output is limited to their official published licence record; no email discovery or outside personal-contact research is performed.
  • Monitoring retains delivered checkpoints on incomplete runs. Missing records are flagged only after a complete state scan. A failed optional policy lookup preserves the previous policy checkpoint rather than inventing a removal.
  • Run a monitoring scope sequentially. A changed filter starts a different scope. A rolling newly-licensed window may stop including older records; a missing-source note in that scope does not establish a licence-status change.
  • Source request limits and up to 250,000 delivered records apply. Incomplete, malformed, repeated or unexpectedly short feeds are reported. Raising the result limit does not remove source access restrictions.

FAQ

Does this cover all US contractor licences?

No. It covers the listed official sources and their published scope. Colorado and New York have limited trade coverage; Oregon and Virginia publish current/active records only.

Can I look up a business without its licence number?

Yes. Use verify mode and businessNames. Contains is the default; exact is available. A name match is a candidate, so use its state, licence number and address to distinguish businesses.

Can I export every matching contractor?

Set maxResults high enough and give the run enough spending room. Check the per-state completeness flags. Records beyond either limit, inaccessible sources and malformed records prevent an exhaustive claim.

How do trades work across states?

The Actor maps published classifications to a common list such as electrical, plumbing, roofing and general-building. It keeps each board’s original code and label. Broad registrations do not prove an unlisted specialty.

Will monitoring catch active-to-suspended changes?

For sources that publish both statuses, monitoring scans all statuses within the selected trade and area and returns changes to watched licences. Active-only sources can only report that a record disappeared, with status unknown.

What happens after an Actor restart?

Rows already acknowledged in the same run’s dataset are recognized by a stable resultId and are not delivered or charged twice. Monitoring can recover their checkpoints from that dataset.

Do I need a board account or an AI key?

No. The Actor reads public, signed-out records and computes deterministic verdicts. It does not solve challenges or sign into licensing sites.

Why can a verdict say review needed while status says active?

The board may publish an active status alongside an expiry date in the past, an expired policy, or an old source snapshot. The original status is preserved and the conflicting evidence is flagged.

Why is a run incomplete if it delivered the requested number?

Reaching maxResults or the spending limit stops collection before exhaustion. Complete means the source/query was exhausted without a known data issue, not merely that a requested batch was delivered.

Support

Questions, a site that changed, or a field you need? Open an issue on this Actor's Issues tab: we answer there, usually within a day.


Also found as: contractor license lookup, contractor license verification, licensed contractor leads, CSLB license lookup, contractor license monitoring, contractor directory by trade.