# NYC Tax Lien Sale Lists - BBL, Borough, Block & Lot (`j0401/nyc-tax-lien-sale`) Actor

New York City tax-lien sale lists (public open data, 264k rows): notice cycle, sale month, borough, block, lot, BBL, street address, ZIP, tax class and building class. Filter by borough, block/lot, BBL, cycle, ZIP or sale year; or aggregate by cycle, borough or class.

- **URL**: https://apify.com/j0401/nyc-tax-lien-sale.md
- **Developed by:** [Wenhao Yang](https://apify.com/j0401) (community)
- **Categories:** Business
- **Features:** Limited permissions
- **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 tax-lien sale 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 Tax Lien Sale Lists

Every property on a New York City Department of Finance tax-lien sale list - the 10/30/60/90-day notices and final sales - with its Borough-Block-Lot, street address and tax class.

### Low cost

Sale-list records: **from $0.00005 per record, down to $0.00003 at Gold.**

Property profiles (PLUTO-matched): **$0.002 per profile, down to $0.0012 at Gold.** A BBL PLUTO does not know is returned at the plain record price instead.

### What you get

- `saleMonth`, `cycle` - the sale period and the notice stage (`Final Sale`, `90 Day Notice`, ...). The source spells several stages both ways (`90 Day Notice` 63,185 rows and `90 Days Notice` 18,907; same for 10/30/60), so a substring such as `cycle="90 Day"` catches both.
- `borough` / `boroughName` - code and name
- `block`, `lot`, `bbl` - the 10-digit Borough-Block-Lot key
- `houseNumber`, `streetName`, `address`, `zip`
- `taxClassCode`, `buildingClass`, `communityBoard`, `councilDistrict`
- `waterDebtOnly` - whether the listed debt is water-only
- In `mode=profile` also: `plutoMatched`, `ownerName`, `plutoAddress`, `yearBuilt`, `residentialUnits`, `assessedTotal`, `plutoBuildingClass`

### Examples

The 50 most recent records:

```json
{ "mode": "rows", "maxResults": 50 }
```

One property by BBL:

```json
{ "bbl": "5080260130" }
```

Brooklyn, final sales only:

```json
{ "borough": "Brooklyn", "cycle": "Final Sale", "maxResults": 100 }
```

Property profile for the 50 most recent lien records - owner, year built, residential units and assessed total joined from PLUTO by exact BBL:

```json
{ "mode": "profile", "maxResults": 50 }
```

```json
{ "mode": "profile", "borough": "Brooklyn", "maxResults": 100 }
```

Sale lists by cycle:

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

By building class:

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

### Coverage and honest limits

- **264,142 rows**, published per sale cycle rather than daily. The dataset's own last-updated stamp is **2025-12-01**, and the most recent sale cycle is **June 2025**; no newer cycle had appeared when this was checked on **2026-10-30**. Filtering and counts are unaffected.
- **One run returns up to 5,000 records** (`maxResults`); aggregate mode returns every group.
- 🔴 **This is a notice list, not a ledger.** The city does not publish the owner name or the amount owed in this dataset. Do not read a row as "what is owed".
- `waterDebtOnly` is returned as **`Y` / `N`** (the city spells the older cycles `YES` / `NO`; both are normalised). The `waterDebtOnly` filter with `true` keeps water-only rows; `false` (the default) applies no filter.
- One row per property per list. The same property can appear on several cycles and in several years.
- `bbl` is built from borough + zero-padded block (5) + lot (4). If a block or lot in the source is longer than that, `bbl` is left blank rather than truncated - use `block` and `lot` for those rows.
- `sourceUpdatedAt` is the city's last dataset update date.

### Related

Also available in this account: **Sonoma County Defaulted Property Taxes** (bill-level default list for a California county) and **NYC ACRIS Liens & UCC** (UCC filings and federal tax liens recorded against NYC properties and debtors).

# Actor input Schema

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

rows = sale-list records (default). aggregate = one count row per group (see groupBy). profile = rows enriched with the PLUTO property record (owner, year built, units, assessed total) by exact BBL.

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

Borough name or code: Manhattan/1, Bronx/2, Brooklyn/3, Queens/4, Staten Island/5.

## `block` (type: `string`):

Exact tax block, e.g. "8026".

## `lot` (type: `string`):

Exact tax lot, e.g. "130".

## `bbl` (type: `string`):

10-digit Borough-Block-Lot, e.g. "5080260130". Combines borough, block and lot.

## `cycle` (type: `string`):

Cycle prefix, e.g. "Final Sale", "90 Day Notice", "30 Day Notice".

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

Exact five-digit ZIP, e.g. "10307".

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

Street-name prefix, case-insensitive, e.g. "JOHNSON".

## `saleYear` (type: `string`):

Four-digit year of the sale month, e.g. "2025".

## `waterDebtOnly` (type: `boolean`):

When true, only properties whose listed debt is water-only (the output value is normalised to "Y" / "N"). When false (default) no filter is applied.

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

Dimension for mode=aggregate (blank = cycle). Every group is returned.

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

Cap on records pushed in rows/profile mode (0 = default 50; up to 5,000 per run; aggregate returns every group). Each record is metered individually, so there is no per-run charge cap.

## Actor input object example

```json
{
  "mode": "",
  "waterDebtOnly": false,
  "groupBy": "",
  "maxResults": 50
}
```

# Actor output Schema

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

NYC tax-lien sale 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-tax-lien-sale").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-tax-lien-sale").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-tax-lien-sale --silent --output-dataset

```

## MCP server setup

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

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/bh2j7EZLjERYg7nSB/builds/7hrb6nW4EsTTlzJ7R/openapi.json
