Every API here is available over the APIs.io API and to AI agents over MCP.
openapi: 3.2.0
info:
title: Casafari Alerts API Feeds API
description: 'The Casafari API provides clients with methods for manipulating alerts feeds, accounts, and consulting a reference
of available locations, features and conditions.
# Authentication methods
-->'
version: 0.1.0
servers:
- url: https://api.casafari.com
tags:
- name: alerts-api---feeds
x-displayName: Feeds
paths:
/alerts-api/feeds:
get:
tags:
- alerts-api---feeds
summary: List feeds
description: Returns a paginated list of feeds, sorted newest first. Follow `next_url` directly to get the next page - it is an opaque URL, do not construct it manually.
operationId: alerts-api__get__feeds
parameters:
- required: false
schema:
anyOf:
- type: string
- type: 'null'
title: Cursor
name: cursor
in: query
- description: Number of feeds to return per page.
required: false
schema:
type: integer
maximum: 100.0
minimum: 1.0
title: Limit
description: Number of feeds to return per page.
default: 20
name: limit
in: query
responses:
'200':
description: Successful Response
content:
application/json:
schema:
$ref: '#/components/schemas/AlertsApiFeedListResponseSchema'
'422':
description: Validation Error
content:
application/json:
schema:
$ref: '#/components/schemas/AlertsApiHTTPValidationError'
security:
- HTTPBearer: []
- OAuth2ClientCredentials: []
post:
tags:
- alerts-api---feeds
summary: Create feed
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": 123456,
"listing_id": 987654321,
"ref": "REF-001",
"alert_type": "sale_price",
"alert_subtype": "price_up",
"old_value": "450000",
"new_value": "470000",
"alert_date_and_time": "2026-06-21T16:33:48",
"property_url": "https://www.casafari.com/home-sale/property-123456",
"url": "https://example.com/listings/123456",
"listing_uid": "listing-uid-123",
"property_id": 123456,
"property_unit_id": 0,
"title": "Beautiful 3 bedroom apartment",
"type": "apartment",
"type_group": "apartment",
"location": {
"location_id": 1,
"name": "Lisbon",
"administrative_level": "city",
"zip_codes": [
"1000-001"
]
},
"locations_structure": [
{
"location_id": 1,
"name": "Lisbon",
"administrative_level": "city",
"zip_codes": []
},
{
"location_id": 2,
"name": "Portugal",
"administrative_level": "country",
"zip_codes": []
}
],
"address": "Rua Example 123",
"zip_code": "1000-001",
"cadastral_reference": "1234567890123",
"coordinates": {
"latitude": 38.7223,
"longitude": -9.1393
},
"condition": "used",
"contacts_info": {
"name": "John Doe",
"email": "john@example.com",
"phone": "+351912345678"
},
"total_area": 120,
"living_area": 100,
"plot_area": 200,
"terrace_area": 15,
"bedrooms": 3,
"rooms": 5,
"bathrooms": 2,
"features": {
"floor": "middle",
"orientation": "exterior",
"views": [
"city"
],
"directions": [
"north"
],
"characteristics": [
"balcony",
"elevator"
]
},
"construction_year": 2015,
"operations": [
"sale"
],
"is_bank_property": false,
"is_auction_property": false,
"is_new_development_property": false,
"is_private_property": true,
"sale_status": "active",
"sale_currency": "EUR",
"sale_price_base": 450000,
"sale_price": 450000,
"sale_price_per_sqm": 3750.0,
"sale_price_per_sqm_base": 3750.0,
"rent_status": "none",
"rent_currency": "EUR",
"rent_price_base": 1500,
"rent_price": 1500,
"rent_price_per_sqm": 12.5,
"rent_price_per_sqm_base": 12.5,
"rent_period": "month",
"agency_legal_id": "PT123456789",
"agency": "Casafari Realty",
"agent": "Jane Smith",
"source_name": "idealista",
"description": "A lovely apartment in the heart of the city.",
"thumbnails": [
"https://img.example.com/thumb1.jpg",
"https://img.example.com/thumb2.jpg"
],
"pictures": [
"https://img.example.com/pic1.jpg",
"https://img.example.com/pic2.jpg"
],
"created_at": "2026-06-21T14:58:05.525958",
"created_at_with_photos": "2026-06-21T14:58:05.525958",
"updated_at": "2026-06-21T14:58:05.525958",
"energy_rating": "B",
"heating_type": "gas",
"available_from": "2026-07-01",
"available_to": "2026-07-01",
"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: 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`).'
operationId: alerts-api__post__feeds
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/AlertsApiCreateAlertFeedRequestSchema'
required: true
responses:
'200':
description: Successful Response
content:
application/json:
schema:
$ref: '#/components/schemas/AlertsApiFeedDetailResponseSchema'
'409':
description: Webhook is not configured.
content:
application/json:
schema:
$ref: '#/components/schemas/AlertsApiErrorDetailSchema'
example:
detail: No webhook configured. Set your delivery URL via PUT /webhooks first.
'422':
description: Validation Error
content:
application/json:
schema:
$ref: '#/components/schemas/AlertsApiHTTPValidationError'
security:
- HTTPBearer: []
- OAuth2ClientCredentials: []
/alerts-api/feeds/{feed_id}:
get:
tags:
- alerts-api---feeds
summary: Get feed
description: Returns the feed configuration in the same format as it was originally created. Filters that were not set at creation time are omitted entirely (not returned as null); filters explicitly set to null are returned as null.
operationId: alerts-api__get__feeds__{feed_id}
parameters:
- required: true
schema:
type: integer
title: Feed Id
name: feed_id
in: path
responses:
'200':
description: Successful Response
content:
application/json:
schema:
$ref: '#/components/schemas/AlertsApiFeedDetailResponseSchema'
'404':
description: Feed not found.
content:
application/json:
schema:
$ref: '#/components/schemas/AlertsApiErrorDetailSchema'
example:
detail: Feed not found.
'422':
description: Validation Error
content:
application/json:
schema:
$ref: '#/components/schemas/AlertsApiHTTPValidationError'
security:
- HTTPBearer: []
- OAuth2ClientCredentials: []
put:
tags:
- alerts-api---feeds
summary: Update feed
description: 'Replaces the feed configuration. The body is the same as for feed creation — both `feed_name` and `filters` are required, and `filters` replaces the previous set entirely: any filter you omit is dropped, not kept. Send the full set every time; `GET /feeds/{feed_id}` returns it in exactly the format this endpoint accepts.
Matching switches to the new filters as soon as the call returns. Alerts already queued for delivery are unaffected and still carry the feed name they matched under.'
operationId: alerts-api__put__feeds__{feed_id}
parameters:
- required: true
schema:
type: integer
title: Feed Id
name: feed_id
in: path
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/AlertsApiCreateAlertFeedRequestSchema'
required: true
responses:
'200':
description: Successful Response
content:
application/json:
schema:
$ref: '#/components/schemas/AlertsApiFeedDetailResponseSchema'
'404':
description: Feed not found.
content:
application/json:
schema:
$ref: '#/components/schemas/AlertsApiErrorDetailSchema'
example:
detail: Feed not found.
'422':
description: Validation Error
content:
application/json:
schema:
$ref: '#/components/schemas/AlertsApiHTTPValidationError'
security:
- HTTPBearer: []
- OAuth2ClientCredentials: []
delete:
tags:
- alerts-api---feeds
summary: Delete feed
description: Permanently removes the feed. No further alerts will be delivered for it.
operationId: alerts-api__delete__feeds__{feed_id}
parameters:
- required: true
schema:
type: integer
title: Feed Id
name: feed_id
in: path
responses:
'200':
description: Successful Response
content:
application/json:
schema:
$ref: '#/components/schemas/AlertsApiSuccessResponseSchema'
'404':
description: Feed not found.
content:
application/json:
schema:
$ref: '#/components/schemas/AlertsApiErrorDetailSchema'
example:
detail: Feed not found.
'422':
description: Validation Error
content:
application/json:
schema:
$ref: '#/components/schemas/AlertsApiHTTPValidationError'
security:
- HTTPBearer: []
- OAuth2ClientCredentials: []
components:
schemas:
AlertsApiHTTPValidationError:
properties:
detail:
items:
$ref: '#/components/schemas/AlertsApiValidationError'
type: array
title: Detail
type: object
title: HTTPValidationError
AlertsApisrc__structures__schemas__ranges__IntRangeSchema__4:
properties:
min:
anyOf:
- type: integer
maximum: 15000.0
minimum: 0.0
- type: 'null'
title: Min
max:
anyOf:
- type: integer
maximum: 15000.0
minimum: 0.0
- type: 'null'
title: Max
type: object
title: IntRangeSchema
AlertsApiCoordinatesDto:
properties:
latitude:
type: number
maximum: 90.0
minimum: -90.0
title: Latitude
longitude:
type: number
maximum: 180.0
minimum: -180.0
title: Longitude
type: object
required:
- latitude
- longitude
title: CoordinatesDto
AlertsApisrc__structures__schemas__ranges__IntRangeSchema__3:
properties:
min:
anyOf:
- type: integer
maximum: 15000.0
minimum: 1.0
- type: 'null'
title: Min
max:
anyOf:
- type: integer
maximum: 15000.0
minimum: 1.0
- type: 'null'
title: Max
type: object
title: IntRangeSchema
AlertsApiFeedSummarySchema:
properties:
id:
type: integer
title: Id
feed_name:
type: string
title: Feed Name
created_at:
type: string
format: date-time
title: Created At
updated_at:
type: string
format: date-time
title: Updated At
type: object
required:
- id
- feed_name
- created_at
- updated_at
title: FeedSummarySchema
AlertsApiErrorDetailSchema:
properties:
detail:
type: string
title: Detail
type: object
required:
- detail
title: ErrorDetailSchema
AlertsApiOperationEnum:
type: string
enum:
- sale
- rent
title: OperationEnum
AlertsApiDirectionEnum:
type: string
enum:
- north
- south
- east
- west
title: DirectionEnum
AlertsApisrc__structures__schemas__ranges__IntRangeSchema__5:
properties:
min:
anyOf:
- type: integer
maximum: 1000000.0
minimum: 1.0
- type: 'null'
title: Min
max:
anyOf:
- type: integer
maximum: 1000000.0
minimum: 1.0
- type: 'null'
title: Max
type: object
title: IntRangeSchema
AlertsApiAlertFeedFiltersSchema:
properties:
location_ids:
anyOf:
- items:
type: integer
type: array
maxItems: 100
minItems: 1
- type: 'null'
title: Location Ids
types:
anyOf:
- items:
$ref: '#/components/schemas/AlertsApiEstateTypeEnum'
type: array
minItems: 1
- type: 'null'
title: Types
business_type:
$ref: '#/components/schemas/AlertsApiOperationEnum'
statuses:
anyOf:
- items:
anyOf:
- $ref: '#/components/schemas/AlertsApiSaleStatusEnum'
- $ref: '#/components/schemas/AlertsApiRentStatusEnum'
type: array
minItems: 1
- type: 'null'
title: Statuses
alert_subtypes:
anyOf:
- items:
$ref: '#/components/schemas/AlertsApiAlertSubtypeEnum'
type: array
- type: 'null'
title: Alert Subtypes
custom_locations:
anyOf:
- items:
items:
$ref: '#/components/schemas/AlertsApiCoordinatesDto'
type: array
maxItems: 25
minItems: 4
type: array
maxItems: 4
minItems: 1
- type: 'null'
title: Custom Locations
description: 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.
private:
anyOf:
- type: boolean
- type: 'null'
title: Private
price_range:
anyOf:
- $ref: '#/components/schemas/AlertsApisrc__structures__schemas__ranges__IntRangeSchema__1'
- type: 'null'
price_psqm_range:
anyOf:
- $ref: '#/components/schemas/AlertsApisrc__structures__schemas__ranges__IntRangeSchema__2'
- type: 'null'
bathrooms_range:
anyOf:
- $ref: '#/components/schemas/AlertsApisrc__structures__schemas__ranges__IntRangeSchema__3'
- type: 'null'
bedrooms_range:
anyOf:
- $ref: '#/components/schemas/AlertsApisrc__structures__schemas__ranges__IntRangeSchema__4'
- type: 'null'
total_area_range:
anyOf:
- $ref: '#/components/schemas/AlertsApisrc__structures__schemas__ranges__IntRangeSchema__5'
- type: 'null'
new_development:
anyOf:
- type: boolean
- type: 'null'
title: New Development
bank:
anyOf:
- type: boolean
- type: 'null'
title: Bank
auction:
anyOf:
- type: boolean
- type: 'null'
title: Auction
construction_year_range:
anyOf:
- $ref: '#/components/schemas/AlertsApisrc__structures__schemas__ranges__IntRangeSchema__6'
- type: 'null'
plot_area_range:
anyOf:
- $ref: '#/components/schemas/AlertsApisrc__structures__schemas__ranges__IntRangeSchema__7'
- type: 'null'
floors:
anyOf:
- items:
$ref: '#/components/schemas/AlertsApiFloorCategoryEnum'
type: array
minItems: 1
- type: 'null'
title: Floors
conditions:
anyOf:
- items:
$ref: '#/components/schemas/AlertsApiConditionEnum'
type: array
minItems: 1
- type: 'null'
title: Conditions
orientation:
anyOf:
- $ref: '#/components/schemas/AlertsApiOrientationEnum'
- type: 'null'
views:
anyOf:
- items:
$ref: '#/components/schemas/AlertsApiViewEnum'
type: array
minItems: 1
- type: 'null'
title: Views
description: A matching listing must have every requested view, not just one.
directions:
anyOf:
- items:
$ref: '#/components/schemas/AlertsApiDirectionEnum'
type: array
minItems: 1
- type: 'null'
title: Directions
description: A matching listing must face every requested direction, not just one.
characteristics:
anyOf:
- items:
$ref: '#/components/schemas/AlertsApiCharacteristicEnum'
type: array
minItems: 1
- type: 'null'
title: Characteristics
description: A matching listing must have every requested characteristic, not just one.
has_phone:
anyOf:
- type: boolean
- type: 'null'
title: Has Phone
has_email:
anyOf:
- type: boolean
- type: 'null'
title: Has Email
has_agency_name:
anyOf:
- type: boolean
- type: 'null'
title: Has Agency Name
ref_numbers:
anyOf:
- items:
type: string
type: array
maxItems: 100
minItems: 1
- type: 'null'
title: Ref Numbers
listing_ids:
anyOf:
- items:
type: integer
type: array
maxItems: 100
minItems: 1
- type: 'null'
title: Listing Ids
additionalProperties: false
type: object
required:
- business_type
title: AlertFeedFiltersSchema
AlertsApiCharacteristicEnum:
type: string
enum:
- balcony
- elevator
- no_elevator
- garage
- garden
- parking
- storage
- swimming_pool
- terrace
- rental_license
- furniture
- rented_out
- life_annuity
title: CharacteristicEnum
AlertsApiFeedListResponseSchema:
properties:
feeds:
items:
$ref: '#/components/schemas/AlertsApiFeedSummarySchema'
type: array
title: Feeds
next_url:
anyOf:
- type: string
- type: 'null'
title: Next Url
type: object
required:
- feeds
title: FeedListResponseSchema
AlertsApisrc__structures__schemas__ranges__IntRangeSchema__1:
properties:
min:
anyOf:
- type: integer
maximum: 2147483647.0
minimum: 1.0
- type: 'null'
title: Min
max:
anyOf:
- type: integer
maximum: 2147483647.0
minimum: 1.0
- type: 'null'
title: Max
type: object
title: IntRangeSchema
AlertsApiViewEnum:
type: string
enum:
- water
- landscape
- city
- golf
- park
title: ViewEnum
AlertsApiOrientationEnum:
type: string
enum:
- exterior
- interior
title: OrientationEnum
AlertsApiRentStatusEnum:
type: string
enum:
- active
- reserved
- rented
- hold
- none
title: RentStatusEnum
AlertsApiCreateAlertFeedRequestSchema:
properties:
feed_name:
type: string
maxLength: 255
minLength: 1
title: Feed Name
filters:
$ref: '#/components/schemas/AlertsApiAlertFeedFiltersSchema'
additionalProperties: false
type: object
required:
- feed_name
- filters
title: CreateAlertFeedRequestSchema
AlertsApiSuccessResponseSchema:
properties:
success:
type: boolean
title: Success
type: object
required:
- success
title: SuccessResponseSchema
AlertsApiValidationError:
properties:
loc:
items:
anyOf:
- type: string
- type: integer
type: array
title: Location
msg:
type: string
title: Message
type:
type: string
title: Error Type
input:
title: Input
ctx:
type: object
title: Context
type: object
required:
- loc
- msg
- type
title: ValidationError
AlertsApisrc__structures__schemas__ranges__IntRangeSchema__7:
properties:
min:
anyOf:
- type: integer
maximum: 1000000.0
minimum: 1.0
- type: 'null'
title: Min
max:
anyOf:
- type: integer
maximum: 1000000.0
minimum: 1.0
- type: 'null'
title: Max
type: object
title: IntRangeSchema
AlertsApiConditionEnum:
type: string
enum:
- new
- used
- ruin
- very-good
- other
title: ConditionEnum
AlertsApisrc__structures__schemas__ranges__IntRangeSchema__6:
properties:
min:
anyOf:
- type: integer
maximum: 3000.0
minimum: 1.0
- type: 'null'
title: Min
max:
anyOf:
- type: integer
maximum: 3000.0
minimum: 1.0
- type: 'null'
title: Max
type: object
title: IntRangeSchema
AlertsApiFloorCategoryEnum:
type: string
enum:
- no_floor
- ground
- middle
- top
title: FloorCategoryEnum
AlertsApisrc__structures__schemas__ranges__IntRangeSchema__2:
properties:
min:
anyOf:
- type: integer
maximum: 2147483647.0
minimum: 1.0
- type: 'null'
title: Min
max:
anyOf:
- type: integer
maximum: 2147483647.0
minimum: 1.0
- type: 'null'
title: Max
type: object
title: IntRangeSchema
AlertsApiAlertSubtypeEnum:
type: string
enum:
- new
- price_up
- price_down
- reserved
- delisted
- sold
title: AlertSubtypeEnum
AlertsApiFeedDetailResponseSchema:
properties:
feed_id:
type: integer
title: Feed Id
feed_name:
type: string
title: Feed Name
filters:
$ref: '#/components/schemas/AlertsApiAlertFeedFiltersSchema'
type: object
required:
- feed_id
- feed_name
- filters
title: FeedDetailResponseSchema
AlertsApiEstateTypeEnum:
type: string
enum:
- 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
title: EstateTypeEnum
AlertsApiSaleStatusEnum:
type: string
enum:
- active
- reserved
- sold
- hold
- none
title: SaleStatusEnum
securitySchemes:
HTTPBearer:
type: http
description: '
Sign in with your account: `POST /login` with your email and password returns an `access_token` and a
`refresh_token`. Send the access token as `Authorization: Bearer <access_token>`. When it expires, call
`GET /refresh-token` with `Authorization: Bearer <refresh_token>` for a new access token.
'
scheme: bearer
bearerFormat: JWT
OAuth2ClientCredentials:
type: oauth2
description: "**Recommended.** Create a client in Settings → API Clients and save its ID and secret. The secret is displayed only once, and the client can be used only in the environment where it was created.\n\nExchange the client ID and secret for an access token using HTTP Basic authentication:\n\n```bash\ncurl -X POST 'https://api.casafari.com/oauth/token' \\\n -u 'CLIENT_ID:CLIENT_SECRET' \\\n -d 'grant_type=client_credentials' \\\n -d 'scope=api'\n```\n\nThe access token is valid for 30 minutes. No refresh token is issued, so you must request a new access token when the current one expires.\n\nInclude the access token in API requests using the following header:\n\n```\nAuthorization: Bearer <token>\n```"
flows:
clientCredentials:
scopes:
api: Access to the CASAFARI REST API.
tokenUrl: https://api.casafari.com/oauth/token
x-tagGroups:
- name: User Management
tags:
- user-management---authentication
- name: API
tags:
- api---valuation
- api---alerts
- api---comparables
- api---references
- api---properties
- name: Market Analytics API
tags:
- market-analytics-api---time series
- market-analytics-api---distributions
- market-analytics-api---analysis
- name: Alerts API
tags:
- alerts-api---webhooks
- alerts-api---feeds