# CA LA County Building Permits (EPIC-LA) (`j0401/ca-epic-la-permits`) Actor

LA County unincorporated building & planning cases (EPIC-LA public data, 916k records): residential / commercial / multifamily / electrical / plumbing / mechanical / solar / pool / road permits with status, valuation, dates, AIN, ADU & affordable-housing flags.

- **URL**: https://apify.com/j0401/ca-epic-la-permits.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 ca epic-la permit 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

## CA LA County Building Permits (EPIC-LA) - Unincorporated Permit & Planning Cases

LA County Public Works publishes its **entire unincorporated-area case history** - every building, construction and planning case filed in the county's unincorporated communities - as open data. This actor turns that register into a **charged-per-record lookup and diligence tool**.

**Built for:** construction & development leads (who just pulled a permit, what's being built where), contractor / builder prospecting, real-estate & property diligence, ADU / affordable-housing market research, disaster-recovery rebuild tracking, and LA County building-activity analytics.

### What it covers

**916,509 cases** across the county's unincorporated communities (the areas outside LA's 88 city limits - Malibu, East LA, Altadena, Hacienda Heights, unincorporated Torrance / Santa Monica Mountains, and hundreds more). Two case modules:

| Module | What it is | Rows |
|---|---|---|
| `permits` | **building & construction permits** - the useful slice | 614,180 |
| `planning` | zoning / land-use plan reviews | 302,329 |

#### `permits` - the building-permit register (default)

**614,180 building & construction cases**, including:

| Permit type | What it is |
|---|---|
| Unincorporated Building Residential / Commercial / Multifamily | building permits (new, additions, alterations) |
| Electrical / Plumbing / Mechanical / Solar | trade permits |
| Road / Sewer / Grading / Pool & Spa | infrastructure & site work |
| Construction & Demolition / Flood / Film | special permits |

Every case carries its **case number**, project name, **status**, the **apply / complete / expire / issuance / last-inspection dates**, **permit valuation** (filled on ~34% of rows - building & valuation-carrying cases; many trade permits are zero), the **main address** (filled on ~95% of rows) and **assessor parcel number (AIN)**, the supervisorial district and countywide statistical area, current & proposed **land-use codes**, **ADU (accessory dwelling unit)** and **junior-ADU flags**, **new-dwelling-unit counts**, **affordable-housing** designation, and disaster-recovery rebuild tracking (for the county's disaster areas).

#### `planning` - zoning & land-use reviews

**302,329** plan reviews (RPPL series) - the zoning conformance and land-use cases that precede or accompany building. Useful for understanding what's been cleared for a property.

### Status

The source carries a **large status vocabulary (~40 values)** - this actor matches status exactly, never by loose substring. Key values: **Finaled** (333,838) / **Issued** (146,000) / **Approved** (98,956) / Completed / Void / Accepted / Canceled / Open / Expired / Denied / In Review / Withdrawn / Rejected / Revoked. Ask for `open` (or `active`) to get the live in-progress slice (Open / In Review / New / Waiting for Applicant / Approved Pending Clearances / ...).

### Typical questions

- "What **building permits were pulled in this neighborhood** in the last year?"
- "Show recent **residential permits** in unincorporated East LA."
- "Which **contractor** is building the big **ADU** projects?"
- "What's the **permit valuation mix** - find permits over $500k."
- "**Finaled commercial permits** by countywide statistical area."
- "Permits on **this parcel (AIN)** - current and historical."
- "Where is the **disaster-recovery rebuild** activity (fire-damage areas)?"
- "Aggregate the whole register by **permit type** or **status**."

### Inputs

| Input | What it does |
|---|---|
| `module` | permits (default) / planning |
| `permitType` | building-permit type: residential, commercial, multifamily, electrical, plumbing, mechanical, solar, sewer, grading, pool/spa, road, C\&D, flood, film |
| `status` | exact source value (Finaled / Issued / Approved / ...) or `open` / `active` for the live slice. Blank = any status |
| `caseNumber` | exact case number -> that case's record |
| `address` / `ain` | property filter (substring) |
| `minValuation` / `maxValuation` | permit-valuation range |
| `appliedFrom/To` / `issuedFrom/To` | date-range filters (applied / issued dates) |
| `supervisorialDistrict` / `countywideStatArea` | district / community filter |
| `aggregate` / `groupBy` | one summary row per group - caseType / status / module / countywideStatArea / supervisorialDistrict / useCurr / workClassName |
| `maxResults` | cap records (default 200) |

**Default run = the 200 newest building cases** (by the register's insert order - the county appends cases as they're filed, so the newest rows are the most recently filed / updated; not sorted by apply date). A live slice, fast for the daily auto-test. For a targeted query add a `caseNumber` / `address` / `permitType` / `status` filter; for a broad view use `aggregate` (a handful of summary rows, not a full dump).

### Low cost

**From $0.001 per record** - billed only for the rows you use, with a per-run charge cap so a broad query can't surprise-bill.

LA County's EPIC-LA case history is one of those "public portal" exports that hides its mess in plain sight: **building permits and zoning reviews live in the same feed** (two case modules that behave differently), the **status field runs ~40 values** that overlap confusingly (a *New* case vs *New - Online*, *In Review* vs *Review*), permit **valuation is filled on only ~34% of rows**, and **many planning cases carry no address at all**. Sorting that into a register where a `permitType` / `status` / date-range query returns exactly the cases you mean - never the near-misses - is the actual product. Every pull is integrity-checked against the feed's known shape, so a degraded source fails loudly instead of returning bad rows.

### Source

- [LA County Public Works EPIC-LA](https://dpw.lacounty.gov/epic/) - the county's public case-management portal. This actor reads the published `EPIC-LA_Case_History_view` service.
- Reflects the county's published record as of the refresh date; not an endorsement of any project or contractor.

# Actor input Schema

## `module` (type: `string`):

permits = building & construction cases (PermitManagement, ~614k): residential / commercial / multifamily / electrical / plumbing / mechanical / solar / road / sewer / pool permits. planning = zoning & land-use plan reviews (PlanManagement, ~302k). Blank = building permits on a plain browse; both modules when you add a locating filter (address / AIN / case number / ...).

## `permitType` (type: `string`):

Building-permit type (fuzzy, matches the source list). E.g. residential, commercial, multifamily, electrical, plumbing, mechanical, solar, sewer, grading, pool/spa, road, construction & demolition, flood, film.

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

Case status. Use a source value exactly (Finaled, Issued, Approved, Completed, Void, Accepted, Canceled, Open, Expired, Denied, Withdrawn, Rejected, Revoked ...), or 'open' / 'active' for the live in-progress slice. Blank = any status (default).

## `caseNumber` (type: `string`):

Exact case number (e.g. UNC-BLDR260902008726, RPPL2024006019) -> that case's record.

## `projectName` (type: `string`):

Project name substring, case-insensitive.

## `address` (type: `string`):

Main address substring (e.g. a street name). Populated on ~95% of building rows.

## `ain` (type: `string`):

Assessor parcel number (10-digit AIN) substring.

## `supervisorialDistrict` (type: `string`):

LA County supervisorial district number (1-5).

## `countywideStatArea` (type: `string`):

Countywide statistical area / community name substring, e.g. 'East Los Angeles', 'Altadena'.

## `minValuation` (type: `integer`):

Only cases with permit valuation >= this amount. Valuation is filled on ~34% of rows.

## `maxValuation` (type: `integer`):

Only cases with permit valuation <= this amount.

## `appliedFrom` (type: `string`):

Only cases applied on/after this date (YYYY-MM-DD).

## `appliedTo` (type: `string`):

Only cases applied on/before this date (YYYY-MM-DD).

## `issuedFrom` (type: `string`):

Only cases with a permit issuance date on/after this date.

## `issuedTo` (type: `string`):

Only cases with a permit issuance date on/before this date.

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

When on, returns one summary record per group (see groupBy) with count - instead of individual cases. Computed server-side.

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

Which dimension to aggregate over. caseType -> the permit-type mix (residential vs electrical vs road vs ...); status -> how many are finaled/issued/open/...; countywideStatArea -> where the work is.

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

Cap the number of records pushed (0 = up to ~10k rows per run - the practical page limit; a case query can hit the run's charge cap first). An aggregate has at most a few hundred groups.

## Actor input object example

```json
{
  "module": "",
  "permitType": "",
  "status": "",
  "caseNumber": "",
  "projectName": "",
  "address": "",
  "ain": "",
  "supervisorialDistrict": "",
  "countywideStatArea": "",
  "appliedFrom": "",
  "appliedTo": "",
  "issuedFrom": "",
  "issuedTo": "",
  "aggregate": false,
  "groupBy": "caseType",
  "maxResults": 200
}
```

# Actor output Schema

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

LA County building / planning case records or aggregates - 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/ca-epic-la-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 = {}

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

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,j0401/ca-epic-la-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/ThNprYGWrncoFNOLE/builds/vG2gN1ZlSrNgLfLvx/openapi.json
