# City Building Permits Scraper - Solar, EV, Roofing, ADU (`groundplanes/city-solar-ev-permits`) Actor

Scrape newly issued solar PV, EV charger, heat pump/HVAC, roofing, and ADU permits from Austin, Chicago, Los Angeles, Seattle, and San Francisco open-data portals. Coverage varies by city: Los Angeles covers roofing, ADU, and HVAC only.

- **URL**: https://apify.com/groundplanes/city-solar-ev-permits.md
- **Developed by:** [Groundplane Labs](https://apify.com/groundplanes) (community)
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.10 / 1,000 permits

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

## City Building Permits Scraper - Solar, EV, Roofing, ADU

Scrape newly issued building and electrical permits for **solar PV systems**, **EV chargers (EVSE)**, **heat pumps / HVAC**, **roofing / re-roofing**, and **accessory dwelling units (ADUs)** from five municipal open-data portals (**Austin**, **Chicago**, **Los Angeles**, **Seattle**, and **San Francisco**), normalized into one unified schema. Coverage is not uniform across cities: **Los Angeles covers ROOFING, ADU, and HVAC only**, because its source dataset publishes no electrical permits (see the coverage table below). Seattle solar, EV charger, and HVAC permits come from its separate Electrical Permits dataset.

> **Disclaimer:** This Actor is an independent tool and is not affiliated with or endorsed by the City of Austin, the City of Chicago, the City of Los Angeles, the City of Seattle, or the City and County of San Francisco.

***

### What it does

- **Queries 5 Municipal Socrata Open-Data Portals Live:** Uses server-side SoQL `$where` filtering combined with word-boundary classification rules to pull newly issued clean-energy and construction permits across:
  - **Austin, TX** (`data.austintexas.gov/resource/3syk-w9eu.json`)
  - **Chicago, IL** (`data.cityofchicago.org/resource/ydr8-5enu.json`)
  - **Los Angeles, CA** (`data.lacity.org/resource/pi9x-tg5x.json`): building permits only, so ROOFING, ADU, and HVAC categories only
  - **Seattle, WA** (`data.seattle.gov/resource/c4tj-daue.json` Electrical Permits for SOLAR, EV_CHARGER, and HVAC; `data.seattle.gov/resource/76t5-zqzr.json` Building Permits for ROOFING and ADU)
  - **San Francisco, CA** (`data.sf.gov/resource/i98e-djp9.json`)
- **Unified Multi-City Schema:** Normalizes city-specific column names, dates, valuations, geocoded coordinates, and contractor details into a single flat schema (`city`, `permitNumber`, `category`, `permitType`, `workDescription`, `status`, `appliedDate`, `issuedDate`, `valuationUsd`, `address`, `zip`, `latitude`, `longitude`, `contractorName`, `contractorLicense`, `contractorPhone`, `sourceUrl`).
- **Fault-Tolerant Across Cities:** If one municipal portal is temporarily undergoing maintenance, the Actor logs a warning and continues collecting permits from the remaining selected cities.
- **Privacy Controls Built In:** Homeowner / property owner person names are excluded by default (`includeOwnerNames: false`), while commercial contractor business names, licenses/certifications, and business phone numbers are always included when published.
- **Newest-First Ordering:** Results are deduplicated by `city + permitNumber` and sorted by `issuedDate` descending before applying `maxItems`.

***

### Coverage by city and category

Permits issued in the last 30 days (2026-10-02 to 2026-11-01), counted live via SoQL on 2026-11-01 with this Actor's classifier and deduplication applied. Counts shift daily as cities publish new permits.

| City | SOLAR | EV_CHARGER | HVAC | ROOFING | ADU |
|---|---|---|---|---|---|
| Austin | 57 | 57 | 154 | 27 | 4 |
| Chicago | 153 | 31 | 42 | 158 | 11 |
| Los Angeles | Not published | Not published | 23 | 1,286 | 468 |
| Seattle | 31 | 95 | 281 | 17 | 18 |
| San Francisco | 14 | 3 | 32 | 9 | 16 |

- **Los Angeles:** the source dataset (`pi9x-tg5x`) publishes building permits only. It contains no electrical permit types and its solar flag has never been set, so SOLAR and EV_CHARGER return nothing for Los Angeles. (A keyword search of its building permit text finds about 5 incidental solar mentions in the window; those are not solar permits.) Requesting Los Angeles with SOLAR or EV_CHARGER is flagged in the run status: if those are the only requested pairs, the run ends `PARTIAL:` with the reason stated; if mixed with covered pairs, the status carries a note naming the uncovered pairs.
- **Seattle:** SOLAR, EV_CHARGER, and HVAC are read from Electrical Permits (`c4tj-daue`), where Seattle permits that work. ROOFING and ADU are read from Building Permits (`76t5-zqzr`). Before this split, Seattle returned 1 solar/EV row in the same 30-day window; the Electrical Permits source returns 126 (31 solar, 95 EV charger), against 135 raw keyword candidates in a direct SoQL count on `c4tj-daue`.

***

### Who it's for

- **Solar, Battery Storage & EVSE Equipment Distributors:** Track active solar and EV charger installers (`contractorName`, `contractorLicense`, `contractorPhone`) and volume by metro area.
- **HVAC, Roofing & Electrical Subcontractors:** Monitor newly issued permits and commercial remodel activity across major metro markets.
- **Clean-Energy & Urban Housing Researchers:** Analyze rooftop solar adoption, EV charging infrastructure deployment, electrification (heat pumps), and ADU construction trends at the street and ZIP code level.
- **Property & Insurance Analysts:** Verify recent roofing, electrical, and solar PV improvements on commercial and residential properties.

***

### Input

All parameters have working defaults/prefills that return results in under 2 minutes.

| Field | Type | Default / Prefill | Description |
|---|---|---|---|
| `cities` | `array<string>` | `["AUSTIN", "CHICAGO", "SEATTLE"]` | Municipal portals to query: `AUSTIN`, `CHICAGO`, `LOS_ANGELES`, `SEATTLE`, `SAN_FRANCISCO`. |
| `categories` | `array<string>` | `["SOLAR", "EV_CHARGER"]` | Permit categories to match: `SOLAR`, `EV_CHARGER`, `HVAC`, `ROOFING`, `ADU`. |
| `issuedDateFrom` | `string` | `""` (today − 30 days) | Earliest permit issue date in `YYYY-MM-DD` format. When blank, defaults to 30 days ago. |
| `minValuationUsd` | `integer` | `0` | Minimum reported project valuation in USD (`0` includes all permits, including those without a reported valuation). |
| `includeOwnerNames` | `boolean` | `false` | Include property owner / homeowner names (`ownerName`) when published by the city portal. Defaults to `false` for privacy compliance. |
| `socrataAppToken` | `string` (secret) | `""` | Optional Socrata `X-App-Token` for higher rate limits on large historical queries. |
| `maxItems` | `integer` | `200` | Maximum number of permit records to return. |

#### Example input JSON

```json
{
  "cities": ["AUSTIN", "CHICAGO", "SEATTLE"],
  "categories": ["SOLAR", "EV_CHARGER"],
  "issuedDateFrom": "",
  "minValuationUsd": 0,
  "includeOwnerNames": false,
  "socrataAppToken": "",
  "maxItems": 200
}
```

#### Example run options (with default $50 max charge protection)

When invoking via the Apify API or CLI, set a default maximum charge of **$50** (`"maxTotalChargeUsd": 50`):

```json
{
  "maxTotalChargeUsd": 50
}
```

The Actor checks `calculate_max_event_charge_count_within_limit("apify-default-dataset-item")` before every dataset push and stops cleanly when your spending limit is reached.

***

### Output

Results are saved to the default dataset, deduplicated by `city + permitNumber`, and sorted by `issuedDate` descending.

#### Output fields

| Field | Type | Description |
|---|---|---|
| `city` | `string` | City identifier (`AUSTIN`, `CHICAGO`, `LOS_ANGELES`, `SEATTLE`, `SAN_FRANCISCO`). |
| `permitNumber` | `string` | Official municipal building or electrical permit number. |
| `category` | `string` | Matched permit category (`SOLAR`, `EV_CHARGER`, `HVAC`, `ROOFING`, `ADU`). |
| `permitType` | `string \| null` | City permit type / work class description. |
| `workDescription` | `string \| null` | Official scope of work / permit description text. |
| `status` | `string \| null` | Current permit status (e.g. `Active`, `ACTIVE`, `Issued`, `issued`). |
| `appliedDate` | `string \| null` | Application / filing date in `YYYY-MM-DD` format. |
| `issuedDate` | `string \| null` | Permit issue date in `YYYY-MM-DD` format. |
| `valuationUsd` | `number \| null` | Reported project cost / job valuation in USD. |
| `address` | `string \| null` | Street address of the permitted project. |
| `zip` | `string \| null` | Postal ZIP code (`XXXXX`). |
| `latitude` | `number \| null` | WGS84 latitude, rounded to 3 decimal places. |
| `longitude` | `number \| null` | WGS84 longitude, rounded to 3 decimal places. |
| `contractorName` | `string \| null` | Contractor company / business name (published by Austin, Chicago, and Seattle). |
| `contractorLicense` | `string \| null` | Contractor license or certification identifier, only when a city publishes it as a structured field. Currently null for all five cities: Austin publishes only a trade classification and Chicago only unattributed certificate numbers inside free text, and neither is emitted as a license. |
| `contractorPhone` | `string \| null` | Contractor phone number as published by Austin (one per permit; Austin labels it the contractor phone, and it may be an individual contractor's line). |
| `sourceUrl` | `string` | Direct URL to the city permit record or Socrata endpoint entry. |
| `ownerName` | `string \| null` | Property owner / applicant name, included **only** when `includeOwnerNames` is `true`. Populated only for Chicago (OWNER party) and Austin (applicant name); always null for Los Angeles, Seattle, and San Francisco, whose portals do not publish it in these tables. |

#### Sample output row (synthetic example)

```json
{
  "city": "AUSTIN",
  "permitNumber": "2026-149800 EP",
  "category": "SOLAR",
  "permitType": "Electrical Permit",
  "workDescription": "Installation of 8.4 kW roof mounted solar PV system with 13.5 kWh battery energy storage.",
  "status": "Active",
  "appliedDate": "2026-10-25",
  "issuedDate": "2026-10-30",
  "valuationUsd": 28500.0,
  "address": "4810 BURNET RD",
  "zip": "78756",
  "latitude": 30.319,
  "longitude": -97.739,
  "contractorName": "SUNBELT CLEAN ENERGY SOLUTIONS LLC",
  "contractorLicense": null,
  "contractorPhone": "512-555-0148",
  "sourceUrl": "https://abc.austintexas.gov/web/permit/public-search-other?t_detail=1&t_selected_folderrsn=13999999"
}
```

***

### How pricing works

Pay per result: **$3.00 per 1,000 results** ($0.003 per row). You only pay for rows returned.

***

### Data source and terms

- **Official Open-Data Portals (Updated Daily / Weekly by Each Municipality):**
  - **Austin:** [City of Austin Issued Construction Permits (`3syk-w9eu`)](https://data.austintexas.gov/Building-and-Development/Issued-Construction-Permits/3syk-w9eu): Public Domain / City of Austin Open Data Terms of Use
  - **Chicago:** [City of Chicago Building Permits (`ydr8-5enu`)](https://data.cityofchicago.org/Buildings/Building-Permits/ydr8-5enu): [City of Chicago Terms of Use](https://www.chicago.gov/city/en/narr/foia/data_disclaimer.html)
  - **Los Angeles:** [Building Permits Issued from 2020 to Present (N) (`pi9x-tg5x`)](https://data.lacity.org/City-Infrastructure-Service-Requests/Building-and-Safety-Permit-Information-Old/pi9x-tg5x): City of Los Angeles Open Data Terms
  - **Seattle:** [Seattle Building Permits (`76t5-zqzr`)](https://data.seattle.gov/Permitting/Building-Permits/76t5-zqzr) and [Seattle Electrical Permits (`c4tj-daue`)](https://data.seattle.gov/Permitting/Electrical-Permits/c4tj-daue): [City of Seattle Open Data Terms of Use](https://www.seattle.gov/tech/initiatives/open-data/terms-of-use)
  - **San Francisco:** [DataSF Department of Building Inspection Permits (`i98e-djp9`)](https://data.sf.gov/Housing-and-Buildings/Building-Permits/i98e-djp9): [DataSF Terms of Use](https://datasf.org/opendata/terms-of-use/)

***

### Compliance

This Actor retrieves public building permit records published by municipal open-data portals. Homeowner / property owner names are turned **off by default** (`includeOwnerNames: false`).

If you enable `includeOwnerNames` or use contractor/property data for outreach:

- **Regulatory Compliance:** Buyers are solely responsible for complying with the Telephone Consumer Protection Act (**TCPA**), the **National Do-Not-Call (DNC) Registry**, the **CAN-SPAM Act**, the EU **GDPR** where it applies, and all applicable state and local privacy and telemarketing laws before calling any party.
- **No Consumer / Individual Targeting:** This Actor is intended for B2B commercial research, contractor intelligence, and market analysis, and must not be used for unlawful consumer or individual homeowner solicitation.

#### Privacy and residual risk

- **Residual risk: property addresses and coordinates.** Most solar, EV charger, and heat pump permits are issued for private residences, and every row carries the permitted property's street address (`address`) by default. That is inherent to the source data and to the permit record itself; it cannot be removed without removing the record's usefulness for permit verification. As a mitigation, `latitude` and `longitude` are rounded to 3 decimal places (about 100 m) in the output, so coordinates locate a property only approximately. The street address itself is not rounded or masked. Treat downloaded datasets as location data about private homes and handle them accordingly.
- **Contractor fields can name individuals.** `contractorName` is a business field, but sole operators appear under personal names: Chicago contractor slots sometimes hold a person's name rather than a company, and the Austin `contractorPhone` is one phone per permit as labeled by the city, which may be an individual contractor's line. Treat both as personal data where they name or reach an individual.

***

### Limits and FAQ

- **Which cities publish contractor names and phone numbers?**
  - **Austin** publishes `contractorName` and a contractor phone (one per permit, as labeled by the city; it may be an individual contractor's line). Austin does not publish a contractor license number: its `contractor_trade` field is a trade classification, so `contractorLicense` is `null` for Austin.
  - **Chicago** publishes `contractorName` (across up to 15 party slots on each permit). Chicago publishes no structured license field; certificate numbers appear only inside free-text work descriptions, unattributed to any named party, so they are not emitted: `contractorLicense` is `null` for Chicago.
  - **Seattle** publishes `contractorName` (`contractorcompanyname`).
  - **Los Angeles** and **San Francisco** do not include contractor detail columns in their primary Socrata permit table (`pi9x-tg5x` and `i98e-djp9`), so `contractorName` is `null` for those two cities.
- **San Francisco address variants:** one permit can appear in the source with several street-address spellings (for example 228, 230, and 230 A 04th Ave). The dedupe key (city plus permitNumber) keeps one variant, so the surviving address spelling can differ between runs.
- **Why is `zip` null for Chicago permits?**
  The Chicago dataset publishes no property ZIP column. Its per-party ZIP fields are mailing ZIPs (often in another city or state), so they are never emitted as the property ZIP: `zip` is `null` for Chicago by disclosure.
- **What happens if one city's Socrata portal times out?**
  Each city is queried independently with up to 6 tries and jittered exponential backoff (2 to 32 seconds, capped at 120 seconds, honoring the portal's `Retry-After` header). If one city portal fails, the Actor logs a warning, continues returning permits from the remaining selected cities, and ends with a `PARTIAL:` status naming the failed city and the per-city row counts.
- **Why did my run end `PARTIAL:` because a source is stale?**
  Each run checks every requested source's Socrata `rowsUpdatedAt` metadata. If a source has not updated in more than 21 days, the run ends `PARTIAL:` naming the city, the dataset, and its last update date, because its counts may be silently incomplete. Los Angeles normally lags about a week, which is inside the threshold.
- **Why does Los Angeles return no solar or EV charger permits?**
  The Los Angeles source dataset publishes building permits only: it has no electrical permit types and its solar flag has never been set. Los Angeles covers ROOFING, ADU, and HVAC. Requesting SOLAR or EV_CHARGER for Los Angeles is flagged in the run status rather than silently returning nothing.

***

### Troubleshooting

- **Run ends `PARTIAL:`:** the status message names the reason (a failed city portal, a stale source with its last update date, a requested city and category pair the source does not publish, skipped invalid rows, or a scan cap) and the per-city row counts. One city failing never fails the whole run.
- **Zero matches:** a healthy run with no matching permits ends `Complete: 0 rows matched your filters`. Widen `issuedDateFrom`, add cities or categories, or lower `minValuationUsd`.
- **Caps:** reaching `maxItems` is reported in the status. Reaching your max charge stops the run early as a `PARTIAL:` with the reason stated.
- **Canary input** (returns rows in under 30 seconds):
  ```json
  {
    "cities": ["CHICAGO"],
    "categories": ["SOLAR"],
    "issuedDateFrom": "",
    "minValuationUsd": 0,
    "includeOwnerNames": false,
    "socrataAppToken": "",
    "maxItems": 5
  }
  ```

Found a problem or need a field? Open an issue on the Issues tab; we respond quickly.

***

### Changelog

#### v0.1.3 (2026-11-01)

- Seattle solar, EV charger, and HVAC permits now come from the Seattle Electrical Permits dataset (`c4tj-daue`); Building Permits (`76t5-zqzr`) still supplies Seattle roofing and ADU. Seattle solar/EV yield for the last 30 days went from 1 row to 126.
- Los Angeles coverage corrected: Los Angeles covers ROOFING, ADU, and HVAC only, because its source publishes no electrical permits. An explicit per-city category capability map now flags any requested pair a source cannot supply in the run status (a run requesting only unsuppliable pairs ends `PARTIAL:` with the reason).
- Listing honesty: title no longer claims uniform 5-city coverage, a per-city by category coverage table with measured 30-day counts was added, and the README intro states the per-city coverage plainly.
- Per-city freshness gate: a source whose Socrata `rowsUpdatedAt` is more than 21 days old ends the run `PARTIAL:` naming the city and its last update date.
- Retry policy: up to 6 tries with jittered backoff (2 to 32 seconds, capped at 120 seconds) and `Retry-After` honored as seconds or an HTTP-date.
- Privacy: latitude and longitude are rounded to 3 decimal places, and the residual risk of property street addresses and coordinates is documented in the Compliance section.
- Added `exampleRunInput`, the per-1,000 pricing figure, and the current Los Angeles dataset name in the source links.

#### v0.1.2 (2026-10-31)

- Red Team correction round: `contractorLicense` is now null for every city. Austin's value was the source trade classification (not a license) and Chicago's was an unattributed certificate number mined from free text that could belong to a different party than the named contractor; neither is emitted as a license. The field now carries a value only if a city publishes a license as a structured field.
- Disclosures added: per-city `ownerName` availability (Chicago and Austin only), the Austin contractor phone residual note (one phone per permit, may be an individual contractor's line), GDPR in the Compliance section, and the San Francisco address-variant dedupe note. TEST_NOTES marked as a historical v0.1 record.

#### v0.1.1 (2026-10-31)

- Status contract fixed: runs now end `Complete:` or `PARTIAL:` with per-city counts; zero matches on a healthy source is a `Complete:` success, not a failure.
- Chicago `zip` is now `null`: the dataset has no property ZIP column, and per-party mailing ZIPs were previously emitted as the property ZIP.
- Added per-row validation and a per-city core-column sentinel (schema drift now fails that city loudly as a `PARTIAL:` source reason).
- Store categories set to BUSINESS only; default run options now carry the $50 max charge.

#### v0.1 (2026-10-31)

- Initial release supporting Austin, Chicago, Los Angeles, Seattle, and San Francisco Socrata permit portals across `SOLAR`, `EV_CHARGER`, `HVAC`, `ROOFING`, and `ADU` categories.

# Actor input Schema

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

Permit trade/equipment categories to extract: SOLAR (solar PV, photovoltaic), EV_CHARGER (EVSE, electric vehicle charger), HVAC (heat pump, furnace, mini-split, HVAC), ROOFING (reroof, roof replacement), ADU (accessory dwelling unit, DADU, JADU).

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

Select one or more municipal open-data permit portals to query: AUSTIN, CHICAGO, LOS_ANGELES, SEATTLE, SAN_FRANCISCO.

## `includeOwnerNames` (type: `boolean`):

Defaults to false for privacy compliance because municipal permit portals often list private homeowners as the property owner or applicant. Contractor business names, licenses, and business phones are always included.

## `issuedDateFrom` (type: `string`):

Earliest permit issue date in YYYY-MM-DD format. Leave blank to default to 30 days ago (today - 30 days).

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

Maximum number of normalized permit records to return, sorted newest first by issuedDate.

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

Minimum reported project cost / job valuation in USD. Set to 0 to include all permits (including permits where valuation is unreported).

## `socrataAppToken` (type: `string`):

Optional Socrata X-App-Token header for higher rate limits on large historical queries. Not required for normal runs.

## Actor input object example

```json
{
  "categories": [
    "SOLAR",
    "EV_CHARGER"
  ],
  "cities": [
    "AUSTIN",
    "CHICAGO",
    "SEATTLE"
  ],
  "includeOwnerNames": false,
  "issuedDateFrom": "",
  "maxItems": 200,
  "minValuationUsd": 0,
  "socrataAppToken": ""
}
```

# Actor output Schema

## `results` (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 = {
    "categories": [
        "SOLAR",
        "EV_CHARGER"
    ],
    "cities": [
        "AUSTIN",
        "CHICAGO",
        "SEATTLE"
    ],
    "includeOwnerNames": false,
    "issuedDateFrom": "",
    "maxItems": 200,
    "minValuationUsd": 0,
    "socrataAppToken": ""
};

// Run the Actor and wait for it to finish
const run = await client.actor("groundplanes/city-solar-ev-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 = {
    "categories": [
        "SOLAR",
        "EV_CHARGER",
    ],
    "cities": [
        "AUSTIN",
        "CHICAGO",
        "SEATTLE",
    ],
    "includeOwnerNames": False,
    "issuedDateFrom": "",
    "maxItems": 200,
    "minValuationUsd": 0,
    "socrataAppToken": "",
}

# Run the Actor and wait for it to finish
run = client.actor("groundplanes/city-solar-ev-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 '{
  "categories": [
    "SOLAR",
    "EV_CHARGER"
  ],
  "cities": [
    "AUSTIN",
    "CHICAGO",
    "SEATTLE"
  ],
  "includeOwnerNames": false,
  "issuedDateFrom": "",
  "maxItems": 200,
  "minValuationUsd": 0,
  "socrataAppToken": ""
}' |
apify call groundplanes/city-solar-ev-permits --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,groundplanes/city-solar-ev-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/VRQExk5idoRWKfhBz/builds/wuCzKbdxFPDxsFYHg/openapi.json
