Platform

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.The most complete property index in Europe: a deduplicated, cleaned property graph.

How the graph is built

Screen investments · Use case

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

To find properties priced below an area's market value, benchmark the area's asking price per m² with Area Insights (area-insights_get_time_series_data, area-insights_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 comparables_get_comparables by comparing its asking price with estimated_prices.fair_market_price. The biggest spread marks the strongest candidate.

Products: Area Insights, References, Property Sourcing, 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 comparables_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.

Steps

Benchmark: area-insights_get_time_series_data with avg_price_psqm (latest period) and area-insights_get_price_distribution

  1. Resolve the place name with locations_search. 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 area-insights_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 area-insights_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

  1. 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.

Confirm: comparables_get_comparables on each candidate with exclude_outliers false; compare asking price with fair_market_price and look at is_outlier

  1. For each candidate, call comparables_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
  2. 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

  1. 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 locations_search with Lisbon. It then calls area-insights_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. area-insights_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 (new users search with Property Sourcing on the self-serve platform, POST /v1/property-sourcing/searches, a different API with its own fields):

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 comparables_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 comparables_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 is self-serve over REST, not over MCP

What is self-serve, and where:

  • Self-serve over MCP: the Area Insights tools and comparables_get_comparables are on the self-serve Casafari API and MCP Platform. Existing Casafari clients sign up there too; contract clients are set up on the Custom plan. Comparables is self-serve over REST as well as MCP: the platform's REST comparables search takes the same input as comparables_get_comparables and returns the same answer.
  • Over REST: POST /api/v2/properties/search is available to Casafari client accounts; new users have Property Sourcing's own search on the self-serve platform, a different API with its own fields. It is not offered over Casafari MCP (details).

Without REST access, start from a property you already know (an address, coordinates or, in Spain only, a cadastral reference) and use comparables (example).

Coverage limits:

  • The API's permissions list 16 markets.
  • The cadastral-reference input of comparables_get_comparables is Spain only.
  • locations_search 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.

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.

Ask in Claude or ChatGPT

Property Sourcing has an MCP server, https://platform.casafari.com/mcp/property-sourcing, so an assistant can run this from a chat. In Claude or ChatGPT, add a custom connector with that URL; in Claude Code: claude mcp add --transport http casafari-property-sourcing https://platform.casafari.com/mcp/property-sourcing. Sign in with your Casafari Platform account in the browser (a new account starts on the Free plan). Then ask, for example:

Flats in Madrid under €650K, 2+ bedrooms: show each with every agency advertising it and its price history.

The assistant finds the place with locations_search (free), searches with property-sourcing_search (50 tokens a page, property-sourcing_next_page for more), reads each home with property-sourcing_get_property (10 tokens: every agency and portal advertising it and its asking price history) and turns a pasted portal or agency link into its home with property-sourcing_resolve_listing (25 tokens). Prices are asking prices. See Property Sourcing.

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 locations_search, area-insights_get_time_series_data, area-insights_get_price_distribution and comparables_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, as a new user, with Property Sourcing on the self-serve platform, or give the assistant candidate addresses to check.

How do I add price cuts as a second signal?

Each comparables_get_comparables result carries price-cut fields: total_sale_price_change, last_sale_price_reduction and sale_price_last_change. At area level, area-insights_get_time_series_data with data_point price_down counts price decreases per period. Over REST, GET /api/v1/properties/search/{property_id} returns a property's sale_price_history, with a Casafari client account; new users read a property's price history with Property Sourcing on the self-serve platform, and High Potential Seller Leads lists homes with repeated price cuts. 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 comparables_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. comparables_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 comparables_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

Tip: add .md to any URL to read it as Markdown.