# NYC HPD Housing Violations - Building Code Enforcement (`j0401/nyc-hpd-violations`) Actor

New York City housing code violations from HPD (public open data, 11.3M records): building and apartment, violation class A/B/C/I, inspection and compliance dates, the notice text and current status. Screen a building by HPD id, or filter by class, borough, ZIP, street, status or date.

- **URL**: https://apify.com/j0401/nyc-hpd-violations.md
- **Developed by:** [Wenhao Yang](https://apify.com/j0401) (community)
- **Categories:** Business
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.03 / 1,000 nyc hpd violation records

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

## NYC HPD Housing Violations - Building Code Enforcement

Every housing code violation issued by New York City's Department of Housing
Preservation and Development, straight from the City's open data. **11.3 million
violations** - what was wrong, in which building and apartment, how serious, and
whether it is still open.

### Low cost

**From $0.00005 per record, down to $0.00003 at Gold.** Pay only for the
records you actually receive - the whole register stays queryable, you are
never billed for the scan behind it.

### What you get

One row per violation:

- **Where** - the borough, house number, street, ZIP, apartment, story, block
  and lot, plus the BBL, BIN and community board
- **How serious** - the violation class: A (non-hazardous), B (hazardous),
  C (immediately hazardous) or I (informational)
- **What** - the notice-of-violation text describing the condition
- **When** - the inspection date, the notice issue date, the compliance deadline
  and the certification date
- **Where it stands** - the current status, the Open/Close flag, the notice type
  (original or reissued) and whether the violation impairs the rent

The building id joins the HPD complaint table, and the BBL joins the City's
property records.

### Filter it

- **Class** - `class="C"` for immediately-hazardous violations.
- **Status** - `violationStatus="Open"` for violations not yet cleared.
- **Rent impairing** - `rentImpairing="Y"` for the rent-abatement tier.
- **Place** - `boro="BROOKLYN"`, `zip="11206"`, `street="BROADWAY"`.
- **One building** - `buildingId="375411"` for that building's most recent
  violations (up to 2,000 per run).
- **Period** - `dateFrom="2026-01-01"`, or `recentDays=30` for the last month.

### Example inputs

**The serious, still-open violations** - class C, not yet cleared.

```json
{ "class": "C", "violationStatus": "Open", "maxResults": 50 }
```

**One building's record** - `buildingId` is the HPD key.

```json
{ "buildingId": "375411", "maxResults": 100 }
```

**Recent Brooklyn cases** - a borough and a window.

```json
{ "boro": "BROOKLYN", "class": "C", "recentDays": 90, "maxResults": 50 }
```

**How the violations break down** - `mode=aggregate` counts per class.

```json
{ "mode": "aggregate", "groupBy": "class" }
```

### Or roll it up

Set `mode=aggregate` and get a count by **class**, **status**, **borough**,
**notice type** or **current status**. Every group comes back - this mode is not
cut off by `maxResults`.

### Then use it

- **Tenant / legal diligence** - a building's open class-C violations and
  rent-impairing findings.
- **Underwriting** - violation density and open-case load as a property risk
  signal.
- **Watch a building** - pull its violations by `buildingId` and track new ones.

### Example output

**One open class-C violation** - a lead-paint hazard, as captured on 2026-10-17:

```json
{
 "platform": "nyc-hpd-violations",
 "source": "nyc-hpd-housing-violations",
 "mode": "rows",
 "groupKey": "",
 "groupCount": "",
 "groupBy": "",
 "violationId": "19287708",
 "buildingId": "557821",
 "registrationId": "412403",
 "boro": "QUEENS",
 "houseNumber": "79-05",
 "streetName": "147 STREET",
 "zip": "11367",
 "apartment": "E1",
 "story": "1",
 "block": "6691",
 "lot": "1",
 "class": "C",
 "inspectionDate": "2026-10-06T00:00:00.000",
 "approvedDate": "2026-10-06T00:00:00.000",
 "originalCertifyByDate": "2026-11-05T00:00:00.000",
 "originalCorrectByDate": "2026-10-31T00:00:00.000",
 "certifiedDate": "",
 "orderNumber": "624",
 "novId": "10696081",
 "novDescription": " 27-2056.6 ADM CODE - CORRECT THE LEAD-BASED PAINT HAZARD-PAINT THAT IS PEELING OR ON A DETERIORATED SUBSURFACE AND EITHER TESTED INCONCLUSIVE FOR LEAD CONTENT AT 0.5MG/CM2 OR TESTED POSITIVE FOR LEAD CONTENT ON A METAL OR CERAMIC SUBSTRATE AS SET FORTH IN (28 RCNY 11-07(b)) USING WORK PRACTICES SET FORTH IN 28 RCNY 11-06(b)(2). 1st DOOR FROM SOUTH AT WEST WALL IN THE FOYER LOCATED AT APT E1, 1st STORY, 1st APARTMENT FROM NORTH AT EAST , SECTION ''79-19''",
 "novIssuedDate": "2026-10-07T00:00:00.000",
 "currentStatus": "NOV SENT OUT",
 "currentStatusDate": "2026-10-07T00:00:00.000",
 "novType": "Original",
 "violationStatus": "Open",
 "rentImpairing": "N",
 "communityBoard": "8",
 "councilDistrict": "24",
 "bbl": "4066910001",
 "bin": "4144769",
 "nta": "Kew Gardens Hills",
 "sourceUpdatedAt": "2026-10-17"
}
```

**`mode=aggregate`, `groupBy=class`** - one count row per class:

```
B                                           5,312,252
C                                           2,615,952
A                                           2,585,034
I                                             806,060
```

### Notes on the data, from the source

- **Counts in this section are a 2026-10-18 snapshot.** The register refreshes
  daily, so the live figures differ slightly.

- **Class C is the one that matters.** A = non-hazardous, B = hazardous,
  **C = immediately hazardous** (2.6M records, 585k still open), I =
  informational. Filter on `class` to find it.

- **Open vs closed.** `violationStatus` is `Open` (2.87M) or `Close` (8.43M);
  `currentStatus` gives the finer workflow state. `rentImpairing="Y"` marks the
  775,900 violations that impair an apartment's rent.

- **The listing is keyed by `buildingId` and BBL.** One `buildingId` lookup
  returns the most recent violations, up to 2,000 per run (192 buildings have
  more than 2,000 rows in the register); the BBL joins the City's CAMA records.

- **`buildingId` is exact, not a name.** It is the HPD numeric id, not an
  address - look it up from the building, then pull its violations here.

- **The register refreshes daily**; `sourceUpdatedAt` carries the
  dataset's own refresh date.

# Actor input Schema

## `class` (type: `string`):

HPD violation class: A = non-hazardous, B = hazardous, C = immediately hazardous (the tenant-risk tier), I = informational. Blank = any.

## `violationStatus` (type: `string`):

Open = not yet cleared; Close = cleared. Blank = any.

## `rentImpairing` (type: `string`):

Y = the violation impairs the apartment's rent (the tenant may have a rent abatement claim). Blank = any.

## `novType` (type: `string`):

Original or Reissued notice of violation. Blank = any.

## `boro` (type: `string`):

The borough the building is in. Blank = any.

## `zip` (type: `string`):

Substring match on the ZIP code, e.g. '11206', '104'. Blank = any.

## `street` (type: `string`):

Substring match on the street name, e.g. 'BROADWAY', 'GRAND'. Blank = any.

## `buildingId` (type: `string`):

Look up every violation on one building by its HPD building id, e.g. '375411'. This is the key that joins the HPD complaint table. Blank = any.

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

Earliest inspection date, YYYY-MM-DD. Blank = any.

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

Latest inspection date, YYYY-MM-DD. Blank = any.

## `recentDays` (type: `integer`):

Only violations inspected within the last N days. Cannot be combined with 'Inspected on or after' (the run fails if both are set). 0 = off.

## `mode` (type: `string`):

rows = violation records matching your filters (default). aggregate = one count row per group (see groupBy).

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

Which dimension to aggregate over (mode=aggregate). Blank = class. Every group is returned - aggregate mode is not cut off by maxResults.

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

Cap the number of records pushed in rows mode (0 = default 50; up to 2,000 per run). Each record is metered individually, so there is no per-run charge cap. Aggregate mode returns every group.

## Actor input object example

```json
{
  "class": "",
  "violationStatus": "",
  "rentImpairing": "",
  "novType": "",
  "boro": "",
  "zip": "",
  "street": "",
  "buildingId": "",
  "dateFrom": "",
  "dateTo": "",
  "recentDays": 0,
  "mode": "rows",
  "groupBy": "",
  "maxResults": 50
}
```

# Actor output Schema

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

New York City HPD housing violation records - as JSON

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

No description

## `runUrl` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {};

// Run the Actor and wait for it to finish
const run = await client.actor("j0401/nyc-hpd-violations").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {}

# Run the Actor and wait for it to finish
run = client.actor("j0401/nyc-hpd-violations").call(run_input=run_input)

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

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

```

## CLI example

```bash
echo '{}' |
apify call j0401/nyc-hpd-violations --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,j0401/nyc-hpd-violations"
        }
    }
}
```

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/CYSWJ7chce7xZtiFk/builds/0UIgzN0kedfp3NyGk/openapi.json
