StateLicense blog

Oregon CCB API: Query the Socrata Dataset Like a Developer

Oregon CCB API guide: query the CCB Active Licenses Socrata dataset (g77e-6bhs) for license, bond, and insurance fields, and handle its text-date trap.

By StateLicensePublished

The Oregon CCB API most developers start with is not a board-run API at all. It is the Construction Contractors Board's Active Licenses dataset on Oregon's open data portal, published through Socrata under dataset ID g77e-6bhs. One HTTP request returns license, bond, and insurance fields for active Oregon contractors, no scraping or form submission required. That makes it the fastest way to prototype an Oregon check, and the easiest place to build a wrong assumption into production: the dataset is active-licenses-only, its dates are text, and it carries none of the complaint or disciplinary history the CCB's own search shows.

This guide shows the endpoint, the fields worth pulling, the three traps that break most first integrations, and the point where hand-rolling per-state queries stops paying. If you only need Oregon, Socrata may be all you need. If you need Oregon plus five other states, read the last section before writing your second state adapter.

Last reviewed October 28, 2026. This is an operational guide, not legal advice. Dataset fields and portal rules change; confirm current requirements with the CCB first.

What is the Oregon CCB Socrata dataset?

Oregon publishes open data through data.oregon.gov, and every dataset there gets a Socrata endpoint. The CCB's dataset is called CCB Active Licenses, at https://data.oregon.gov/resource/g77e-6bhs.json. You query it with SoQL, Socrata's SQL-like query language, using $select, $where, $limit, and $offset.

The data dictionary lists the fields that matter for verification work:

  • license_number: the CCB license number, the stable key to join on and check against the CCB search.
  • license_type: the endorsement code, such as RGC (residential general) or RSC (residential specialty).
  • full_name: the legal name of the license holder, which must match the Secretary of State business filing.
  • county_name and city: where the license holder is based, useful for geographic filtering.
  • bond_company, bond_amount, bond_exp_date: surety, bond amount, expiration date.
  • ins_company, ins_amount, ins_exp_date: liability carrier, coverage amount, expiration date.
  • lic_exp_date and orig_regis_date: license expiration, and the effective date of its first term.
  • rmi_name: the Responsible Managing Individual, whose experience and exam stand behind the license.

Two facts shape everything else. First, bond and insurance are first-class fields here, unusually generous for a state dataset: one query answers "is this contractor bonded and insured, and when do both expire" without a second source. Second, what is missing matters just as much: no complaint history, disciplinary action, or unpaid-claims field. For those, use the CCB's own Contractor License Search, which our Oregon CCB license lookup guide walks through.

How do you query the Oregon CCB API?

A single-license lookup is one request. Ask for only the columns you need and filter on the license number:

import requests

BASE = "https://data.oregon.gov/resource/g77e-6bhs.json"
HEADERS = {"X-App-Token": "YOUR_APP_TOKEN"}

params = {
    "$select": "license_number,license_type,full_name,lic_exp_date,"
               "bond_company,bond_amount,bond_exp_date,"
               "ins_company,ins_amount,ins_exp_date",
    "$where": "license_number='123456'",
    "$limit": 5,
}
resp = requests.get(BASE, headers=HEADERS, params=params, timeout=30)
resp.raise_for_status()
rows = resp.json()

A bulk pull, such as licenses expiring in a given month, needs pagination. Socrata returns 1,000 rows by default, and its SODA 2.0 endpoints cap a single request at 50,000 rows. Page with $limit and $offset, order by license_number so rows do not shift between pages, and stop when a page comes back empty. Select only the columns you need: pulling the full row set over tens of thousands of records is slow for no benefit.

Register a free app token before you run anything on a schedule. Without one, your requests share a throttled pool keyed to your IP address, and a pagination loop is exactly the workload that gets throttled halfway through. With a token, Socrata gives your application its own pool, and its newer Soda3 API asks for a token or authentication anyway, so treat one as a requirement.

What trips developers up?

Three traps break most first Oregon integrations.

1. Dates are text, not dates. Every date column, lic_exp_date, bond_exp_date, ins_exp_date, orig_regis_date, is plain text in MM/DD/YYYY form. You cannot run a server-side date range comparison on it. Narrow on the server with a like match on month and year, for example ins_exp_date like '11/%/2026', then parse and filter the exact window in your own code. If your window crosses New Year, query both years. Comparing these text dates as timestamps silently returns the wrong set, and the wrong set is worse than an error.

2. Active-only means absence is ambiguous. A license that expired, was suspended, or was revoked drops out of the picture, and a missing row does not tell you which of those happened, or whether you simply misspelled the business name. Never report "not licensed" from a Socrata miss alone: confirm against the CCB search, try name variations, and check the phone number first. An expiration date in the past is likewise a signal to recheck, not a verdict on its own.

3. Names are messy, and sole proprietors are people. The dataset mixes businesses and sole proprietors, and full_name for a sole proprietor is a person's name. If you are building a lead list or roster, filter to businesses by entity markers such as LLC, Inc, or Corp, and leave rmi_name out unless you genuinely need it. On matching, search with less, not more: a short name fragment beats a full legal name with punctuation, because one apostrophe difference is enough to miss a real record.

A fourth, quieter trap is freshness. The CCB's own search updates every 6 hours daily, but the Socrata dataset is a published extract, not the live board system, so check its metadata for its last update before promising same-day freshness. Our contractor license monitoring guide explains how to design alerts around that gap.

When does a normalized API beat hand-rolled Socrata queries?

For one state and one use case, Socrata wins on cost: it is free, documented, and one afternoon of work. The math changes at the second state.

Hand-rolling means one adapter per state, each with its own schema, date format, pagination rule, and failure mode. California's CSLB data is HTML, Texas TDLR is a search form, Florida DBPR is an HTML table, and Washington L&I is another Socrata dataset with different columns. None of them agree on what a license record looks like, and none warn you when they change a column name. Add workers' compensation status, which Oregon's dataset does not carry, and you are joining extra sources per state with different keys.

A normalized API earns its price when any of these are true:

  • You verify in more than two states, and every new state would mean a new adapter and a new on-call failure mode.
  • You recheck on a schedule, so a silent schema change or a throttled pagination loop becomes a data-quality incident, not a one-off error.
  • You need one stable record shape downstream: onboarding, COI tracking, and draw approvals should not each parse a different state's date format.
  • You need fields the open dataset lacks, such as complaint history, or a status that distinguishes expired from suspended from revoked.

Oregon CCB Socrata checklist

  1. Register a free app token on data.oregon.gov before running scheduled queries.
  2. Query g77e-6bhs with $select limited to the columns you need, and filter server-side with $where.
  3. Page with $limit and $offset, ordered by license_number; remember the 1,000-row default.
  4. Parse text dates in your own code; never compare MM/DD/YYYY strings as dates on the server.
  5. Treat a missing row as "unconfirmed," not "unlicensed," and confirm against the CCB search.
  6. Filter lead and roster pulls to businesses, and leave rmi_name out unless you need it.
  7. Check the dataset metadata for its last update before promising freshness.
  8. For complaint history, and for any state beyond Oregon, use the board search or a normalized API.

For a single Oregon lookup, Socrata is the fastest honest answer. For a roster across states, the same checks run faster through one normalized record. StateLicense offers a free public license lookup covering OR, CA, FL, TX, VA, WA, and NYC, and our contractor license verification API returns the same fields in one shape across states.

Frequently asked questions

Is there an official Oregon CCB API?

There is no board-run REST API for CCB licenses. The closest official machine-readable source is the CCB Active Licenses dataset on Oregon's open data portal, dataset g77e-6bhs. For the authoritative record, including complaint and disciplinary history, use the CCB's own Contractor License Search.

What fields does the CCB Socrata dataset include?

License number, license type, business name, location, bond and insurance company, amount, and expiration, license expiration, original registration date, and the Responsible Managing Individual. It does not include complaint history, disciplinary actions, or workers' compensation status.

Why does my Socrata query return only 1,000 rows?

That is Socrata's default page size. Add $limit (up to 50,000 on SODA 2.0 endpoints) and page with $offset until a page comes back empty. Without an app token, large pagination loops can also hit shared IP throttling, so register a token first.

Sources