REST API
A versioned HTTP API at https://staging-api.nosyneighbor.nyc/v1/*. Every response is JSON. Every request other than GET /v1/usage is a POST with a JSON body.
Base URL. The API is https://staging-api.nosyneighbor.nyc. The web app at https://nosyneighbor.nyc does not serve /v1/*. A request sent there returns a 404 that repeats this sentence.
1. Get an API key
Sign in, open the developer dashboard, and create a key. The full key is shown exactly once. Copy it immediately, because it cannot be retrieved again (you can only revoke or rotate it after that). Production keys start with nn_live_. Staging keys start with nn_test_. A key created against one environment is never valid against the other, whatever prefix it is given.
2. Authenticate
Send the key as a bearer token on every request:
Authorization: Bearer nn_test_0000000000000000_<paste-your-own-secret-here>That key is a placeholder. See the security note at the bottom of this page. No other header, cookie, or query parameter authenticates this API.
3. Quickstart with curl
curl -s https://staging-api.nosyneighbor.nyc/v1/lookup \
-H "Authorization: Bearer nn_test_0000000000000000_<paste-your-own-secret-here>" \
-H "Content-Type: application/json" \
-d '{"address": "20 W 34th St, New York NY 10001"}'The operations
| Path | Purpose |
|---|---|
POST /v1/lookup | Full property report for one NYC address |
POST /v1/search | Browse listings in a ZIP code or area with filters |
POST /v1/comps | Comparable sold homes, or a valuation, for an address |
POST /v1/rentals | Comparable active rentals, or a rent estimate, for an address |
POST /v1/updates | Digest of new, price-dropped, and off-market listings for an area |
POST /v1/rates | Current US mortgage rates for a loan scenario |
GET /v1/usage | Your current rate-limit and quota usage (free, costs nothing) |
Every field, request shape, and response shape is in the interactive API reference (generated from the same registry that defines the operations, so it cannot drift from what the API serves). This page is a guide, not the full schema.
Response envelope
A successful call always returns:
{
"data": { /* operation-specific result */ },
"meta": {
"request_id": "…",
"operation": "lookupProperty",
"units_charged": 10,
"minute_remaining": 230,
"daily_remaining": 9990
}
}Error envelope
Every failure, whatever the cause, returns the same JSON shape, with a matching HTTP status:
{
"code": "rate_limited",
"message": "You've hit the per-minute rate limit for the Pro REST API.",
"request_id": "…"
}code is a small closed set: unauthorized (401), forbidden (403), invalid_request (400), not_found (404), outside_coverage (400), rate_limited (429), quota_unavailable (503), method_not_allowed (405), upstream_error (502), and internal_error (500). Keep request_id if you need to report a problem. It is also echoed as the x-request-id response header on every request except CORS preflights. The next section tells outside_coverage, not_found, and invalid_request apart.
Coverage vs. not found
These response codes are easy to mix up:
| Code | Status | Meaning |
|---|---|---|
outside_coverage | 400 | The address or area sits outside the five boroughs. Coverage is NYC only, and a different spelling will not change the answer. |
not_found | 404 | The address is in NYC, but it has no tax lot on record, or the API cannot place it on a map. |
invalid_request | 400 | The request is malformed, or it carries a field the operation does not accept. An unknown field names each one: Unknown field(s): city, state, zip. POST /v1/lookup accepts: address, include_comps, include_rentals. |
Anatomy of a lookup
POST /v1/lookup returns these fields inside data.
property: the building's address, normalized to one canonical form.bbl: the NYC Borough-Block-Lot for the subject building, ornullwhen no tax lot resolves.bin: the DOB Building Identification Number, ornullwhen PAD carries none.canonical_path: the report's stable page path onhttps://nosyneighbor.nyc, ornull.sources: one key per registered source (nyc_ecb,nyc_dob,redfin, and dozens more). Each source'sstatusisok,not_found,error, orgated. Itsdatafield isnullfor every status other thanok. A few sources cap their example records at the newest 100 and flag it with a boolean:hmc_violations_truncated,ecb_violations_truncated, anddob_violations_truncated. Their count fields (hmc_violation_count,ecb_total_violations,dob_total_violations, and the rest) always count every violation filed against the building, however many appear in the capped list above.cache:cached_at,refresh_available_at, andstatus(okorpartial). A complete report (ok) setsrefresh_available_atto 7 days after assembly. The next/v1/lookupcall past that point re-fetches every source. Apartialreport (one or more sources errored) sets it to about 10 minutes after assembly instead. The next call past that point re-runs only the sources that errored and merges the result into the same report. It never refetches a source that already succeeded. Every report expires 7 days after its first assembly, whatever its status.
See the interactive API reference for every per-source field.
Units and formats
Money fields report US dollars. Most are whole numbers. A few carry a decimal fraction for cents, such as tax_amount. No field states an amount in cents. balance_due can be negative, which the city's ledger records when payments exceed the penalty imposed.
Every date value comes straight from the NYC agency that publishes it, in whatever format that agency uses. Most sources use ISO YYYY-MM-DD. nyc_ecb uses YYYYMMDD for issue_date and hearing_date. nyc_dob uses it for issue_date and disposition_date. nyc_dob_jobs uses MM/DD/YYYY for pre__filing_date. The API never reformats these strings.
Searching
Set location (a ZIP or a borough neighborhood name) or zip_codes (an array of 5-digit NYC ZIPs) to pick an area. Page results with limit and offset. has_more is true when another page exists at offset + results.length. There is no total count.
source_status reports one entry per listing call. Its keys are cached when the answer comes from the daily-refreshed index (the normal case), the listing source's own name, such as redfin, on the rare live call, and not_warm when the area has no entitlement or no coverage yet. Redfin is currently the only listing source, so each result's own sources map has one key and its discrepancies list is always empty. Both fields stay in the shape so a second source can join later without a shape change.
Retries and 429 handling
A 429 rate_limited response includes a Retry-After header, in seconds. Wait at least that long before you retry the same call.
A permanent refusal is the exception. It happens when the operation's cost exceeds your entire per-minute or per-day ceiling. No Retry-After is offered, and a retry can never succeed. Raise the limit instead.
The RateLimit and RateLimit-Policy headers follow the IETF draft shape. They appear on responses sent after your account's limits are known, which means successes and 429s. They report whichever budget is tighter, per-minute or per-day. The JSON meta block is the stable contract to read against, and the headers are a convenience.
A 502 or a 503 is safe to retry with backoff. A 4xx other than 429 does not succeed on retry unless you change the request. See Rate Limits for the full numbers.
Versioning policy
The current (and only) version is v1. Once published, a response field is not removed or repurposed and an error code keeps its HTTP status and meaning: a new failure mode is mapped onto the closest existing code rather than growing the set. A breaking change arrives as a new version prefix (/v2/*), never a silent change under /v1/*.
Acceptable use & legal
Full terms: Terms of Use. The parts specific to programmatic access:
- Not a consumer report. Nosy Neighbor is not a consumer reporting agency, and API responses are not consumer reports or investigative consumer reports under the federal Fair Credit Reporting Act (FCRA). You may not use this API, in whole or in part, as a factor in establishing anyone's eligibility for credit, insurance, employment, housing, or tenancy — and you may not use it to screen a prospective or current tenant.
- Fair housing. Neighborhood-level statistics and similarity scores are automated and area-level; you may not use this API to steer, exclude, or target anyone on the basis of a protected characteristic.
- No redistribution as a competing feed. Access is personal to your account; don't resell or bulk-republish raw responses as a data product.
- Accuracy. Check anything you'll act on against the original record. Nosy Neighbor assembles this automatically from public government records and third-party feeds, so it can be incomplete, out of date, or matched to the wrong property. See the full data-accuracy terms.
nn_test_0000000000000000_<paste-your-own-secret-here>) is a placeholder. The bracketed part is never a real secret. Get a real key from the developer dashboard, and never commit one to source control.