# Oregon CCB Contractors - Licenses, Bonds & Insurance (`j0401/or-ccb-contractors`) Actor

Oregon Construction Contractors Board licence register (public open data, 56.3K rows, 45.6K licences): licence type, surety bond company/amount/expiry, liability insurer/amount/expiry, responsible managing individual and business address. Filter by type, name, city or carrier.

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

## Pricing

from $0.03 / 1,000 oregon contractor licence records

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

## Oregon CCB Contractors - Licenses, Bonds & Insurance

Every contractor licence on the Oregon Construction Contractors Board
register, straight from the State's own open data portal. **56.3K licence records /
45.6K distinct licences, refreshed continuously.**

### Low cost

**From $0.00005 per record, down to $0.00003 at Gold.** Pay only for the
records you actually receive - the whole register stays queryable (a single
run delivers up to 10,000 rows), and you are never billed for the scan behind it.

### What you get

Most contractor directories stop at the licence. This one carries the three
things a general contractor actually checks before subcontracting:

- **The surety bond** - the bond company, the bond amount and the bond's
  expiry date
- **The liability insurance** - the carrier, the coverage amount and its
  expiry date
- **The responsible managing individual (RMI)** - the named person behind the
  licence

Plus the licence itself: number, CCB licence type, original registration date
and expiry, the business name, the full address, county, phone and fax.

### Modes

- **rows** (default) - licence records matching your filters
- **aggregate** - counts by licence type, county or state

### Filters

Licence number, licence type (exact CCB class), business / individual name,
city, state, county, ZIP, bond company, insurance company, responsible
managing individual, expiry year and original registration year.

### Example inputs

**A residential general contractor in Portland, with its bond and insurance**

```json
{ "licenseType": "RGC", "city": "Portland", "maxResults": 25 }
```

**Every licence backed by one surety**

```json
{ "bondCompany": "WESTERN SURETY", "maxResults": 25 }
```

**Licences expiring in a given year**

```json
{ "expirationYear": "2028", "licenseType": "RGC", "maxResults": 25 }
```

**One licence by number** - a number covers one licence; a firm with several
endorsement classes appears once per class.

```json
{ "licenseNumber": "99833" }
```

### Example output

**An RGC licence in Portland** - `licenseType=RGC`, `city=Portland`:

```json
{
 "platform": "or-ccb",
 "source": "or-ccb-contractors",
 "corpus": "licenses",
 "recordKind": "contractor-license",
 "mode": "rows",
 "groupKey": "",
 "groupCount": "",
 "groupBy": "",
 "licenseNumber": "99833",
 "licenseType": "RGC",
 "relatedKey": "",
 "relatedType": "",
 "countyCode": "26",
 "countyName": "Multnomah",
 "licenseExpirationDate": "2028-06-13",
 "originalRegistrationDate": "1994-06-13",
 "bondCompany": "PHILADELPHIA INDEMNITY INS CO",
 "bondAmount": "25000",
 "bondExpirationDate": "2028-06-13",
 "insuranceCompany": "THE CINCINNATI CASUALTY COMPANY",
 "insuranceAmount": "1000000",
 "insuranceExpirationDate": "2026-10-01",
 "businessName": "WESTECH CONSTRUCTION INC",
 "address": "2204 NE 194TH AVE",
 "city": "PORTLAND",
 "state": "OR",
 "zip": "97230",
 "phone": "5037777000",
 "fax": "",
 "rmiName": "JAMES CLESSON WOODWARD",
 "exemptText": "Nonexempt",
 "endorsementText": "Residential General Contractor",
 "sourceUpdatedAt": "2026-09-26"
}
```

**`mode=aggregate`, `groupBy=licenseType`** - one count row per CCB class:

```
RGC       30,515
RSC        7,534
CGC2       5,505
LBPR       4,385
CSC2       2,483
CGC1       2,288
```

### Notes on the data, from the source

- **A licence number is not a unique row.** ~56.3k rows map to ~45.6k distinct
  licence numbers, because a firm holding several endorsement classes appears
  once per class. Searching by number can return more than one row.
- **The bond and insurance blocks are populated on roughly nine in ten
  licences** - bond on 90.1%, insurance on 88.7% of rows. They are not
  universal, and blank means the source records no bond or carrier for that
  licence.
- **Date filters are year-granularity.** Every date column in this source is
  text in `MM/DD/YYYY`, so a range comparison is lexicographic and wrong across
  years. Expiry and registration are therefore filtered by 4-digit year, and
  every date is normalised to `YYYY-MM-DD` on output so you can do exact work
  on the results.
- **The `related_type` column is blank on 98% of rows.** It marks the ~1,075
  rows that also carry a related CCB or OCHI key. It is exposed as data and
  never presented as a headline.

### Notes

- Public open data from data.oregon.gov. No login, no scraping.
- The register is refreshed continuously; every record carries
  `sourceUpdatedAt` so you can see the feed's currency without running
  anything.
- Charges are metered per record delivered, so a targeted query costs a
  fraction of a cent.

# Actor input Schema

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

rows = records matching your filters (default). aggregate = one count row per group.

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

Aggregate dimension, only used when mode=aggregate.

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

Exact licence number. NOTE: a number covers one licence, and a firm with several endorsement classes appears once per class.

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

Exact CCB licence type. Blank = any.

## `name` (type: `string`):

Business or individual name substring. Blank = any.

## `business` (type: `string`):

Business-name substring. Blank = any.

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

City substring, e.g. 'Portland'. Blank = any.

## `state` (type: `string`):

Two-letter state. Blank = any.

## `county` (type: `string`):

County-name substring. Blank = any.

## `zip` (type: `string`):

ZIP prefix, e.g. '972'. Blank = any.

## `bondCompany` (type: `string`):

Surety bond company substring, e.g. 'WESTERN SURETY'. Blank = any.

## `insuranceCompany` (type: `string`):

Liability insurance carrier substring. Blank = any.

## `rmiName` (type: `string`):

RMI name substring. Blank = any.

## `expirationYear` (type: `string`):

4-digit year: licences EXPIRING in that year, e.g. '2028'. Blank = any. Dates are MM/DD/YYYY text, so filtering is year-granularity only.

## `registeredYear` (type: `string`):

4-digit year: licences originally REGISTERED in that year. Blank = any.

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

Cap records returned for this run. Default 50 keeps the daily auto-test fast. 0 = no cap (the full matching slice, up to 10,000).

## Actor input object example

```json
{
  "mode": "rows",
  "groupBy": "licenseType",
  "licenseNumber": "",
  "licenseType": "",
  "name": "",
  "business": "",
  "city": "",
  "state": "",
  "county": "",
  "zip": "",
  "bondCompany": "",
  "insuranceCompany": "",
  "rmiName": "",
  "expirationYear": "",
  "registeredYear": "",
  "maxResults": 50
}
```

# Actor output Schema

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

Oregon CCB Contractors - Licenses, Bonds & Insurance - 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/or-ccb-contractors").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/or-ccb-contractors").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/or-ccb-contractors --silent --output-dataset

```

## MCP server setup

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

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/UwwWXHPyPxFwNJI8a/builds/6WaN3Wos7CdFZp4g6/openapi.json
