# Create feed

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

`POST https://api.casafari.com/alerts-api/feeds`

[Alerts](/docs/alerts) · [REST API](/docs/rest/alerts). Send `Authorization: Bearer $CASAFARI_TOKEN`; see [how to get a token](/docs/rest#get-a-token).

Over MCP: no tool does this. See [MCP and REST compared](/docs/parity#alerts).

## Description

Create a new alert feed that delivers matching real estate events to your webhook URL.

## Alert Delivery Format

Events are delivered as a **POST** request with a single JSON object body:

```json
{
  "alert_id": 100042,
  "url": "https://www.casafari.com/listing/12345",
  "address": "Rua do Exemplo 12, Lisbon",
  "location": "Lisbon",
  "sale_status": "active",
  "sale_price": 250000,
  "sale_price_psqm": 2500.0,
  "sale_currency": "EUR",
  "rent_status": "none",
  "rent_price": 0,
  "rent_period": "none",
  "rent_price_psqm": 0.0,
  "rent_currency": "EUR",
  "thumbnails": [
    "https://cdn.example.com/thumb1.jpg"
  ],
  "matched_feeds": [
    {
      "feed_id": 42,
      "feed_name": "My Alert Feed"
    }
  ]
}
```

Your server must respond with HTTP **200**. Any other status code is treated as a failure.

## Before You Start: Configure Your Webhook

Feeds deliver to your **per-user webhook URL** — one URL for all feeds, managed separately:

1. `PUT /webhooks` — set your delivery URL (it is probed with a GET and must answer 200)
2. Create feeds — this endpoint returns **409** until the webhook is configured

Changing the URL via `PUT /webhooks` instantly affects all feeds, including already-queued alerts.

## Retry Policy

If your server does not respond with HTTP 200 within **5 seconds**, delivery is retried —
**60 seconds** after the first failure, then every **10 minutes** — until the alert expires
(typically 24h). Feeds are never disabled automatically.

## Authentication of deliveries

Every delivery is signed with [Standard Webhooks](https://www.standardwebhooks.com/): each POST
carries `webhook-id`, `webhook-timestamp`, and `webhook-signature` headers. Verify the
HMAC-SHA256 signature over the raw request body using the secret from `PUT /webhooks`
(rotate it via `POST /webhooks/rotate-secret`).

## Request body

Content type `application/json`. Required. Type: `object`.

- `feed_name` (string, required)
- `filters` (object, required)
  - `location_ids` (integer[], optional, nullable) 1–100 items.
  - `types` (string[], optional, nullable) Values: `apartment`, `studio`, `duplex`, `penthouse`, `dachgeschosswohnung`, `etagenwohnung`, `erdgeschosswohnung`, `country_house`, `house`, `palace`, `townhouse`, `villa`, `country_estate`, `chalet`, `bungalow`, `family_house`, `reihenhaus`, `reihenendhaus`, `reihenmittelhaus`, `einfamilienhaus`, `zweifamilienhaus`, `landwirtschaftliche_betriebe`, `retail`, `office`, `industrial`, `warehouse`, `hotel`, `building`, `other_commercial`, `restaurant`, `werkstatt`, `urban_plot`, `rural_plot`, `room`, `parking`, `garage`, `other`, `apartment_building`, `office_building`, `mix_use_building`, `apartment_development`, `house_development`. at least 1 item.
  - `business_type` (string, required) Values: `sale`, `rent`.
  - `statuses` ((string | string)[], optional, nullable) at least 1 item.
  - `alert_subtypes` (string[], optional, nullable) Values: `new`, `price_increased`, `price_decreased`, `reserved`, `delisted`, `sold`.
  - `custom_locations` (object[][], optional, nullable): List of closed polygons of geo-points to search within. Each polygon must contain at least 4 points. First and last points must match in each polygon. Maximum 4 polygons allowed. 1–4 items; 4–25 items.
    - `latitude` (number, required) -90–90.
    - `longitude` (number, required) -180–180.
  - `private` (boolean, optional, nullable)
  - `price_range` (object, optional, nullable)
    - `min` (integer, optional, nullable) 1–2147483647.
    - `max` (integer, optional, nullable) 1–2147483647.
  - `price_psqm_range` (object, optional, nullable)
    - `min` (integer, optional, nullable) 1–2147483647.
    - `max` (integer, optional, nullable) 1–2147483647.
  - `bathrooms_range` (object, optional, nullable)
    - `min` (integer, optional, nullable) 1–15000.
    - `max` (integer, optional, nullable) 1–15000.
  - `bedrooms_range` (object, optional, nullable)
    - `min` (integer, optional, nullable) 0–15000.
    - `max` (integer, optional, nullable) 0–15000.
  - `total_area_range` (object, optional, nullable)
    - `min` (integer, optional, nullable) 1–1000000.
    - `max` (integer, optional, nullable) 1–1000000.
  - `new_development` (boolean, optional, nullable)
  - `bank` (boolean, optional, nullable)
  - `auction` (boolean, optional, nullable)
  - `construction_year_range` (object, optional, nullable)
    - `min` (integer, optional, nullable) 1–3000.
    - `max` (integer, optional, nullable) 1–3000.
  - `plot_area_range` (object, optional, nullable)
    - `min` (integer, optional, nullable) 1–1000000.
    - `max` (integer, optional, nullable) 1–1000000.
  - `floors` (string[], optional, nullable) Values: `no_floor`, `ground`, `middle`, `top`. at least 1 item.
  - `conditions` (string[], optional, nullable) Values: `new`, `used`, `ruin`, `very-good`, `other`. at least 1 item.
  - `orientation` (string, optional, nullable) Values: `exterior`, `interior`.
  - `views` (string[], optional, nullable): A matching listing must have every requested view, not just one. Values: `water`, `landscape`, `city`, `golf`, `park`. at least 1 item.
  - `directions` (string[], optional, nullable): A matching listing must face every requested direction, not just one. Values: `north`, `south`, `east`, `west`. at least 1 item.
  - `characteristics` (string[], optional, nullable): A matching listing must have every requested characteristic, not just one. Values: `balcony`, `elevator`, `no_elevator`, `garage`, `garden`, `parking`, `storage`, `swimming_pool`, `terrace`, `rental_license`, `furniture`, `rented_out`, `life_annuity`. at least 1 item.
  - `has_phone` (boolean, optional, nullable)
  - `has_email` (boolean, optional, nullable)
  - `has_agency_name` (boolean, optional, nullable)
  - `ref_numbers` (string[], optional, nullable) 1–100 items.
  - `listing_ids` (integer[], optional, nullable) 1–100 items.

## Example request

Placeholders only: replace the token and the values with your own.

```bash
curl -X POST "https://api.casafari.com/alerts-api/feeds" \
  -H "Authorization: Bearer $CASAFARI_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "feed_name": "<feed_name>",
  "filters": {
    "business_type": "sale"
  }
}'
```

## Responses

### 200 Successful Response

Type: `object`.

- `feed_id` (integer, required)
- `feed_name` (string, required)
- `filters` (object, required)
  - `location_ids` (integer[], optional, nullable) 1–100 items.
  - `types` (string[], optional, nullable) Values: `apartment`, `studio`, `duplex`, `penthouse`, `dachgeschosswohnung`, `etagenwohnung`, `erdgeschosswohnung`, `country_house`, `house`, `palace`, `townhouse`, `villa`, `country_estate`, `chalet`, `bungalow`, `family_house`, `reihenhaus`, `reihenendhaus`, `reihenmittelhaus`, `einfamilienhaus`, `zweifamilienhaus`, `landwirtschaftliche_betriebe`, `retail`, `office`, `industrial`, `warehouse`, `hotel`, `building`, `other_commercial`, `restaurant`, `werkstatt`, `urban_plot`, `rural_plot`, `room`, `parking`, `garage`, `other`, `apartment_building`, `office_building`, `mix_use_building`, `apartment_development`, `house_development`. at least 1 item.
  - `business_type` (string, required) Values: `sale`, `rent`.
  - `statuses` ((string | string)[], optional, nullable) at least 1 item.
  - `alert_subtypes` (string[], optional, nullable) Values: `new`, `price_increased`, `price_decreased`, `reserved`, `delisted`, `sold`.
  - `custom_locations` (object[][], optional, nullable): List of closed polygons of geo-points to search within. Each polygon must contain at least 4 points. First and last points must match in each polygon. Maximum 4 polygons allowed. 1–4 items; 4–25 items.
    - `latitude` (number, required) -90–90.
    - `longitude` (number, required) -180–180.
  - `private` (boolean, optional, nullable)
  - `price_range` (object, optional, nullable)
    - `min` (integer, optional, nullable) 1–2147483647.
    - `max` (integer, optional, nullable) 1–2147483647.
  - `price_psqm_range` (object, optional, nullable)
    - `min` (integer, optional, nullable) 1–2147483647.
    - `max` (integer, optional, nullable) 1–2147483647.
  - `bathrooms_range` (object, optional, nullable)
    - `min` (integer, optional, nullable) 1–15000.
    - `max` (integer, optional, nullable) 1–15000.
  - `bedrooms_range` (object, optional, nullable)
    - `min` (integer, optional, nullable) 0–15000.
    - `max` (integer, optional, nullable) 0–15000.
  - `total_area_range` (object, optional, nullable)
    - `min` (integer, optional, nullable) 1–1000000.
    - `max` (integer, optional, nullable) 1–1000000.
  - `new_development` (boolean, optional, nullable)
  - `bank` (boolean, optional, nullable)
  - `auction` (boolean, optional, nullable)
  - `construction_year_range` (object, optional, nullable)
    - `min` (integer, optional, nullable) 1–3000.
    - `max` (integer, optional, nullable) 1–3000.
  - `plot_area_range` (object, optional, nullable)
    - `min` (integer, optional, nullable) 1–1000000.
    - `max` (integer, optional, nullable) 1–1000000.
  - `floors` (string[], optional, nullable) Values: `no_floor`, `ground`, `middle`, `top`. at least 1 item.
  - `conditions` (string[], optional, nullable) Values: `new`, `used`, `ruin`, `very-good`, `other`. at least 1 item.
  - `orientation` (string, optional, nullable) Values: `exterior`, `interior`.
  - `views` (string[], optional, nullable): A matching listing must have every requested view, not just one. Values: `water`, `landscape`, `city`, `golf`, `park`. at least 1 item.
  - `directions` (string[], optional, nullable): A matching listing must face every requested direction, not just one. Values: `north`, `south`, `east`, `west`. at least 1 item.
  - `characteristics` (string[], optional, nullable): A matching listing must have every requested characteristic, not just one. Values: `balcony`, `elevator`, `no_elevator`, `garage`, `garden`, `parking`, `storage`, `swimming_pool`, `terrace`, `rental_license`, `furniture`, `rented_out`, `life_annuity`. at least 1 item.
  - `has_phone` (boolean, optional, nullable)
  - `has_email` (boolean, optional, nullable)
  - `has_agency_name` (boolean, optional, nullable)
  - `ref_numbers` (string[], optional, nullable) 1–100 items.
  - `listing_ids` (integer[], optional, nullable) 1–100 items.

### 409 Webhook is not configured.

Type: `object`.

- `detail` (string, required)

Example from the API description:

```json
{
  "detail": "No webhook configured. Set your delivery URL via PUT /webhooks first."
}
```

### 422 Validation Error

Type: `object`.

- `detail` (object[], optional)
  - `loc` ((string | integer)[], required)
  - `msg` (string, required)
  - `type` (string, required)
  - `input` (any, optional)
  - `ctx` (object, optional)

## Questions about this

- [Can I get alerts (new properties, price cuts, sales) over Casafari MCP?](/docs/faq/alerts-over-mcp)
- [How do I get alerts delivered to a webhook?](/docs/faq/alerts-webhook)
