Search
POST /v1/search
Cost · 1 credit per result returned (minimum 1) · failed calls are free
Sync if maxItems ≤ 50, async otherwise.
Body — option A: structured filters (recommended)
{ "filters": { "status": "for_sale", "location": "San Francisco, CA", "bbox": { "west": -122.55, "south": 37.70, "east": -122.35, "north": 37.85 }, "price": { "min": 500000, "max": 1500000 }, "beds": { "min": 2 }, "baths": { "min": 1 }, "sqft": { "min": 800 }, "yearBuilt": { "min": 1990 }, "homeTypes": ["house", "townhouse"], "daysOnZillow": "30", "hasPool": false, "hasGarage": true, "isWaterfront": false }, "extractionMethod": "PAGINATION", "maxItems": 50, "async": false}bbox is required. A free-text location alone (without coordinates)
isn’t enough — the search engine needs a real bounding box to render results.
Requests missing bbox are rejected with 400 invalid_filters and never
hit upstream. location is still accepted as a hint that flows into the
URL’s usersSearchTerm field, but it’s optional and decorative.
Body — option B: pre-built Zillow URL (advanced)
{ "searchUrls": [{ "url": "https://www.zillow.com/homes/for_sale/?searchQueryState=..." }]}The URL must contain a ?searchQueryState=... query parameter —
pretty URLs like https://www.zillow.com/austin-tx/houses/ are rejected
with 400 invalid_search_url. Open the area on zillow.com, apply your
filters in the UI, then copy the resulting URL — it’ll have
searchQueryState baked into the query string.
extractionMethod
| Value | When |
|---|---|
PAGINATION (default) | Standard search; returns up to ~820 results |
MAP_MARKERS | Fastest; up to ~500 results, less data per row |
PAGINATION_WITH_ZOOM_IN | Exhaustive; recursive map-tile zoom; can return huge result sets |
PAGINATION_WITH_ZOOM_IN always runs async.
Sync 200 response
{ "data": [ { "zpid": "...", "address": "1 Main St", "addressCity": "San Francisco", "price": "$1,250,000", "unformattedPrice": 1250000, "beds": 2, "baths": 2, "area": 1100, "latLong": { "latitude": 37.78, "longitude": -122.41 }, "statusType": "FOR_SALE", "hdpData": { "homeInfo": { "homeStatus": "FOR_SALE", "daysOnZillow": 8, "...": "..." } } } ], "meta": { "count": 50 }, "request_id": "..."}Async 202 response
{ "data": { "job_id": "...", "status": "running" }, "request_id": "..." }POST /v1/search/with-details
Cost · 1 credit per search result + 1 credit per detail record (two stages billed separately) · failed calls are free
Runs a search, then enriches each zpid with the full property-detail blob — in one chained job. Always async.
Body
{ "filters": { "status": "for_sale", "bbox": { "west": -97.94, "south": 30.10, "east": -97.56, "north": 30.52 }, "beds": { "min": 3 } }, "extractionMethod": "PAGINATION", "maxItems": 200, "propertyStatus": "FOR_SALE", "extractBuildingUnits": "disabled"}202 response
{ "data": { "job_id": "...", "status": "running", "stage": "search" }, "request_id": "..." }When the job completes, GET /v1/jobs/{id}/results returns the detail rows
(not the search rows). The intermediate search dataset is discarded.
Output formats
Sync responses support ?format=csv and ?format=ndjson. See Output formats.