# 🏗️ NYC Building Permits ✅ $1.50/1K Records (`peaceful_volute/construction-permit-leads`) Actor

Search recent NYC DOB NOW construction permits by borough, estimated cost, work keywords and use clues. Export structured project data with service tags and explainable review priorities.

- **URL**: https://apify.com/peaceful_volute/construction-permit-leads.md
- **Developed by:** [adrian luis](https://apify.com/peaceful_volute) (community)
- **Categories:** Lead generation, Real estate
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.50 / 1,000 construction permits

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 Building Permits ✅ $1.50/1K Records

**Find recent New York City construction permit activity without manually browsing individual records.** Filter the official DOB NOW approved permits dataset, review service-related signals, and export structured results for your research workflow.

**Pay Per Event pricing is active.**

**💰 Pricing: $1.50 / 1,000 delivered permit records ($0.0015 per record)**, plus a $0.00005 run-start event for runs allocated up to 1 GB RAM. No additional platform-usage costs are passed on to the user. Pricing is based on records returned, not verified commercial leads.

**Public status:** available on [Apify Store](https://apify.com/peaceful_volute/construction-permit-leads) with active Pay Per Event pricing. The title’s checkmark is visual emphasis, not a certification of leads, properties or contracts.

### 🚀 What this Actor does

This Actor queries New York City's **DOB NOW: Build — Approved Permits** open dataset and returns structured permit information. Choose a recent date range, NYC boroughs, minimum estimated job cost, work-description keywords, and an optional use clue. The Actor also adds rule-based service tags and an **explainable review-priority assessment**.

The data can help contractors, construction suppliers, analysts and local business development teams prioritize **projects to investigate**. A permit is not an open bid, contract, verified customer or confirmation that suppliers are being sought.

**Source:** [NYC Open Data — DOB NOW: Build — Approved Permits](https://data.cityofnewyork.us/d/rbx6-tga4).

### ✅ Why use it?

- **Focused NYC search:** filter by borough, date, estimated project cost and description keywords.
- **Use clues, not unsupported certainty:** select `commercial`, `residential`, `unknown`, or `all` based on conservative evidence in the available data.
- **Structured project signals:** review permit IDs, dates, work descriptions, service tags and estimated job costs.
- **Explainable priority:** a rule-based assessment highlights recent, detailed records for manual review. It is **not** a sales probability.
- **Export-ready records:** use Apify dataset exports or its API to retrieve structured records for your own workflow. No CRM or alert integration is built into this Actor.

### 💰 Pricing

**Both Pay Per Event events below are active.** Apify charges them automatically; there is no extra custom result event and no additional platform-usage costs are passed on to the user.

| Event | Price | Charged when |
| --- | ---: | --- |
| Permit record delivered (`apify-default-dataset-item`) | **$0.0015 per item** | A permit record is stored in the default dataset |
| Actor start (`apify-actor-start`) | **$0.00005** for runs up to 1 GB RAM | The run starts; memory allocations above 1 GB may involve additional start-event units |

**Examples at the configured prices, not actual bills:** 100 returned records = **$0.15005**, and 500 returned records = **$0.75005**, assuming one start-event unit and before any applicable discounts.

These billing details apply:

- A zero-result run can still incur the start-event charge.
- Records returned again in a later run are billed again. The Actor does **not** maintain an `onlyNew` history across runs.
- Separate permits for the same underlying project can each count as a delivered record.
- Your selected spending limit can stop the run before all matching records are returned. Page and item limits also apply.
- Check the pricing panel and any discounts on Apify before running. This README's pricing section must be updated if the Console pricing changes.

### 🎯 Who it's for

- General contractors researching permit activity.
- Plumbing, renovation, structural and other construction service providers.
- Suppliers and business development teams screening project activity.
- Real estate and construction market researchers.
- Developers adding NYC permit data to a workflow or CRM review queue.

### ⚙️ Available filters

| Input | Default / range | Actual behavior |
| --- | --- | --- |
| `daysBack` | `30`; 1–3650 | From midnight in New York this many days ago through the end of today. |
| `boroughs` | `[]` | Bronx, Brooklyn, Manhattan, Queens or Staten Island; empty means all; case insensitive. |
| `minEstimatedCost` | `100000`; 0–1e15 USD | Minimum estimated job cost. Missing or invalid costs are excluded. |
| `keywords` | `[]` | Match ANY literal word/phrase in description or work type, ignoring case. Empty means no restriction. |
| `usageHint` | `"all"` | Exact clue: `all`, `commercial`, `residential`, or `unknown`. |
| `maxItems` | `100`; 1–500 | Maximum distinct permit records saved, not a guarantee of that many matches. |
| `maxPages` | `10`; 1–100 | Maximum pages searched; each requests up to `min(100, maxItems)` source rows. Retries can add requests. |

Borough and keyword lists accept up to 50 nonempty entries, each at most 100 characters. Date, cost, borough and keywords are filtered on the source API and checked locally. Use clues are filtered after retrieval.

`commercial`, `residential` and `unknown` match only their exact clue. **Unknown never matches commercial.** `all` also preserves `mixed_or_ambiguous` and `conversion_to_residential`; the three specific filters exclude those two categories. A reference to previous commercial use in a residential conversion is not a commercial match. Clues concern the mentioned work area, not verified legal occupancy of an entire property. Restrictive filters can return fewer records or reach the page limit.

### ▶️ Quick start

1. Open the Actor's **Input** tab.
2. Choose a recent date range and maximum results. Start with 10–20 for a quick review.
3. Optionally filter by borough, minimum cost, keywords, and use clue.
4. Run the Actor and review its **Dataset**.
5. In Dataset, choose **Export** for JSON, CSV or Excel, or use Apify’s dataset-items API. JSON preserves nested assessments; select/flatten the needed nested fields for a spreadsheet. Exporting existing results does not require another run.

Suggested starting resources: **512 MB RAM and a 120-second timeout**; these defaults are not a customer memory cap. Check **SUMMARY** in the run’s key-value store for `emitted`, `filtered`, `pages`, `retries` and `stop_reason`. A failed or aborted run can retain partial records.

Programmatic retrieval uses `GET /v2/datasets/{datasetId}/items?format=json` with your account’s supported authentication. Never include tokens in shared examples. The public `source_url` in each record points to NYC data, not your Apify dataset.

### 🧪 Example input

A small Manhattan review using the supported input parameters:

```json
{
  "daysBack": 30,
  "boroughs": [
    "Manhattan"
  ],
  "minEstimatedCost": 100000,
  "keywords": [],
  "usageHint": "all",
  "maxItems": 10,
  "maxPages": 2
}
```

### 📦 Example result — complete real record

This record was retrieved in the **0.1.2 commercial-filter test on October 16, 2026**. It also meets the example input's borough, cost and use filters. The example input is illustrative; it is not presented as the exact input of that historical run, and the next run may return different records. The assessment reflects the recorded date, not a current sales verification.

```json
{
  "permit_id": "M01370350-S1-PL:1",
  "job_filing_number": "M01370350-S1",
  "issued_date": "2026-10-15T00:00:00",
  "borough": "Manhattan",
  "property_address": "16 WEST 39 STREET",
  "work_type": "Plumbing",
  "job_description": "SUBSEQUENT FILING PLUMBING WORK UNDER DOB APPLICATION# M01370350-I1 FOR CELLAR AND FIRST FLOOR RESTAURANT. NO CHANGE OF USE, EGRESS OR OCCUPANCY.",
  "estimated_cost_usd": 160000,
  "opportunity_tags": [
    "plumbing"
  ],
  "source_url": "https://data.cityofnewyork.us/resource/rbx6-tga4.json?%24select=job_filing_number%2Cwork_permit%2Csequence_number%2Cissued_date%2Cborough%2Chouse_no%2Cstreet_name%2Cwork_type%2Cjob_description%2Cestimated_job_costs&%24where=work_permit+%3D+%27M01370350-S1-PL%27+AND+sequence_number+%3D+%271%27",
  "opportunity_assessment": {
    "version": "rules-v1",
    "assessed_on": "2026-10-16",
    "score": 60,
    "band": "medium",
    "usage_hint": "commercial",
    "usage_evidence": [
      "RESTAURANT"
    ],
    "quality_flags": [
      "cross_referenced_filing"
    ],
    "reasons": [
      "Budget: +10; estimated job cost, not available contract value.",
      "Recency: +20; 1 days since issuance.",
      "Scope: +20; identifiable work or discipline.",
      "Specificity: +10; description detail.",
      "Quality adjustment: 0.",
      "Scale is capped at 90: hiring availability is unverified."
    ]
  }
}
```

### 📦 What you get

| Field | Meaning |
| --- | --- |
| `permit_id` | Permit number and sequence, or a deterministic fallback identifier when absent. |
| `job_filing_number` | Source filing reference; useful for reviewing related permits. |
| `issued_date` | Issue timestamp as supplied by the source, interpreted in New York local time. |
| `borough` | NYC borough. |
| `property_address` | Work-site address, not the applicant's mailing address. |
| `work_type` | Source work discipline. |
| `job_description` | Source work description, with whitespace normalized. |
| `estimated_cost_usd` | Estimated job cost, not the value of an available contract. |
| `opportunity_tags` | Keyword-based service categories; multiple tags can apply. |
| `source_url` | Public source API link restricted to the permit and permitted output columns. |
| `opportunity_assessment` | Rule version, assessment date, coarse score/band, use clue/evidence, quality flags and reasons. |

The score uses estimated job cost, recency, identifiable work and description detail. It is a coarse priority in steps of ten, currently capped at 90. Essential missing information produces `score: null` and `band: "insufficient_data"`. It is not a probability of a sale, confirmation of a customer, procurement requirement or available contract value. Read `usage_evidence`, `quality_flags` and `reasons` alongside the source description.

### Related permits and repetitions

Within a run, deduplication uses permit number plus sequence, with a deterministic filing/discipline/date/worksite fallback when needed. Separate plumbing, electrical or structural permits remain separate records even when they describe one project. Later sequences can be revisions rather than new projects. Use filing numbers, site details and description cross-references to review relationships; **one permit is not one independent customer**. Do not add related filing estimates as if they were independent available budgets.

There is no cross-run history or `onlyNew` setting. Repeated runs can return the same permit; each returned occurrence is billed again under the active PPE pricing.

### 💡 Best practices

- Start with `usageHint: "all"` to understand the coverage, then narrow the search.
- If your commercial-only search returns few records, consider whether excluding ambiguous use clues is appropriate.
- Use the source permit ID when verifying a project; related filings may belong to the same project.
- Set `maxPages` thoughtfully. Reaching the page limit can stop the run before all matches are collected.
- Always verify procurement status and project details independently before contacting suppliers or allocating sales effort.

### ❓ FAQ

**Does this provide verified contractor contacts?**\
No. It provides structured permit/project information and does not enrich results with applicant names, phone numbers or verified emails.

**Are these open bids or confirmed construction leads?**\
No. Approved permits are records of authorized construction activity; they do not prove that a contract is available or that a buyer is actively sourcing vendors.

**Does the `commercial` filter cover every commercial property?**\
No. It returns only records with commercial clues recognized by the current rules. Missing or ambiguous data may exclude otherwise relevant projects.

**Will I get only new permits on my next run?**\
No. Results may repeat between runs; repeated delivered records are billed again under the active PPE pricing.

**Is the score the probability of getting business?**\
No. It is a rule-based review priority based on available attributes such as recency, cost and description specificity.

**Does the dataset include every type of NYC permit?**\
No. Coverage is limited to the linked DOB NOW approved permits dataset; other permit programs and categories may be outside this source.

**Why did I get fewer records than requested?**\
Filters, missing/invalid source values, duplicates or limits can reduce output. SUMMARY distinguishes `maxItems`, `maxPages`, `exhausted` and `chargeLimit`. Reaching `maxPages` is a bounded-search outcome, not proof that no other matches exist.

**Does this include CRM integrations, alerts or other cities?**\
No. This release has no contact enrichment, built-in CRM sync, alert service, external AI or multi-city scraper. Export/API access is supplied by the Apify platform.

### ⚠️ Limitations & data provenance

- Data source: official NYC Open Data, DOB NOW: Build — Approved Permits, **rbx6-tga4**. Coverage does not span every DOB system; legacy `ipu4-2q9a` is not the primary source.
- NYC lists a daily update frequency; publication may lag and is not real-time guaranteed. Missing fields, API outages, inconsistent or truncated descriptions and live dataset changes can affect output. Stable ordering within queries cannot freeze a changing source between pages.
- A recent issue date does not necessarily mean a brand-new project. Some filings may be later sequences or related disciplines.
- Related permits may refer to a single project; amounts should not be added together as if they were independent open contracts.
- Applicant, owner and filing-representative contact columns are excluded. `property_address` is a worksite address; the source description is public free text and is not a contact-enrichment product.
- Completed, assigned or superseded work may appear; issuance does not prove construction is yet to begin or that hiring is open.
- This is an independent data-processing tool, **not affiliated with or endorsed by NYC government**. Source accuracy and availability are not guaranteed. See the [NYC Open Data FAQ](https://www.nyc.gov/opendata/get-started/FAQs) and [portal terms](https://data.cityofnewyork.us/stories/s/Terms-of-Use/k9k7-3cje).

### 🤝 Support

Use the **Issues** tab on [this Actor’s Apify Store page](https://apify.com/peaceful_volute/construction-permit-leads) to report a reproducible problem. Include a sanitized input, run ID and what result you expected; never send account tokens or personal information.

# Actor input Schema

## `daysBack` (type: `integer`):

Find permits issued from midnight in New York this many days ago through the end of today. Source updates may lag issuance.

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

Optional borough names: Bronx, Brooklyn, Manhattan, Queens, Staten Island. Leave empty for all five. Case does not matter.

## `minEstimatedCost` (type: `number`):

Keep filings with an estimated job cost at least this amount. This is a project estimate, not an available contract or remaining budget. Missing costs are excluded.

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

Optional words or phrases to find in the work description or work type. A permit matches if ANY term appears, ignoring case. Leave empty for all work.

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

Stop after saving this many distinct permit records (1–500). Related disciplines may belong to one project. Fewer records may match your filters or page limit.

## `maxPages` (type: `integer`):

Limit how far to search: 1–100 pages, up to 100 source rows per page (or Maximum permits, if lower). Filtering can produce fewer results. Retries may make additional requests.

## `usageHint` (type: `string`):

Optional clue from the work description, not verified legal occupancy. Commercial, residential and unknown match only that exact clue. Unknown is never commercial. All also includes mixed/ambiguous work and conversions to residential use. Applied after retrieval, so restrictive filters may hit the search page limit.

## Actor input object example

```json
{
  "daysBack": 30,
  "boroughs": [],
  "minEstimatedCost": 100000,
  "keywords": [],
  "maxItems": 100,
  "maxPages": 10,
  "usageHint": "all"
}
```

# Actor output Schema

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

No description

## `summary` (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("peaceful_volute/construction-permit-leads").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("peaceful_volute/construction-permit-leads").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 peaceful_volute/construction-permit-leads --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,peaceful_volute/construction-permit-leads"
        }
    }
}
```

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/4s9QmtzSHe30hc85n/builds/pDapex0UjJr3AyINa/openapi.json
