Preview a property-database search — free match count + credit cost
GET /api/workspace/search/count/
Free
What it returns
A free preview of a property-database search: count (how many properties match the filters) and cost (the credits the full search would charge). This call never charges credits.
This is the mandatory safety step before run_property_search. The charged search costs 1 credit per matching property, so a broad filter set can cost thousands of credits. Always preview here, tell the user the count and cost, and get an explicit yes before running the paid search.
When to use it
- ALWAYS before run_property_search, to size and price the result set.
- To tighten filters (narrow the location, add a price band / condition / ROI floor) until the count and cost fit the user's budget.
- To confirm a search returns anything before spending.
Required filters
Every search needs a location (a city, county, or ZIP — NEVER a whole state: state-wide queries time out, this free preview included), a property_status, AND at least one investment filter (price range, property type, condition, investment-potential grade, ROI range, …). The investment-filter rule keeps results pertinent and cost-effective. It can be waived with allow_location_only=true, but a location-only search in a dense metro can match thousands of properties — check the cost first.
Pricing
Free — 0 credits. Only run_property_search charges.
Errors
| Status | Meaning |
|---|---|
| 400 | Required filters missing — the missing array names them (location, property_status, and/or investment_lens). |
| 401 | Authentication failed. |
| 402 | No active subscription. |
Parameters
location(query, required) — A JSON-encoded array of one or more area objects. City: {"type":"city","city":"Austin","state_code":"TX"}; county: {"type":"county","county":"Travis County","state_code":"TX"}; ZIP: {"type":"postal_code","zip_code":"78704","state_code":"TX"}. State-wide scope is not supported — a state-level area times out instead of returning. When the user asks about a whole state or a huge metro, pick the specific city, county, or ZIP that best serves their goal (or run a few targeted searches) yourself; never surface a 'narrow your area' error to the user. Several area objects in one array are searched together, so a multi-ZIP or multi-city search is one preview and one charged call.property_status(query, required) — Listing status to search. active/pending search live for-sale listings; sold searches historical sales (enables the from/to date range); any = active + pending.price_min(query) — Minimum price in USD (list price for for-sale, sold price for sold).price_max(query) — Maximum price in USD.property_type(query) — Pipe-delimited property types. One or more of: detached|townhouse|apartment|multi family|other.property_condition(query) — Pipe-delimited condition grades (Homesage.ai ML-derived). One or more of: excellent|good|outdated|very poor|poor|unlivable.investment_potential_grades(query) — Pipe-delimited investment-potential grades (for-sale only). Codes: excel (ROI ≥ 35%), high (25–35%), med (15–25%), low (5–15%), noPot (< 5%).roi_min(query) — Minimum projected ROI, as a percentage (e.g. 15 = 15%).roi_max(query) — Maximum projected ROI percentage.monthly_rent_min(query) — Minimum estimated monthly rent in whole USD. Properties with no rent estimate are excluded.monthly_rent_max(query) — Maximum estimated monthly rent in whole USD.rent_to_price_min(query) — Minimum monthly rent as a RATIO of price — 0.007 is 0.7%/mo, not 0.7. Note the contrast with cap_rate_min and cash_on_cash_min below, which are percentages.rent_to_price_max(query) — Maximum monthly rent as a ratio of price (0.02 = 2%/mo).cap_rate_min(query) — Minimum capitalisation rate as a PERCENTAGE (6.5 = 6.5%), computed at all-cash, 20% down, 4.5%, 30-year assumptions. Negative values are valid and meaningful: a property with high HOA or tax costs genuinely returns a negative cap rate. Only properties with a verified rent carry this metric — about 35% of for-sale listings — and the rest are absent from the results rather than treated as zero. FOR-SALE ONLY: sold listings never carry it, so combining this with property_status=sold returns no results.cap_rate_max(query) — Maximum capitalisation rate as a percentage. Use a negative value (e.g. -1) to search for cash-flow-negative properties.cash_on_cash_min(query) — Minimum cash-on-cash return as a PERCENTAGE (4 = 4%), at the same default assumptions as cap_rate_min. Negative values are valid. Only properties with a verified rent carry this metric — about 35% of for-sale listings — and the rest are absent from the results rather than treated as zero. FOR-SALE ONLY: sold listings never carry it, so combining this with property_status=sold returns no results.cash_on_cash_max(query) — Maximum cash-on-cash return as a percentage.pfs_min(query) — Minimum Seller Motivation Score — the Price Flexibility Score, 1–100: how much negotiating room the asking price has, higher = more flexible. FOR-SALE ONLY: sold listings carry no value for it, so combining this with property_status=sold returns no results.pfs_max(query) — Maximum Seller Motivation Score (1–100).lpfp_min(query) — Minimum LP/ARV — the list price as a PERCENTAGE of the property's full-potential (after-repair) value, 1–100, lower is better (80 = listed at 80% of full potential). FOR-SALE ONLY: sold listings carry no value for it, so combining this with property_status=sold returns no results.lpfp_max(query) — Maximum LP/ARV percentage (85 = listed at no more than 85% of full potential).gap_min(query) — Minimum Value Gap as a PERCENTAGE (15 = 15%): the spread between the full-potential value and the list price, relative to the list price. FOR-SALE ONLY: sold listings carry no value for it, so combining this with property_status=sold returns no results.gap_max(query) — Maximum Value Gap percentage.investment_potential_min(query) — Minimum Investment Potential score (0–100), for-sale only. Ignored when investment_potential_grades is also sent — the grades win — so send one or the other.dom(query) — Days-on-market ceiling (for-sale only): only listings listed within the last N days.from(query) — Sold-search only: earliest sold date (ISO-8601, YYYY-MM-DD).to(query) — Sold-search only: latest sold date (ISO-8601, YYYY-MM-DD).auction(query) — Which catalogue to search. OMIT it to search MLS listings — the default, which hides auction-only homes. off_mls = only off-MLS auction homes: foreclosure and bank-owned auctions on Auction.com, Xome and Hubzu with no MLS listing. The two are separate searches, exactly as the Homesage portal's market switch is (MLS = omitted, Off-MLS = off_mls): an MLS listing's ROI, Spread, LP/ARV and grade are worked out at its list price, and an off-MLS home's at its expected winning bid (the price such homes typically sell for at auction, or the published bid when higher). Never merge, rank or compare the two in one list; if the user wants both, run one search for each and present two lists. Off-MLS homes are live auctions: send property_status=active with them, and use auction_within_days rather than dom, since no auction site publishes a listing date. On an off-MLS auction home the other filters read its auction numbers: price_min/price_max read the published bid (the current bid, else the opening bid) and a home with no published bid drops out of them; roi_min/roi_max read the ROI at the expected winning bid; investment_potential_grades and investment_potential_min read its auction Investment Potential score (that ROI, held to 0-100); lpfp_min/lpfp_max read LP/ARV at the expected winning bid; gap_min/gap_max read the spread at the expected winning bid over the published bid, so a home with no published bid drops out of them. cap_rate_min/cap_rate_max and cash_on_cash_min/cash_on_cash_max read its cap rate and cash-on-cash at its max bid (the yield if you win the auction at the max bid, paying cash), and a home with no max bid or no rent drops out of them. property_condition and pfs_min/pfs_max EXCLUDE off-MLS auction homes, so combining either with auction=off_mls returns no results: they have no seller-motivation score, and the condition filter reads the listing's condition column, which is empty on them. An off-MLS home whose auction listing has inside photos is graded from them, and its row says so in its auction block (condition, with condition_basis: "inside_photos" and condition_photos, the number of photos); every other one has condition: null and condition_basis: "assumed".also_at_auction(query) — Set true to keep only MLS listings that are ALSO up for auction on Auction.com, Xome or Hubzu — for example a bank listing a repossessed home with an agent while auctioning it at the same time. A filter on the MLS search: use it with auction omitted.auction_within_days(query) — Auction-date window: only homes whose next auction falls between today and today + N days — 7, 30 or 90. A home with no upcoming auction date does not match. Use with auction=off_mls.sale_type(query) — Pipe-delimited auction sale types. One or more of: foreclosure (trustee and foreclosure sales), bank_owned (REO — the lender already owns the home), other (short sales, private sellers, and sales of unknown type). Use with auction=off_mls.published_bid_only(query) — Set true to leave out auction homes whose opening bid is not published yet (it keeps only homes with a price above zero). Use with auction=off_mls.allow_location_only(query) — Set true to waive the investment-filter requirement and search by location + status alone. Use with care — location-only searches can match thousands of properties. Location and status remain required.
Responses
200— Match count and the credit cost of running the full search. No charge.400— Required filters missing. The missing array lists the unmet obligations. Costs 0 credits.401— Authentication failed — missing or invalid credential. Costs 0 credits.402— No active subscription. Costs 0 credits.
More in Property Search
- Resolve a city / county / ZIP name into a search-area object (free) —
GET /api/area/autocomplete/
Up to 5 area suggestions (city, county, or ZIP) matching a partial place name — each a structured object you pass straight into the location filter of preview_property_search / run_property_search. - Search the property database by investment criteria (1 credit per result) —
POST /api/workspace/search/
The full set of properties matching your investment filters — each with valuation, investment metrics, condition, and location detail.