Zillow API docs
Send a Zillow link or an address. Get back the listing price, status, Zestimate, rent Zestimate, home facts, photos, price history, tax history and broker as JSON.
We may add fields over time; we'll try to give notice before changing documented ones. Data is provided as-is, as shown on public Zillow pages. It isn't official and isn't guaranteed.
Each lookup reads the property's public Zillow page when you ask. Which fields come back varies by listing: a field the page doesn't show comes back as null.
Base URL and authentication
All endpoints live under https://api.propertiesapi.com/v1. Send your key in the x-api-key header. Requests without a key get 401 missing_api_key; an unknown key gets 401 invalid_api_key.
curl -G "https://api.propertiesapi.com/v1/zillow/property" \
-H "x-api-key: $PROPERTIESAPI_KEY" \
--data-urlencode "address=2640 Steiner St, San Francisco, CA 94115"Use with Claude
PropertiesAPI also runs a remote MCP server at https://api.propertiesapi.com/mcp, so Claude Code, Claude Desktop and claude.ai can look up Zillow homes with your API key, at the same credits as the API. See Use PropertiesAPI with Claude.
Bulk lookup and Google Sheets
For a list of homes, upload a CSV of Zillow links, zpids or addresses in your dashboard and download it back with the main fields on every row (Bulk lookup), or use the Google Sheets script for =ZILLOW(A2) formulas. Both use the same credits as the API.
SDKs and integrations
Official clients for Python and Node.js install from this site (not from PyPI or npm); an n8n community node and a Zapier app aren't published yet. See SDKs and integrations for what they do and how to call the API from n8n and Zapier today.
Endpoints
| Endpoint | What it returns |
|---|---|
| GET /v1/zillow/property | One property by Zillow URL or address: listing price and status, Zestimate, rent Zestimate, beds, baths, living area, lot, year built, home type, photo URLs, days on Zillow, price history, tax history, schools, broker and agent. |
| POST /v1/zillow/batch | Up to 50 Zillow URLs or addresses in one request. Each item is looked up exactly as GET /v1/zillow/property would, and comes back with its own ok flag. |
| POST /v1/zillow/rental-analysis | A rental property analysis for one home by Zillow link, zpid or address: cash flow, cap rate, cash-on-cash return, DSCR, GRM, the 1% rule, break-even rent and a five-year projection. Price, rent, taxes and HOA are filled from the property; every other input is a documented default you can override. |
The response
A successful lookup returns { data, meta }. data is the property, with camelCase fields. The main ones:
zpid,detailUrl,address(plusstreetAddress,unit,city,state,zipcode,latitude,longitude): which property this is. An apartment building haszpid: null; use itsdetailUrlas its id.homeStatus,statusTextandprice: the listing status and listing price. A sold home whose sale price isn't disclosed hasprice: null, never 0.- Apartment buildings (
zillow.com/apartments/...links): you get the building, andprice,beds,baths,livingAreaandunitdescribe its lowest-priced unit available now (no move-in date, or one on or before the lookup date; if none is available yet, its lowest-priced unit). The other units aren't returned yet. zestimateandrentZestimate: Zillow's estimates, when Zillow shows them.beds,baths,livingArea,lotSize,yearBuilt,homeType: the home facts.daysOnZillow(Zillow's own day count, usually set for sold and off-market homes too; for days on market usecalculated.days_on_market),imgSrcandphotos(a list of image URLs).calculated: figures PropertiesAPI calculates from the returned fields, such as price per square foot, gross yield and price drops. See the property endpoint.priceHistory,taxHistoryandschools: lists of past events, tax years and nearby schools.brokerName,agentNameand their phones: who listed it.
meta has credits, cached, cache_key, fetched_at, source, release, took_ms and completeness (which of the commonly missing fields this response supplied), plus warning when something needs checking. When source_age is "approximate", the source served a copy it may have collected earlier: fetched_at is when we received it, so the data can be a few hours older. Which fields are filled can depend on how the home was first looked up (by link, zpid or address). With raw=true, data.raw is the unmapped source record: it is unstable, so don't parse it. See every field on the property endpoint page, or read what each one means, with recorded examples, in the response field reference.
Null fields
If Zillow doesn't show a field for a property, it comes back as null. Lists come back empty. Don't treat null as zero.
| Field | Usually null when |
|---|---|
price | The home isn't listed for sale or rent (an off-market home's Zestimate or tax value is never returned as its price), the listing doesn't show a price, or a sold home's sale price isn't disclosed (some states don't publish sale prices). |
datePosted | The home isn't currently listed. |
zestimate | Zillow doesn't show a Zestimate for this home. |
rentZestimate | Zillow doesn't show a rent Zestimate for this home. |
beds, baths, livingArea, lotSize, yearBuilt | The Zillow page doesn't list this fact (common for land and new construction). |
daysOnZillow | Zillow doesn't give a day count (common for apartment buildings). Sold and off-market homes usually still have one; it isn't days on market (see calculated.days_on_market). |
brokerName, agentName | The listing doesn't name a broker or agent, or the home isn't listed. |
Latency
A live lookup (x-cache: MISS) takes typically 6 seconds, up to about 20. Set a client timeout of at least 120 seconds: an occasional lookup takes longer. Repeat lookups of the same home within 24 hours come from our cache and are free. For many properties, use batch instead of calling one at a time.
Errors
Errors use standard HTTP status codes and one JSON shape, { error: { code, message, details? }, meta: { took_ms } }:
{
"error": {
"code": "not_found",
"message": "No Zillow property matches this input"
},
"meta": {
"took_ms": 11840
}
}| Status | code | When |
|---|---|---|
| 400 | missing_param | None of url, address or zpid was sent. |
| 400 | bad_param | More than one of url, address, zpid; url isn't a zillow.com property link (a home's /homedetails/, /homes/ or new-construction /community/ link with its zpid, or a /b/ or /apartments/ building link; sub-pages such as /photos/ after it are fine; search pages, other pages and links with more than one zpid are refused) or is too long; address is outside 5-200 characters, has no house number, or has neither a city and state nor a ZIP code (US addresses only; checked before any lookup, so it's free); zpid isn't digits; status isn't for_sale, sold or for_rent; raw isn't true or false. |
| 400 | bad_body | Batch only: the body isn't JSON, or items is missing or empty. |
| 400 | too_many_items | Batch only: more than 50 items. |
| 401 | missing_api_key | The x-api-key header is missing. |
| 401 | invalid_api_key | The key is unknown. |
| 401 | revoked_api_key | The key was revoked. Create a new one in your dashboard. |
| 402 | credits_exhausted | The account's lookups are used up: the Free plan's one-time lookups and any prepaid (pay-as-you-go) credits, or a paid plan's included lookups and prepaid credits while usage past the plan is off (it pauses while a payment is failing). Not billed, no lookup made. details.upgrade_url links to the plan and billing section of your dashboard, where you can choose a plan or buy prepaid credits. Cached properties still work. |
| 402 | spend_limit_reached | Only if you set an optional monthly spending limit (there is none by default, and usage past the plan isn't capped): a paid plan went past its included lookups at its overage rate and reached that limit. Not billed, no lookup made. details has the limit (spend_limit_usd), your plan's overage rate, the overage used so far and dashboard_url, where you can raise or remove the limit. Cached properties still work; the limit resets with your billing period. |
| 402 | payment_disputed | A payment for the account's plan was disputed or refunded, so live lookups on the plan and usage past it are paused until it is resolved; prepaid credits stay usable, and this answer means none are left. Not billed, no lookup made. Cached properties still work. details.dashboard_url; contact support to restore the plan. |
| 404 | not_found | No Zillow property matches the URL, address or zpid, or the page has no listing data to return. Not billed. details.reason may say why. A checked not-found, and a page with no listing data, is remembered for an hour: repeating the same input in that time returns the same not_found error at once, without a new lookup. |
| 408 | request_timeout | Batch only: the request body didn't arrive in time. Not billed. Retry. |
| 409 | zpid_mismatch | Zillow answered the link or zpid with a different home, and the one asked for couldn't be confirmed. Not billed, and nothing is cached. details.candidate has the other home's zpid and detailUrl. Check the link or zpid, or retry later. It isn't an address problem: it never comes as address_ambiguous. |
| 409 | address_ambiguous | Zillow's closest match for the address is a different home (another house number, street, directional, unit, ZIP, city or state). Not billed. details.candidate.detailUrl is that home's Zillow link and details.mismatch says what differed. Repeating the same address within an hour returns the same 409 without a new lookup. If the candidate is the home you meant, look it up with url=detailUrl (a normal, billed lookup); otherwise add the unit, city, state or ZIP. |
| 413 | property_response_too_large | This property's response would be larger than we can deliver (almost always because of raw=true on a home with a very large Zillow record). Not billed. Retry with raw=false. |
| 413 | batch_response_too_large | Batch only, per item: the batch's response reached its size limit, so this item was not added. Not billed. Retry it in a smaller batch, on its own, or with raw=false. |
| 413 | bad_body | Batch only: the request body is over 64 KB. Send fewer items per request. |
| 422 | unprocessable_input | The upstream (the data collector) rejected this input. Check the Zillow URL or address. |
| 422 | rental_input_missing | Rental analysis only: the home has no price (no list price, sold price or Zestimate) or no rent estimate, and the request didn't pass price or monthly_rent. details.missing names the input; nothing else about the home is returned. Not billed, and nothing is cached: asking again with the input is a normal lookup. |
| 429 | rate_limited | Too many requests a minute for your account: all its keys and batch items count together (see Rate limits). Wait retry-after seconds. Not billed. |
| 429 | daily_share_exhausted | A Free account made today's live lookups (see Rate limits), or the Free tier's shared daily budget is used. Cached properties still work; live lookups start again after midnight UTC (retry-after has the seconds until then). Not billed. |
| 429 | env_key_daily_cap | A legacy environment-list key used today's live-lookup allowance. Use a dashboard key, or wait retry-after seconds (until midnight UTC). Cached properties still work. Not billed. |
| 429 | too_many_failed_lookups | Too many of the account's live lookups today found nothing or failed (they are not billed, but each one costs an upstream run). New uncached lookups pause until midnight UTC (retry-after); cached properties still work. Check the links, zpids or addresses you send. |
| 500 | internal | Something failed on our side. Safe to retry with backoff. |
| 502 | upstream_error | The upstream (the data collector) failed (also upstream_unreachable, upstream_bad_response, upstream_run_failed; and from the self-hosted collector upstream_response_too_large, upstream_bad_redirect, upstream_redirect_limit, job_expired and job_cancelled). Not billed. Safe to retry with backoff. |
| 502 | upstream_blocked | Zillow denied access from the self-hosted collector. No data is returned or billed. Collection pauses; wait for retry-after and check collector readiness. |
| 502 | upstream_schema_changed | The self-hosted collector could not read valid detail data from the page. No data is returned or billed. |
| 502 | upstream_incomplete | An operator-required field was not supplied, or a listed home came back without its price or status. Nothing was billed for this result; missing_fields identifies what was missing. When details.retryable is true, a later retry may succeed; otherwise repeating unchanged source absence is not a recovery strategy. |
| 502 | upstream_identity_mismatch | The self-hosted collector received a different property than requested and refused the result. Not billed. |
| 422 | upstream_unsupported_page | We can't look up this kind of Zillow link (for example a building or community page the self-hosted collector does not support, or a link the data collector refuses). Not billed. Use the home's zillow.com/homedetails/ link, its zpid or its address. |
| 502 | upstream_cost_cap | The lookup was stopped at its per-lookup upstream cost limit before it found the home. Not billed. Retry at most once, with status=for_sale, sold or for_rent if you know it. |
| 503 | upstream_busy | The upstream is busy (the data collector couldn't take the lookup). Wait for retry-after seconds. Other 503 codes (no_api_keys, live_lookups_disabled, upstream_auth, upstream_quota, upstream_misconfigured) mean live lookups are unavailable on our side, and retrying soon won't help. Every 503 from a lookup carries retry-after, so a client that waits it out doesn't hammer us. |
| 503 | upstream_unavailable | Live lookups are paused for a while because our upstream refused new work (its monthly capacity is used up, or a credential needs fixing). Cached properties still work and nothing is billed. Retry after retry-after seconds; /status shows when lookups are back. |
| 503 | live_lookups_capped | Today's service-wide safety limit on live lookups is reached: our daily upstream budget (for paid plans, details.scope is paid_daily_budget). It is our limit, not one on your account, and nothing is billed. Cached properties still work; new lookups resume at 00:00 UTC (retry-after has the seconds until then). |
| 503 | store_unavailable | Our usage and cache store is unreachable, so live lookups are refused rather than run unmetered. Retry after retry-after seconds (30). |
| 503 | state_unavailable | The self-hosted collector can't take the lookup right now: its working state is unavailable (also storage_full: its storage is full). Not billed. Retry after retry-after seconds. |
| 504 | upstream_timeout | The live lookup took too long. Not billed. Safe to retry. |
| 504 | batch_deadline | Batch only, per item: the batch ran out of time before this item started. Not billed. Retry it. |
Codes with a retry-after wait (429 rate_limited, daily_share_exhausted and env_key_daily_cap; 503 upstream_busy, upstream_unavailable, store_unavailable, live_lookups_capped, state_unavailable and storage_full) can be retried after that many seconds (not upstream_blocked: its 502 carries retry-after too, but collection is paused, so it isn't retried automatically); the daily caps wait until midnight UTC. Retry 500, other 502 codes and 504 with exponential backoff. Don't retry other 4xx errors without changing the request. Other 503 codes mean live lookups are off on our side: retrying soon won't help. Errors aren't billed.
Rate limits
Two limits apply to every account. Each one is per account: all of its API keys count together.
| Plan | Requests a minute | Live lookups a day (UTC) |
|---|---|---|
| Free | 60 | 25 (lookups paid from prepaid credits don't count) |
| Starter | 120 | No daily cap |
| Pro | 300 | No daily cap |
| Business | 600 | No daily cap |
| Scale | 1,200 | No daily cap |
- Requests a minute counts every request, cache hits included. Each address, link or zpid in a batch counts as one request. Past it you get 429
rate_limited; wait theretry-afterseconds.x-ratelimit-limitandx-ratelimit-remainingshow where you are. - Live lookups a day (Free only) counts lookups that go to Zillow, including ones that find nothing. Cache hits are free and don't count. Past it you get 429
daily_share_exhausteduntil 00:00 UTC; cached properties still work. Buying a prepaid pack or a plan lifts it. Buying a pack also ends the free trial: from then on lookups use your prepaid credits. - Lookups running at once. Each account can have 8 live lookups running at the same time. A live lookup takes typically 6 seconds, up to about 20, so this is what sets real throughput. Past it you get 503
upstream_busy; retry afterretry-after. Cache hits don't count. - Failed lookups. If too many of an account's live lookups within a UTC day find nothing or fail, new uncached lookups pause until 00:00 UTC with 429
too_many_failed_lookups. Check the addresses, links or zpids you send. - Rarely, a service-wide safety limit answers 503
live_lookups_capped. It isn't about your account; wait theretry-afterseconds.
For big lists, pace batches to your plan's per-minute limit and retry 429s after retry-after.
Headers and plans
Responses, errors included, carry these headers:
| Header | Meaning |
|---|---|
x-api-version | Every response: always v1. |
cache-control | Every response: no-store. |
x-cache | GET /v1/zillow/property successes only: HIT when served from the 24-hour cache (free), MISS when fetched live. |
x-ratelimit-limit | Authenticated requests: your per-minute request limit (see Rate limits). |
x-ratelimit-remaining | Authenticated requests: requests left this minute; zero on 429 rate_limited. It counts requests a minute only, not the daily lookup caps. |
x-credits-remaining | Account (dashboard) keys: included lookups left this billing period; zero on 402 credits_exhausted and spend_limit_reached. |
x-credits-limit | Account keys: included lookups this billing period. |
x-credits-used | Account keys: included lookups used this billing period. |
x-credits-reset | Account keys with a billing period: when it ends and the included lookups reset (ISO 8601). |
x-credits-prepaid-remaining | Account keys: prepaid (pay-as-you-go) lookups left, zero when you have none. They are used after the included lookups and before any usage past a plan. |
x-credits-overage-remaining | Paid plans with usage past the plan on and an optional monthly spending limit set: lookups still allowed past the included ones before that limit. Absent when no limit is set (no cap). |
x-spend-limit-usd | Paid plans with an optional monthly spending limit set: the limit in US dollars (usage past the included lookups, at your plan's overage rate). Absent when no limit is set. |
retry-after | Errors with a wait: 429 rate_limited, daily_share_exhausted and env_key_daily_cap; every 503 (upstream_busy, store_unavailable and live_lookups_capped are the ones to wait out; see Retries); 502 upstream_blocked. Seconds to wait before retrying. The same number is in details.retry_after. |
link | On 402 credits_exhausted and spend_limit_reached: the dashboard's plan and billing page, as <url>; rel="payment". |
server-timing | Lookup responses (property and batch, errors included): how long each step took on our side, in the standard Server-Timing format: one name;dur= entry per step (its duration in ms) and a total. For your own latency charts; the step names may change. |
Plans:
| Plan | Price | Lookups | After the included lookups |
|---|---|---|---|
| Free | $0 | 50 lookups, one-time trial | None (one-time trial) |
| Starter | $29 / month | 4,000 lookups a month | then $10.88 per 1,000 |
| Pro | $79 / month | 11,500 lookups a month | then $10.30 per 1,000 |
| Business | $199 / month | 30,000 lookups a month | then $9.95 per 1,000 |
| Scale | $499 / month | 80,000 lookups a month | then $9.36 per 1,000 |
| Pay as you go | from $20 | 2,000 lookups for $20 | Credits last 12 months; no overage |
Overage on paid plans: your plan's rate per 1,000 lookups, shown on each plan. No cap on usage: after your included lookups, each lookup is billed at your plan's rate. Optionally set a monthly limit. Or pay as you go: $10 per 1,000 lookups, prepaid, in packs from $20 for 2,000 lookups up to $250 for 25,000 lookups. No subscription; credits last 12 months, and on a plan they are used after its included lookups. Buying a pack ends the free trial: from then on lookups use your prepaid credits. Repeat lookups of the same home within 24 hours come from our cache and are free. Zillow links and addresses cost the same: 1 credit per successful lookup. Batch takes up to 50 items per request. See pricing for details.
OpenAPI spec
Download /openapi.json (OpenAPI 3.1). It's generated from the same definitions as these pages.
Acceptable use
The data is provided as-is, without any guarantee of accuracy or completeness. Don't use it for consumer reports or decisions covered by the FCRA, such as credit, insurance, employment or tenant screening.
Zillow is a trademark of Zillow, Inc. PropertiesAPI is an independent service and is not affiliated with, endorsed by or sponsored by Zillow.
Docs questions
Is this Zillow's official API?+
No. PropertiesAPI is an independent service and is not affiliated with, endorsed by or sponsored by Zillow. The data comes from public Zillow pages and is provided as-is.
Where does the data come from?+
Each lookup reads the property's public Zillow page when you ask. Which fields come back varies by listing: a field the page doesn't show comes back as null.
How do I authenticate?+
Send your key in the x-api-key header on every request. Keep the key on your server.
Why is a lookup slow?+
A live lookup fetches the property from Zillow at request time, so it takes typically 6 seconds, up to about 20. Repeat lookups of the same home within 24 hours come from cache without a live lookup, for free. Use the batch endpoint for many properties.
Why are some fields null?+
Because Zillow doesn't show that field for that property. For example, a home that isn't listed has no listing price, and some homes have no Zestimate.
Do failed lookups cost anything?+
No. Only successful live lookups are billed. Errors and cache hits use no credits; meta.credits tells you what each call cost.
Is there an OpenAPI spec?+
Yes. /openapi.json is an OpenAPI 3.1 document for every endpoint. Import it into Postman, Insomnia or a code generator.
What can't I use it for?+
No consumer reports or decisions covered by the FCRA, such as credit, insurance, employment or tenant screening.
What about public-records data like owners and comps?+
That's a separate property data API we plan to release later. It isn't part of the Zillow API.
Related guides
- Zillow API errors: decide what to fix, review, or retry
Handle Zillow API validation, authentication, ambiguous addresses, quotas, and transient failures with a bounded retry policy.
- Free Real Estate APIs: What You Can Test Before Paying
A free tier is an evaluation budget. Use it to test identity, missing fields, freshness, error billing and cache behavior on your own properties before you choose a real estate data API.
- A Zillow API integration checklist before launch
Test property identity, missing fields, batch failures, secret handling, and freshness before shipping a Zillow data integration.