# NYC DOB NOW Permit Watch (`althorlabs/nyc-dob-now-permit-watch`) Actor

Export issued NYC DOB NOW Build permits by borough, ZIP and work type. Get dates, status, estimated cost and parcel IDs as structured rows. No people or contact fields. $1 per 1,000 successful records.

- **URL**: https://apify.com/althorlabs/nyc-dob-now-permit-watch.md
- **Developed by:** [Althor Labs](https://apify.com/althorlabs) (community)
- **Categories:** Real estate, Automation
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$1.00 / 1,000 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?

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

## NYC DOB NOW Permit Watch

Export dated permit rows from the official NYC Department of Buildings DOB NOW Build dataset. Each run is a bounded snapshot over `issued_date`, filtered by borough, ZIP code, work type, filing number, or sequence number.

### Default run

With no input, the Actor reads Manhattan records issued during the 14 days before the run date and writes up to 25 validated rows.

```json
{
  "queries": [
    {"borough": "Manhattan"},
    {"zipCode": "10001", "workType": "General Construction"}
  ],
  "issuedAfter": "2026-10-18",
  "issuedBefore": "2026-11-01",
  "maxItems": 1000
}
```

The date window defaults to the most recent 14 days and cannot exceed 90 days. Results are limited snapshots, ordered by newest issue date within each filter. They do not enumerate every matching permit or page beyond the limit. Queries run sequentially, share one global row cap, and are rate-limited to at least 1.5 seconds apart. A run accepts 1 to 100 query objects. Each object must contain at least one typed filter. It accepts no URL, free-form SoQL, or extra input fields.

### Output

Each row has a stable `permit_id` derived from the source filing, work permit, sequence, and work type. NYC can publish multiple work types under the same filing, work permit, and sequence identifiers. It includes issue and expiry dates, work type, borough, ZIP code, permit status, BBL, estimated cost when numeric, the official dataset URL, and observation time.

Estimated cost is the source's `estimated_job_costs`; it is not a bid, fee, valuation, or verified final cost. Missing or invalid values are `null`. The Actor does not assign a commercial or residential classification.

Only these source fields are selected: `job_filing_number`, `work_permit`, `sequence_number`, `borough`, `zip_code`, `work_type`, `issued_date`, `expired_date`, `estimated_job_costs`, `permit_status`, and `bbl`. The Actor does not request owner, applicant, person, contact, description, or address fields and ignores unexpected response keys.

Scope is DOB NOW Build permit filings in the linked dataset. It excludes Electrical, Elevator, and LAA records. The source is a dated feed; repeated scheduled windows may return the same permits. The Actor keeps no seen-ID baseline and does not report new, changed, deleted, or revoked permits. Missing rows do not establish revocation or deletion. Source freshness and completeness are controlled by the City dataset.

The Actor makes one request per filter. It does not follow redirects or retry a failed query. HTTP 401, 403, 429, source login/CAPTCHA responses, or a redirect stop the run. HTTP 5xx responses receive a five-second backoff and then stop without retry. Requests use Apify's configured US Residential proxy; no source cookies or credentials are sent. Successful rows are written to the default dataset. Invalid rows, duplicate rows, and failed queries are counted in `OUTPUT` and are not dataset-item billing events.

### Run summary

Successful query example:

```json
{
  "status": "ok",
  "records_written": 1,
  "planned_inputs": 1,
  "attempted_inputs": 1,
  "unattempted_inputs": 0,
  "health": {"attempted": 1, "succeeded": 1, "blocked": 0},
  "results": [{"query_index": 1, "status": "ok", "http_status": 200, "records_seen": 1, "rows_written": 1, "rows_skipped": 0, "duplicates_skipped": 0}],
  "errors": [],
  "stop_reason": null,
  "issued_after": "2026-10-18",
  "issued_before": "2026-11-01",
  "billing_event": "apify-default-dataset-item",
  "source": "NYC DOB NOW Build Permits",
  "mode": "dated_snapshot"
}
```

Blocked query example:

```json
{
  "status": "blocked",
  "records_written": 0,
  "planned_inputs": 1,
  "attempted_inputs": 1,
  "unattempted_inputs": 0,
  "health": {"attempted": 1, "succeeded": 0, "blocked": 1},
  "results": [{"query_index": 1, "status": "blocked", "http_status": 403, "records_seen": 0, "rows_written": 0, "rows_skipped": 0, "duplicates_skipped": 0, "reason": "source_access_blocked"}],
  "errors": [{"code": "source_access_blocked"}],
  "stop_reason": "source_access_blocked",
  "issued_after": "2026-10-18",
  "issued_before": "2026-11-01",
  "billing_event": "apify-default-dataset-item",
  "source": "NYC DOB NOW Build Permits",
  "mode": "dated_snapshot"
}
```

### Pricing

$0.001 per successfully written permit record, or $1 per 1,000 records. Residential proxy and platform usage are included. Failed, invalid, duplicate and empty results have no result charge. The billing event is one successfully written default-dataset row. There is no start charge or manual charge call. The Actor writes permit rows to the Apify default dataset and query diagnostics to `OUTPUT`; it creates no custom baseline storage. Apify retains run inputs and output under its configured platform retention.

### Source

[NYC DOB NOW Build Permits, official NYC Open Data API](https://data.cityofnewyork.us/resource/rbx6-tga4.json). Observed schema and source access were validated with a dated 20-query Residential probe on 2026-11-01. A probe does not prove ongoing availability, complete coverage, a commercial classification, or customer demand.

# Actor input Schema

## `queries` (type: `array`):

Each query needs at least one typed filter. Queries run sequentially and share the maxItems output cap.

## `issuedAfter` (type: `string`):

ISO date; defaults to 14 days before the run date.

## `issuedBefore` (type: `string`):

ISO date; defaults to the current UTC date. The date range is limited to 90 days.

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

One global cap shared across all filters; repeated permits are written once.

## Actor input object example

```json
{
  "queries": [
    {
      "borough": "Manhattan"
    }
  ],
  "maxItems": 25
}
```

# Actor output Schema

## `dataset` (type: `string`):

Validated permit records written to the default dataset.

## `summary` (type: `string`):

Attempted, failed, skipped, and unattempted query counts.

# 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 = {
    "queries": [
        {
            "borough": "Manhattan"
        }
    ],
    "maxItems": 25
};

// Run the Actor and wait for it to finish
const run = await client.actor("althorlabs/nyc-dob-now-permit-watch").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 = {
    "queries": [{ "borough": "Manhattan" }],
    "maxItems": 25,
}

# Run the Actor and wait for it to finish
run = client.actor("althorlabs/nyc-dob-now-permit-watch").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 '{
  "queries": [
    {
      "borough": "Manhattan"
    }
  ],
  "maxItems": 25
}' |
apify call althorlabs/nyc-dob-now-permit-watch --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,althorlabs/nyc-dob-now-permit-watch"
        }
    }
}
```

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/zd3VmW3QYFpZIpb1y/builds/BdnVGPKsE3ld81Ze5/openapi.json
