# MD Baltimore City Building Permits (`j0401/md-baltimore-building-permits`) Actor

Baltimore City building & housing permits (~292k, 2019-present, open data): full permit file - scope-of-work, cost, existing/proposed land use, address, neighborhood, district, housing typology, original vs modification. Search by case/keyword/address/cost/date; aggregate by neighborhood/use.

- **URL**: https://apify.com/j0401/md-baltimore-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.30 / 1,000 md baltimore city 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

## Baltimore City (MD) Building & Housing Permits

The live Baltimore City building-permit record - every permit's full file, from
the scope-of-work text to the project cost and the before/after land use. One
query API over the city's permit pipeline, 2019 to this week.

### Data

Baltimore City government open data (public permit register). **~292,000
permits issued 2019-01-01 to present**, live to this week.

Each record is the complete permit - this is not the shallow case-rows table,
it carries the depth that makes a permit searchable:

- **Scope-of-work text** - the real description of what was permitted ("install
  new fire sprinkler system", "demolish existing front concrete stoop and
  rebuild", "change cabinets in existing kitchen")
- **Project cost** - where the city recorded a valuation (~68% of permits)
- **Existing vs proposed land use** - what the property was and what it becomes
  (rowhouse / single-family / commercial / vacant lot ...)
- **Address, block & lot, neighborhood, council district**
- **Baltimore housing-market typology** (A-J + rental categories)
- **Original permit vs modification** - the amendment flag, so you can separate
  new work from change-orders
- **Issue + expiration dates**

There is no separate "permit type" dropdown in the city's data - the type is
written into the scope text, which is exactly why the full description matters.
We keep every word of it.

### Low cost

**From $0.0003 per record.**

City permit data comes as one long table with no obvious keys to cut it on, so
most people end up either paying per-screen on the city portal or pulling the
whole thing and filtering locally. We made the depth searchable directly: exact
`caseNumber`, a **keyword search over the scope-of-work text**, cost range,
address, neighborhood, council district, land-use words, original-vs-
modification, and issue-date windows - all filtering happens before a single
record is returned. Aggregates by neighborhood / district / housing market /
use / original-vs-modification come back as clean counts. You query a permit
pipeline that behaves like a database; the plumbing stays on our side.

**Every record is one flat JSON object** - no portal sessions, no pagination to
chase, no screenshots.

### Use cases

- **Construction & renovation intelligence** - what kind of work is being
  permitted where, by neighborhood or council district, over time
- **Property diligence** - every recent permit on a property or in a building,
  with real cost and use change
- **Market & investment analysis** - Baltimore's own housing-market typology
  dimension is built in; track which market segments are seeing permit activity

### Inputs

| Field | What it does |
|---|---|
| `caseNumber` | exact permit lookup (e.g. `BRCM-26-005127`) |
| `keyword` | search scope-of-work + project name |
| `address` / `neighborhood` / `councilDistrict` | geography filters |
| `minCost` / `maxCost` | project-cost range |
| `use` | land-use word (dwelling / rowhouse / commercial ...) |
| `housingMarketTypology` | A-J / rental market class |
| `modification` | original vs modification |
| `issuedFrom` / `issuedTo` | issue-date window |
| `aggregate` + `groupBy` | counts by neighborhood / district / typology / use / mod |

### Output fields

`caseNumber` / `description` / `issuedDate` / `expirationDate` / `address` /
`blockLot` / `existingUse` / `proposedUse` / `permitName` / `cost` /
`neighborhood` / `councilDistrict` / `housingMarketTypology` /
`isModification` / `parcel`.

> Honesty note: the city leaves project cost blank on roughly a third of permits
> and drops the parcel project-name on most - this API returns those fields only
> where the city actually recorded them, and never fills them in.

Source: Baltimore City open data (Housing & Community Development permit
register, public records).

# Actor input Schema

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

Exact permit case number (e.g. BRCM-26-005127, BCCM-25-000001), case-insensitive.

## `keyword` (type: `string`):

Search the full scope-of-work text + project name (e.g. 'sprinkler', 'deck', 'roof', 'monument sign'). The permit type lives in this free text.

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

Street address substring (e.g. 'Monroe').

## `neighborhood` (type: `string`):

Neighborhood name substring (e.g. 'Canton', 'Fells Point').

## `councilDistrict` (type: `integer`):

Baltimore City council district 1-14. 0 / blank = all districts.

## `modification` (type: `string`):

original = new permits (IsPermitModification 0); modification = amendments to existing permits (1). Blank = both.

## `minCost` (type: `integer`):

Only permits with recorded project cost >= this amount. Cost is blank on ~32% of permits the city did not value.

## `maxCost` (type: `integer`):

Only permits with recorded project cost <= this amount (0 = no upper bound).

## `use` (type: `string`):

Substring matched against existing or proposed land use (e.g. 'Dwelling', 'Rowhouse', 'Commercial'). Matches the human-readable use names.

## `housingMarketTypology` (type: `string`):

Baltimore's housing-market class (2017 typology A-J + rental categories) used in the city's own market analysis.

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

Only permits issued on/after this date (YYYY-MM-DD). Register starts 2019-01-01.

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

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

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

When on, returns one summary record per group (see groupBy) with a count instead of individual permits.

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

Which dimension to aggregate over. isModification = original vs modification split.

## `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
{
  "caseNumber": "",
  "keyword": "",
  "address": "",
  "neighborhood": "",
  "councilDistrict": 0,
  "modification": "",
  "minCost": 0,
  "maxCost": 0,
  "use": "",
  "housingMarketTypology": "",
  "issuedFrom": "",
  "issuedTo": "",
  "aggregate": false,
  "groupBy": "neighborhood",
  "maxResults": 200
}
```

# Actor output Schema

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

Baltimore City building & housing 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/md-baltimore-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/md-baltimore-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/md-baltimore-building-permits --silent --output-dataset

```

## MCP server setup

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