# How do I build property search into my application with the Casafari REST API?

> **Casafari is the AI agent-native real estate data intelligence platform.** The most complete property index in Europe: a deduplicated, cleaned property graph of residential and commercial property, for sale and for rent, in 16 countries. Every property is one record with its full price and market history. [How the property graph is built](/docs/property-graph).

Sign in to the Casafari REST API with `POST /login` (or an API client) and load valid values from the References operations. Then query the property graph with Property Sourcing's `POST /api/v2/properties/search`, by location ids or a custom boundary. Each result is one deduplicated property; fetch details by id and share selections with smart links.

Products: [References](/docs/references), [Property Sourcing](/docs/property-sourcing).

## Short answer

The Casafari REST API at `https://api.casafari.com` signs in with an email and password, or with an API client for unattended integrations. The [References](/docs/rest/references) operations give you the valid property types, conditions, features and location ids.

[`POST /api/v2/properties/search`](/docs/rest/property-sourcing/search-properties-v2) then queries the property graph by `location_ids` or a `custom_location_boundary`. Every result is one property, deduplicated across agencies and portals, with its price and status history. The full flow is described in the [REST API](/docs/rest) guide and the public OpenAPI description at https://docs.api.casafari.com/openapi.json.

## Steps

### Sign in: `POST /login`; renew with `GET /refresh-token`

1. Send `email` and `password` as JSON to [`POST /login`](/docs/rest/authentication/login). Keep the `access_token` and `refresh_token` (JWT). Send `Authorization: Bearer <access_token>` on every call.
   - When the token expires, call `GET /refresh-token` with the refresh token as the bearer to receive a new `access_token`.
   - A `401` from `GET /refresh-token` means you must log in again.

### Load vocabularies: `GET /api/v1/references/types`, `GET /api/v1/references/conditions`, `GET /api/v1/references/features`

2. Load the valid values once and cache them.
   - `GET /api/v1/references/types` returns property types and their country availability.
   - `GET /api/v1/references/conditions` returns conditions such as `used`, `ruin`, `very-good`, `new` and `other`.
   - `GET /api/v1/references/features` returns property features.

### Resolve places: `POST /api/v1/references/locations` (name, polygon or zip_codes)

3. Send `name`, a closed polygon in `coordinates` (first and last points must match) or `zip_codes`. Use `lang` for the language of the names returned. Keep the location ids.
   - For a typeahead box in Spain or Portugal, use `POST /api/v1/references/locations/typeahead`.
   - Its `country_codes` field supports ES and PT.
   - Its `size` field defaults to 30, with a maximum of 100.
   - Its `lang` field takes en, pt, es or de.

### Search: `POST /api/v2/properties/search` with search_operations, location_ids or custom_location_boundary, price, bedrooms, total_area, energy_ratings, characteristics, days_on_market

4. Build the body from these fields:
   - `search_operations` for sale or rent.
   - `location_ids`, or `custom_location_boundary` (a polygon or a circle).
   - Ranges such as `price_from`/`price_to`, `bedrooms_from`/`bedrooms_to`, `total_area_from`/`total_area_to` and `days_on_market_from`/`days_on_market_to`.
   - `energy_ratings`, `characteristics` and `types`.
   - Optional filters include `private`, `gross_yield_from`/`gross_yield_to` and `ref_numbers`.

### Detail: `GET /api/v1/properties/search/{property_id}`

5. Fetch one property with its full history when a user opens it. See [the operation's page](/docs/rest/property-sourcing/get-property-by-id-v1).

### Share: `POST /api/v1/properties/smart-links` from primary_listing_ids

6. Send the selected properties' primary ad ids in `primary_listing_ids`, with `settings`, `user` and `company` as described on [the operation's page](/docs/rest/property-sourcing/create-a-smart-link-beta-v1). The result is a shareable link for a client.

## Example request and response

This example searches 2-bedroom apartments for sale in Lisbon under 400,000.

First resolve Lisbon to a location id:

```http
POST https://api.casafari.com/api/v1/references/locations
Authorization: Bearer <access_token>
Content-Type: application/json

{ "name": "Lisbon" }
```

Then search. Replace `LISBON_LOCATION_ID` with the id returned above, and check accepted values on the [reference page](/docs/rest/property-sourcing/search-properties-v2):

```http
POST https://api.casafari.com/api/v2/properties/search
Authorization: Bearer <access_token>
Content-Type: application/json

{
  "search_operations": ["sale"],
  "location_ids": [LISBON_LOCATION_ID],
  "types": ["apartment"],
  "bedrooms_from": 2,
  "bedrooms_to": 2,
  "price_to": 400000
}
```

A trimmed result for one property is shown below. These are field names Casafari uses in its property records. Values are elided, and the envelope and paging are on the reference page.

```json
{
  "property_id": "...",
  "primary_listing_id": "...",
  "type": "apartment",
  "bedrooms": "...",
  "total_area": "...",
  "energy_rating": "...",
  "sale_status": "...",
  "sale_price": "...",
  "sale_currency": "...",
  "sale_price_per_sqm": "...",
  "rent_status": "...",
  "rent_price": "...",
  "gross_yield": "..."
}
```

## How to read the result

Each result is a property, not an advertisement. Your result count is the number of distinct homes, so you can show it to users as supply without double counting.

### One record per property with sale and rent fields side by side

One record can hold both sale and rent fields.

- **Sale side:** `sale_status`, `sale_price` in the currency given by `sale_currency`, `sale_price_base` in euros, and `sale_price_per_sqm`.
- **Rent side:** the same set with `rent_` in place of `sale_`, plus `rent_period`.
- **Yield:** `gross_yield` is the gross yield in percent, which helps investors shortlist.

Use the `_base` fields when you compare prices across currencies.

### Deprecated fields: `floor`, `view`, `direction`, `energy_certificate`; use `floors`, `views`, `directions`, `energy_ratings`

The singular fields `floor`, `view`, `direction`, `energy_certificate` and `energy_certificates` are marked deprecated and will be removed in the next major update. Build on `floors`, `views`, `directions` and `energy_ratings`.

The `characteristics` filter changed from an array of strings to an object. Check its shape on the reference page.

## Limits

Property Sourcing and References are REST operations for Casafari client accounts. They are not offered over MCP. For property search and fetch, self-serve access for new users is coming soon.

The sources give no figures for pricing, quotas, rate limits, refresh frequency or SLAs. Ask Casafari at https://www.casafari.com/. To see what exists over MCP and over REST, read [MCP vs REST API: which to use](/docs/parity).

### v1 and v2 search both exist; the hub documents both

[`POST /api/v1/properties/search`](/docs/rest/property-sourcing/search-properties-v1) and `POST /api/v2/properties/search` are both live and both documented. Their published request fields are the same. The sources give no retirement date for v1.

### Smart links are BETA

`POST /api/v1/properties/smart-links` is marked BETA. Expect its behaviour to change, and keep the link step separate in your code. See also [How do I build on the Casafari REST API?](/docs/faq/build-on-rest) and [How do I authenticate with the Casafari REST API?](/docs/faq/rest-authentication).

## Questions

### Should I use v1 or v2 search?

Both `POST /api/v1/properties/search` and `POST /api/v2/properties/search` exist and the hub documents both, with the same published request fields. The sources give no retirement date for v1 and no list of differences in the responses, so compare the two reference pages before choosing. This guide uses v2 for new integrations; existing v1 integrations keep working with the documented fields.

### How do I authenticate an unattended integration?

Use an API client instead of a password. The account owner creates it in Settings → API Clients on https://docs.api.casafari.com/ and hands over its `client_id` and `client_secret`. Exchange them at `POST https://api.casafari.com/oauth/token` with the client credentials grant and send the `access_token` as a bearer. There is no refresh step: request a new token when it expires or the API answers `401`.

### Can I search by zip code?

Yes, through a location id or a boundary, because the search filters by `location_ids` or `custom_location_boundary`. Send `zip_codes` to `POST /api/v1/references/locations` to get matching location ids. Alternatively, call `POST /api/v1/references/zipcode-boundary` with `zip_code` and `country_code` and use the returned boundary as a polygon in `custom_location_boundary`.

### Is there a bulk export instead of searching?

Data Export is documented at /docs/data-export: it describes bulk delivery and the fields of each entity, including properties, alerts and locations. It suits teams that want the graph in their own warehouse rather than calling search. The sources publish no terms, pricing or delivery schedule for it; ask Casafari at https://www.casafari.com/.

### Can an MCP assistant call these operations?

Not through the Casafari MCP server: Property Sourcing and References are offered over REST only, and the MCP server has no tool for property search. An AI agent can still call the REST operations directly with a bearer token from `POST /login` or an API client. The page at /docs/parity lists which capabilities exist over MCP and which over REST.

Related: [Deduplicated buyer shortlist from a plain-language brief](/docs/property-sourcing/use-cases/deduplicated-buyer-shortlist-from-a-brief), [Grounded property tool for an AI assistant](/docs/property-sourcing/use-cases/grounded-property-tool-for-an-ai-assistant).

All use cases: [Use cases](/docs/use-cases#property-data).
