List residential properties sold in a ZIP in the last 365 days
GET /api/properties/sold/by-zip/
1 credit per 20 properties
What it returns
Every residential property sold in a given US ZIP code within the last 365 days, with sale date, sale price, coordinates, and basic property characteristics (bed/bath, square footage, year built, lot size). Sourced from the residential_sold collection — a deduplicated rollup of MLS sold records refreshed on demand when the per-ZIP cache is older than 4 hours.
When to use it
- Build a "recent sales in my neighborhood" widget on a property page.
- Estimate market velocity for a ZIP code (sales per month, median DOM).
- Seed a comps analysis without specifying individual subject properties.
- Sanity-check listing prices against actual sale prices.
Date range
By default the endpoint returns the full trailing 365 days. Pass start_date, end_date, or both (YYYY-MM-DD) to narrow that to a specific window — for example one calendar month at a time instead of re-pulling the whole year on every poll:
Both bounds are optional and inclusive, and both are independent: pass only start_date for an open-ended window, or only end_date to cut off recent sales. Passing neither leaves existing behaviour unchanged.
Either bound must fall within the last 365 days. An older date returns 400 naming the earliest date we can serve, rather than quietly returning a partial set.
Property type
Pass property_type to keep only the types you model. One value or a comma-separated list, matched against the same property_type field each row returns:
Omitting it returns every type, exactly as before. An unknown value returns 400 listing the accepted values rather than an empty result.
Pricing
1 credit per 20 properties returned, rounded up. A request that returns 100 properties costs 5 credits. Use the limit parameter to cap the cost — a limit=20 always costs exactly 1 credit. Charged only on 200; 402/400/5xx cost nothing.
Errors
| Status | Meaning |
|---|---|
| 400 | Missing zip parameter, non-integer limit, a malformed / out-of-window start_date or end_date, or an unknown property_type. |
| 401 | Authentication failed or account missing. |
| 402 | No subscription, or insufficient credits for the property count this ZIP would return. The error body includes the credit estimate so you can lower limit and retry. |
| 503 | Upstream datastore or refresh error. Safe to retry. |
FAQ
How fresh is the data?
The per-ZIP cache refreshes when stale (older than 4 hours) on demand. A first request to a cold ZIP may take longer while the refresh runs; subsequent requests within the 4-hour window hit cache.
Why do some properties have sold_price: null?
The MLS suppresses price on private sales, off-market transfers, and some agent-sale records. The property still appears (it sold), but the price field is null. Filter on your side if you need price-bearing records only.
What counts as "residential"?
Everything the sold feed files as residential: single-family, condos, townhomes, multi-family, apartments, mobile homes, plus a small tail of other types. Each row's property_type says which, and the property_type filter takes the same values. Commercial and land-only records are rare here — they live in other collections.
Why is dom sometimes null?
Days-on-market requires listing-history dates that older records may not carry. For records that lack dom natively, we compute it best-effort from list_date to sold_date; when neither path resolves, the field is null.
Parameters
limit(query) — Cap the result count. When set, the response is the most recent N sales (after dedup + recency filter). Used to control credit cost — limit=20 always costs 1 credit. Omit for the full last-365-days list.zip(query, required) — 5-digit US ZIP code. Example: 95630.start_date(query) — Earliest sale date to include, as YYYY-MM-DD. Optional — omit for the full 365-day window. Inclusive: a sale on this exact date is returned. Must fall within the last 365 days; anything older returns 400, since that is the whole window we retain.end_date(query) — Latest sale date to include, as YYYY-MM-DD. Optional — omit for no upper bound. Inclusive: a sale on this exact date is returned. Must be on or after start_date and within the last 365 days.property_type(query) — Keep only these property types. One value or a comma-separated list, e.g. single_family or single_family,townhomes. Optional — omit for every type. Values are the ones the response's property_type field carries, chiefly single_family, condos, townhomes, multi_family, apartment, mobile, duplex_triplex, coop, condo, land, farm, other. Case-insensitive; - and spaces are read as _. An unknown value returns 400 listing the full accepted set.
Responses
200400— Bad request — a required parameter is missing or failed validation. Costs 0 credits.401— Authentication failed — missing or invalid API key. Costs 0 credits.402— Payment required — no active subscription or insufficient credit balance. Costs 0 credits.503— Upstream data provider is temporarily unavailable — retry with backoff.
More in Market Data
- Count of sold properties in a ZIP in the last 365 days —
GET /api/properties/sold/count-by-zip/
Just the count of residential properties sold in a ZIP within the last 365 days. - Mortgage and lien data for a US property —
GET /api/mortgage-lien/analysis/
Mortgage and lien records for a US property — current and historical mortgages, lien summary, involuntary liens, pre-foreclosure status, and data quality metadata.