Implementing search filters
Source-reviewed draft; deployment and release verification pending.
Draft — source-reviewed on 22 October 2026. Deployment settings, live catalogs and enabled capabilities have not been verified. Examples are synthetic.
Form state and request state
Keep incomplete form state separate from the validated public search request. Load reviewed values from GET /api/v1/public/property-reference; submit to POST /api/v1/public/properties/search. The request needs destination: TENERIFE, one BOUNDS/POLYGON area and filters.operation: SALES | RENTAL.
Omit unused filter fields. Explicit nulls, unknown keys, duplicate array selections and invalid nested values are rejected. Empty arrays impose no constraint. Populated fields combine with AND; selections within a field combine with OR. A proposed form model can include empty strings or “Any”; these are UI values, not additional API enum values.
// UI model only. The actual request comes from reviewed public API types.
type ChoiceState = "any" | "yes" | "no";
const choice = "any" as ChoiceState;
const poolFilter = choice === "any" ? {} : { has_pool: choice === "yes" };
// Omit has_pool for Any; never send { has_pool: null }.Supported controls
| Control | Wire field and restrictions |
|---|---|
| Transaction | Required operation: SALES or RENTAL. |
| Rental category | rental_type: SHORT_TERM, TEMPORAL, LONG_TERM. |
| Location | Exact text city, area, complex_name; ubicacion array contains LocalArea keys. |
| Classification | Arrays property_type, features_type, property_detail_type; enforce compatible tuples. |
| Marketing | catalogs array of active keys; no automatic descendant expansion. |
| Counts | bedrooms, bathrooms: inclusive min/max, nonnegative strict integers. |
| Floor area | total_area_m2: inclusive nonnegative finite numeric min/max. |
| Price | Decimal min/max, at most two fractional places. For RENTAL, a price filter requires one rental_type. |
| Known yes/no facts | Strict booleans is_new_construction, has_terrace, has_lift, has_pool, has_parking, sea_view. |
| Views | view_types array of reference values. |
| Update window | updated_at with timezone-aware inclusive from/to; not an incremental synchronization feed. |
Ranges reject a reversed min/max and null bounds. Timestamp windows reject reversed or naive values. There is no free-text query, arbitrary sort, radius parameter or public investment filter.
False means known absence, not unknown: for example has_pool: false matches NO_POOL, excluding unclassified pool state. sea_view: false requires a known non-sea view; an empty view set is not proof of no sea view. Provide Any/Yes/No rather than a checkbox that silently turns unknown into false.
{
"destination": "TENERIFE",
"area": {"kind": "BOUNDS", "south": 28.0, "west": -16.9, "north": 28.6, "east": -16.1},
"filters": {
"operation": "RENTAL",
"rental_type": "TEMPORAL",
"bedrooms": {"min": 2},
"price": {"max": "2500.00"},
"has_pool": true
},
"page": 1,
"page_size": 24,
"sort": "PUBLIC_ID_ASC"
}This synthetic request may return no results; it does not imply synthetic property P9001 has those attributes. Display rental result prices with their returned period and kind, not a guessed label based on the form. Optional response facts can be absent or null; summaries do not return rental_type, area or complex_name just because those are filters.
Submit, paginate and recover
Reset pagination when any filter or geometry changes. Page begins at 1; default size is 24, schema maximum 100, and deployment can impose lower limits. Offset (page - 1) * page_size must remain inside the configured maximum (source default 10,000). Only PUBLIC_ID_ASC is supported. Use total/total_pages from the response; empty items can mean an out-of-range page with a nonzero total.
Disable submission while required metadata is unavailable or required form fields are invalid. Preserve editable form state while showing 422 field guidance; do not parse English error text as stable error codes. Handle 404 capability unavailability, 429 with Retry-After, and 503 with bounded retry. Show loading and successful empty states separately. Ignore obsolete responses and avoid automatic retry loops on invalid requests.
Follow no-store. Do not fetch CRM routes for missing selectors, include private financial filters or persist customer data in analytics. See Classifications and selectors for city matching differences and Errors and pagination.
Related operations
Filters: POST /api/v1/public/properties/search; choices: GET /api/v1/public/property-reference; selected result: GET /api/v1/public/properties/{public_id}. Media URLs use GET /api/v1/public/properties/{public_id}/images/{asset_id} or GET /api/v1/public/agent-images/{asset_id}; neither is an additional search/filter endpoint.
Updated 1 day ago