Zillow ZHVI and ZORI API: Region IDs, Nulls, and Reporting Dates

Published October 16, 2026

data.region.id was null. Yet the saved Seattle market response contained a ZHVI of approximately $822,572 and a ZORI of approximately $2,227. Those populated measurements make an apparently successful record easy to label “Seattle, September.” That label quietly adds two claims the response does not support: a confirmed geographic identity and one reporting month for every metric.

The Zillow Real Estate API exposes an independent, unofficial data product for property and regional research. The useful question here is not whether a number arrived, but what geography, measurement and date you can honestly attach to it. The examples below are static references to accepted saved evidence, not new requests or promises of future values.

The Seattle response has values and no region identity

The observed get-market-analytics request used location=Seattle, WA. Its inner payload had success:true, populated home_values, rentals, sales, listings and neighbors, but this entire identity block was empty:

{
  "region": {
    "id": null,
    "name": null,
    "type": null,
    "parent_state": null,
    "parent_county": null
  }
}

This is a selected excerpt from the service's data, not a complete success-response template. Null identity is not a zero-valued market, and successful transport does not resolve it. Check HTTP status first, then the outer gateway's code, message and data business result; gateway code 200 indicates gateway business success. Next inspect the inner service's success and any error before using its data.

Even an inner success does not establish every resource's identity. A separate nonexistent-property test returned success:true with data.zpid:null, null address fields and default OFF_MARKET status. For property records, require a matching nonnull identifier and meaningful address or facts. For these analytics, record that geography remains unconfirmed.

Keep requested geography separate from returned geography

Autocomplete helps you choose an intended geography; it does not certify a later response. The saved autocomplete-location request used query=Seattle, WA and limit=3. It returned Seattle city with region_id=16037, West Seattle as a flex_region, and Capitol Hill as a neighborhood. Both coordinate fields were null in all three suggestions.

Keep the selected display name, geography type and ID as request provenance. Do not silently choose the first suggestion or substitute a neighborhood for a city. The market operation accepts location text or region_id; at least one is needed for an intentional geographic request even though both are individually optional in the schema. Behavior when both are supplied was not verified.

These are static public request references, not instructions to run automatically:

https://api.opendata-api.com/api/project/zillow-real-estate/autocomplete-location?key=YOUR_API_KEY&query=Seattle%2C%20WA&limit=3
https://api.opendata-api.com/api/project/zillow-real-estate/get-market-analytics?key=YOUR_API_KEY&location=Seattle%2C%20WA

Replace YOUR_API_KEY only with your own authorized platform key when explicitly running a request. No additional cookie, token or session is required. Keep credential-bearing URLs out of shared links and logs. Opening documentation, navigating endpoints, expanding fields and copying examples sends no data request; an explicit run consumes one.

Sending region_id has not been demonstrated to repair the null region block. Nor can the nine returned neighbors certify the parent geography. Their names, IDs, ZHVI values and relative URLs are contextual records, not a replacement for missing response identity.

Read ZHVI and ZORI as different measurements

ZHVI is the Zillow Home Value Index: a regional home-value measurement, not a listing's asking price or the median price of homes sold that month. ZORI is the Zillow Observed Rent Index: a regional rental measurement, not the rent of a particular home or a signed lease amount. Keep those definitions visible wherever values are exported or compared.

The sample's home_values.zhvi was 822572.4254694129; rentals.zori was 2226.6219445592697. Neither belongs in an individual property's price or rent-estimate field. The separate get-property-rent-estimate operation documents a property-level estimate for a known zpid, but no response for that route was saved. Do not invent its fields from the ZORI response.

The market sample also supplied national_zori, index histories and an empty forecast array. Preserve that empty array as absence of returned forecast points, not a forecast of zero growth. The two regional index histories each contained 100 date, value, change_pct records in this sample; that count does not promise a fixed archive or future coverage.

September indices do not turn August sales into September data

The sample dates are the diagnostic clue:

  • home_values.zhvi_date: 2026-09-30.
  • rentals.zori_date: 2026-09-30.
  • sales.median_sale_price_date: 2026-08-31.
  • listings.listings_date: 2026-09-30.

The observed median sale price was 848333.3333333334, while median list price was 724666.6666666666. Their difference is not automatically a September negotiation discount: these fields describe different measurements, and the sales observation belongs to an earlier reporting month. A direct comparison needs explicit labels and attention to the populations being measured.

Preserve each history point's own date too. Never replace missing reporting dates with retrieval time, or assign the newest date in the response to every series. Retrieval time answers when your system obtained a snapshot; a reporting date identifies the period attached to a metric. Store both independently when both are known.

Normalize one record per metric, date, and geography claim

Diagnose the identity and date gaps before writing a normalizer. A useful local record retains the metric name, value, supplied reporting date, requested geography and untouched returned region block. Do not collapse those last two fields into a single authoritative city label.

This Python example reads an already saved inner service payload, shaped like the observed sample. It makes no network request. If your saved file contains the outer gateway envelope, check its business result and extract the inner payload first.

import json
from pathlib import Path

service = json.loads(Path("saved-market-service.json").read_text())
if service.get("success") is not True:
    raise ValueError("Inspect the saved service error before normalization")
market = service.get("data")
if not isinstance(market, dict):
    raise ValueError("Expected a market data object")

requested = {"location": "Seattle, WA"}
fields = [
    ("home_values", "zhvi", "zhvi_date"),
    ("rentals", "zori", "zori_date"),
    ("sales", "median_sale_price", "median_sale_price_date"),
    ("listings", "median_list_price", "listings_date"),
]
records = []
for group, metric, date_field in fields:
    block = market.get(group)
    block = block if isinstance(block, dict) else {}
    records.append({
        "metric": metric,
        "value": block.get(metric),
        "reporting_date": block.get(date_field),
        "requested_geography": dict(requested),
        "returned_region": market.get("region"),
    })

These output keys are your application schema, not additional API response fields. Missing values remain None rather than becoming zeros; missing dates remain unknown. Add retrieval metadata from your own collection record separately. Before comparing regions, verify geographic scope as well as metric and period; normalization preserves uncertainty rather than resolving it.

A rate without an observation date stays undated

The saved get-mortgage-rates read returned rate:7.23 and apr:7.238 with program:fixed_30, loan_type:conventional, credit_score:very_high and state:US. Its context also included loan_amount_bucket:Conforming and loan_to_value_bucket:Normal. Preserve those assumptions when retaining the numbers.

There was no rate observation date. A retrieval timestamp cannot justify “today's rate,” “latest available” or a personalized quote. Treat the observation as undated indicative research, not an approval or rate lock. The separate get-mortgage-rate-history operation documents a rolling 30-day history, but its response shape and timestamps were not verified; it has no state or arbitrary date-range input. Do not fabricate history records or fill missing days.

What this snapshot cannot prove about a home

A populated regional record with unconfirmed identity cannot establish a home's appraised value, achievable rent or financing terms. Even confirmed city indices would not replace property condition checks, comparable transactions, lease evidence or lender underwriting. Property-level estimates answer a different question and can themselves contain missing data.

Keep the limits attached to the export: requested geography is provenance, null returned identity remains null, reporting months stay metric-specific and undated rates remain undated. The accepted samples establish these particular observed shapes, not complete historical coverage, future availability or permission to redistribute data. Preserve those boundaries instead of making the record look more certain than it is.