Austin + DFW property screening data — search, map filters, facets, exports and annotations.
Base URL: https://179-236-232-116.sslip.io/api · Interactive spec: /api/docs
Paste into a browser:
# view the first 100 properties as JSON
https://179-236-232-116.sslip.io/api/v1/properties?limit=100
# download EVERYTHING as CSV (77k rows, all columns)
https://179-236-232-116.sslip.io/api/v1/export.csv
# the full field catalog (what you can filter on)
https://179-236-232-116.sslip.io/api/v1/schema
Or search with filters (works from anywhere):
curl -s -X POST https://179-236-232-116.sslip.io/api/v1/search \
-H 'content-type: application/json' -d '{
"area": {"type": "bbox", "bbox": [-96.95, 33.05, -96.60, 33.30]},
"filters": {"beds": {"gte": 3}, "price": {"lte": 600000}},
"sort": {"field": "price", "dir": "asc"},
"limit": 10
}'
| Endpoint | What it does |
|---|---|
GET/healthz | Service alive check |
GET/v1/schema | The live catalog: every filterable field, operators, expression language, limits |
POST/v1/search | The workhorse: area + filters + sort + paging → property rows |
POST/v1/aggregate | Facet counts for filter UIs (price histogram, group-bys) |
POST/v1/clusters | Map pins: grid cells with counts (zoom-dependent) |
GET/v1/properties | Simple paged list of all properties (browser friendly) |
GET/v1/properties/{zpid} | One property: full row + county values + tags + notes |
GET/v1/export.csv · /v1/export.jsonl | Download everything (or ?limit=N) |
POST/v1/export | Same as above but with filters in the body |
POST GET PATCH DELETE /v1/notes | Notes on properties (/v1/notes?zpid=… to list) |
PUT DELETE GET /v1/properties/{zpid}/tags/{tag} | Attach / remove / list tags (PUT is idempotent) |
GET/v1/tags | All tags with usage counts |
POST GET PATCH DELETE /v1/saved_searches | Save / list / edit / delete filter combinations |
{
"area": { "type": "bbox", "bbox": [minLng, minLat, maxLng, maxLat] }, // optional
"filters": { "beds": {"gte": 3}, "price": {"between": [300000, 600000]} }, // optional
"sort": { "field": "price", "dir": "asc" }, // any field in /v1/schema
"limit": 50, // max 200
"offset": 0, // max 50000
"count": true // include "total" (adds a count query)
}
Area types: bbox · polygon (GeoJSON, draw-your-own) · region () · radius ({"lat":33.2,"lng":-96.8,"meters":5000})
This section renders live from /v1/schema, so it is always current.
Operators:
{"price": {"gte": 300000, "lte": 600000}} // range
{"beds": {"gte": 3}} // at least
{"year_built": {"between": [2010, 2025]}} // inclusive
{"zestimate": {"exists": true}} // has a value
{"baths": {"in": [2, 2.5, 3]}} // any of
{"enriched_at": {"gte": "2026-09-01"}} // since Sep 1
Operators:
{"status": {"in": ["Active", "Pending"]}}
{"home_type": "SINGLE_FAMILY"}
{"agent": {"contains": "smith"}} // case-insensitive substring
{"status": {"ne": "Sold"}} // not equal
{"enriched": true} // only deeply-enriched records
{"county_matched": true} // has county appraisal data
{"zip": {"in": ["75034", "75035"]}}
{"county": {"in": ["collin", "denton", "travis"]}}
{"county_market_value": {"gte": 400000}} // unified county market value
{"data": {"challenge": true}} // raw JSONB containment (any scraped field)
{"text": "oak street"} // free text on address + description
{"schools_text": "Frisco", "school_rating": {"gte": 8}}
{"county_col": {"field": "currvalassessed", "county": "collin", "gte": 500000}}
{"county_col": {"field": "ownermarketvalue", "gte": 400000}} // county auto-detected
{"county_col": {"field": "imprvActualYearBuilt", "gte": 2010}} // denton: year built
{"$or": [
{"beds": {"gte": 4}, "price": {"lte": 400000}},
{"area_sqft": {"gte": 3000}, "year_built": {"gte": 2015}}
]}
When a filter depends on other columns (price vs county value, price per sqft, conditional thresholds), use expr:
a safe JSON expression tree (no raw SQL, everything validated).
Columns available:
Accessors:
Operators:
// price per sqft under $200
{"expr": ["<", ["/", ["col","price"], ["col","area_sqft"]], 200]}
// below-market: asking price under 80% of county market value
{"county_matched": true,
"expr": ["<", ["col","price"], ["*", ["col","county_market_value"], 0.8]]}
// conditional thresholds: newer homes must clear a higher price bar
{"expr": ["if", [">", ["col","year_built"], 2015],
[">", ["col","price"], 300000],
[">", ["col","price"], 200000]]}
// multiple expressions are ANDed
{"expr": [ ["notnull", ["col","zestimate"]],
["<", ["col","price"], ["col","zestimate"]] ]}
// any county column in an expression
{"expr": [">", ["col","county.collin.currvalassessed"], 500000]}
{"area": {"type": "polygon", "geojson": {…}},
"filters": {"beds": {"gte": 3}},
"limit": 50}POST /v1/clusters
{"area": {"type": "bbox", …},
"max_cells": 200}POST /v1/aggregate
{"area": {…},
"aggs": {"price_histogram": true,
"group_by": ["status","region"]}}GET /v1/properties?limit=1000&offset=0
… repeat with offset += 1000GET /v1/export.csv
GET /v1/export.jsonlPOST /v1/saved_searches
{"name": "frisco 3bd",
"body": {"filters": {"beds": {"gte": 3}}},
"owner": "das"}POST /v1/notes {"zpid": "…", "body": "check flood zone"}
PUT /v1/properties/{zpid}/tags/hotGET /v1/properties/102956128
→ row + county values + tags + notes| Rule | Value |
|---|---|
| Rate limit | 10 requests/second per IP (burst 30) |
| Search page size | limit ≤ 200 · offset ≤ 50000 |
| List page size | limit ≤ 1000 |
| Export | ≤ 200,000 rows per request (CSV or JSONL) |
| Auth | None yet — testing phase. Treat URLs as team-internal. |
Errors come back as {"detail": "…"} with HTTP 400 (bad filter/field/operator), 404 (not found), 405 (wrong method), 429/503 (rate limit).
Runs a real search against the live database.
Property Data API · served from the company VPS · guide source: /srv/team/property-data/api/guide.html
Everything on this page is live: fields, counts and the playground all read from the running API.