NYC Open Data API for Property Violations: A Normalization Playbook

How to join HPD, DOB, and OATH records through the NYC Open Data API without erasing source meaning, overstating balances, or turning address matching into a silent data-quality bug.

Municipal property records converging through a normalization pipeline into one organized NYC building record
EstatesCheck editorial image · AI-generated

The NYC Open Data API can power a property violations service, but it does not expose one canonical endpoint. A reliable integration must resolve the property, query HPD, DOB, and OATH datasets, preserve source identifiers and statuses, and label monetary fields conservatively. Normalization should make records comparable without pretending every source means the same thing.

The NYC Open Data API exposes datasets, not one violation ledger

NYC Open Data exposes HPD and DOB datasets through Socrata, but the city does not publish a canonical “property violation” ledger. The Department of Buildings explains that its inspectors issue both DOB violations and OATH violations . HPD separately publishes Housing Maintenance Code violations. OATH publishes hearing data for most summonses filed with its Hearings Division.

Those records can describe the same building while answering different questions. A housing-code condition, a DOB safety violation, and a summons with an adjudicated balance are not interchangeable rows. Flattening them into one generic status destroys information that the user needs to choose the next official system.

The minimum source distinctions an aggregator should retain
Source familyWhat the record representsUseful identifiersMoney semantics
HPD Housing Maintenance Code violationsA condition HPD verified against the Housing Maintenance Code or Multiple Dwelling LawViolation ID, Building ID, BBL fields, apartment/story where publishedViolation record; do not assume a payable balance
DOB violationsA Department of Buildings code or safety violationBIN, BBL, DOB violation numberMay involve civil penalties, but the violation record and payment workflow remain distinct
DOB-issued OATH/ECB summonsesA summons issued by DOB and adjudicated by OATH/ECBECB violation number, DOB violation number, BIN, BBLDataset publishes penalty imposed, amount paid, and balance due fields
OATH hearing recordsThe hearing posture and disposition of a summonsSummons number, hearing date, respondent and issuing agency fieldsHearing status is not a substitute for the enforcement agency’s correction status

This is the first normalization rule: keep source , sourceRecordId , sourceCaseNumber , and the official record URL on every canonical record. A normalized category can sit beside those fields; it should never replace them.

Resolve the property before querying violation datasets

Free-form address matching is useful for discovery and fragile as a join key. Street suffixes, hyphenated Queens house numbers, aliases, unit text, and geocoder formatting can all produce strings that look different while pointing to the same place. The inverse problem also occurs: a tax lot can contain several buildings.

A production lookup should convert the selected address into the identifiers used by the official datasets. NYC describes a BBL as a 10-digit borough, block, and lot identifier and a BIN as a 7-digit building identifier. The City’s Geosupport Function BBL can return the BINs associated with a tax lot.

  1. Normalize only for lookup: trim whitespace, standardize borough and street tokens, and keep the user-selected display address.
  2. Resolve stable identifiers: prefer BIN for a specific structure and BBL for the tax lot; retain both when available.
  3. Represent ambiguity: if one BBL returns several BINs, query or present the buildings explicitly instead of selecting one silently.
  4. Keep provenance: store which geocoder or city resolver produced the identifier and when it was resolved.

Do not attach a record to a property merely because the respondent mailing address resembles the building address. In enforcement data, those fields can describe different places.

Query the NYC Open Data API deliberately, not as an unbounded export

The NYC Open Data API runs on Socrata and supports server-side selection, filtering, ordering, and pagination through SoQL. Use those controls to request the records and fields needed for one property rather than downloading a growing citywide dataset during a user request.

The Socrata application-token documentation says simple unauthenticated SODA 2.x queries are possible, but an application token gives the application a separate, higher-capacity throttling pool. Newer SODA3 query requests require user authentication or a valid application token. Send the token server-side in the X-App-Token header over HTTPS; it is a provider credential, not the API key a browser should receive.

GET /resource/6bgk-3dad.json
  ?$select=ecb_violation_number,dob_violation_number,bin,boro,block,lot,
           issue_date,hearing_date,ecb_violation_status,hearing_status,
           penality_imposed,amount_paid,balance_due,violation_description
  &$where=bin='3000000'
  &$order=ecb_violation_number
  &$limit=500

The field name penality_imposed is misspelled in the official DOB ECB dataset. Correct it at the adapter boundary, but retain the original raw field name in tests and source metadata so a future schema change is visible.

Every provider adapter also needs a timeout, maximum page count, maximum record count, retry policy for transient failures, and a terminal partial-result state. “One provider timed out” is different from “the building has no violations.”

Use a canonical contract that preserves uncertainty

The canonical model should be smaller than the union of every source schema. It needs stable display and workflow fields, plus enough provenance to reconstruct why a value appeared. Source-specific payloads can remain behind an adapter or bounded raw snapshot rather than leaking into every consumer.

type PropertyViolationRecord = {
  jurisdiction: 'NYC';
  source: string;
  sourceRecordId: string;
  sourceCaseNumber?: string;
  sourceViolationNumber?: string;
  bin?: string;
  bbl?: string;
  category: CanonicalCategory;
  normalizedCategory?: CanonicalCategory;
  officialStatus?: string;
  issueDate?: LocalDate;
  hearingDate?: LocalDate;
  imposedFineAmount?: Money;
  amountPaid?: Money;
  outstandingBalance?: Money;
  monetaryStatus: 'FINE_READY' | 'FINE_UNCLEAR' | 'VIOLATION_ONLY';
  officialRecordUrl?: string;
  sourceFetchedAt: Instant;
};

Optional fields are not a weakness here. A null balance can mean the source does not publish a balance, not that the balance is zero. The explicit monetaryStatus makes that distinction available to the API and UI.

Normalize fields without changing their meaning

Normalization should be a series of narrow, testable decisions. Parse source dates into one date type. Convert numeric strings into decimal money values. Map agency-specific categories into a small display taxonomy. Keep the official status text beside any normalized label.

Do not normalize by forcing every source into the richest source’s schema. HPD’s open-data guidance says an open violation remains active on HPD records and directs users to filter the Violation Status field for Open . That source meaning should remain visible even if another provider uses values such as ACTIVE , DEFAULT , or RESOLVED .

Safe normalization versus unsafe inference
InputSafe normalized outputDo not infer
`PENALITY_IMPOSED``imposedFineAmount` with source field documentedThat the same amount remains due
`BALANCE_DUE``outstandingBalance` when parsed successfullyThat payment alone closes the underlying DOB violation
HPD violation status `Open`Official status `Open`; normalized lifecycle `ACTIVE` if usefulA hearing, payable fine, or uncured legal conclusion
Issue, served, and hearing datesThree separate typed datesA due date that the source did not publish
Agency descriptionOriginal description plus an optional display categoryA replacement legal characterization

Money needs stronger guardrails than text

The DOB ECB dataset is useful because its official schema includes penality_imposed , amount_paid , and balance_due . Use those as three different values. Do not recalculate the balance as penalty minus payments: adjustments, defaults, reversals, or other source rules may make arithmetic disagree with the published balance.

A provider that exposes no monetary fields should produce VIOLATION_ONLY . A provider with ambiguous or incomplete money fields should produce FINE_UNCLEAR . Only a provider with an explicit, successfully parsed source balance should be eligible for FINE_READY , and the UI should still identify the official source and checked time.

Deduplicate by source identity and model lifecycle separately

Use a deterministic key such as (source, sourceRecordId) for upserts. If a source lacks one stable identifier, document the bounded composite key and its collision risks. Do not merge two records solely because their descriptions, dates, or addresses look similar; separate agencies may issue related but operationally distinct records.

A refresh should record what was observed, when it was observed, and whether the provider result was complete. If a previously stored record disappears from a complete source snapshot, mark it NO_LONGER_FOUND rather than PAID , DISMISSED , or CLOSED . Disappearance is an observation about the feed, not an agency decision.

This design also separates correction from closure. A physical repair, a certification, a hearing response, a payment, and the agency’s public-record update can be five different events. One normalized status cannot safely stand in for all five.

Keep AI normalization optional and subordinate

A model can be useful for turning an all-caps description into a short summary or suggesting a broad category. It should not control property identity, source status, monetary amounts, official URLs, due dates, deduplication, or lifecycle transitions.

The safe boundary is deterministic-first: build the canonical record from provider fields, apply monetary guardrails, then optionally request a bounded display-only normalization. Validate the response against a schema, retain the deterministic record, record the method used, and fall back cleanly when the model service is disabled or unavailable.

This makes the API key boundaries explicit. The municipal provider token authorizes higher-volume source queries. A separate service key authenticates an aggregator client. An optional Intelligence key authorizes model-backed display normalization. None of those keys should reach the public browser, and the core lookup should remain correct without an AI response.

Design the public lookup for partial failure and repeat traffic

A property lookup fans out across services with different update schedules and failure modes. Cache completed results by a privacy-safe property reference, but include the checked time and a clear refresh policy. Coalesce concurrent requests for the same property so a burst of visitors does not repeat identical provider calls.

Rate-limit anonymous users with a bounded allowance, keep provider credentials on the server, and cap every provider response. Cache only authorized or genuinely public data, and never let a shared cache key cross tenant or account boundaries.

Return provider-level status alongside the merged records. A useful response can say that DOB completed, HPD timed out, and OATH returned no rows. A misleading response collapses all three into an empty list.

  1. Resolve the selected address to stable property identifiers.
  2. Build bounded, source-specific queries.
  3. Fetch providers independently with deadlines and record limits.
  4. Map each response through a deterministic adapter.
  5. Apply monetary and lifecycle guardrails.
  6. Return records with source completeness, official links, and checked time.
  7. Cache the completed snapshot and invalidate it deliberately.

How the EstatesCheck public lookup applies these boundaries

As reviewed on August 12, 2026, the free EstatesCheck NYC property violations lookup accepts a selected NYC address, requests a stateless snapshot through fineAgg, maps returned provider records into a source-aware display contract, and caches the completed result. The public request does not create a landlord property profile, background refresh job, or stored fine record.

The display treats confirmed balances conservatively, labels violation-only and unclear records separately, preserves official links when provided, and shows when the snapshot was checked. The public route is a discovery tool, not an official clearance certificate. Users should open the linked agency record before making a payment, certification, hearing, or legal decision.

That product constraint is intentional: normalization should reduce the cost of finding and reading records without becoming a new authority over the agencies that issued them.

Frequently asked questions

These are the implementation questions that most often determine whether an NYC violations integration remains trustworthy in production.

Is the NYC Open Data API free for property-violation queries?

NYC publishes relevant property-violation datasets through the NYC Open Data API. Socrata permits simple unauthenticated SODA 2.x queries, but production applications should use an application token for a dedicated, higher-capacity request pool. A third-party aggregation service may separately require its own server-to-server API key.

Is there one API for every NYC property violation?

No. HPD housing-code violations, DOB violations, DOB-issued summonses adjudicated by OATH, and other agency records have different datasets, identifiers, statuses, update schedules, and monetary fields. A useful property view must preserve those source distinctions.

Should an application search NYC violations by address?

Use an address to start the lookup, then resolve it to stable NYC identifiers whenever possible. BIN identifies a building, while BBL identifies a tax lot. One lot can contain multiple buildings, and address text can change format across datasets.

Does a violation record mean money is currently owed?

Not necessarily. Some datasets describe code conditions without publishing a payable balance. Even when a source includes penalty, payment, and balance fields, the application should expose the source-provided balance and status rather than infer debt from a violation label.

Should AI normalize property-violation data?

AI can optionally help summarize descriptions or suggest categories, but it should not determine the official status, invent a due date, merge unrelated records, or calculate an amount owed. Deterministic mappings and source-provided monetary fields should control those decisions.

The hard part of using the NYC Open Data API for property violations is not fetching JSON. It is preserving the boundary between a building and a tax lot, a condition and a summons, an imposed penalty and an outstanding balance, a missing record and an official closure. Build those distinctions into the contract first. Search, caching, and optional AI summaries become much safer once the source meaning cannot be silently erased.

This engineering article describes public data and EstatesCheck product behavior reviewed on August 12, 2026. It is general technical information, not legal advice or an official property-record determination. NYC datasets and provider schemas can change; verify current agency documentation before relying on an integration.

Official sources

Keep reading

ESTATESCHECK ARTICLES Engineering notes about source-aware civic data and property-management systems.

Back to top