# Building Permit Lead Monitor for Contractors (`lavender_whistle/building-permits-monitor`) Actor

Turn new building permits into contractor and supplier sales leads. Pulls the most-recent issued permits from NYC DOB open data or any Socrata civic portal: address, work type, job description, estimated cost, applicant business, and owner. Zero-config default run. Public data, no login.

- **URL**: https://apify.com/lavender\_whistle/building-permits-monitor.md
- **Developed by:** [Cathal Judge](https://apify.com/lavender_whistle) (community)
- **Categories:** Business
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$4.00 / 1,000 result rows

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/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are a software tools running on the Apify platform, for all kinds of web data extraction and automation use cases.
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.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/platform/integrations/mcp.md).

If your project is in a different language, use 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

## Building Permit Lead Monitor

**Apify Store title:** `Building Permit Lead Monitor for Contractors`

**Apify Store description:**
> Turn new building permits into ready-to-work sales leads. Every issued permit is a construction job about to start, which means a buyer for materials, equipment, subcontracting, roofing, solar, plumbing, insurance, and financing. This actor pulls the most-recent issued permits from New York City DOB open data (or any Socrata civic portal you point it at) and returns clean rows: address, work type, job description, estimated job cost, applicant business, owner, license, coordinates, a NYC.gov building record link, and a Google Maps link. Zero-config default run returns fresh permits immediately. 100% public government data: no login, no PII.

### Source + legality
`GET https://data.cityofnewyork.us/resource/rbx6-tga4.json?$where=...&$order=issued_date DESC&$limit=...` - the NYC Department of Buildings "DOB NOW: Build - Approved Permits" dataset on the city's public Socrata (SODA) open-data portal. Statutorily public municipal records; no authentication, no API key needed for modest use, no consumer PII. A descriptive `User-Agent` is sent as good-citizen practice.

### Which dataset (and why)
NYC publishes building permits in two Socrata datasets:
- **`rbx6-tga4` - "DOB NOW: Build - Approved Permits" (this actor's default).** The current live system. Proper `calendar_date` columns, so "most recent" ordering is reliably chronological, and it carries the exact lead fields buyers want: `job_description`, `applicant_business_name`, and `estimated_job_costs`.
- `ipu4-2q9a` - "DOB Permit Issuance" (legacy BIS). Still updated but all date columns are stored as free text with mixed formats, so ordering by newest is unreliable, and it has no job description or estimated cost. Point the actor at it by setting `datasetUrl` to that resource and `dateField` to `issuance_date` if you need the legacy history; the field mapping falls back automatically.

### Zero-config default run
Empty input pulls the newest issued NYC building permits (`issued_date IS NOT NULL`, ordered `issued_date DESC`, 25 rows) and returns real fresh leads, so the Store "try it" button works on first click.

### Generalises to any city
`datasetUrl` and `dateField` are inputs. Point the actor at any Socrata building-permit dataset (Chicago, Los Angeles, Austin, Seattle, and many more) and it returns the newest records. Curated lead fields are mapped by name with multi-alias fallback across common NYC DOB schemas; the full original record is always included under `raw`, so no data is lost on an unmapped portal.

### Inputs
| Input | Default | Purpose |
|---|---|---|
| `datasetUrl` | NYC DOB NOW | Socrata resource endpoint ending in `.json`. |
| `dateField` | `issued_date` | Column used to sort newest-first and apply the lookback. |
| `borough` | all | Optional NYC borough filter (case-insensitive). |
| `workType` | all | Optional case-insensitive `work_type` contains filter (e.g. Solar, Plumbing). |
| `minJobCost` | 0 | Only permits with estimated cost at least this (bigger leads). |
| `lookbackDays` | 0 | Only permits within N days; 0 returns newest regardless of age. |
| `maxResults` | 25 | Rows per run. |

### Output fields
`permitId, workPermitNo, permitType, workType, filingReason, permitStatus, houseNo, street, borough, zip, address, issuedDate, approvedDate, expiredDate, jobDescription, estimatedJobCost, applicantBusiness, applicantName, applicantLicenseType, applicantLicenseNo, ownerBusiness, ownerName, bin, latitude, longitude, neighborhood, permitLink, mapUrl, raw`

### Run locally (no Apify account)
```bash
npm install
npm test --workspace actors/building-permits-monitor
## or run the actor directly:
node actors/building-permits-monitor/src/main.js
````

### Proposed pricing (set in Apify at publish - CJ-gated)

Pay-Per-Event in the documented winning band:

- **~$0.004 per permit lead returned**

Pricing is NOT set here - configured on the Apify Store at publish, CJ-gated. No account, no publish, no spend happens in this repo.

# Actor input Schema

## `datasetUrl` (type: `string`):

The Socrata (SODA) resource endpoint ending in .json. Default is NYC DOB NOW Approved Permits. Point it at any city's building-permit dataset (e.g. Chicago, LA, Austin) to reuse this actor.

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

The dataset column used to sort by newest first and to apply the lookback window. Default issued\_date (NYC DOB NOW). Use issuance\_date for the legacy NYC DOB dataset, or the target portal's own permit-date column.

## `borough` (type: `string`):

Optional NYC borough filter. Leave blank for all boroughs. Ignored on non-NYC datasets that have no borough column.

## `workType` (type: `string`):

Optional case-insensitive filter on the work\_type column, e.g. Solar, Plumbing, General Construction, Boiler. Leave blank for all permit types.

## `minJobCost` (type: `integer`):

Only return permits whose estimated job cost is at least this amount, to focus on larger, higher-value leads. 0 disables the filter.

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

Only return permits dated within this many days of today, using the recency date field. 0 disables the window and returns the newest permits regardless of age (safest for a guaranteed result).

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

Maximum number of permit lead rows to return per run.

## Actor input object example

```json
{
  "datasetUrl": "https://data.cityofnewyork.us/resource/rbx6-tga4.json",
  "dateField": "issued_date",
  "borough": "",
  "workType": "Solar",
  "minJobCost": 0,
  "lookbackDays": 0,
  "maxResults": 25
}
```

# 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 = {
    "datasetUrl": "https://data.cityofnewyork.us/resource/rbx6-tga4.json",
    "dateField": "issued_date",
    "workType": "Solar",
    "minJobCost": 0,
    "lookbackDays": 0,
    "maxResults": 25
};

// Run the Actor and wait for it to finish
const run = await client.actor("lavender_whistle/building-permits-monitor").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 = {
    "datasetUrl": "https://data.cityofnewyork.us/resource/rbx6-tga4.json",
    "dateField": "issued_date",
    "workType": "Solar",
    "minJobCost": 0,
    "lookbackDays": 0,
    "maxResults": 25,
}

# Run the Actor and wait for it to finish
run = client.actor("lavender_whistle/building-permits-monitor").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "datasetUrl": "https://data.cityofnewyork.us/resource/rbx6-tga4.json",
  "dateField": "issued_date",
  "workType": "Solar",
  "minJobCost": 0,
  "lookbackDays": 0,
  "maxResults": 25
}' |
apify call lavender_whistle/building-permits-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=lavender_whistle/building-permits-monitor",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "Building Permit Lead Monitor for Contractors",
        "description": "Turn new building permits into contractor and supplier sales leads. Pulls the most-recent issued permits from NYC DOB open data or any Socrata civic portal: address, work type, job description, estimated cost, applicant business, and owner. Zero-config default run. Public data, no login.",
        "version": "0.1",
        "x-build-id": "cArhlSD9N2lmjgm8g"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/lavender_whistle~building-permits-monitor/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-lavender_whistle-building-permits-monitor",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/lavender_whistle~building-permits-monitor/runs": {
            "post": {
                "operationId": "runs-sync-lavender_whistle-building-permits-monitor",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/lavender_whistle~building-permits-monitor/run-sync": {
            "post": {
                "operationId": "run-sync-lavender_whistle-building-permits-monitor",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "properties": {
                    "datasetUrl": {
                        "title": "Socrata dataset URL",
                        "type": "string",
                        "description": "The Socrata (SODA) resource endpoint ending in .json. Default is NYC DOB NOW Approved Permits. Point it at any city's building-permit dataset (e.g. Chicago, LA, Austin) to reuse this actor.",
                        "default": "https://data.cityofnewyork.us/resource/rbx6-tga4.json"
                    },
                    "dateField": {
                        "title": "Recency date field",
                        "type": "string",
                        "description": "The dataset column used to sort by newest first and to apply the lookback window. Default issued_date (NYC DOB NOW). Use issuance_date for the legacy NYC DOB dataset, or the target portal's own permit-date column.",
                        "default": "issued_date"
                    },
                    "borough": {
                        "title": "Borough (NYC only)",
                        "enum": [
                            "",
                            "Manhattan",
                            "Bronx",
                            "Brooklyn",
                            "Queens",
                            "Staten Island"
                        ],
                        "type": "string",
                        "description": "Optional NYC borough filter. Leave blank for all boroughs. Ignored on non-NYC datasets that have no borough column.",
                        "default": ""
                    },
                    "workType": {
                        "title": "Work type contains",
                        "type": "string",
                        "description": "Optional case-insensitive filter on the work_type column, e.g. Solar, Plumbing, General Construction, Boiler. Leave blank for all permit types.",
                        "default": ""
                    },
                    "minJobCost": {
                        "title": "Minimum estimated job cost (USD)",
                        "minimum": 0,
                        "type": "integer",
                        "description": "Only return permits whose estimated job cost is at least this amount, to focus on larger, higher-value leads. 0 disables the filter.",
                        "default": 0
                    },
                    "lookbackDays": {
                        "title": "Lookback (days)",
                        "minimum": 0,
                        "maximum": 3650,
                        "type": "integer",
                        "description": "Only return permits dated within this many days of today, using the recency date field. 0 disables the window and returns the newest permits regardless of age (safest for a guaranteed result).",
                        "default": 0
                    },
                    "maxResults": {
                        "title": "Max results",
                        "minimum": 1,
                        "maximum": 1000,
                        "type": "integer",
                        "description": "Maximum number of permit lead rows to return per run.",
                        "default": 25
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
