Documentation
Everything you need to get Zillow property data into your app, pipeline, or AI agent.
Overview
APIllow is a Zillow property data API. Send a city name, ZIP code, property ID, or Zillow URL and get back 50+ structured data fields per property — address, price, Zestimate, beds/baths, price history, tax records, school ratings, agent info, and photos.
Two ways to use it:
- REST API — standard HTTP requests from any language
- MCP Server — native integration with Claude, Cursor, and other AI agents
Authentication
All API requests require an API key passed via the X-API-Key header:
curl -H "X-API-Key: your_key" https://api.apillow.co/v1/properties
Get a free key (50 requests/month) by signing up on the homepage or through the MCP server.
Quick Start
# Search for properties in Los Angeles curl -X POST https://api.apillow.co/v1/properties \ -H "Content-Type: application/json" \ -H "X-API-Key: your_key" \ -d '{"search": "Los Angeles", "type": "sale", "max_items": 5}'
Python
import requests resp = requests.post( "https://api.apillow.co/v1/properties", headers={"X-API-Key": "your_key"}, json={"search": "Los Angeles", "type": "sale", "max_items": 5} ) for r in resp.json()["results"]: p = r["property"] print(f"{p['street_address']}, {p['city']} — ${p['price']:,}")
JavaScript
const resp = await fetch("https://api.apillow.co/v1/properties", { method: "POST", headers: { "Content-Type": "application/json", "X-API-Key": "your_key" }, body: JSON.stringify({ search: "Los Angeles", type: "sale", max_items: 5 }) }); const data = await resp.json(); data.results.forEach(r => console.log(r.property.street_address, r.property.price));
POST /v1/properties
Get property data from Zillow. Accepts multiple input types in a single request.
Request Body
| Field | Type | Description |
|---|---|---|
search | string | Free-text search query (e.g. "Los Angeles", "Miami Beach FL") |
zipcodes | int[] | US ZIP codes (e.g. [90210, 90211]) |
zpids | int[] | Zillow Property IDs |
urls | string[] | Zillow listing URLs or search page URLs |
type | string | all (default), sale, rent, sold, fsbo |
max_items | int | Max results, 1-1000 (default 200) |
search, zipcodes, zpids, or urls is required. You can combine multiple in one request.Sync vs Async
- 1-5 results — returned immediately in the response
- 6+ results — returns a
job_idwith status"processing". PollGET /v1/results/{job_id}
GET /v1/results/{job_id}
Poll for results from an async batch job. The status field will be "processing", "complete", or "failed".
curl https://api.apillow.co/v1/results/YOUR_JOB_ID \ -H "X-API-Key: your_key"
Poll every 5-10 seconds until status is "complete".
Input Types
Search by city
{ "search": "Austin TX", "type": "sale", "max_items": 10 }
Search by ZIP code
{ "zipcodes": [90210, 90211], "type": "sale" }
Look up by ZPID
{ "zpids": [20794780, 20637558] }
Get data by URL
{ "urls": ["https://www.zillow.com/homedetails/123-Main-St/12345_zpid/"] }
Search page URL
{ "urls": ["https://www.zillow.com/beverly-hills-ca/"], "max_items": 20 }
Mix and match
{ "search": "Miami", "zipcodes": [33139], "type": "rent", "max_items": 50 }
Response Format
{
"job_id": "4a021afd-c429-...",
"status": "complete",
"results": [
{
"url": "https://www.zillow.com/homedetails/.../20794780_zpid/",
"success": true,
"zpid": 20794780,
"elapsed_seconds": 2.8,
"property": {
"street_address": "1735 N Fuller Ave APT 425",
"city": "Los Angeles",
"price": 379888,
"zestimate": 374200,
... 50+ fields ...
}
}
],
"errors": []
}
Data Fields
| Field | Type | Description |
|---|---|---|
zpid | int | Zillow Property ID |
street_address | string | Street address |
city, state, zipcode | string | Location |
latitude, longitude | float | Geocoordinates |
price | int | Listing price (USD) |
zestimate | int | Zillow's estimated value |
rent_zestimate | int | Estimated monthly rent |
bedrooms, bathrooms | int/float | Bed and bath count |
living_area | int | Interior sqft |
lot_size | float | Lot size (sqft) |
year_built | int | Year constructed |
property_type | string | SINGLE_FAMILY, CONDO, TOWNHOUSE, etc. |
home_status | string | FOR_SALE, SOLD, FOR_RENT, OTHER |
description | string | Full listing description |
hoa_fee | float | Monthly HOA fee |
days_on_zillow | int | Days listed |
page_view_count | int | Zillow page views |
favorite_count | int | Times favorited |
price_history | array | Price events with date, event, price, source |
tax_history | array | Tax records with year, tax paid, assessed value |
listing_agent | object | Agent name, phone, email, company |
listing_broker | string | Brokerage name |
nearby_schools | array | Schools with rating, grades, distance |
image_urls | array | Property photo URLs |
Error Handling
| HTTP Code | Meaning |
|---|---|
200 | Success (check results and errors arrays) |
400 | No valid input provided |
401 | Invalid or missing API key |
429 | Rate limit or monthly quota exceeded |
Individual property failures appear in the errors array with details:
{
"url": "https://www.zillow.com/homedetails/invalid/0_zpid/",
"success": false,
"error": "HTTP 404",
"attempts": 3
}
MCP Server Installation
The MCP server lets AI agents (Claude, Cursor, Windsurf, etc.) access Zillow property data directly as tools.
Install
pip install apillow-mcp
Claude Desktop
Add to ~/.claude/claude_desktop_config.json:
{
"mcpServers": {
"apillow": {
"command": "apillow-mcp",
"env": {
"APILLOW_API_KEY": "your_key"
}
}
}
}
Claude Code
claude mcp add apillow -- apillow-mcp
MCP Tools
Property Data
| Tool | Description |
|---|---|
search_properties(query, type, max_items) | Search by city or area name |
search_by_zip(zipcodes, type, max_items) | Search by ZIP codes |
get_property(zpid) | Look up by Zillow Property ID |
get_property_by_url(url) | Get data from a Zillow listing URL |
Account Management
| Tool | Description |
|---|---|
signup(email) | Create free account, get API key instantly |
check_usage() | See current month's usage, quota, and plan |
upgrade_plan(plan, email) | Get a Stripe checkout URL to upgrade |
Zero-Browser Signup
Users can sign up and start querying entirely through the AI agent:
# User asks their AI agent: "Sign me up for Apillow with user@example.com" # Agent calls signup("user@example.com") and gets: { "api_key": "zs_abc123...", "plan": "free", "monthly_limit": 50 } # Agent can immediately query: "Find 3-bedroom homes under $500K in Austin TX" # When they hit the limit, agent suggests upgrading: "You've used 50/50 requests. Upgrade to Pro?" # Agent calls upgrade_plan("pro") → returns Stripe URL
The only step requiring a browser is the Stripe payment page (PCI compliance).
Plans
| Plan | Price | Requests/mo | Rate Limit |
|---|---|---|---|
| Free | $0 | 50 | 5/min |
| Pro | $9.99/mo | 3,333 | 20/min |
| Ultra | $29.99/mo | 10,000 | 60/min |
| Mega | $99.99/mo | 50,000 | 120/min |
Billing API
POST /billing/signup
Create a free API key. No authentication required.
{ "email": "user@example.com" }
GET /billing/usage?api_key=your_key
Check current usage and quota.
POST /billing/checkout
Generate a Stripe Checkout URL for upgrading to a paid plan.
{ "email": "user@example.com", "plan": "pro" }
Returns a checkout_url — open in browser to complete payment.
POST /billing/webhook
Stripe webhook endpoint for subscription events. Configured in your Stripe Dashboard.