NHDdata API · v1

One REST call. Hazards + tax for any California parcel.

Three endpoints share one input shape (APN + county FIPS, or address). Use /v1/parcel for the unified envelope (recommended), or call /v1/tax and /v1/hazards individually if you only need one half.

Endpoints

POST

/v1/parcelRecommended

Unified envelope — NHD + Tax in one call.

POST

/v1/tax

California tax decode only. Drop-in replacement for the legacy CTD Tax Summary JSON.

POST

/v1/hazards

Statewide NHD layers only — FEMA / CAL FIRE / CGS / DWR / CalGEM / EPA.

Auth

Every request must carry an X-API-Key header. Keys start with tl_live_ (or tl_test_ for sandbox) and are issued from the customer dashboard. Treat them like passwords — we hash with SHA-256 before storage and show the raw key once. Rate limit: 100 requests per minute per key.

POST /v1/parcel — unified

The headline endpoint. One call returns property snapshot, statewide hazards, and tax decode. Internally fans out to the tax and hazards lookups in parallel — either half failing degrades to a partial response (the failure shows up in errors[] rather than blowing up the whole call).

request
curl -X POST https://nhddata.com/api/v1/parcel \
  -H "Content-Type: application/json" \
  -H "X-API-Key: tl_live_xxxxxxxxxxxx" \
  -d '{
    "apn": "4286-022-011",
    "county_fips": "06037"
  }'
response
{
  "property": {
    "apn": "4286-022-011",
    "county": "Los Angeles",
    "owner_name": "JAMES E PRICE REVOCABLE TRUST",
    "year_built": 1921,
    "property_type": "DUPLEX",
    "formatted_address": "27 SUNSET AVE, VENICE, CA 90291",
    "centroid": { "lat": 33.993301, "lng": -118.478 },
    "source": "licensed_provider"
  },
  "resolved_geom": "polygon",
  "hazards": [
    { "layer": "fema_flood",         "inside_centroid": false, "parcel_intersects": false, "pct_overlap": 0,    "severity": "none",      "details": { "zones": [] },                     "source": "federal_dataset" },
    { "layer": "calfire_fhsz",       "inside_centroid": true,  "parcel_intersects": true,  "pct_overlap": 1.0,  "severity": "very_high", "details": { "lra_class": 3, "jurisdiction": "LRA" }, "source": "state_dataset" },
    { "layer": "cgs_alquist_priolo", "inside_centroid": false, "parcel_intersects": false, "pct_overlap": 0,    "severity": "none",      "details": { "mapped": false },                  "source": "state_dataset" },
    { "layer": "cgs_seismic_hazard", "inside_centroid": true,  "parcel_intersects": true,  "pct_overlap": 0.42, "severity": "high",      "details": { "liquefaction_in_zone": true, "landslide_in_zone": false }, "source": "state_dataset" },
    { "layer": "cgs_tsunami",        "inside_centroid": true,  "parcel_intersects": true,  "pct_overlap": 1.0,  "severity": "high",      "details": { "county": "Los Angeles" },          "source": "state_dataset" },
    { "layer": "dwr_dam_inundation", "inside_centroid": false, "parcel_intersects": false, "pct_overlap": 0,    "severity": "none",      "details": {},                                   "source": "state_dataset" },
    { "layer": "calgem_wells",       "inside_centroid": false, "parcel_intersects": false, "pct_overlap": null, "severity": "none",      "details": { "count": 0 },                       "source": "state_dataset" },
    { "layer": "epa_environmental",  "inside_centroid": false, "parcel_intersects": false, "pct_overlap": null, "severity": "low",       "details": { "total": 0 },                       "source": "federal_dataset" }
  ],
  "tax": {
    "annual_tax": 19648.66,
    "direct_charges": [
      { "name": "SANTA MARGARITA WTR DIST CFD 2013-1", "agency_code": "0734", "amount": 1814.35, "kind": "cfd", "bond_payoff_year": 2042, "cfd_id": "2013-0234" }
    ],
    "has_mello_roos": true,
    "has_1915_bond": false,
    "has_pace": false,
    "data_sources": { "property": "licensed_provider", "tax_bill": "county_treasurer", "cfd_master": "state_dataset" },
    "cache_hit": true
  },
  "queried_at": "2026-05-21T16:32:14Z"
}

Parcel polygon vs centroid resolution

California Civil Code §1103.2 requires natural-hazard disclosure when "the property is located in" a hazard zone — meaning the parcel polygon, not its centroid. A legacy centroid-only lookup silently under-discloses on larger lots where the rooftop sits on safe ground but the lot boundary crosses a FEMA flood, CAL FIRE FHSZ, fault, or dam-inundation polygon.

NHDdata runs ST_Intersects(hazard.geom, parcel.geom) directly against the parcel boundary when one is available, and also reports the fraction of the lot that lies inside each hazard (pct_overlap, 0–1). This is the same polygon-vs-polygon model used by every legitimate NHD provider.

Each response surfaces three fields per layer:

  • inside_centroid — true if the parcel centroid is inside the hazard polygon.
  • parcel_intersects — true if any part of the parcel polygon intersects. The legally-defensible disclosure flag.
  • pct_overlap — fraction (0–1) of the parcel area inside the hazard. Null when the layer is proximity-based (oil & gas wells, EPA sites) or when polygon mode is unavailable.

The top-level resolved_geom field tells you which mode ran (polygon or centroid) — when no parcel polygon is available, the response degrades to centroid mode and flags the degradation explicitly.

POST /v1/tax

Drop-in replacement for the legacy CTD Tax Summary JSON. Same wire shape, decoded direct charges (Mello-Roos / 1915 / PACE / other), bond-payoff enrichment, and the 5,500+ agency fund-code dictionary.

request
curl -X POST https://nhddata.com/api/v1/tax \
  -H "Content-Type: application/json" \
  -H "X-API-Key: tl_live_xxxxxxxxxxxx" \
  -d '{ "apn": "4286-022-011", "county_fips": "06037" }'

POST /v1/hazards

Returns the eight statewide NHD layers for a parcel or arbitrary lat/lng point. Same envelope as the hazards[] array inside /v1/parcel: per-layer parcel_intersects, inside_centroid, pct_overlap, severity, and details (layer-specific shape).

apn-or-point
curl -X POST https://nhddata.com/api/v1/hazards \
  -H "Content-Type: application/json" \
  -H "X-API-Key: tl_live_xxxxxxxxxxxx" \
  -d '{
    "apn": "4286-022-011",
    "county_fips": "06037"
  }'

# or lat/lng directly (no parcel resolution)
curl -X POST https://nhddata.com/api/v1/hazards \
  -H "X-API-Key: tl_live_xxxxxxxxxxxx" \
  -d '{ "point": { "lat": 33.993301, "lng": -118.478 } }'

Billing & credits

NHDdata runs on a prepaid credit balance. You buy credits up front via Stripe Checkout from /dashboard/billing, the balance loads instantly, and each API call atomically debits the balance. No invoices, no Net 30, no AR.

What each call costs

EndpointCost per unique APN per month
POST /v1/parcel$10.00 — NHD + Tax bundled
POST /v1/tax$5.00 — tax-only
POST /v1/hazards$5.00 — NHD-only

If you call a singleton then later call /v1/parcel for the same APN in the same calendar month, you pay the difference, not the full bundle again. The bundled call is strictly cheaper than buying singletons separately.

Cache hits don't consume credits

Every successful lookup is cached per-APN for 30 days. Cache hits within that window return instantly and do not debit your balance. The response includes "cache_hit": true so you can confirm it on your side.

When you run out

A request that would drop your balance below zero is rejected with HTTP 402 Payment Required and a JSON body of the shape:

402 response
{
  "error": {
    "code": "insufficient_credits",
    "message": "Your credit balance is exhausted. Top up at https://nhddata.com/dashboard/billing.",
    "balance_cents": 0,
    "required_cents": 1000
  }
}

Your existing API key stays valid — top up the balance from /dashboard/billing and the next call goes through. Pricing details at /pricing.

Errors

CodeReason
401Invalid, missing, or revoked X-API-Key.
402Insufficient credits. Top up balance at /dashboard/billing.
404Parcel not found — APN unknown to property data sources, or address not geocodable.
422Malformed body — missing apn/address, bad FIPS, etc.
429Rate limit exceeded — 100 requests per minute per key.
500Upstream failure. Response includes `error_id` + `retry_after`.
501Endpoint understood but not yet implemented for this input shape.

Hazard layer coverage

LayerScopeStatus
FEMA flood (NFHL)StatewideLive
CAL FIRE FHSZStatewideLive
CGS Alquist-Priolo (fault zone)StatewideLive
CGS seismic hazard (liquefaction + landslide)StatewideLive
CGS tsunami inundationCoastal CALive
DWR dam inundationStatewideLive
CalGEM oil/gas wellsStatewideLive
EPA environmental sitesStatewideLive

Tax direct-charge coverage

CountyStatus
Orange (06059)Live — full direct-charge decode
San Diego (06073)Live — full direct-charge decode
Riverside (06065)Live — full direct-charge decode
San Bernardino (06071)Live — full direct-charge decode
Los Angeles (06037)Live — full direct-charge decode
Contra Costa (06013)Live — full direct-charge decode
Butte · Colusa · Del Norte · El Dorado · Glenn · Humboldt · Imperial · Lake · Madera · Mariposa · Merced · Modoc · Mono · Monterey · Napa · Nevada · Placer · Plumas · San Benito · San Joaquin · Shasta · Siskiyou · Sonoma · Stanislaus · Tehama · Trinity · Tulare · Tuolumne · Yolo · YubaLive — full direct-charge decode
Fresno (06019)Live — full direct-charge decode
Alpine (06003)Live — full direct-charge decode
Sacramento · Santa Clara · San Francisco · San Mateo · Alameda · Santa Barbara · Ventura · San Luis Obispo · MarinPartial — coverage in progress; property snapshot live, direct-charge decode rolling out
All 58 countiesProperty snapshot live; per-APN direct-charge coverage rolling out

Full live matrix at /coverage. For counties without direct-charge coverage yet, the response still returns property + assessed values and sets data_sources.tax_bill: "unverified".

Changelog

  • 2026-05-21Upgraded hazard resolution from centroid-only to parcel polygon. /v1/parcel and /v1/hazards now return resolved_geom plus per-hazard parcel_intersects and pct_overlap when a parcel boundary is available.
  • 2026-05-20Added /v1/parcel (unified) and /v1/hazards endpoints. NHD layers now exposed via REST.
  • 2026-05-19Voter-approved bond enrichment added to tax response (voter_approved_bonds[]).
  • 2026-05-15Per-APN tax-bill direct-charge coverage shipped for Orange, San Diego, Riverside, San Bernardino.
  • 2026-05-10Initial /v1/tax release. Bond-payoff enrichment + 5,500-row agency dictionary.