# How do I find properties priced below the area's market value?

> **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).

To find properties priced below an area's market value, benchmark the area's asking price per m² with Area Insights (`ma_get_time_series_data`, `ma_get_price_distribution`). Then search Property Sourcing with `POST /api/v2/properties/search` and `price_per_sqm_to` under that benchmark. Confirm each candidate with `comps_get-comparables` by comparing its asking price with `estimated_prices.fair_market_price`. The biggest spread marks the strongest candidate.

Products: [Area Insights](/docs/area-insights), [References](/docs/references), [Property Sourcing](/docs/property-sourcing), [Comparables & Valuation](/docs/comparables-valuation).

## Short answer

Work as a three-step funnel:

1. **Benchmark.** Get the area's average asking price per m² from Area Insights.
2. **Search.** Look in the property graph for properties asking less than that per m², with the type, bedrooms and condition you want.
3. **Confirm.** Run Comparables & Valuation on each candidate. Compare its asking price with `estimated_prices.fair_market_price` from `comps_get-comparables`, and check whether it is flagged `is_outlier`.

The graph keeps one record per property. A property advertised by several agencies and portals counts once in the benchmark and appears once in the search. See [The property graph](/docs/property-graph).

## Steps

### Benchmark: ma_get_time_series_data with avg_price_psqm (latest period) and ma_get_price_distribution

1. Resolve the place name with `ma_get_location_typeahead`. The `location_name` must be in English, for example `Lisbon`. When several places share a name, pick the right `location_id` from `breadcrumbs` and `administrative_level`.
2. Call `ma_get_time_series_data` with these `request_data` fields:
   - `type_group`: `apartment` or `house`
   - `business_type`: `sale`
   - `alias`: a name for the segment
   - `custom_location_boundary`: `location_ids` (1 to 10 ids) or a `circle` (`distance` in meters, 50 to 50000)
   - `data_point`: `avg_price_psqm`
   - `date_interval`: for example `month`
   - `date_range.min`

   Add `bedrooms_range` and `conditions` to match the segment you will search. The `value` of the latest `date_start` is your benchmark.
3. Call `ma_get_price_distribution` with the same boundary and filters. Each bucket returns `lower_bound`, `upper_bound`, `properties_count` and `is_mean`. Together they show how total prices spread and which bucket holds the mean, so you can tell whether the cheap end of the area is thin or crowded.

### Search: POST /api/v2/properties/search with location_ids and price_per_sqm_to below the benchmark, plus type, bedrooms and condition

4. Call `POST /api/v2/properties/search` with:
   - `search_operations`: sale
   - `location_ids`: documented as the ids returned by `POST /api/v1/references/locations`, so resolve them there
   - `price_per_sqm_to`: below the benchmark, for example benchmark × 0.85 for 15% under
   - `types`
   - `bedrooms_from` and `bedrooms_to`
   - `conditions`

   Leave `ruin` out of `conditions` so run-down properties do not look like bargains. Other useful filters are `total_area_from`/`total_area_to`, `days_on_market_from`/`days_on_market_to` and `private`. The response schema is on the [operation page](/docs/rest/property-sourcing/search-properties-v2).

### Confirm: comps_get-comparables on each candidate with exclude_outliers false; compare asking price with fair_market_price and look at is_outlier

5. For each candidate, call `comps_get-comparables` with:
   - `location_boundary.circle.target_point`: the candidate's `coordinates` or `address`
   - `distance`: in kilometers. The tool suggests 0.5 to 1 km in urban areas and 2 to 5 km in rural ones.
   - `operation`: `sale`
   - `comparables_types`: types from one type group only
   - `comparables_count`: 1 to 50
   - the candidate's `bedrooms`, `condition`, `floors` and `total_area`
   - `exclude_outliers`: `false`
6. Read `estimated_prices.fair_market_price`, `fair_market_price_per_sqm`, `fast_sell_price` and `out_of_market_price`. Then find the candidate in `results` by `property_id` and read its `is_outlier` and `similarity_score`.

### Sort by the spread

7. For each candidate, compute spread = (`fair_market_price` − asking price) / `fair_market_price`, and sort from largest to smallest.
   - Take the asking price from the search response, or from `sale_price` if the candidate appears in the comparables `results`.
   - Keep `casafari_link` (the Comparative Market Analysis page) and `valuation_id` (persistent, expires in a year) for your shortlist.

## Example: apartments in Lisbon under the area price per m²

A person asks their assistant: *"Find 2 to 3-bedroom apartments in Lisbon asking at least 15% under the area price per m², and leave out ruins."*

The assistant calls `list_servers`, then `ma_get_location_typeahead` with `Lisbon`. It then calls `ma_get_time_series_data` with `type_group` `apartment`, `business_type` `sale`, `data_point` `avg_price_psqm`, `date_interval` `month` and `bedrooms_range` 2 to 3. Call the latest `value` B. The threshold is T = 0.85 × B. `ma_get_price_distribution` on the same boundary shows how many properties sit in each price bucket.

The search step runs over REST, from your own integration with a Casafari client account:

```json
{
  "search_operations": ["sale"],
  "location_ids": ["<LOCATION_ID>"],
  "types": ["apartment"],
  "price_per_sqm_to": "<T>",
  "bedrooms_from": 2,
  "bedrooms_to": 3,
  "conditions": ["used", "very-good", "new"]
}
```

Replace the placeholders with numbers, and check value formats on the operation page. For each candidate, the assistant then calls `comps_get-comparables`:

```json
{
  "comparables_count": 20,
  "location_boundary": {"circle": {"target_point": {"address": "Avenida da Liberdade, Lisbon"}, "distance": 1}},
  "operation": "sale",
  "comparables_types": ["apartment"],
  "bedrooms": 2,
  "exclude_outliers": false
}
```

If a candidate asks P and `fair_market_price` is F, its spread is (F − P) / F. The assistant ranks candidates by that spread and reports `casafari_link` for each. All figures come from the responses; this page gives no market numbers.

## How to read the result

### Outliers are excluded by default: turn exclude_outliers off on purpose

`exclude_outliers` defaults to true in `comps_get-comparables` and in the Area Insights tools. It removes properties that are significantly underpriced or overpriced compared to similar ones, which are exactly the properties you are hunting.

- **Benchmark:** keep it on, so extreme values do not pull the average.
- **Comparables call:** turn it off, so the candidate stays visible.

A candidate with `is_outlier` `true` is priced far from similar properties. That makes it either a real bargain or a case with a reason behind the price, so verify it before acting.

### A low price may reflect condition, floor or ruin status: read the fields

Before calling a property underpriced, read these fields:

- `condition` (`ruin`, `used`, `very-good`, `new`, `other`)
- `floor_number` and `features.floor` (`no_floor`, `ground`, `middle`, `top`)
- `features.orientation`
- `energy_rating`
- `total_area` against `living_area`
- `features.characteristics`: values such as `rented_out`, `life_annuity` or `no_elevator` can explain a lower asking price that is not a discount to market value

`total_sale_price_change` and `last_sale_price_reduction` show whether the price got there through cuts.

## Limits

### The search step needs a Casafari client account

What each step needs:

- **MCP access:** the Area Insights tools and `comps_get-comparables` are available to Casafari clients with MCP access, using their Casafari account.
- **Casafari client accounts:** `POST /api/v2/properties/search` is a REST operation for Casafari client accounts. It is not offered over Casafari MCP ([details](/docs/faq/properties-over-mcp)).
- Self-serve access for new users is coming soon, for these tools and for the search.

Without it, start from a property you already know (an address, coordinates or, in Spain only, a cadastral reference) and use comparables ([example](/docs/faq/example-valuation)).

Coverage limits:

- The API's permissions list 16 markets.
- The cadastral-reference input of `comps_get-comparables` is Spain only.
- `ma_get_location_typeahead` expects English place names.
- The Area Insights tools take `type_group` `apartment` or `house` only.
- Other tools name no market.

The sources give no figures for pricing, quotas, rate limits or data refresh frequency; ask [Casafari](https://www.casafari.com/).

### The spread is computed by you from the returned fields

No tool returns a discount or spread field: you compute it from the asking price and `estimated_prices`. The estimates are calculated from the comparables found, so they depend on the boundary and filters you set.

The data cannot tell you a property's interior state beyond `condition`, its legal situation, or why the seller asks what they ask. Inspect before you buy.

## Questions

### Can an AI assistant run this whole funnel for me?

An AI assistant connected to Casafari MCP can run the benchmark and the confirmation steps itself, with `ma_get_location_typeahead`, `ma_get_time_series_data`, `ma_get_price_distribution` and `comps_get-comparables`. The search step is `POST /api/v2/properties/search`, which is REST only and not offered over Casafari MCP. Run it from your own integration with a Casafari client account, or give the assistant candidate addresses to check.

### How do I add price cuts as a second signal?

Each `comps_get-comparables` result carries price-cut fields: `total_sale_price_change`, `last_sale_price_reduction` and `sale_price_last_change`. At area level, `ma_get_time_series_data` with `data_point` `price_down` counts price decreases per period. Casafari client accounts can read a property's `sale_price_history` with `GET /api/v1/properties/search/{property_id}`. New Market Leads alert feeds follow price cuts as they happen.

### Can I do this for houses and plots?

You can do this for houses throughout, because the Area Insights tools accept `type_group` `house` and `comps_get-comparables` takes house types such as `villa` or `townhouse`. Plots are only partly supported. The Area Insights MCP tools take `apartment` or `house` only, so there is no plot benchmark there. `comps_get-comparables` accepts `urban_plot` and `rural_plot`, but then requires `plot_area` unless you give a cadastral reference.

### Does fair_market_price account for condition and floor?

`fair_market_price` is calculated from the comparables found, so it reflects condition and floor as far as your request filters the comparable set by them. Pass `condition`, `floors` or `floor_number`, and `characteristics` in the `comps_get-comparables` call to get comparables that match. The docs do not describe how the estimate weights each attribute, so read `similarity_score` on each result.

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