Search
Search your listings and the Fondaro network with ranked text, filters, map areas, sorting and cursor pages.
POST /properties/search searches Fondaro listings: your own in any status, and the active listings of every agency on the Fondaro network. It combines ranked free text, structured filters, map areas, sorting and cursor pages. To search Resales Online, Zoddak, Inmobalia or property sites, use Property sources.
Needs the properties:read scope. Send the key as Authorization: Bearer <key>; X-API-Key is still accepted. Every body field is optional: {} returns the newest active network listings.
Search listings
POST /properties/search
| Query parameter | Type | Meaning |
|---|---|---|
includeBranding | boolean | Add organizationBranding and the agent card to each row |
includeAdCount, includeAdCreatives | boolean | Add the ad creative count, or the creatives, to each row |
filterByOrganization | boolean | Deprecated spelling of "scope": "own"; the response carries Deprecation: true |
Choose whose listings
scope | Returns |
|---|---|
network | Every agency's active listings, yours included. The default. |
own | Your agency's listings, in any status you ask for |
partners and followed are dashboard-only scopes; an API key gets 400 (PROPERTY_FILTER_UNSUPPORTED).
With no scope, asking for any non-active status makes the search own. These combinations are refused, so an own-listings request never turns into a network search:
| Request | Code |
|---|---|
network with ?filterByOrganization=true | PROPERTY_SCOPE_CONFLICT |
network with a non-active status | PROPERTY_SCOPE_NETWORK_ACTIVE_ONLY |
network with a commission range or sort | PROPERTY_FILTER_UNSUPPORTED |
agentId or agentUserIds without "scope": "own" | PROPERTY_FILTER_UNSUPPORTED |
Another agency's listing comes back with everything except its private commission, viewingInstructions and import-only additionalFeatures keys. It keeps the street address, postcode, exact coordinates and sharedCommission (what the agency offers a collaborating agency). With includeBranding=true, its agent card has the agent's name, photo and title, plus email and phone numbers when that agent shares their contact with the network. Read sharedCommissionNotes with GET /properties/:id.
Search by text
query takes web-search syntax and searches each listing's reference, title, town, community, region, postcode, type, description (every translation), amenities and street address. Accents and case are ignored, and English words match their other forms (villas finds villa).
| Syntax | Example | Matches |
|---|---|---|
| Words | villa pool marbella | Every word |
"phrase" | "La Quinta" | The words together, in order |
-word | villa -golf | Excludes the word |
OR | penthouse OR duplex | Either word |
| Reference prefix | FDR-A2B | References starting with it |
Numbers are plain words: 3 bedrooms under 500000 is not read as filters. With a query and no sort, results are ranked by relevance (an exact reference first, then reference and title, then place and type, then description and amenities).
Filter
| Field | Type | Values |
|---|---|---|
ids | string[] | Listing UUIDs; other filters still apply |
referenceNumbers | string[] | Exact, case-sensitive references |
agentId | UUID | Your listings assigned to this roster agent ("scope": "own" only) |
agentUserIds | string[] | Your listings assigned to any of these people, by user id (up to 50, "scope": "own" only) |
propertyType | string[] | apartment, condominium, house_detached, house_semi_detached, house_terraced, townhouse, multi_family_home, penthouse, studio, land_residential, land_commercial, land_agricultural, land_other, office, retail, commercial_other, industrial_warehouse, industrial_other, hospitality, other |
propertyCategory | string[] | residential, commercial, industrial, land |
listingType | string[] | sale, rent, sale_or_rent, fraction |
status | string[] | active, inactive, pending, sold, rented, deleted |
countryCode | string[] | ISO 3166-1 alpha-2 codes |
region, city | string[] | Names as stats/aggregations lists them |
bedrooms, bathrooms | { min?, max? } | Inclusive bounds |
price | { min?, max? } | In the listing's currency |
livingArea, plotArea | { min?, max? } | In the listing's area unit |
commission | { min?, max? } | Your private commission percentage; own listings only |
features | string[] or object | Below |
An unknown enum value is a 400 naming the field. An agentId that is not on your roster is a 400 (PROPERTY_FILTER_VALUE_INVALID).
Features. A list of 1 to 30 slugs from the amenity list returns listings with every one:
The object form takes hasPool, hasSeaView, hasGarage, hasTerrace, hasGarden, hasAirConditioning, hasLift and isFurnished: true requires the feature, false excludes it. isFurnished: true matches partly and fully furnished listings.
Search a map area
Send at most one shape. If several arrive, boundingBox wins, then polygon, then location.
| Field | Shape |
|---|---|
location | { "lat": 36.51, "lon": -4.88, "distance": "5km" } (radius in km or m, default 10km) |
boundingBox | { "northEast": { "lat", "lon" }, "southWest": { "lat", "lon" } } |
polygon | At least three [longitude, latitude] pairs; the ring is closed for you |
A boundingBox search returns up to 1,000 rows per page and no total.
Sort
Fields: relevance, price, createdAt, updatedAt, publishedAt, bedrooms, bathrooms, livingArea, plotArea, commission, yearBuilt, city, countryCode, referenceNumber, status, propertyType, propertyCategory, listingType. order is asc or desc (default desc). The older sortBy and sortOrder fields still work.
With no sort, a search with query is ordered by relevance and one without by most recently published. relevance cannot be combined with another field. Ties always break on the listing id, so the order is stable.
Commission is private. Another agency's commission never selects or orders its listings. With no scope, a commission range matches only your listings, and a commission sort puts other agencies' listings after yours. Compare offers with sharedCommission instead.
Page through results
Cursor (recommended). Send "cursor": "*" for the first page, then the same body with each response's nextCursor. Listings published while you page never repeat or shift a page.
| Field | Type | Meaning |
|---|---|---|
cursor | string | *, then the previous nextCursor |
limit | integer | 1 to 100, default 20; may change between pages |
Only the first page carries total: exact up to 10,000, beyond that 10000 with totalIsLowerBound: true. Whether more exist is nextCursor, never a comparison with total. A cursor is bound to your organization, scope and criteria and lasts 30 minutes; anything else is a 400 (PROPERTY_CURSOR_INVALID).
Page numbers. Without cursor, send page (from 1) and limit; every page carries the exact total. page and cursor together are a 400.
Price histogram
Add priceDistribution to also get a histogram of every match, counted with all filters except price, so a price slider can show what lies either side.
| Field | Default | Meaning |
|---|---|---|
priceDistribution.interval | 50000 | Bucket width |
priceDistribution.min, max | none | Count only prices inside these bounds |
Response fields
| Field | Meaning |
|---|---|
results | Listing objects (see Create and update listings) |
total | Exact count on page-number searches; first cursor page only otherwise |
totalIsLowerBound | true when total is 10000 and more match |
nextCursor | Present while more results exist (cursor searches) |
priceDistribution | Only when requested |
relaxedFilters | Present when a network search found nothing and was widened. The steps applied, in order: features, query, listingType, price, priceDropped, bedrooms, propertyType |
What Ask Fondaro can do that the API cannot
Ask Fondaro searches properties with the same engine, but a few things differ from the routes with an API key. The assistant's tools are listed under MCP server. The key routes are this page's POST /properties/search and, for other sources, POST /property-sources/{source}/search on Property sources.
| Capability | Assistant | Key routes |
|---|---|---|
| Source, query, places, operation, property types, price, bedrooms, bathrooms, build size, plot size, features, stages, statuses, listing types, reference numbers, new developments, sort, map circle or polygon, cursor, up to 20 per page | Yes | Yes, with the same names and bounds |
Room counts (minRooms, maxRooms) and a bounding-box map area | No | Yes |
Whose listings: scope | Defaults to your own active listings (own) | Defaults to the whole network. Send scope explicitly |
scope of partners or followed agencies, organizationId, agentUserId, and open houses within a number of days | Not offered | Refused with 400 and PROPERTY_FILTER_UNSUPPORTED; dashboard sessions only |
Stable place rows (locations) | No | Dashboard sessions only; a key sends locationIds |
| One search across several sources at once | No | Not for keys; search each source in turn (POST /property-sources/search is for dashboard sessions) |
Ranking by what the photos show (visualPreference) | Yes | No |
| Detail by an older listing reference | Resolved for you | Send the reference as the source returned it |
The daily allowance for property sites is shared with the assistant and the dashboard. The existing POST /property-sources/{source}/search answers a used-up allowance with 400 and PROPERTY_PORTAL_QUOTA_EXHAUSTED; the /v1 routes answer 429 with DAILY_LIMIT_REACHED.
Errors
| Status | Code | When |
|---|---|---|
400 | PROPERTY_FILTER_UNSUPPORTED | A filter or scope this caller or scope cannot use |
400 | PROPERTY_FILTER_VALUE_INVALID | An agentId not on your roster |
400 | PROPERTY_SCOPE_CONFLICT, PROPERTY_SCOPE_NETWORK_ACTIVE_ONLY | See Choose whose listings |
400 | PROPERTY_CURSOR_INVALID | Expired cursor, changed criteria, or page with cursor |
403 | API_KEY_SCOPE_MISSING | The key lacks properties:read |