# US Building Permits with Job Types & Solar kW (`blazume/us-building-permits`) Actor

Recent building permits from official open data of 11 US cities and counties, tagged by job type (solar, battery, EV charger, roof, HVAC, ADU, new homes...) with solar kW, battery kWh, new units, ZIP income and home value, and the contractor's state license status.

- **URL**: https://apify.com/blazume/us-building-permits.md
- **Developed by:** [Blazume](https://apify.com/blazume) (community)
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.00 / 1,000 permit delivereds

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

## US Building Permits with Job Types & Solar kW

Recent building permits from the official open-data portals of **11 US cities and counties** (New York, Los Angeles, Chicago, Boston, San Francisco, Seattle, Austin, Washington DC, Minneapolis, Sacramento County, Miami-Dade County), in one table, with every permit tagged by **job type** and the numbers you filter on:

- **Job types**: solar PV, battery storage, EV charger, electrical service/panel, roof, HVAC/heat pump, water heater, plumbing, pool/spa, ADU, new single-family, new multifamily, new commercial, addition, remodel, kitchen/bath, windows/doors, foundation/structural, fence/deck/patio, demolition, fire alarm/sprinkler, sign.
- **Numbers**: solar system size (kW), battery capacity (kWh), number of EV chargers, new housing units, and whether the property is residential.
- **Area context**: median household income and median home value of the permit's ZIP code (US Census), and the state's average residential electricity price (US EIA).
- **Contractor license status**: in New York City, San Francisco, Sacramento County, Seattle and Austin, the contractor on the permit is matched to the state or city license board's own list: license number, classes, status (active, expired, suspended...), expiry, and bond and workers' compensation where the board publishes them.

Permit descriptions are free text written differently in every city ("installing 20 solar pv modules … total no. of rating 8.8 kw … 3 energy storage unit … 9.02 kwh each", "Installation of a roof-mounted … PV system, not exceeding 38.4kW"). This Actor reads them for you: keyword rules always run, and an optional AI step (Claude Haiku) fixes the job types and reads the numbers, adding up battery units (3 × 9.02 kWh = 27.06 kWh) and ignoring permit-class limits such as "not exceeding 38.4kW" that are not the system size.

### Use cases

- Market research: how many solar, battery, heat-pump or ADU permits were issued this week, by city and ZIP code.
- Supplier and distributor sales: new construction and large remodels with their job value and contractor.
- Contractor intelligence: which contractors pull which kinds of permits, and whether their license is active, suspended or about to lapse.
- Prioritising leads: sort solar, battery or remodel permits by the ZIP code's income and home value, or compare states by electricity price.
- Daily lead feed: schedule it with *Only new*, your ZIP codes and job types (for example battery storage and EV chargers in five ZIP codes), and get each new permit once.

### Input

| Field | What it does |
|---|---|
| Cities | One or more of the 11 cities and counties below. |
| Days back / From / To | Issue-date window. Default: the last 7 days. |
| Job types | Only permits covering at least one of these types. Empty = all. |
| Property type | Any, residential only, or commercial only. |
| Minimum job value | Only permits stating at least this value. |
| ZIP codes | Only permits in these ZIP codes (filtered in the city's own data API). |
| Keywords | Only permits whose type or description contains one of these words, for work outside the job types (e.g. skylight, elevator). |
| Refine tags with AI | On by default; included in the price. |
| Add contractor license status | On by default; included in the price. See below for the cities it covers. |
| Max permits | Caps the number of permits, and so the cost of a run. |
| Only new since my last run | Remembers what it delivered (in a key-value store in your account) and returns only permits it has not sent before. Schedule the Actor daily to get each new permit once. *Monitor name* keeps separate memories for different filter sets. |

### Output

One item per permit:

```json
{
  "id": "san-francisco:S20260727695",
  "city": "San Francisco",
  "state": "CA",
  "permitNumber": "S20260727695",
  "issuedDate": "2026-10-13",
  "address": "160 Upland Dr",
  "zipCode": "94127",
  "latitude": 37.728993193,
  "longitude": -122.462769069,
  "permitType": null,
  "workClass": null,
  "description": "solar permit: installing 20 solar pv modules, 440 watts per module, total no. of rating 8.8 kw. mounted: roof, ballasted: n, including 3 energy storage unit, of 240 vac, with 9.02 kwh each in capacity, ...",
  "valuationUsd": 50082,
  "contractor": null,
  "status": "issued",
  "jobTypes": ["solar", "battery"],
  "solarKw": 8.8,
  "batteryKwh": 27.06,
  "evChargers": null,
  "unitsAdded": null,
  "residential": null,
  "zipMedianHouseholdIncomeUsd": 214167,
  "zipMedianHomeValueUsd": 1847400,
  "stateResidentialElectricityCentsPerKwh": 33.25,
  "classifiedBy": "ai",
  "sourceDataset": "DBI Building Permits",
  "sourceUrl": "https://data.sf.gov/d/i98e-djp9"
}
```

`classifiedBy` is `"ai"` when the AI step reviewed the permit and `"rules"` when only keyword rules did (AI turned off, or unavailable for that batch). A number is `null` when the permit does not state it; nothing is guessed.

Area context comes from public US government statistics bundled with the Actor, not from the permit:

- `zipMedianHouseholdIncomeUsd`, `zipMedianHomeValueUsd`: US Census Bureau, American Community Survey 2020–2024 5-year estimates (tables B19013 and B25077), by ZIP Code Tabulation Area, which matches the ZIP code for almost all street addresses. The Census caps the top values: 250001 means $250,000 or more, and 2000001 means $2,000,000 or more. `null` when the city publishes no ZIP code (Chicago, Minneapolis, Miami-Dade) or the Census has no estimate for that ZIP code.
- `stateResidentialElectricityCentsPerKwh`: US Energy Information Administration, Electric Power Monthly, table 5.6.B, average residential price from January to July 2026, in cents per kWh.

### Contractor license status

`contractorLicense` is the contractor's license as the license board lists it, or `null` when the city publishes no contractor, the board has no list we can use, or no single license fits the name:

| City | License board | How the contractor is matched |
|---|---|---|
| New York | NYC Department of Buildings (general contractors, master plumbers, fire suppression, riggers, sign hangers, oil burner installers) | License type and number on the permit |
| San Francisco | California Contractors State License Board (CSLB) | CSLB number from the city's permit contacts list |
| Sacramento County | CSLB | Business name |
| Seattle | Washington State Department of Labor & Industries | Business name |
| Austin | Texas Department of Licensing and Regulation | Business name; Texas licenses only electrical and air-conditioning contractors (no state general-contractor license) |

A permit with a matched license (San Francisco):

```json
{
  "contractor": "Redlog Flooring Services Corp",
  "contractorLicense": {
    "board": "California Contractors State License Board (CSLB)",
    "licenseNumber": "1033872",
    "licenseType": null,
    "classifications": ["B", "C15", "C33", "C54"],
    "status": "active",
    "statusDetail": null,
    "issuedDate": "2017-12-11",
    "expirationDate": "2027-12-31",
    "pendingSuspensionDate": null,
    "workersComp": "insured",
    "workersCompExpires": "2027-09-08",
    "bondAmountUsd": 25000,
    "bondImpaired": null,
    "liabilityInsuranceExpires": null,
    "disciplinaryBond": false,
    "soleProprietor": false,
    "matchedBy": "license number",
    "boardDataDate": "2026-10-26",
    "lookupUrl": "https://www.cslb.ca.gov/OnlineServices/CheckLicenseII/CheckLicense.aspx"
  }
}
```

- `status` is one of `active`, `expired`, `suspended`, `revoked`, `inactive`, or `not listed` (San Francisco only: the permit's CSLB number is not among the board's current or renewable licenses, which means it expired more than five years ago, was cancelled or revoked, or was mistyped on the permit). `statusDetail` gives the reason in plain words where the board publishes one (for example "workers' compensation insurance" for a CSLB suspension).
- Fields a board does not publish are `null`: California has classes, workers' compensation, bonds and pending suspensions; Washington has specialties, bonds and liability insurance; New York City has the license type and status only; Texas has the license type and expiry.
- `matchedBy` says how the license was found. License numbers match exactly. Business names are compared after removing punctuation, "Inc", "LLC" and common abbreviations, and only when one company fits; in our tests about 1 to 2 name matches in 100 pointed to the wrong company, so check `lookupUrl` before relying on a single license.
- `boardDataDate` is the date the board gives for its list: the date of the CSLB download file, or when the open-data dataset was last updated (Washington, New York City, Texas). We check each list once a day, but boards update on their own schedule, so the date can be several days old. A license can change after that date.

**No personal names.** Owner and applicant names published by some cities are not included. Contractor business names are, except for sole owners whose license the board lists under the owner's own name (`soleProprietor: true`): their `contractor` is `null`, and the license fields remain.

### Data sources and freshness

| City | Source (official open data) | Updated by the city | ZIP codes |
|---|---|---|---|
| New York, NY | NYC Department of Buildings, DOB NOW: Build – Approved Permits | Daily | Yes |
| Los Angeles, CA | LA Department of Building and Safety, Building and Electrical Permits Issued from 2020 to Present | Weekly | Yes |
| Chicago, IL | City of Chicago, Building Permits | Daily | No |
| Boston, MA | City of Boston, Approved Building Permits (last 12 months) | Daily, about 1 day behind; our copy currently ends on November 2, 2026 (see Limits) | Yes |
| San Francisco, CA | Department of Building Inspection, Building Permits | Daily | Yes |
| Seattle, WA | Seattle Department of Construction and Inspections, Building, Electrical and Trade Permits | Daily (building permits run a few days behind) | Yes |
| Austin, TX | City of Austin, Issued Construction Permits | Daily | Yes |
| Washington, DC | DC Department of Buildings, Building Permits (one dataset per year) | About a week behind | Yes |
| Minneapolis, MN | City of Minneapolis, CCS Permits | Daily | No |
| Sacramento County, CA | Sacramento County, Permits | Daily | Yes |
| Miami-Dade County, FL | Miami-Dade County, Building Permits (2 previous years to present) | Daily, about 2 days behind | No |

Sources without ZIP codes are skipped when you filter by ZIP code. Washington DC publishes no job value.

Data is read live from each city's public data service every time you run the Actor, politely (requests are spaced as each site's robots.txt asks, and the Actor identifies itself). Boston publishes its permits only as one large file, so that file is read once a day instead and its last 12 months are kept. The contractor license lists are read once a day the same way: the CSLB statewide list of licensed contractors, and the open-data license datasets of Washington L\&I (data.wa.gov), the NYC Department of Buildings (NYC Open Data) and Texas TDLR (data.texas.gov); only the license fields above and business names (for matching) are kept. Each item links to its source dataset. Source data: City of New York, City of Los Angeles, City of Chicago, City of Boston, City and County of San Francisco, City of Seattle, City of Austin (data.austintexas.gov), District of Columbia, City of Minneapolis, County of Sacramento, Miami-Dade County. Area context: US Census Bureau and US Energy Information Administration.

Required notice for Chicago data: "This site provides applications using data that has been modified for use from its original source, www.cityofchicago.org, the official website of the City of Chicago. The City of Chicago makes no claims as to the content, accuracy, timeliness, or completeness of any of the data provided at this site. The data provided at this site is subject to change at any time. It is understood that the data provided at this site is being used at one's own risk."

### Pricing

One price per permit delivered, AI and contractor license status included, plus Apify's tiny run-start fee. Use *Max permits*, or a maximum charge per run, to cap the cost of a run: the Actor stops at the cap and the AI never reviews more permits than you pay for. Turning the AI step off does not change the price; it only leaves you with keyword-rule tags.

### Permitted use

- Follow each city's open-data terms. **Austin's terms ask that its data not be used to contact the individuals it represents**, so use Austin permits for analysis, not outreach.
- Do not use the data for credit, employment, tenant screening or insurance decisions. This Actor is not a consumer reporting agency, and the license fields are not a background check: confirm a license with the board (`lookupUrl`) before relying on it.
- If you contact anyone listed in permits, you are responsible for complying with telemarketing, do-not-call and anti-spam laws.

### Limits

- 11 cities and counties for now. Permits are only as complete and timely as each city's publication.
- Boston: since November 4, 2026 the City's data portal shows a browser check to automated requests, so we have paused reading it. Boston results currently end with permits issued on November 2, 2026. We are asking the City whether automated downloads are allowed, and will resume Boston or remove it depending on the answer.
- New York publishes one row per work type of a job, so one construction job can appear as several permits.
- Contractor licenses cover the five cities above. Los Angeles, Boston and Washington DC publish no contractor business name with their permits, and Minneapolis only the applicant's name; Illinois has no state general-contractor license; Florida's license files are not available to us.

# Actor input Schema

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

Cities to read. Most publish daily; Los Angeles weekly; Seattle's building permits run a few days behind. Boston is available for the last 12 months, currently up to November 2, 2026 (paused, see the README). Chicago, Minneapolis and Miami-Dade publish no ZIP codes, so they are skipped when you set ZIP codes.

## `daysBack` (type: `integer`):

Permits issued in the last N days, counting today. Default 7, or 14 with 'Only new'. Ignored when 'From' is set.

## `since` (type: `string`):

Optional: permits issued on or after this day.

## `until` (type: `string`):

Optional: permits issued on or before this day. Empty = today.

## `jobTypes` (type: `array`):

Only permits covering at least one of these job types. Empty = all permits.

## `propertyType` (type: `string`):

Permits whose property type cannot be told are kept only with 'Any'.

## `minValuationUsd` (type: `integer`):

Only permits with a stated job value of at least this amount. Many trade permits state no value and are then left out.

## `zipCodes` (type: `array`):

Only permits in these 5-digit ZIP codes, e.g. 78704. Empty = the whole city.

## `keywords` (type: `array`):

Only permits whose type or description contains at least one of these words (not case-sensitive), e.g. skylight or elevator. Use it for work outside the job types above; it combines with them.

## `useAi` (type: `boolean`):

Keyword rules always run. With this on, a language model (Claude Haiku) reviews each permit to fix job types and read solar kW, battery kWh, EV chargers and new units. Included in the per-permit price; turn it off only if you want rule tags alone.

## `contractorLicenses` (type: `boolean`):

Matches each permit's contractor to the state license board's list and adds its license number, classes, status (active, expired, suspended...), expiry, bond and workers' compensation where the board publishes them. Available for New York City, San Francisco, Sacramento County (California CSLB), Seattle (Washington L\&I) and Austin (Texas TDLR, electrical and air-conditioning contractors only). Included in the per-permit price.

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

You pay per permit delivered, so this also caps the cost of a run.

## `onlyNew` (type: `boolean`):

Return only permits this monitor has not delivered before, so a daily schedule gets each permit once. Looks back 14 days by default to catch permits that cities publish late.

## `monitorName` (type: `string`):

Keeps a separate 'only new' memory for each filter set. Leave empty for one default monitor.

## Actor input object example

```json
{
  "cities": [
    "austin"
  ],
  "daysBack": 7,
  "propertyType": "any",
  "useAi": true,
  "contractorLicenses": true,
  "maxItems": 10,
  "onlyNew": false
}
```

# Actor output Schema

## `permits` (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 = {
    "cities": [
        "austin"
    ],
    "daysBack": 7,
    "maxItems": 10
};

// Run the Actor and wait for it to finish
const run = await client.actor("blazume/us-building-permits").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 = {
    "cities": ["austin"],
    "daysBack": 7,
    "maxItems": 10,
}

# Run the Actor and wait for it to finish
run = client.actor("blazume/us-building-permits").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 '{
  "cities": [
    "austin"
  ],
  "daysBack": 7,
  "maxItems": 10
}' |
apify call blazume/us-building-permits --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,blazume/us-building-permits"
        }
    }
}
```

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/aR7oNgjWF1MqUON2I/builds/KzVI3RuksRZCjSSoz/openapi.json
