CityBuilderDeveloper API

NYC building data · REST API

Fresh building records for every NYC address — not last month's Open Data dump.

One API for DOB BIS, DOB NOW, FDNY, HPD, LPC and OATH/ECB records. Ask how fresh any building is, trigger an on-demand refresh straight from the source agencies, then pull the structured data — paged just like Socrata, but current.

Why it beats Open Data

Live from the source

We pull from the agencies' own systems — DOB NOW's portal, FDNY's building-profile PDFs — which land days-to-weeks before the NYC Open Data mirrors catch up.

Refresh on demand

Don't wait for a nightly ETL. Ask for a refresh of a specific building and we re-fetch it now, within a 12-hour courtesy window so we never hammer the city sites.

One freshness timestamp

Every building carries a single last-refreshed time. Poll it, decide if it's fresh enough for you, and only refresh when you actually need to.

Quickstart

Grab a key, then try the three core calls right here in the browser.

1 · Get an API key

Free trial key, delivered instantly. Rate-limited and capped per day — enough to build and test.

Shown once at creation — stored only in this browser. Send it as Authorization: Bearer …

2 · Try it live

Runs against this API with your key. Enter a BIN or an address.

…or from your terminal

# 1. Sign up for a key
curl -s -X POST https://developers.citybuilder.nyc/api/v1/keys \
  -H 'content-type: application/json' \
  -d '{"email":"you@company.com"}'

# 2. How fresh is this building? (BIN or address)
curl -s https://developers.citybuilder.nyc/api/v1/freshness?bin=1001780 \
  -H 'authorization: Bearer cb_live_…'

# 3. Not fresh enough? Ask for a refresh, then poll freshness again.
curl -s -X POST https://developers.citybuilder.nyc/api/v1/refresh \
  -H 'authorization: Bearer cb_live_…' \
  -H 'content-type: application/json' \
  -d '{"address":"1 Centre St, Manhattan"}'

# 4. Pull the data for an agency (paged, max 1000/page)
curl -s 'https://developers.citybuilder.nyc/api/v1/data?bin=1001780&agency=DOB%20BIS&limit=100&offset=0' \
  -H 'authorization: Bearer cb_live_…'

API reference

Base URL https://developers.citybuilder.nyc/api/v1. Authenticate every request (except signup) with Authorization: Bearer <key> or X-API-Key.

POST/keys

Create a trial API key. Body: { "email": "you@company.com" }. The key is returned once.

GET/freshness?bin= | address= | q=

Returns the building's last-refresh time and per-agency status, or found: false if we don't hold it yet. Pass a bin, an address, or q (auto-detected). Top-level status is "ready" or "refreshing".

{
  "found": true,
  "bin": "1001780",
  "address": "1 CENTRE STREET, MANHATTAN",
  "status": "ready",
  "lastRefreshedAt": "2026-07-08T18:20:11.004Z",
  "ageSeconds": 512,
  "refreshInProgress": false,
  "refreshStartedAt": null,
  "canRefresh": false,
  "cooldownRemainingSeconds": 42688,
  "agencies": [
    { "id": "bis_jobs", "label": "BIS Jobs", "status": "ok", "count": 143, "source": "live" }
  ]
}

Data is served live-only— we don't substitute stale NYC Open Data. If an agency's website is down when you refresh, that source keeps the last data we successfully scraped and carries a refreshError in agencies[] (its status is error if we hold no prior data). A handful of agencies with no live source yet (CofO, HPD, LPC violations) are still served from Open Data.

While a refresh is running, status is "refreshing", refreshInProgress is true, and lastRefreshedAt still reflects the last completedrefresh (it only advances once the new one finishes) — so a poller can tell "done" from "still going". Individual sources report status: "loading" in agencies[] until they land.

POST/refresh

Queue a refresh from the source agencies. Body: { "bin": "…" } or { "address": "…" }. We scrape one building at a time(a single shared connection to the city's systems), so your request joins a queue and returns 202 with a jobId and your place in line. A 429 refresh_cooldown means it was refreshed within the last 12h — just read it from /freshness.

{
  "status": "queued",              // or "running" if it started immediately
  "deduped": false,                // true = you rejoined a pending refresh
  "bin": "1001780",
  "queue": {
    "status": "queued",
    "position": 3,                 // 1 = being scraped right now
    "refreshesAhead": 2,           // buildings that finish before yours
    "queueLength": 2,
    "jobId": "job_1001780_7"
  },
  "message": "Queued at position 3 — 2 refreshes ahead of you…"
}
GET/refresh?bin= | address= | jobId=

Poll your place in the queue. Pass the same building (or the jobId you got back) and watch queue.status move queued → running → done (or error). While queued, position counts down to 1. Once it's done, read the fresh data from /freshness and /data. (Queue status is also mirrored in the queue field of every /freshness response.) not_found means no pending or recent job — check /freshness for the current data.

GET/data?bin= | address= &agency= &limit= &offset=

Returns the stored records for one agency. agency is a dataset id (e.g. bis_jobs, fdny) or a group name (e.g. DOB BIS, HPD) which expands to all its datasets. Row datasets page with limit (max 1000) + offset.

GET/agencies

Lists every dataset id, its label, and its group — the values /data accepts. No auth required.

GET/health

Liveness probe. No auth required.

Available datasets

DOB BIS
  • BIS Jobsbis_jobs
  • BIS Violationsbis_violations
DOB NOW
  • NOW Jobsnow_jobs
  • NOW Violationsnow_violations
  • Sched. of Occupancynow_soo
OATH
  • ECB/OATH Violationsecb_violations
DOB
  • Cert. of Occupancycofo
FDNY
  • FDNY Inspectionsfdny
HPD
  • HPD Violationshpd_violations
  • HPD Complaintshpd_complaints
LPC
  • LPC Violationslpc_violations
  • LPC Permitslpc_permits

Limits & fair use

Daily quota

500 requests/day per key on the free trial. Response headers carry X-RateLimit-Remaining-Day and the reset time.

Burst limit

60 requests/minute per key. A 429 with Retry-After tells you when to resume.

Refresh cooldown

A given building can only be refreshed once every 12 hours — shared across all clients, to protect the city's sites.