v2
latestOpenAPI 3.1.02026-08-043458243.4 KBSearch Properties
Beta. Query parameters, response fields, and the absence-trust surface may still change in response to how the endpoint is used in practice. Treat the shape as unstable while it is in beta. Returns properties within a geo scope (state, county, city, ZIP, ZIP+4, or address) and/or owned by named legal_owners, most recently permitted first. At least one of geo_id and legal_owner is required; a legal_owner search needs no geo scope. Pass cursor from a page's next_cursor to page through results. Filter by permit_tags (presence and --prefixed exclusion), permit_status, permit_from, and property_type. Properties with no attributed type are excluded; property attributes are available for 70.1% of properties. An absence filter (a --prefixed tag) returns properties with no resolved permit of the excluded type in covered, arrived data: a permit that never linked to an address, or one that has not yet arrived within a jurisdiction's ingestion lag, is not counted against the claim. Every absence-class row carries a trust object stating three honesty terms — the jurisdiction's permit coverage_tier, its unresolved_rate (the share of its permits that never linked to an address), and the row's data_horizon — plus horizon_basis (whether that horizon is measured, pooled, or a state prior) and footprint_basis (whether suppression could resolve the row's geo); the response trust_summary row-weights them across the page. A presence-only search omits both. Freshness: /properties is served from a whole-table rebuild swapped in by a blue/green cutover — the rebuild is the unit of refresh, and the absence-trust metadata is rebuilt from the same data it describes. An absence claim's staleness bound is the rebuild cadence plus each jurisdiction's permit-ingestion lag: permits reach the data a median 84 days (p90 188 days) after their start_date, so a recent 'no permit since D' stays under-observed until that lag elapses. Each row's data_horizon is the per-row handle on that bound — the most recent start_date past which 'no X since D' is under-observed for that row. Not supported, each for one reason: permit_to or any upper date bound — a max-date rollup cannot bound a closed date window without dropping addresses whose latest permit postdates it (use /permits/search); 'before D' absence — a max-date cannot tell a history that also holds later permits from one that does not; closed-window absence within [D1, D2] — only 'ever' and 'since D' are expressible on max-date maps; 'has X since D and no Y since D' in one query — a mixed query binds an exclusion to 'ever', so per-predicate dates cannot be composed; and jurisdiction geo_ids as a scope.
Query parameters
Scope: a 2-letter state, 5-digit ZIP, ZIP+4, or a Shovels state/county/city/address geolocation id. Jurisdiction ids are not accepted. Optional when legal_owner is given, required otherwise.
Scope: a 2-letter state, 5-digit ZIP, ZIP+4, or a Shovels state/county/city/address geolocation id. Jurisdiction ids are not accepted. Optional when legal_owner is given, required otherwise.
Filter by the property's legal owner, matched on the owner's canonical form — case and spacing variants of one name return the same properties. Pass up to 10 legal_owner params to span several owners. Without a geo_id this searches an owner's properties nationwide; with one it narrows that scope to the owner. A name the data uses for an unidentified owner (for example 'RECORD OWNER') is rejected.
Filter by the property's legal owner, matched on the owner's canonical form — case and spacing variants of one name return the same properties. Pass up to 10 legal_owner params to span several owners. Without a geo_id this searches an owner's properties nationwide; with one it narrows that scope to the owner. A name the data uses for an unidentified owner (for example 'RECORD OWNER') is rejected.
Filter by canonical permit tags, one comma-separated value (e.g. roofing,-solar). A positive tag keeps properties with that tag on some permit; a - prefix excludes the tag (properties without it). Multiple positive tags require each tag (address grain — a documented divergence from /permits/search, where they must share one permit). With permit_status, each positive tag must be matched by a permit that also has one of the statuses. With permit_from: a positive tag matches since the date; an exclusion means 'no such tag since the date' in a pure-absence query, or 'never' when combined with any positive filter.
Filter by canonical permit tags, one comma-separated value (e.g. roofing,-solar). A positive tag keeps properties with that tag on some permit; a - prefix excludes the tag (properties without it). Multiple positive tags require each tag (address grain — a documented divergence from /permits/search, where they must share one permit). With permit_status, each positive tag must be matched by a permit that also has one of the statuses. With permit_from: a positive tag matches since the date; an exclusion means 'no such tag since the date' in a pure-absence query, or 'never' when combined with any positive filter.
Filter by permit status, comma-separated (final, in_review, inactive, active). With positive permit_tags this is a same-permit conjunction; on its own it keeps properties with a permit of one of the statuses. 'unknown' is not a filterable status.
Filter by permit status, comma-separated (final, in_review, inactive, active). With positive permit_tags this is a same-permit conjunction; on its own it keeps properties with a permit of one of the statuses. 'unknown' is not a filterable status.
Bind the tag/status/absence filters to this ISO date (YYYY-MM-DD): a positive filter matches since the date, a pure-absence exclusion means 'none since the date'. With no tag/status filter it keeps properties whose most recent permit is on or after the date.
Bind the tag/status/absence filters to this ISO date (YYYY-MM-DD): a positive filter matches since the date, a pure-absence exclusion means 'none since the date'. With no tag/status filter it keeps properties whose most recent permit is on or after the date.
Not supported on /properties/search — use /permits/search for a date-window search.
Not supported on /properties/search — use /permits/search for a date-window search.
Filter by property type: residential, commercial, industrial, agricultural, vacant land, exempt, miscellaneous, office, recreational. Repeat the key to match any of several types (e.g. ?property_type=residential&property_type=commercial). Properties with no attributed type are excluded; property attributes are available for 70.1% of properties.
Filter by property type: residential, commercial, industrial, agricultural, vacant land, exempt, miscellaneous, office, recreational. Repeat the key to match any of several types (e.g. ?property_type=residential&property_type=commercial). Properties with no attributed type are excluded; property attributes are available for 70.1% of properties.
Keep properties with an UNFINALED permit of each named canonical tag, one comma-separated value (e.g. solar,roofing). Permit status — not a permit's final_date — is the finaled flag: a final permit carries a NULL final_date 14.7% of the time, and ~41% of permits with a NULL final_date are in fact finaled by status, so a final_date IS NULL test over-counts unfinaled permits and is wrong ~41% of the time. A tag is unfinaled for an address only when its latest non-final permit of that tag is more recent than its latest final permit of that tag (equal dates count as finaled); this clear rule removes the false positives a plain 'any non-final permit of this tag' test would keep — for solar, 31.5% of them, though the share varies by tag (nearer 13-18% for tags such as roofing and hvac). A permit whose status is unknown (NULL) counts as neither final nor unfinaled. With permit_from, the tag's latest unfinaled permit must be on or after the date.
Keep properties with an UNFINALED permit of each named canonical tag, one comma-separated value (e.g. solar,roofing). Permit status — not a permit's final_date — is the finaled flag: a final permit carries a NULL final_date 14.7% of the time, and ~41% of permits with a NULL final_date are in fact finaled by status, so a final_date IS NULL test over-counts unfinaled permits and is wrong ~41% of the time. A tag is unfinaled for an address only when its latest non-final permit of that tag is more recent than its latest final permit of that tag (equal dates count as finaled); this clear rule removes the false positives a plain 'any non-final permit of this tag' test would keep — for solar, 31.5% of them, though the share varies by tag (nearer 13-18% for tags such as roofing and hvac). A permit whose status is unknown (NULL) counts as neither final nor unfinaled. With permit_from, the tag's latest unfinaled permit must be on or after the date.
Minimum assessed market value in integer cents (dollars x 100). A property with no assessed market value never matches a range filter (a value is available for 61.0% of properties).
Minimum assessed market value in integer cents (dollars x 100). A property with no assessed market value never matches a range filter (a value is available for 61.0% of properties).
Maximum assessed market value in integer cents (dollars x 100). A property with no assessed market value never matches a range filter (a value is available for 61.0% of properties).
Maximum assessed market value in integer cents (dollars x 100). A property with no assessed market value never matches a range filter (a value is available for 61.0% of properties).
Minimum lot size in square feet. A property with no lot size never matches a range filter (a value is available for 68.7% of properties).
Minimum lot size in square feet. A property with no lot size never matches a range filter (a value is available for 68.7% of properties).
Maximum lot size in square feet. A property with no lot size never matches a range filter (a value is available for 68.7% of properties).
Maximum lot size in square feet. A property with no lot size never matches a range filter (a value is available for 68.7% of properties).
Minimum building area in square feet. A property with no building area never matches a range filter (a value is available for 60.8% of properties).
Minimum building area in square feet. A property with no building area never matches a range filter (a value is available for 60.8% of properties).
Maximum building area in square feet. A property with no building area never matches a range filter (a value is available for 60.8% of properties).
Maximum building area in square feet. A property with no building area never matches a range filter (a value is available for 60.8% of properties).
Minimum unit count. A property with no unit count never matches a range filter (a value is available for 70.1% of properties).
Minimum unit count. A property with no unit count never matches a range filter (a value is available for 70.1% of properties).
Maximum unit count. A property with no unit count never matches a range filter (a value is available for 70.1% of properties).
Maximum unit count. A property with no unit count never matches a range filter (a value is available for 70.1% of properties).
Minimum year built. A property with no year built never matches a range filter (a value is available for 61.1% of properties).
Minimum year built. A property with no year built never matches a range filter (a value is available for 61.1% of properties).
Maximum year built. A property with no year built never matches a range filter (a value is available for 61.1% of properties).
Maximum year built. A property with no year built never matches a range filter (a value is available for 61.1% of properties).
Opaque keyset cursor from a previous page's next_cursor.
Opaque keyset cursor from a previous page's next_cursor.
Page size (1-100).
Page size (1-100).
When true and on the first page (no cursor), include a total_count capped at 10,000.
When true and on the first page (no cursor), include a total_count capped at 10,000.
Response
A page of properties in the scope.