ListingsFeed

GET /v1/listings

Search and page through listings. Every parameter is optional; combine as many as you like. Unknown parameters return 400.

Query parameters

This table is generated from the same allowlist the server validates against.

NameTypeDescription
statestringTwo-letter state code(s), comma-separated. Example: TX,OK
citystringCity name (case-insensitive exact match).
zipstringZIP code(s), comma-separated; trailing * matches a prefix (e.g. 973*).
countystringCounty name (case-insensitive). Populated for a subset of listings.
property_typestringOne or more of: land, industrial, office, retail, multifamily, hospitality, special, other
property_subtypestringSubstring match on the source's subtype (e.g. warehouse).
transactionstring
sale · lease
sale = for sale (incl. sale/lease); lease = for lease (incl. sale/lease).
statusstringOne or more of: active, under_contract, sold, leased, withdrawn, closed
min_pricenumberMinimum asking sale price (USD). Accepts 1.5m / 250k.
max_pricenumberMaximum asking sale price (USD).
min_sfnumberMinimum building square feet.
max_sfnumberMaximum building square feet.
min_acresnumberMinimum land acres.
max_acresnumberMaximum land acres.
min_capnumberMinimum cap rate (percent).
max_capnumberMaximum cap rate (percent).
bboxstringwest,south,east,north in decimal degrees.
nearstringlat,lng centre for a radius search (use with radius_mi).
radius_minumberRadius in miles around `near` (max 200).
updated_sincestringOnly listings changed after this ISO-8601 timestamp.
first_seen_sincestringOnly listings first observed after this timestamp.
brokeragestringBrokerage public id (from /v1/brokerages).
has_pricebooleanOnly listings with a numeric asking price.
has_brochurebooleanOnly listings with a brochure/flyer link.
qstringFull-text search over name, address, city and description (web-search syntax: quoted phrases, OR, -excluded).
include_inactivebooleanInclude listings no longer published (plan-gated).
sortstring
updated_at · first_seen · sale_ask_total · building_sf · land_acres
Sort column (default updated_at).
orderstring
asc · desc
Sort direction (default desc).
limitintegerPage size (plan-capped; default 100).
cursorstringOpaque cursor from the previous page's meta.next_cursor.
fieldsstringComma list of fields to return, or `all`.
formatstring
json · geojson · csv
Response format (default json).
include_totalbooleanAdd meta.total (a count query; rate-limited harder).

Numbers accept shorthand: min_price=1.5m, min_sf=50k, $1,500,000. Lists are comma-separated: state=TX,OK,AR, property_type=industrial,land.

Response envelope

{
  "data": [ …listings… ],
  "meta": {
    "count": 100,                   // records in this page (what you were billed)
    "records_billed": 100,
    "next_cursor": "eyJz…",        // null on the last page
    "total": 4821,                  // only with include_total=1
    "quota": {"limit": 10000, "used": 1300, "remaining": 8700, "hard_cap": 50000, "period_end": "2026-10-01"},
    "source": "managed listings; health-checked and refreshed weekly",
    "notice": "Broker email/phone are included on paid plans."   // Free plan only
  },
  "links": {"next": "https://listingsfeed.com/v1/listings?…&cursor=eyJz…"}
}

Headers: X-Quota-Limit, X-Quota-Used, X-Quota-Remaining, X-Next-Cursor, X-RateLimit-Limit, X-RateLimit-Remaining.

Pagination

Keyset cursors, signed and opaque. Pass meta.next_cursor back as cursor with the same filters, sort and order; a cursor from a different sort is rejected with 400. Pages are stable while you walk them: new listings arriving mid-walk do not shift rows. limit is capped by plan (Free 100, pay-as-you-go 1,000).

Sorting

sort one of updated_at (default), first_seen, sale_ask_total, building_sf, land_acres; order=asc|desc. Nulls sort last in descending order.

Field selection

By default a listing omits description, highlights, photos and attributes to keep pages small. Ask for them with fields=all or a comma list, e.g. fields=hash_id,address,city,state,lat,lng,building_sf,brokers. hash_id is always included.

Formats

  • format=json (default) — the envelope above.
  • format=geojson — a FeatureCollection; each feature has id = hash_id, a Point geometry [lng, lat] and every other field as properties. Listings without coordinates get geometry: null.
  • format=csv — one row per listing, brokers flattened to broker_name / broker_email / broker_phone (semicolon-separated when several). Plan-capped rows per call; continue with X-Next-Cursor.

Geography

  • bbox=west,south,east,north — decimal degrees.
  • near=lat,lng&radius_mi=25 — great-circle radius, max 200 miles.
  • zip=761* — prefix match; zip=76137,76140 exact list.
  • county — populated for a growing subset; check fill_rates in /v1/stats.

Change detection

updated_since compares against updated_at, which moves only when a field actually changes (not on every weekly re-observation). first_seen_since finds new arrivals. With include_inactive=1 (pay-as-you-go) retired listings are returned with is_active=false and, when merged, superseded_by.

Contacts

brokers[].email and brokers[].phone are returned on paid plans; the Free plan gets names only and a meta.notice. Contacts that a broker has asked us to suppress are removed for everyone.

GET /v1/listings/{hash_id}

Returns one listing with every field (equivalent to fields=all) and bills one record. Retired listings still resolve, with is_active=false. Unknown id → 404.

Examples

# Land over 100 acres for sale in the Southeast, newest first
/v1/listings?state=GA,SC,NC,TN,AL&property_type=land&transaction=sale&min_acres=100&sort=first_seen

# Everything a brokerage has active
/v1/listings?brokerage=7c1d0a9b3e5f2c4d8a1b&include_total=1

# Office for lease near downtown Seattle
/v1/listings?near=47.6062,-122.3321&radius_mi=5&property_type=office&transaction=lease

# Priced industrial with brochures, as CSV
/v1/listings?property_type=industrial&has_price=1&has_brochure=1&format=csv&limit=1000