# Contractor License Lookup: WA, OR, TX & NY Status & Insurance (`yzy001/contractor-license-check`) Actor

Verify contractor licenses or list them by city, trade, new or expiring, in Washington, Oregon, Texas and New York, from each state's official open data. Status, expiration, first-issued date, bond and insurance on file, New York compliance flags.

- **URL**: https://apify.com/yzy001/contractor-license-check.md
- **Developed by:** [宗諭 楊](https://apify.com/yzy001) (community)
- **Categories:** Lead generation, Business, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.00 / 1,000 licenses

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

## What's an Apify Actor?

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

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

## How to integrate an Actor?

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

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

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

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

# README

## Contractor License Lookup: Washington, Oregon, Texas & New York

Check whether a contractor is licensed, or pull every contractor license that matches a city, a trade, a new-license window or an expiry window, read straight from each state's official open-data portal. One table across four states, with status, expiration, the date the license was first issued, and the bond and insurance the state has on file.

### Two ways to use it

- **Verify.** Paste license numbers (`WA:ECOSTSC758NN`, `TX:36159`, `OR:1441`, or just the number to look it up in every selected state) or business names. Every match comes back whatever its status, so expired and suspended licenses show up as such, and the run summary lists the numbers that were not found.
- **List.** Leave the lookups empty and filter: trade, status (active by default), cities, ZIP prefixes, **newly licensed within N days** (Washington and Oregon) or **expiring within N days**. New licenses are sorted newest first, expiring ones soonest first.

### What you get for each license

| Field | Meaning |
|---|---|
| `state`, `licenseNumber`, `businessName`, `dba` | The state, its license or registration number, the licensed business name (New York also gives a DBA) |
| `licenseType`, `category`, `specialties` | The state's own license type; one of `GENERAL`, `SPECIALTY`, `ELECTRICAL`, `PLUMBING`, `HVAC`, `ELEVATOR`, `OTHER`; Washington's specialty (roofing, painting, HVAC and so on) |
| `status`, `statusRaw`, `statusIsDerived` | `ACTIVE`, `EXPIRED`, `SUSPENDED`, `INACTIVE`, `SUPERSEDED`, `REVOKED` or `OTHER`; the state's own wording; `true` when the state publishes no status and it was worked out from the expiration date |
| `firstIssuedDate` | When the license was first issued (Washington, Oregon) |
| `certificateIssuedDate` | New York: issue date of the current registration certificate |
| `expirationDate`, `daysToExpiration` | As published; negative when already expired |
| `address`, `county` | Business address as filed; county where the state gives it |
| `bonds`, `insurance` | Surety bonds and liability insurance on file that are not cancelled or expired: company, amount, dates. Washington and Oregon only |
| `endorsements` | Oregon: every CCB endorsement on the license, with its official name |
| `compliance` | Oregon: workers' compensation status. New York: the state's yes/no answers on debarment, outstanding wage assessments, labor or tax law violations, safety violations, workers' compensation insurance, MWBE ownership |
| `stateBusinessId` | Washington UBI number |
| `matchedInput` | Verify mode: which of your numbers or names this row answers |
| `sourceRecordUrl` | The exact record on the state's open-data portal |

### Coverage

| State | Source | What is included |
|---|---|---|
| Washington | Department of Labor & Industries | Construction, electrical, plumbing and elevator contractors, every status, with bonds and insurance |
| Oregon | Construction Contractors Board | Active licenses with all endorsements, bond and insurance |
| Texas | Department of Licensing and Regulation | Electrical, A/C, elevator, appliance installation and sign contractors; individual electricians and technicians on request. Texas plumbers are licensed by a different board and are not included |
| New York | Department of Labor | The Contractor Registry for public work projects, with its compliance answers |

### Things to know

- **Texas publishes no status**, only an expiration date, so its status is derived from that date (`statusIsDerived`).
- **Oregon and New York publish lists of active licenses.** A license removed from the list comes back as not found in a lookup. A few Oregon licenses stay on the list past their expiration date; they are returned as `EXPIRED` (`statusIsDerived`).
- **The city filter matches the city name in every selected state**: Portland finds Oregon contractors and Washington contractors based in Portland. Choose states to narrow it.
- **Texas individual licenses rarely carry a business address**, so city and ZIP filters find few of them; look them up by license number.
- **Empty `bonds` or `insurance` for Texas and New York means not published, not "none".**
- If a portal has not been refreshed for more than 10 days, that state is reported as failed instead of being returned as if it were current.

### Personal data

No phone numbers, e-mail addresses, or names of owners, principals, officers or responsible managing individuals are collected; those columns are not even requested from the portals. Sole proprietors are licensed under their own name, so a business name can be a person's name; that is the public license record each state publishes for verification.

### Run summary

Stored under `SUMMARY` in the key-value store: mode, each state's status, source dataset, last refresh and rows read, rows left out by reason, counts by trade and status, lookups not found, and the caveats.

### Data

Datasets published by the four state agencies on their open-data portals (Washington and Oregon in the public domain), read through each portal's public API. No login, no scraping of search pages, and one request per second per portal as the portals ask.

# Actor input Schema

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

Which states to read. Each comes from that state's official open-data portal.

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

Optional. License or registration numbers as the state prints them, optionally with the state first, for example WA:ECOSTSC758NN, TX:36159, OR:1441. A number without a state is looked up in every selected state. Expired and suspended licenses are returned too. Up to 500 numbers and names together.

## `businessNames` (type: `array`):

Optional. Every license whose business name contains this text (3 characters or more).

## `categories` (type: `array`):

Keep these categories. General contractors, specialty contractors (roofing, painting, flooring and so on), electrical, plumbing, HVAC, elevator, other. Empty = all.

## `statuses` (type: `array`):

Keep these license statuses when listing. Lookups always return every status.

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

Optional. Keep licenses whose business address is in one of these cities (exact name, any case). The city name is matched in every selected state.

## `zipPrefixes` (type: `array`):

Optional. Keep licenses whose business ZIP starts with one of these, for example 981 or 97209.

## `firstIssuedWithinDays` (type: `integer`):

Optional. Only licenses first issued in the last N days (1-365), newest first. Washington and Oregon only: Texas and New York do not publish a first-issued date.

## `expiringWithinDays` (type: `integer`):

Optional. Only licenses that expire in the next N days (1-365), soonest first.

## `includeIndividualLicenses` (type: `boolean`):

Texas journeyman, apprentice and technician licenses, and Oregon home inspector and locksmith certifications. Off = contractor licenses only.

## `includeBondInsurance` (type: `boolean`):

Join Washington's separate bond and insurance datasets (current policies only). Oregon's bond and insurance are always included.

## `allowPartial` (type: `boolean`):

On by default: if one state's portal cannot be read, the others are still returned and the status message names it. Turn off to make any failed state fail the run.

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

Upper bound on rows returned. Listing more than 5,000 needs at least one filter.

## Actor input object example

```json
{
  "states": [
    "WA",
    "OR"
  ],
  "licenseNumbers": [],
  "businessNames": [],
  "categories": [],
  "statuses": [
    "ACTIVE"
  ],
  "cities": [],
  "zipPrefixes": [],
  "firstIssuedWithinDays": 7,
  "includeIndividualLicenses": false,
  "includeBondInsurance": true,
  "allowPartial": true,
  "maxItems": 100
}
```

# Actor output Schema

## `items` (type: `string`):

Normalised licenses from every state.

## `summary` (type: `string`):

Per-state status and freshness, rows left out and why, lookups not found, caveats.

# 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 = {
    "states": [
        "WA",
        "OR"
    ],
    "firstIssuedWithinDays": 7,
    "maxItems": 100
};

// Run the Actor and wait for it to finish
const run = await client.actor("yzy001/contractor-license-check").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 = {
    "states": [
        "WA",
        "OR",
    ],
    "firstIssuedWithinDays": 7,
    "maxItems": 100,
}

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

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

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

```

## CLI example

```bash
echo '{
  "states": [
    "WA",
    "OR"
  ],
  "firstIssuedWithinDays": 7,
  "maxItems": 100
}' |
apify call yzy001/contractor-license-check --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,yzy001/contractor-license-check"
        }
    }
}
```

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

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/2QsoGVxLLnIUDgvGd/builds/7ueMZu3aMFd7WPAb2/openapi.json
