Part of the Content API. Saved property searches drive the listings shown on content pages, area pages and the home page, and search links (/search/results/?...) appear throughout site content. This page covers the criteria format, how to discover the fields a site accepts, and a procedure for building searches that actually filter.
Criteria format
Criteria are an object of {"field_id": ["value", ...]}. The same shape is accepted by the search and search_field_defaults fields on pages, by /api/v2/search/ as a query string, and in /search/results/?... links.
- Keys are field ids from the site’s search form; values are always arrays of strings, and never empty — every field present must have at least one value.
- Range fields take
<id>_min/<id>_maxkeys, e.g.{"list_price_max": ["800000"]}. - Multi-select fields take the stored value, not the display label:
"con", not"Condo". Repeat values for several, e.g.{"type": ["res", "con"]}. - Boolean fields take
["True"]or["False"]. - Only include fields relevant to the search — an omitted field means “any”.
Discovering a site’s search fields
/search_forms/api/advanced_search_form.json/api/v2/search/metadata//api/v2/search/autocomplete-options//api/v2/search/Search fields and their values are site-specific (they follow the site’s MLS and its search form setup). These endpoints on the site’s public search stack let a tool explore them before writing a criteria object or a search link into content. They sit outside /api/v3/ and need no API key.
GET /search_forms/api/advanced_search_form.jsonreturns the advanced search form as{"primary": [...], "secondary": [...]}. Each entry is one field:attr(the criteria key),label,widget_type,default_value,value(one row per checkbox value, e.g.type=res),dependent_fields, andchoicesas[value, label]pairs. City and subdivision choice lists follow the site’s default county.GET /api/v2/search/autocomplete-options/returns the site’s autocomplete index as[{"field", "value"}, ...]— every value the site knows for a field across all counties and cities, beyond the form’s default lists.GET /api/v2/search/metadata/?<criteria>echoes{"description", "criteria"}: the site’s own parse of a query string. The site’s search pages silently drop unknown criteria (the page “works” but matches everything), so compare what you sent with the echoedcriteria— any key missing there was ignored.GET /api/v2/search/?<criteria>runs the search;page,per_page,fields,include_descriptionandsort_highest/sort_lowest/sort_latest/sort_oldest/sort_relevancecontrol the response, and the match count is in theX-Total-Countheader.
Building criteria that work
These are the rules our own search-building tools follow. They exist because the failure mode of a bad search is silent: the page renders, the listings look plausible, and nothing is actually being filtered.
- Only use field ids the site lists. Never guess or invent a field id. The site’s search pages ignore unknown keys silently; the
/api/v3/searchfield rejects them with a422naming each one. - Verify values before using them. Values are site-specific: a city, subdivision or school name that exists on one site may not exist on another, and a misspelled value matches nothing. Confirm it in the form’s
choicesor the autocomplete index first. Where fields depend on each other (subdivisions within a city, schools within an area), check the value against the rest of your criteria, not just globally. - Map only what actually maps. When a request mentions something no field covers — “jacuzzi”, “good schools”, “nice neighborhood” — skip it rather than approximating with an unrelated field, and say so in whatever notes or summary you give the user. A wrong filter is worse than a missing one.
- Set the property type when one is implied. “Homes”, “condos”, “townhouses”, “land” all map to the
typefield; include it whenever the request names one. - Check the parse. Before writing a search link into content, run the criteria through
metadata/and confirm every key came back. A link built from ignored keys shows every listing on the site.
Test before you attach
A criteria object that validates can still be a bad search. Before saving it or attaching it to a page:
- Run it (
GET /api/v2/search/?<criteria>&per_page=1) and read the match count fromX-Total-Count. - Zero results? Broaden stepwise while keeping the request’s core intent: drop the least important filters first, widen price ranges, reduce bedroom/bathroom minimums, expand the location to nearby areas — re-verifying values as you go. Re-test after each change and keep the best version rather than the last one. If nothing helps after a few rounds, report that honestly instead of shipping a search that shows nothing.
- Suspiciously large counts? If the count is close to the site’s whole inventory, the criteria probably are not filtering — check for ignored keys with
metadata/. - Sanity-check the description.
metadata/returns the site’s own human-readable description of the search; if it does not read like what was asked for, the criteria do not mean what you think.
Saving searches and links
POST /api/v2/search/?<criteria> stores the search and returns {"search_id", "search_id_int"}. The base36 search_id is the short id that appears in the site’s own URLs; identical criteria reuse the same saved search.
- Link to results with
/search/results/<search_id>/(or/search/results/?<criteria>without saving), and the map view with/map_search/results/<search_id>/1/. - Attach the search to a page through the
searchfield on content pages, area pages and the home page — it accepts thesearch_id, the numeric id, or a criteria object directly (the API saves or reuses a search for you). search_field_defaultstakes the same values to pre-fill a page’s search form without filtering its listings.
