# TX Austin Building Permits (`j0401/tx-austin-building-permits`) Actor

Austin, TX building permits (public open data, 2.37M records) - the city's full consolidated permit file (electrical/plumbing/building/mechanical) with the contractor behind each job plus valuation, housing units and status. Filter by office/contractor/valuation or aggregate.

- **URL**: https://apify.com/j0401/tx-austin-building-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

$0.10 / 1,000 tx austin building 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

## TX Austin Building Permits - the City's Full Consolidated Permit File

The City of Austin publishes its **entire building-permit file** - every permit issued since 1921 across the five offices the city consolidates into one register - as open data. This actor turns that register into a **charged-per-record lookup and filter tool** that carries what the national building-permit aggregators don't: **the contractor behind each job**.

**Built for:** construction lead-gen (which contractor is pulling work where - and how to reach them), homebuilder & development research, property diligence, and permitting-activity analysis by council district or office.

### What it covers

**2,374,365 permits** - the complete consolidated file, active and historical:

| Office | Permits |
|---|---|
| Electrical | 687,175 |
| Plumbing | 545,459 |
| Building | 519,982 |
| Mechanical | 505,238 |
| Driveway / sidewalks | 116,511 |

Each permit carries the job's depth - **the contractor company, contact name, phone, address and city** (populated on about half the file - 1.19M records with a real contractor company, and the reason this actor exists), plus:

- **total job valuation** - a *real numeric column*, so you can range-filter it server-side: 491,957 permits are valued at $50k+, 22,639 at $1M+
- **housing units** (77% covered) - 32,432 building permits carry more than one unit = the multifamily signal
- **number of floors**, **condominium** flag, existing / new / remodel square footage
- **permit class** (residential vs commercial), **work class** (new / remodel / repair / addition...), **council district** (91%), **jurisdiction** - Austin full-purpose vs the ETJ / extraterritorial belt
- the **applied / issued / status / expires / completed date chain**, street address + **latitude/longitude**, and the work description

### Status & live work

Statuses are the city's own words, and they're mostly terminal: **Final** (2,004,536 - completed) / **Expired** (169,150) / **VOID** (153,260) / **Active** (28,085) / Withdrawn / Cancelled. The long tail mixes office notes ("Cancelled - Contractor Required", "Inactive Pending Revision") that a naive parser trips on.

**Live work** has its own lane: the city flags every permit **issued in its last-30-days window** - the `recent` mode hands you that exact fresh slice (~4,981 permits right now), so you can watch what's being pulled this month without dumping 2.4M rows.

### Typical questions

- "Every permit **D R Horton** / **KB Home** pulled in Austin - current and historical."
- "Show recent **building** permits valued over **$1M** with the contractor's phone."
- "Where are the **multifamily projects** (5+ units) going in, by council district?"
- "What did each office issue **last month**?"
- "Every permit on **this address**."
- "Aggregate the register by **office** or **council district**."

### Inputs

| Input | What it does |
|---|---|
| `mode` | `rows` (default) / `recent` (last-30-days live work) / `aggregate` |
| `permitType` | office: electrical / plumbing / building / mechanical / driveway |
| `contractor` | contractor company or contact name (fuzzy) |
| `status` | Active / Final / Expired / VOID / Withdrawn / ... Blank = any |
| `permitClass` / `workClass` | residential/commercial + new/remodel/repair... |
| `address` / `councilDistrict` | where the work is |
| `valuationMin/To` | total job valuation range (numeric, filtered server-side) |
| `housingUnitsMin` | minimum housing units (multifamily finder) |
| `issuedFrom/To` / `appliedFrom/To` | date-range filters |
| `groupBy` | aggregate over office / class / status / council district / work class / year |
| `maxResults` | cap records (default 200) |

**Default run = the 200 most recently issued permits** - fast for the daily auto-test. For a targeted query add a filter; for a broad view use `aggregate` (a handful of summary rows, not a 2.4M-row dump).

### Low cost

**From $0.0001 per record** - billed only for the rows you use, at the platform floor. Cost scales with what you pull, not with the size of the register - and because each record is metered individually there's no per-run charge cap to hit on a big pull.

Austin's permit file is a "just download the CSV" dataset that hides real traps: **the status column mixes terminal words and office notes** (Final vs "Cancelled - Contractor Required" vs "Inactive Pending Revision") so a substring filter drags in the wrong records; **the contractor and valuation fields are filled on only part of the file** and there is no honest way to know which rows carry them without counting every column; the **five offices each assign their own permit numbers** (so the register is not one clean sequence); and the city publishes **no daily refresh marker**, so "what changed today" has to be read off the issue-date stream, not a delta column. Normalizing that into a register where a `contractor` / `valuation` / `recent` query returns exactly the permits you mean 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

- [City of Austin Open Data: Building Permits](https://data.austintexas.gov/Building-and-Development/Building-Permits/3syk-w9eu) - the city's consolidated register. Reflects the city's record as of each pull; not an endorsement of any contractor or project.

# Actor input Schema

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

rows = permits matching your filters (default). recent = permits issued in the city's last-30-days window (live work). aggregate = one count row per group (see groupBy).

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

The consolidated office the permit was pulled under: electrical, plumbing, building, mechanical, driveway / sidewalk. Blank = any.

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

Permit status. Use a source value: Active, Final, Expired, VOID, Withdrawn, Cancelled, ... Blank = any. Most of the file is Final (completed); live work is Active.

## `permitClass` (type: `string`):

residential / commercial (the broad split), or free text over the finer class codes (e.g. 'Single Family', 'Commercial Remodel').

## `workClass` (type: `string`):

New / Remodel / Repair / Addition / Change Out / Demolition ... (fuzzy).

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

Street number or street name from the permit's address line, e.g. 'Congress' or '1200'.

## `contractor` (type: `string`):

Contractor company or contact name (fuzzy), e.g. 'KB Home' or 'D R Horton'. The file carries the job's contractor on ~half its records.

## `councilDistrict` (type: `string`):

Austin city council district (1-10).

## `valuationMin` (type: `integer`):

Only permits with total job valuation at least this amount (the valuation column is numeric, so this range-filters on the register).

## `valuationMax` (type: `integer`):

Only permits with total job valuation below this amount.

## `housingUnitsMin` (type: `integer`):

Only permits with at least this many housing units (e.g. 5+ = a multifamily project).

## `recentOnly` (type: `boolean`):

When on, returns only permits the city flags as issued in its last-30-days window (the freshest work).

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

Only permits issued on/after this date (YYYY-MM-DD).

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

Only permits issued before this date (YYYY-MM-DD).

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

Only permits applied on/after this date.

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

Only permits applied before this date.

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

Which dimension to aggregate over. permitTypeDescription -> which office (electrical/plumbing/building/mechanical); status -> the live vs done mix; councilDistrict -> where; calendarYearIssued -> volume by year.

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

Cap the number of records pushed (0 = up to ~10k per run; each record is metered individually, so there is no per-run charge cap). An aggregate has at most a few hundred groups.

## Actor input object example

```json
{
  "mode": "rows",
  "permitType": "",
  "status": "",
  "permitClass": "",
  "workClass": "",
  "address": "",
  "contractor": "",
  "councilDistrict": "",
  "valuationMin": 0,
  "valuationMax": 0,
  "housingUnitsMin": 0,
  "recentOnly": false,
  "issuedFrom": "",
  "issuedTo": "",
  "appliedFrom": "",
  "appliedTo": "",
  "groupBy": "permitTypeDescription",
  "maxResults": 200
}
```

# Actor output Schema

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

Austin building permit 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/tx-austin-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 = {}

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

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,j0401/tx-austin-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/B6bn5B1p1N0QnTogY/builds/ji80Q8nbp9kCK3uVv/openapi.json
