Redfin API: Search Homes, Then Property and Valuation
Perceptlayer is a web data API, and its Redfin API has four GET endpoints: locations, search, property and valuation. locations returns the region_id, region_type and market that search needs, search returns homes with a property_id, and property and valuation take that ID. Every call costs 1 credit, a failed call costs nothing, and the free tier gives you 1,000 credits a month.
What can you get from the Redfin API?
Perceptlayer's Redfin API has four GET endpoints, each costing 1 credit per successful call. The flow runs from finding a region, to listing homes in it, to detail or valuation for one home. Each endpoint returns named fields as JSON instead of a page of HTML.
| Endpoint | Returns | Credits | Required parameters |
|---|---|---|---|
GET /v1/redfin/locations |
Locations | 1 | query |
GET /v1/redfin/search |
Search | 1 | region_id, region_type, market |
GET /v1/redfin/property |
Property | 1 | property_id |
GET /v1/redfin/valuation |
Valuation | 1 | property_id |
property and valuation also accept an optional listing_id. Each endpoint has its own page with a playground: Locations, Search, Property and Valuation. The wider real estate section lists the other property sources in the catalogue.
How do you authenticate and find a region?
Send your key in the X-API-Key header. Keys start with sk_live_, and you get one by verifying an email address at signup, with 1,000 free credits every month and no credit card. If a header isn't possible, the api_key query parameter works too. The authentication docs cover both.
Start with locations. It takes one query string of up to 100 characters:
curl "https://api.perceptlayer.com/v1/redfin/locations?query=Seattle%2C+WA" \
-H "X-API-Key: $API_KEY"
This is the recorded response, trimmed:
{
"data": {
"locations": [
{
"name": "Seattle",
"subName": "Seattle, WA, USA",
"region_id": 16163,
"region_type": 6,
"region_type_name": "city",
"market": "seattle",
"url": "/city/16163/WA/Seattle"
},
{
"name": "West Seattle",
"region_id": 3040,
"region_type": 1,
"region_type_name": "neighborhood",
"market": "seattle",
…
}
],
"query": "Seattle, WA",
"_usage": {
"step": "Use region_id, region_type, and market from the locations response in your search query",
"region_types": {
"1": "neighborhood",
"2": "zip",
"5": "county",
"6": "city"
},
…
}
}
}
The same query returns the city and its neighborhoods, each with its own region_id. Pick the row you want and pass its region_id, region_type and market to search.
What do the region_type codes mean?
region_type is an integer, and search accepts 1, 2, 4, 5 or 6. The recorded locations response lists four of them in _usage.region_types and repeats the name on each row as region_type_name. Rather than hard-code a code, read it from the row you picked.
region_type |
Name |
|---|---|
| 1 | neighborhood |
| 2 | zip |
| 5 | county |
| 6 | city |
Code 4 is accepted by search, but the recording doesn't show a name for it.
Which parameters does the search endpoint take?
search requires region_id (integer), region_type (integer) and market (string, up to 30 characters), all three taken from a locations row. Everything else narrows the results. The Search endpoint page lets you try combinations in the playground before you write any code.
| Parameter | Type | Required |
|---|---|---|
region_id |
integer | yes |
region_type |
integer | yes |
market |
string | yes |
min_price, max_price, num_beds, num_baths, property_types, status, sold_within_days, num_homes, page |
integer, except num_baths (number) and property_types (string) |
no |
status accepts one of 1, 9, 130 or 131.
What does a search response look like?
A recorded /v1/redfin/search response for Seattle (region_id=16163, region_type=6, sold_within_days=30) returns data.properties with fields such as property_id, listing_id, address, price, beds, baths, sqft and status, plus a count of 350. Optional fields like lot_size appear only on some rows.
curl "https://api.perceptlayer.com/v1/redfin/search?region_id=16163®ion_type=6&market=seattle&sold_within_days=30" \
-H "X-API-Key: $API_KEY"
{
"data": {
"properties": [
{
"property_id": 7716,
"listing_id": 224554789,
"address": "7700 E Green Lake Dr N Unit D4",
"price": 885000,
"status": "Coming Soon",
…
},
{
"property_id": 124182,
"listing_id": 224635828,
"address": "2517 25th Ave W",
"city": "Seattle",
"state": "WA",
"zip": "98199",
"price": 2750000,
"beds": 3,
"baths": 4,
"sqft": 3570,
"lot_size": 5120,
"year_built": 2005,
"status": "Coming Soon",
…
}
],
"count": 350,
"region_id": 16163,
"region_type": 6
}
}
Each row carries both property_id and listing_id, the identifiers that property and valuation take. Both rows show "status": "Coming Soon" even though the request passed sold_within_days, so read status on each row instead of assuming it from your filters. The first row has no lot_size, so treat optional fields as optional in your code.
What does the valuation endpoint return?
The valuation endpoint returns a JSON object with the listing price, the last sold price and date, and an estimate summary in sectionPreviewText. For property 124182 in the recorded call, the estimate section read "Estimate Not Available". The valuation is for a home that is currently listed, and it came back without an estimate.
curl "https://api.perceptlayer.com/v1/redfin/valuation?property_id=124182&listing_id=224635828" \
-H "X-API-Key: $API_KEY"
{
"data": {
"numBeds": 3,
"numBaths": 4,
"sqFt": { "displayLevel": 1, "value": 3570 },
"listingPrice": 2750000,
"lastSoldPrice": 1050000,
"lastSoldDate": 1285830000000,
"priceInfo": { "amount": 2750000, "label": "Listed at Price", … },
"sectionPreviewText": "Estimate Not Available",
"propertyId": 124182
}
}
What you do get is context: a listingPrice of 2,750,000 against a lastSoldPrice of 1,050,000. lastSoldDate looks like epoch milliseconds, which for 1285830000000 is 30 September 2010. What you don't get, for this home, is an estimate. That's a real limit if you plan to value a batch of listed homes: some rows may return a price history but no estimate, so count them instead of assuming every call yields a number.
Redfin explains how its estimates work on its Redfin Estimate page, worth reading before you build anything that depends on a valuation.
What does the property endpoint add?
property returns the detail record for one home. The recorded call for the same home returned address, price, price_label ("Listed at Price"), beds, baths, sqft, lot_size, year_built, latitude, longitude and a photos array of URLs, each call costing 1 credit.
curl "https://api.perceptlayer.com/v1/redfin/property?property_id=124182&listing_id=224635828" \
-H "X-API-Key: $API_KEY"
If you only need price, beds and address, the search rows already have them. Call property when you need more than a search row holds, such as coordinates and photos, and valuation when the estimate or price history is the point. Keep the raw JSON from your own runs: data is collected from publicly available sources and returned as found at the time of the call, so treat a valuation as a snapshot.
How do you value a batch of addresses in Python?
To value a batch, search once, collect each property_id and listing_id, then call /v1/redfin/valuation in a loop at no more than the account's request rate. On a 429 or 503 response, wait for the Retry-After seconds. The script below stores each response untouched and counts the homes that returned no estimate.
import os
import time
import requests
BASE = "https://api.perceptlayer.com"
HEADERS = {"X-API-Key": os.environ["API_KEY"]}
def get(path, **params):
for _ in range(3):
r = requests.get(BASE + path, headers=HEADERS, params=params, timeout=30)
if r.status_code in (429, 503):
time.sleep(int(r.headers.get("Retry-After", "1")))
continue
r.raise_for_status()
print(path, "remaining:", r.headers.get("X-Credits-Remaining"))
return r.json()
raise RuntimeError(f"gave up on {path}")
search = get(
"/v1/redfin/search",
region_id=16163,
region_type=6,
market="seattle",
sold_within_days=30,
)
valuations = {}
for home in search["data"]["properties"][:20]:
valuations[home["property_id"]] = get(
"/v1/redfin/valuation",
property_id=home["property_id"],
listing_id=home["listing_id"],
)
time.sleep(1.1) # free accounts: 1 request a second
missing = [
pid
for pid, v in valuations.items()
if v["data"].get("sectionPreviewText") == "Estimate Not Available"
]
print(len(missing), "of", len(valuations), "returned no estimate")
Two cautions. Requests have no idempotency key, so a call that timed out on your side may still have succeeded and been billed. And a plain retry loop is fine at 1 request a second, but on faster accounts read RateLimit-Remaining. The rate limits docs and the errors docs cover both.
What does valuing a batch cost?
Valuing homes through the Redfin API costs 1 credit per valuation call. Valuing 100 homes takes 1 locations call, N search calls and 100 valuation calls: 1 + N + 100 = 101 + N credits. In general, credits = calls × 1 credit and seconds = calls ÷ requests per second. Failed calls return X-Credits-Used: 0.
| Job | Calls | Credits |
|---|---|---|
| Value 100 homes | 1 locations + N search + 100 valuation |
101 + N |
| Value 100 homes, plus details | the above + 100 property |
201 + N |
| Value 1,000 homes | 1 locations + N search + 1,000 valuation |
1,001 + N |
N is the number of search calls it takes to list your homes; check how many properties your own searches return. The 1,000-credit monthly free tier never covers the third row, since 1,001 + N is always more than 1,000. It covers the first row while N is 899 or less, and the second while N is 799 or less. Remember that a valuation call that returns "Estimate Not Available" still costs its credit.
Time matters too. As of 2026-10-24, free accounts get 1 request a second (60 a minute), so 1,000 valuations take 1,000 ÷ 1 = 1,000 seconds, about 17 minutes. Paying accounts run at least 5 requests a second, so the same batch takes 1,000 ÷ 5 = 200 seconds. The credits docs explain how balances work, and pricing shows what credits cost and the faster-rate options.
When is another source a better fit?
If you want aggregate market statistics rather than individual homes, Redfin publishes downloadable market-level data on its own Data Center, which suits trend charts better than thousands of per-property calls.
For other countries, the catalogue has similar guides: Immobilienscout24 for German listings, Rightmove for UK property and Craigslist postings. More walkthroughs sit in the API guides category.
Your next step: get a free API key, run locations for your own city, and feed one property_id and listing_id from the search into the valuation playground.
APIs in this post
Frequently asked questions
How much does the Redfin API cost per call?
Each of the four Redfin endpoints costs 1 credit per successful call. Failed calls cost nothing and return X-Credits-Used: 0. Every account gets 1,000 free credits a month after verifying an email, with no credit card. Purchased credits last 12 months. Pack sizes and what credits cost are on the pricing page.
What do I need before calling the valuation endpoint?
You need a property_id, an integer. The easiest source is a row from a search response, where each home carries a property_id and a listing_id; listing_id is optional. Call locations first if you don't yet know which region to search, since it returns the region_id, region_type and market that search requires.
Does the valuation endpoint always return an estimate?
No. The recorded valuation for a listed Seattle home (property 124182) returned listingPrice, lastSoldPrice and lastSoldDate, but its sectionPreviewText was "Estimate Not Available". Check that field on every response in a batch and keep the count of homes without an estimate.
What happens when I hit the rate limit?
You get a 429 response with a Retry-After header giving the seconds to wait, and the body has the code rate_limited. Free accounts get 1 request a second. Limits are per account and shared by all keys. Wait the stated time and retry; a rate-limited call isn't billed. See rate limits.
Can an AI agent call these endpoints?
Yes. The MCP server at https://api.perceptlayer.com/mcp exposes search_endpoints, get_endpoint and call_endpoint. An agent can look up the Redfin endpoints for free, then spend 1 credit per successful call. The AI agents docs show how to add the server.