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 field catalog; values are always arrays of strings, and never empty — every field present must have at least one value.
- Map areas:
polygontakes one string oflat,lngpairs joined by;(latitude first, decimal degrees to about 5 places, at least 3 points, closed by repeating the first point), e.g.{"polygon": ["26.94600,-80.09400;26.94600,-80.07000;26.92000,-80.07000;26.94600,-80.09400"]}. A polygon replaces the location fields: city, zip, subdivision and the like are dropped from a search that has one. - 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/dump_uberform_fields.json/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/dump_uberform_fields.jsonis the search field catalog: every field the site’s searches accept, including ones its search forms don’t show (such as subdivision or school on many MLSs). Each entry hasid(the criteria key),label,widget,flagsandchoicesas{"val", "label"}.min_max_fieldwidgets take<id>_min/<id>_max; send the choiceval, not the label; fields flaggeddynamic(city, subdivision, school…) take their values from the MLS and list none here, so use the autocomplete index below.polygonis accepted but not listed (see Criteria format). AI assistants connected over MCP get the same catalog from thesearch_fieldstool.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.
From the command line: geekcli search fields, geekcli search choices <field> with geekcli (see the geekcli guide).
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 catalog’s
choicesor the autocomplete index first. The/api/v3/searchfield fixes capitalization to the MLS spelling and warns about values it does not know (unknown_value, with suggestions), but a correct value is still better than a warning. 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.
From the command line: geekcli search check city=Riverside, geekcli search run city=Riverside with geekcli (see the geekcli guide). search check flags criteria the site ignored.
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.
From the command line: geekcli search url --save city=Riverside, geekcli pages update <page> --search-criteria city=Riverside with geekcli (see the geekcli guide).
