# WA Contractor Licenses - Bonds & Insurance Profiles (`j0401/wa-contractor-licenses`) Actor

Washington contractor licenses (WA L\&I register, 160k+ records): construction, electrical, plumbing and elevator contractors. Look up a license number for its complete profile - current bond, liability insurance and principals - or search by name / city / UBI / type.

- **URL**: https://apify.com/j0401/wa-contractor-licenses.md
- **Developed by:** [Wenhao Yang](https://apify.com/j0401) (community)
- **Categories:**
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$1.00 / 1,000 wa contractor license records

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?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

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

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

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

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

# README

## WA Contractor Licenses - Bonds & Insurance Profiles (`wa-contractor-licenses`)

Pull **Washington contractor licenses** - the full WA Dept of Labor & Industries contractor register (**160,889 records**, construction / electrical / plumbing / elevator contractors), free public open data, and go **deeper than the license**: every contractor joins to their current **bond coverage**, **liability insurance** and **principals**, all in one profile.

Washington requires registered contractors to carry a bond and liability insurance. This is the data that tells you **whether a contractor actually has them** - and who is behind the license.

Built for **general contractors and homeowners vetting a contractor**, **lead-gen / list-building for anyone selling to construction** (insurance, bonding, tools, materials), **subcontractor qualification**, and **background/verification use**.

### The core tool: a contractor's full profile by license number

Give a license number, get the **complete picture assembled from the L\&I family** - registration + current bond + insurance + principals:

```
input { "licenseNumber": "ECOSTSC758NN" }
  general     ECOSTSC758NN   !ECO STAR C G CONSTRUCTION LLC
              type=Construction  status=ACTIVE  specialty=01 GENERAL
              UBI 605854613   Vancouver WA   expires 2027-08-15
  insurance   ACTIVE   State National Ins Co    policy NXT9PTHTLT-01-GL   $1,000,000
  bond        ACTIVE   Merchants Bonding Co     $30,000   (Until Canceled)
  principal   GUERRERO MARTINEZ, CARLOS I.      started 2025-08-15
```

**One run = the whole file on one contractor.** A bond listed as *Until Canceled* is the standing bond; insurance with a coverage amount tells you their liability limit.

### What each record has

| Field | Meaning |
|---|---|
| `recordType` | `general` / `insurance` / `bond` / `principal` / `aggregate` |
| `contractorLicenseNumber` | The 12-char L\&I license number (join key) |
| `businessName` / `ubi` | Registered company name + WA UBI |
| `licenseType` / `licenseTypeCode` | Construction / Electrical / Plumbing / Elevator contractor |
| `status` | `ACTIVE` (75.8k) / `EXPIRED` / `SUSPENDED` / `RE-LICENSED` / `OUT OF BUSINESS` /  |
| `specialtyCode` / `specialtyDesc` | L\&I specialty scope (e.g. `01 GENERAL`, `CB PAINTING/WALLCOVERING`) |
| `city` / `state` / `zip` / `phone` | Registered address + phone |
| `licenseEffectiveDate` / `licenseExpirationDate` | License term |
| `insurance*` | Insurer, policy no., **amount**, effective/expiration (insurance rows) |
| `bond*` | Bond firm, **amount**, effective/expiration, `bondIsCurrent` (bond rows) |
| `principalName` / `principalStartDate` | A principal behind the license (principal rows) |

Every row type shares the same key set, so a profile's rows land in one clean dataset.

### Typical questions it answers

- **Does this contractor carry bond + insurance?** - `licenseNumber` -> the profile. The fastest due-diligence check before hiring or writing a subcontract.
- **What's a contractor's liability limit?** - same profile, the `insurance` row's `insuranceAmount`.
- **Who is behind this license?** - the `principal` rows (`principalName` + start date).
- **Who's registered in an area?** - `city=Seattle` (or `businessName`, substring). A lead list of licensed contractors.
- **Who's licensed for a specialty?** - `specialty` is in the register; search + `maxResults`.
- **How many active vs lapsed contractors statewide?** - `aggregate=true`, `groupBy=status`.

### Inputs

| Input | What it does |
|---|---|
| `licenseNumber` | Exact 12-char license number -> **full profile** (the core tool). Any status license can be profiled; the sub-table rows shown are the ACTIVE bond/insurance on file |
| `businessName` | Company name substring (search mode) |
| `ubi` | Exact WA UBI number (search mode) |
| `city` | City substring (search mode) |
| `licenseType` | `Construction Contractor` / `Electrical` / `Plumbing` / `Elevator` (search + aggregate) |
| `status` | Default `Active` (the ~75.8k live slice); `all` / specific status for the full register |
| `aggregate` / `groupBy` | One row per license type or status instead of individual records |
| `maxResults` | Cap records pushed (default 200) |
| `mode` | `profile` / `search` / `aggregate` - auto-routed from the other inputs; rarely needed |

**Empty input** returns a safe statewide summary: the contractor count by license type (also the daily-quality-test default).

### Low cost

**From $0.001 per record** - with a per-run charge cap so a mistake can't run up a big bill.

A contractor's "license" is actually scattered across **four separate state tables** (the registration, the insurance filings, the bonds, the named principals) - we rejoin them on the exact 12-digit license number into a single profile, then judge which bond is *current* rather than trusting the date column (WA mixes ISO dates, `MM/DD/YYYY` and a literal "Until Canceled" in the same field). You query one contractor file that already carries the **current** bond and insurance; the four-table reassembly and bond-date judgment stay on our side. Each profile caps at 3 insurance, 4 bonds and 8 principals - most recent first; a license can carry more history than the cap shows.

### Data source & freshness

- **Source**: [data.wa.gov - WA L\&I Contractor License family](https://data.wa.gov/) (`m8qx-ubtq` General + `ciwg-agsx` Insurance + `bzff-4fmt` Bond + `4xk5-x9j6` Principal, Socrata SODA API, free public, no login). Same register as L\&I's public license lookup.
- **Coverage**: 160,889 licenses - 148.5k Construction, 9.2k Electrical, 3.1k Plumbing, 121 Elevator; ~75.8k currently ACTIVE. Insurance on file 76.4k active certificates; 166k active bond rows (176.8k total bond history).
- **Update cadence**: L\&I maintains the register live; the Socrata tables refresh continuously.

# Actor input Schema

## `mode` (type: `string`):

profile = a single license's complete file (needs licenseNumber). aggregate = one row per group. Leave blank to auto-route: licenseNumber -> profile, otherwise search (or aggregate when aggregate=true).

## `licenseNumber` (type: `string`):

Exact 12-char license number, e.g. "04CONCL862CR" or "ECOSTSC758NN". With this set (and no aggregate), returns the complete profile: registration + current bond(s) + insurance + principals.

## `businessName` (type: `string`):

Company name, substring, case-insensitive. E.g. "Merit" or "04 Construction".

## `ubi` (type: `string`):

Exact WA Unified Business Identifier, e.g. "603320569".

## `city` (type: `string`):

City name, substring (e.g. "Seattle", "Vancouver").

## `licenseType` (type: `string`):

The kind of contractor license. Default blank = all types.

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

License status. Default "Active" (~75.8k live licenses). Set to "all" for the full register (including expired / suspended / out of business), or a specific status like "Expired", "Suspended", "Re-Licensed".

## `aggregate` (type: `boolean`):

When on, returns one summary record per group (license type or status) with count and share, instead of individual licenses. Computed server-side.

## `groupBy` (type: `string`):

licenseType -> how many of each kind (construction / electrical / plumbing / elevator); status -> active vs expired vs suspended mix.

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

Cap the number of records pushed (0 = a reasonable ceiling). A profile is the license plus up to 3 insurance, 4 bonds and 8 principals (most recent first).

## Actor input object example

```json
{
  "status": "Active",
  "aggregate": false,
  "groupBy": "licenseType",
  "maxResults": 200
}
```

# Actor output Schema

## `recordsUrl` (type: `string`):

Washington contractor-license records or profiles - as JSON

## `datasetUrl` (type: `string`):

No description

## `runUrl` (type: `string`):

No description

# 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 = {};

// Run the Actor and wait for it to finish
const run = await client.actor("j0401/wa-contractor-licenses").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 = {}

# Run the Actor and wait for it to finish
run = client.actor("j0401/wa-contractor-licenses").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 '{}' |
apify call j0401/wa-contractor-licenses --silent --output-dataset

```

## MCP server setup

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

```

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/4l8luey7dysqTgxyX/builds/DktaBcb7VfCCo6okj/openapi.json
