Search

May 13, 2026 · View on GitHub

Two endpoints serve listing search, depending on how you want to pass filters.

  • GET /v1/listings — flat query-string filters, simplest call, sync only.
  • POST /v1/search — structured JSON body, supports more advanced filters, sync if maxItems ≤ 50 and async otherwise.

Both return the same row shape. Use the GET form for quick lookups and curl debugging; use the POST form when you need bbox-as-object, boolean amenity filters, or searchUrls with a pre-built searchQueryState.

Quick example — GET

curl -s "https://api.zillapi.com/v1/listings" \
  -G \
  --data-urlencode "status=for_sale" \
  --data-urlencode "bbox=-122.45,37.74,-122.40,37.79" \
  --data-urlencode "price_min=800000" \
  --data-urlencode "price_max=2000000" \
  --data-urlencode "beds_min=2" \
  --data-urlencode "home_types=house,condo,townhouse" \
  --data-urlencode "max_items=20" \
  -H "Authorization: Bearer $ZILLAPI_KEY" \
  | jq '.data[] | {zpid, address, unformattedPrice, beds, baths, area}'

Quick example — POST

curl -s "https://api.zillapi.com/v1/search" \
  -H "Authorization: Bearer $ZILLAPI_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "filters": {
      "status": "for_sale",
      "bbox": { "west": -122.45, "south": 37.74, "east": -122.40, "north": 37.79 },
      "price": { "min": 800000, "max": 2000000 },
      "beds": { "min": 2 },
      "homeTypes": ["house", "condo", "townhouse"],
      "hasGarage": true
    },
    "maxItems": 50
  }'

Parameters (GET / filters body)

FilterGET formPOST form (filters.*)Notes
Statusstatus=for_salestatus: "for_sale"for_sale, for_rent, sold
Bounding boxbbox=west,south,east,northbbox: { west, south, east, north }Required. A free-text location alone is rejected with 400 invalid_filters.
Location hintlocation=location:Optional decorative hint that flows into the usersSearchTerm field; does not replace bbox.
Price rangeprice_min / price_maxprice: { min, max }
Beds / bathsbeds_min, beds_max, baths_min, baths_maxbeds: { min, max }, baths: { min, max }
Sqftsqft_min, sqft_maxsqft: { min, max }
Year builtyear_built_min, year_built_maxyearBuilt: { min, max }
Home typeshome_types=house,condohomeTypes: [...]house, condo, townhouse, multi_family, manufactured, lot, apartment
Days on Zillowdays_on_zillow=30daysOnZillow: "30"1, 7, 14, 30, 90, 6m, 12m, 24m, 36m
Amenitiesn/ahasPool, hasGarage, hasAirConditioning, hasBasement, isWaterfrontPOST only
Max itemsmax_items (≤50)maxItemsPOST goes async above 50.
Output format`format=jsoncsvndjson`

Response shape

{
  "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": "..."
}

Search rows have a different shape than property-detail records. Use beds / baths (not bedrooms / bathrooms), address as a string (not object), unformattedPrice for the integer, latLong for coords. To enrich a row with the full 300-field record, hit GET /v1/properties/{zpid} per zpid — or use POST /v1/search/with-details to run search and detail in one chained async job.

Errors

400 invalid_filters (missing or malformed bbox) · 400 invalid_search_url (POST with a searchUrls[] that lacks ?searchQueryState=) · 401 invalid_api_key · 402 out_of_credits · 429 rate_limited.

Credit cost

1 credit per result returned. A search returning 50 rows costs 50 credits. Failed searches and 0-result searches cost 0 credits. Async batches via POST /v1/search/with-details bill the search stage and the detail stage separately.

See also