# NYC Building Permits Scraper: DOB NOW Approved Permits (`humble-echidna/nyc-building-permits`) Actor

Get NYC DOB NOW approved building permits from NYC Open Data as clean records, one per permit: dates, borough, address, BIN/BBL, work types, job description, estimated cost, contractor and owner business. Filter by date, borough, work type, ZIP. Only-new-or-changed mode for daily feeds.

- **URL**: https://apify.com/humble-echidna/nyc-building-permits.md
- **Developed by:** [Michael Costa](https://apify.com/humble-echidna) (community)
- **Categories:** Real estate, Lead generation, Automation
- **Stats:** 1 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

### What does NYC Building Permits Scraper do?

**NYC Building Permits Scraper** returns **New York City building permits** issued or approved through **DOB NOW**,
as clean records: **one per permit**, with dates, address, BIN/BBL, work types, job description, estimated cost and
the contractor's business. The data comes live from the Department of Buildings' official dataset on **NYC Open
Data** (no login).

Schedule it with **only new or changed permits** switched on and every run returns just what DOB added or changed
since the last one: a daily NYC construction-permit feed for your sheet, CRM or database.

[Input fields](https://apify.com/humble-echidna/nyc-building-permits/input-schema) ·
[API](https://apify.com/humble-echidna/nyc-building-permits/api) ·
[Use it from Claude, ChatGPT or Cursor (MCP)](#can-i-use-nyc-building-permits-scraper-from-an-ai-agent-mcp)

**Jump to:** [Fields](#what-data-does-nyc-building-permits-scraper-return) ·
[Price](#how-much-does-it-cost-to-scrape-nyc-building-permits) · [How to use](#how-to-scrape-nyc-building-permits) ·
[Daily feed](#can-i-get-only-new-or-changed-permits-since-my-last-run) · [Input](#input) · [Output](#output) ·
[AI agents (MCP)](#can-i-use-nyc-building-permits-scraper-from-an-ai-agent-mcp) · [Limits](#limits) · [FAQ](#faq)

**Try it in one click:** the input comes pre-filled with General Construction permits issued in Brooklyn in the last 7
days. On 2026-10-04 that was 184 permits, about $0.55 (184 × $0.003, plus $0.00005 for the run start). **Then pick
your own boroughs, work types and dates.**

### What data does NYC Building Permits Scraper return?

| Field | Example | Notes |
|---|---|---|
| `id` | `B01441702-I1-GC/1/487381108` | Stable across runs: permit / sequence / tracking number |
| `workPermit` | `B01441702-I1-GC` | DOB permit number; `null` for approved permits not yet issued |
| `filingReason` | `Initial Permit` | Or a renewal (with or without changes), or No Work Permit |
| `permitStatus` | `Permit Issued` | Or `Signed-off` (work completed) |
| `workTypes` | `["General Construction"]` | Every work type of the permit's job |
| `issuedDate`, `approvedDate`, `expiredDate` | `2026-10-02` | YYYY-MM-DD |
| `address` | `2565 FLATBUSH AVENUE, Brooklyn, NY 11234` | Also `houseNumber`, `streetName`, `zipCode`, `borough` |
| `bin`, `bbl` | `3238574`, `3084700050` | Building and tax-lot ids, to join with other NYC data |
| `jobDescription` | `Proposed alteration to an existing boat showroom, ...` | As filed |
| `estimatedJobCost` | `261000` | US dollars, the filer's estimate |
| `applicantBusinessName` | `SEASON BUILDERS CORP` | With `applicantLicenseNumber`, `permitteeLicenseType` (`GC`, `P`, ...) |
| `ownerBusinessName` | `Marina at Kings Plaza LLC` | Business names only, never people's names |
| `changeType` | `new` | In only-new mode: `new` or `changed`; otherwise `null` |
| `sourceUrl` | `https://data.cityofnewyork.us/resource/rbx6-tga4.json?work_permit=...` | The permit's source rows on NYC Open Data |

Plus `jobFilingNumber`, `sequenceNumber`, `trackingNumber`, `workOnFloor`, `aptCondoNumbers`, `block`, `lot`,
`communityBoard`, `councilDistrict`, `censusTract`, `nta` (neighborhood), `latitude`, `longitude`,
`applicantBusinessAddress`, `filingRepresentativeBusinessName`, `sourceUpdatedAt` and `scrapedAt`. The full list is
under [Output](#output).

### How much does it cost to scrape NYC building permits?

You pay per permit: **$3.00 per 1,000 permits**, plus $0.00005 each time a run starts. Permits the source repeats,
permits outside your filters, and (in only-new mode) permits DOB re-published without any change are never charged.
A monitor run when the dataset hasn't changed returns nothing and costs only the start fee.

- **The example above:** 184 permits × $3.00/1,000 = $0.55.
- **A month, for example:** a daily only-new feed of Brooklyn General Construction permits, about 800 new or changed
  permits a month ≈ **$2.40**.
- **Every permit DOB issued citywide in a week:** about 3,100 permits ≈ $9.25 (raise **Max results per run** to
  5,000 first).
- **Caps:** **Max results per run** in the input (1,000 unless you change it, so a run started with no input costs at
  most about $3), and **Maximum cost per run** in the run options. The run stops cleanly at whichever comes first.

### How to scrape NYC building permits

1. Open NYC Building Permits Scraper and click **Try for free** (or **Start** if you're signed in).
2. Pick a date range: **Last N days**, or a **From date** and **To date**; choose whether they apply to the issued
   or the approved date.
3. Pick **Boroughs** and **Work types** (empty = all), and any other filters: filing reason, status, ZIP codes,
   buildings (BIN), job-description words, minimum estimated cost.
4. Click **Start**, then open the **Output** tab and export as JSON, CSV or Excel.
5. For a daily feed, switch on **Only new or changed permits since the last run**, save the input as a task and
   schedule it.

### Example: General Construction permits in Brooklyn this week

The pre-filled input:

```json
{"lookbackDays": 7, "boroughs": ["Brooklyn"], "workTypes": ["General Construction"]}
```

It returned 184 permits (112 initial permits, 70 renewals, 2 "no work permit"; 55 of them on jobs with more than one
work type), read from 804 source rows in 2.5 seconds. One of them (real output from a local run on 2026-10-04; the
job description shortened):

```json
{
  "id": "B01441702-I1-GC/1/487381108",
  "workPermit": "B01441702-I1-GC",
  "sequenceNumber": 1,
  "trackingNumber": "487381108",
  "jobFilingNumber": "B01441702-I1",
  "filingReason": "Initial Permit",
  "permitStatus": "Permit Issued",
  "workTypes": ["General Construction"],
  "jobDescription": "Proposed alteration to an existing boat showroom, including public and private toilet facilities, ...",
  "estimatedJobCost": 261000.0,
  "issuedDate": "2026-10-02",
  "approvedDate": "2026-09-15",
  "expiredDate": "2026-10-22",
  "borough": "Brooklyn",
  "houseNumber": "2565",
  "streetName": "FLATBUSH AVENUE",
  "zipCode": "11234",
  "address": "2565 FLATBUSH AVENUE, Brooklyn, NY 11234",
  "workOnFloor": "Floor Number(s) 01 through 01",
  "aptCondoNumbers": null,
  "bin": "3238574",
  "bbl": "3084700050",
  "block": "8470",
  "lot": "50",
  "communityBoard": 318,
  "councilDistrict": 46,
  "censusTract": "698",
  "nta": "Marine Park-Mill Basin-Bergen Beach",
  "latitude": 40.608035,
  "longitude": -73.920512,
  "permitteeLicenseType": "GC",
  "applicantLicenseNumber": "621265",
  "applicantBusinessName": "SEASON BUILDERS CORP",
  "applicantBusinessAddress": "77 BOX STREET",
  "filingRepresentativeBusinessName": null,
  "ownerBusinessName": "Marina at Kings Plaza LLC",
  "changeType": null,
  "sourceUpdatedAt": "2026-10-03T18:42:11.170Z",
  "sourceUrl": "https://data.cityofnewyork.us/resource/rbx6-tga4.json?work_permit=B01441702-I1-GC&sequence_number=1&tracking_number=487381108",
  "scrapedAt": "2026-10-04T08:28:56.877917Z"
}
```

### Input

| Field | What it does |
|---|---|
| **Last N days** (`lookbackDays`) | Permits from the last N days (default 7, up to 3,660), counted back from today in UTC. |
| **From date / To date** (`dateFrom`, `dateTo`) | A fixed range, YYYY-MM-DD, inclusive; replaces Last N days. The dataset starts in June 2016. |
| **Date to filter on** (`dateField`) | `issued` (default) or `approved`. Approved also finds permits not yet issued. |
| **Boroughs** | Manhattan, Bronx, Brooklyn, Queens, Staten Island. Empty = all. |
| **Work types** | Any of the 21 DOB NOW work types (General Construction, Plumbing, Full Demolition, Sidewalk Shed, Solar, ...). A permit matches if its job has one of them. Empty = all. |
| **Filing reasons** | Initial Permit, Renewal Permit Without Changes, Renewal Permit with Changes, No Work Permit. Empty = all. |
| **Permit statuses** | Permit Issued, Signed-off. Empty = both. |
| **ZIP codes**, **Buildings (BIN)** | Only these 5-digit ZIP codes or 7-digit BINs (up to 200 each). |
| **Job description contains** | Any of these words or phrases, not case sensitive (e.g. `new building`, `hotel`). |
| **Minimum estimated job cost** | In US dollars, as filed. |
| **Only new or changed permits** (`onlyNewOrChanged`) | Return only what DOB added or changed since this search's last run. |
| **Monitor name** | Optional: gives a search its own memory. |
| **Socrata app token** | Optional: your own free token from NYC Open Data, for very large runs. |
| Max results per run | Caps the number of permits returned. Default 1,000; raise it for bigger runs. |

A daily feed of new Manhattan and Brooklyn demolition and new-building permits:

```json
{
  "lookbackDays": 30,
  "boroughs": ["Manhattan", "Brooklyn"],
  "workTypes": ["Full Demolition", "General Construction"],
  "filingReasons": ["Initial Permit"],
  "keywords": ["new building", "demolition"],
  "onlyNewOrChanged": true
}
```

### Output

Every permit has the same fields; ones the source leaves empty are `null`. Output table columns: issued date, permit,
filing reason, status, work types, address, job description, estimated cost, applicant and owner business, change,
source link.

| Field | Type | Notes |
|---|---|---|
| `id` | text | Permit number / sequence / tracking number. Permits without a permit number: `unissued/<tracking number>/<BIN>`. |
| `workPermit`, `jobFilingNumber` | text or null | DOB's permit and job filing numbers. |
| `sequenceNumber` | number or null | 1 for the first issuance, higher for renewals. |
| `trackingNumber` | text or null | DOB's tracking number for this issuance. |
| `filingReason`, `permitStatus` | text or null | As listed under Input. |
| `workTypes` | list | Every work type of the job, sorted. |
| `jobDescription`, `workOnFloor`, `aptCondoNumbers` | text or null | As filed. |
| `estimatedJobCost` | number or null | US dollars, as filed (some filers enter placeholders such as 0.01). |
| `issuedDate`, `approvedDate`, `expiredDate` | text or null | YYYY-MM-DD. |
| `borough`, `houseNumber`, `streetName`, `zipCode`, `address` | text or null | Borough in one spelling; extra spaces removed. |
| `bin`, `bbl`, `block`, `lot`, `censusTract` | text or null | Identifiers kept as text (no lost leading digits). |
| `communityBoard`, `councilDistrict` | number or null | |
| `nta`, `latitude`, `longitude` | text / number or null | Neighborhood (2020 NTA) and coordinates from the source. |
| `permitteeLicenseType`, `applicantLicenseNumber` | text or null | DOB license type code and number of the applicant. |
| `applicantBusinessName`, `applicantBusinessAddress`, `filingRepresentativeBusinessName`, `ownerBusinessName` | text or null | Businesses only. |
| `changeType` | text or null | Only-new mode: `new` or `changed`. |
| `sourceUpdatedAt` | text | When DOB last changed this permit's rows in the dataset (UTC). |
| `sourceUrl` | text | NYC Open Data API query returning the permit's source rows. |
| `scrapedAt` | text | When this run fetched it (UTC). |

The run's `RUN_STATS` record has the filters, the exact query sent, the dataset version it read (`datasetUpdatedAt`),
how many source rows and permits were read, filtered out, skipped as unchanged or duplicated, and any error.

### Run it on a schedule, or from your own code

Save your input as a [task](https://docs.apify.com/platform/actors/running/tasks) with **Only new or changed
permits** on, and add it to a [schedule](https://docs.apify.com/platform/schedules): DOB updates the dataset once a
day (in the afternoon, New York time, on 2026-10-03), so a daily run in the evening or next morning is enough.
Collect the permits from the [API](https://apify.com/humble-echidna/nyc-building-permits/api)
(`GET https://api.apify.com/v2/actor-tasks/<task id>/runs/last/dataset/items?status=SUCCEEDED&format=csv`, with your
API token), a [webhook](https://docs.apify.com/platform/integrations/webhooks), or Google Sheets, Slack, Make, Zapier
and n8n through [Apify's integrations](https://docs.apify.com/platform/integrations).

#### Can I use NYC Building Permits Scraper from an AI agent (MCP)?

Yes, through [Apify's MCP server](https://docs.apify.com/platform/integrations/mcp), from Claude, ChatGPT, Cursor or
any other MCP client. Add this to your client's MCP configuration; your client signs you in to Apify:

```json
{
  "mcpServers": {
    "apify": {
      "url": "https://mcp.apify.com?tools=humble-echidna/nyc-building-permits"
    }
  }
}
```

To use an [Apify API token](https://console.apify.com/settings/integrations) instead of signing in, add
`"headers": {"Authorization": "Bearer <APIFY_TOKEN>"}` next to `url`.

An agent asking "which new buildings got permits in Queens this month?" can pass `{"boroughs": ["Queens"],
"lookbackDays": 30, "filingReasons": ["Initial Permit"], "keywords": ["new building"], "maxResults": 50}`.

### Who it's for

Construction suppliers and subcontractors looking for jobs that just got permits, property-data and proptech
developers who need NYC permits in their own database, real-estate researchers and analysts tracking construction
activity by neighborhood. The recurring job: every day, the new permits matching a borough, trade or cost threshold,
without re-downloading and re-cleaning the city's file.

### Why this one?

- **One record per permit.** The source has a row per work type of the job, and repeats a few dozen permits; this
  joins them (3,710 source rows were 3,084 permits in the week to 2026-10-04), so you don't pay for or deduplicate the
  repeats.
- **A real change feed.** Only-new mode reads only rows DOB changed since your last run, labels permits `new` or
  `changed` (e.g. signed off, renewed), and skips the ones DOB re-published unchanged, free. A quiet day costs the
  $0.00005 start fee.
- **Ids that survive reloads.** NYC Open Data's own row ids change every time DOB reloads a permit; `id` here is built
  from the permit's own numbers.
- **Clean fields.** Borough in one spelling (the source mixes `BROOKLYN` and `Brooklyn`), dates as dates, costs and
  coordinates as numbers, BIN and BBL as text, an address line, and a link to the source rows.
- **No people's names.** Applicant, filing representative and owner names and owners' mailing addresses are left out
  on purpose; businesses and license numbers are included.
- **Polite.** It identifies itself honestly (User-Agent `HumbleEchidnaApify`), follows the portal's robots.txt and
  its 1-second crawl delay, and backs off when the API asks it to.

### Limits

- **One dataset:** DOB NOW: Build approved permits, which covers DOB NOW filings since 2016. It does not include
  electrical, elevator or Limited Alteration Application permits (NYC publishes those as separate datasets), older
  permits filed in DOB's BIS system, job filings that haven't been approved, or violations.
- **No job type** (NB, A1, DM, ...): this dataset doesn't carry it. Use work types, filing reasons and description
  keywords (e.g. "new building") instead.
- **As fresh as the source:** DOB updates the dataset once a day, roughly a day behind; nothing here is real time.
  Data quality is DOB's: some estimated costs are placeholders, some rows lack coordinates or a BBL.
- In only-new mode with **Last N days**, a permit changed after it falls out of the window isn't reported; use a
  wider window or a fixed **From date** for a long-running feed. A monitor remembers up to 250,000 permits; one it
  has forgotten comes back as `new` if it changes.
- **1,000 permits per run unless you raise Max results per run.** A capped only-new run loses nothing: the next
  run continues from the oldest change it hasn't delivered.
- A run that overlaps DOB's daily load can read a few permits twice (returned once) or miss a few; in only-new mode
  the next run catches up.

### FAQ

#### Is it legal to scrape NYC building permits?

The data is published by the NYC Department of Buildings on NYC Open Data, through an API documented for programs
([SODA API for this dataset](https://dev.socrata.com/foundry/data.cityofnewyork.us/rbx6-tga4)). NYC's Open Data Law
says public data sets "shall be made available without any registration requirement, license requirement or
restrictions on their use", provided the City may require a third party "to explicitly identify the source and
version of the public data set, and a description of any modifications made to such public data set"
([NYC Administrative Code § 23-502(d)](https://nyc-laws.readthedocs.io/en/latest/nycadmincode/t23/c05/), Local Law
11 of 2012). NYC Open Data's own FAQ answers "Are there restrictions on how I can use Open Data?" with "Open Data
belongs to all New Yorkers. There are no restrictions on the use of Open Data."
([NYC Open Data FAQs](https://www.nyc.gov/opendata/get-started/FAQs)). The portal's
[terms of use](https://www.nyc.gov/main/terms-of-use) contain no clause against commercial reuse or automated access;
the City gives no warranty for the data. No login is used.

Source and version: [DOB NOW: Build – Approved Permits](https://data.cityofnewyork.us/Housing-Development/DOB-NOW-Build-Approved-Permits/rbx6-tga4)
(dataset `rbx6-tga4`, NYC Department of Buildings), as of the `datasetUpdatedAt` in each run's `RUN_STATS` and each
permit's `sourceUpdatedAt`. Modifications: rows of one permit joined (work types as a list), duplicates dropped,
borough spelling, whitespace and date formats normalized, numbers parsed, an address line and ids added, and person
names and owners' mailing addresses removed. Permits are public records; how you use contact details of the
businesses in them (for marketing, for example) is subject to the laws that apply to you.

#### Can I get only new or changed permits since my last run?

Yes: switch on **Only new or changed permits since the last run**. The first run returns every permit in your date
range; each later run returns only permits DOB added or changed since, with `changeType` `new` or `changed`, and
skips (without charging) permits DOB re-published with no change in any returned field. The memory is kept in your
own Apify account (key-value store `nyc-building-permits-memory`), one per set of filters; give a search a **Monitor
name** to keep it separate, or a new name to start over. It only remembers permits you actually received, so a run
cut short by your limits picks up where it stopped.

#### Why did my search return nothing, or fewer permits than expected?

DOB publishes once a day and about a day behind, so the last day or two may be empty, and weekends have few permits.
The log and the `RUN_STATS` record show the exact query, how many source rows came back and how many permits your
work-type filter left out. An only-new run returns nothing when DOB hasn't changed anything since your last run.

#### How is this different from downloading the data from NYC Open Data?

The data is free on NYC Open Data, and you can query the API yourself. This saves the work around it: joining the
per-work-type rows into permits, stable ids, the cleaned fields, the filters in a form, and the memory that turns a
daily run into a list of only what's new or changed, delivered where Apify integrations can send it.

#### Do I need a Socrata app token?

No. Without one, NYC Open Data throttles by IP address from a shared pool; a typical run makes a handful of requests.
For very large runs (years of permits) you can add your own free token in **Socrata app token**; it is stored
encrypted by Apify and sent only to NYC Open Data, in a request header.

#### Something that used to work now fails. Why?

The run log and the status say what went wrong, including NYC Open Data's own message when it refuses a query. If
the city changed the dataset, please open an issue with the input you used.

### Related actors

| Actor | Use it when |
|---|---|
| [Dataset Transformer](https://apify.com/humble-echidna/dataset-transform) | You want to filter, rename or reshape the permits, or save them as CSV or Excel your way. |
| [Join Datasets](https://apify.com/humble-echidna/dataset-join) | You want to add your own data (e.g. your customer list by BIN or address) to each permit. |

### Feedback and support

Found a bug, or need a field or filter that isn't here? Open an issue on the **Issues** tab with the input you used.

### Versions

Current version: **0.1**. See the Changelog tab for what changed in each version.

# Changelog

This Actor's version history is a separate document: https://apify.com/humble-echidna/nyc-building-permits/changelog.md

# Actor input Schema

## `lookbackDays` (type: `integer`):

Search permits issued (or approved, see dateField) in the last N days, counted back from today in UTC. Default 7, minimum 1, maximum 3,660. Ignored when dateFrom is set. DOB publishes once a day, about a day behind, so a short window may be empty on a Monday morning.

## `dateFrom` (type: `string`):

Optional start date, YYYY-MM-DD (e.g. 2026-09-01), inclusive. When set, it replaces lookbackDays. The dataset starts in June 2016. Leave empty to use lookbackDays.

## `dateTo` (type: `string`):

Optional end date, YYYY-MM-DD (e.g. 2026-09-30), inclusive. Leave empty for no end (up to the newest permit).

## `dateField` (type: `string`):

Which date the date range applies to: `issued` (default, when DOB issued the permit) or `approved` (when the job filing was approved; also covers approved permits not yet issued).

## `boroughs` (type: `array`):

Only these boroughs: Manhattan, Bronx, Brooklyn, Queens, Staten Island. Empty (the default) = all five; the form starts with Brooklyn as an example. The source spells boroughs in two cases; both are matched.

## `workTypes` (type: `array`):

Only permits whose job includes one of these work types, e.g. General Construction, Plumbing, Full Demolition, Sidewalk Shed, Solar, Structural, Foundation, Mechanical Systems, Sprinklers, Sign, Curb Cut (21 in all; see the list). Empty (the default) = all; the form starts with General Construction as an example. Each permit still lists every work type of its job in workTypes.

## `filingReasons` (type: `array`):

Only these filing reasons: Initial Permit (a new permit), Renewal Permit Without Changes, Renewal Permit with Changes, No Work Permit. Empty (the default) = all. Use \["Initial Permit"] to skip renewals.

## `permitStatuses` (type: `array`):

Only these statuses: Permit Issued (work may be under way) or Signed-off (work completed and signed off). Empty (the default) = both.

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

Only permits at these 5-digit ZIP codes, e.g. 11211. Empty (the default) = any. At most 200.

## `bins` (type: `array`):

Only permits for these buildings, by DOB's 7-digit Building Identification Number (BIN), e.g. 3429263. Empty (the default) = any. At most 200. Find a BIN on DOB's Building Information Search or NYC's Property Information Portal.

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

Only permits whose job description contains any of these words or phrases, not case sensitive, e.g. "new building", "hotel", "solar". Empty (the default) = any. At most 200.

## `minEstimatedCost` (type: `integer`):

Only permits whose job's estimated cost, as filed with DOB, is at least this many US dollars, e.g. 1000000. Empty (the default) = any. Filers' estimates, not verified by DOB.

## `onlyNewOrChanged` (type: `boolean`):

Default false. When true, return only permits DOB added or changed since this search's last successful run, each marked changeType new or changed; a re-published permit with no change is skipped and not charged. Remembered in your Apify account per filter set (and monitorName). The first run returns everything in the date range. Schedule it daily.

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

Optional label that gives this search its own memory for onlyNewOrChanged, e.g. "brooklyn-gc-daily". Without it, runs with the same filters share one memory. Use a new name to start a monitor afresh.

## `appToken` (type: `string`):

Your own free Socrata app token (sign up at data.cityofnewyork.us, then Developer Settings). Without one, NYC Open Data throttles by IP address from a shared pool, which can slow very large runs; with one, requests are counted against your token. Only ever sent to NYC Open Data, in the X-App-Token request header.

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

Stop after this many permits in total. Default 1,000 (about $3), so a run started with no input stays small; raise it for bigger runs, e.g. 5,000 for a week of every permit in NYC or 200,000 for a year. Minimum 1. The run also stops cleanly at the maximum cost per run you set in the run options, whichever comes first. A capped only-new run never loses permits: the next run continues where it stopped.

## Actor input object example

```json
{
  "lookbackDays": 7,
  "dateField": "issued",
  "boroughs": [
    "Brooklyn"
  ],
  "workTypes": [
    "General Construction"
  ],
  "onlyNewOrChanged": false,
  "maxResults": 1000
}
```

# Actor output Schema

## `results` (type: `string`):

No description

## `runStats` (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 = {
    "lookbackDays": 7,
    "boroughs": [
        "Brooklyn"
    ],
    "workTypes": [
        "General Construction"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("humble-echidna/nyc-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 = {
    "lookbackDays": 7,
    "boroughs": ["Brooklyn"],
    "workTypes": ["General Construction"],
}

# Run the Actor and wait for it to finish
run = client.actor("humble-echidna/nyc-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 '{
  "lookbackDays": 7,
  "boroughs": [
    "Brooklyn"
  ],
  "workTypes": [
    "General Construction"
  ]
}' |
apify call humble-echidna/nyc-building-permits --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,humble-echidna/nyc-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/d7kreSvNVrKX1R7Z6/builds/SLVfSrJt1KKVKOD6H/openapi.json
