Skip to content

Loading…

List properties

Return the public property catalogue, filtered, sorted and paginated.

GET/v1/ext/properties

Requires the properties:read scope

On this page

Returns a page of the public catalogue and the total number of matching properties. Without filters, it returns every public property, most recently updated first.

Filters

Filters combine with AND and use the same vocabulary as Vestta. operation and city ignore case; the other text filters must match exactly:

FilterMatchExample
operationContains the value, so alquiler also matches venta,alquileroperation=alquiler
typeExact, lowercase keytype=apartamento
subtypeExact, using the subtype keysubtype=atico
cityExact, ignoring casecity=Madrid
statusExactstatus=reservada
rental_typetemporal or anualrental_type=anual
min_bedroomsAt leastmin_bedrooms=2
is_featuredtrue or falseis_featured=true

Note that subtype filters by key (atico) while responses return a display label (Ático).

Prices

min_price, max_price and sort compare the price of the operation you filter by:

  • operation=alquiler → the monthly rent, specs.price_calc.price_alq.
  • operation=traspaso → the transfer price, specs.price_calc.price_trasp.
  • any other value, or no operation → the sale price, price.

So a rental search in Madrid between 800 and 1,200 € per month, cheapest first, is:

Text
GET /v1/ext/properties?operation=alquiler&city=Madrid&min_price=800&max_price=1200&sort=price_asc

Map areas

locations restricts results to areas drawn on a map. It is a JSON array, URL-encoded into the query string. Each element is one area; a property matches if it falls inside any of them. Three shapes are supported:

JSON
[
  { "geometry": { "type": "circle", "center": { "lat": 40.4168, "lng": -3.7038 }, "radius": 1500 } },
  { "geometry": { "type": "polygon", "coordinates": [
    { "lat": 40.43, "lng": -3.71 }, { "lat": 40.43, "lng": -3.68 }, { "lat": 40.41, "lng": -3.69 }
  ] } },
  { "type": "point", "position": { "lat": 39.4699, "lng": -0.3763 }, "radius": 800 }
]
  • Circle — center and radius in metres.
  • Polygon — at least three coordinates; rectangle is accepted as a synonym. Coordinates can also be [lat, lng] pairs, and lon is accepted in place of lng.
  • Point — a position and an optional radius in metres, 500 by default. marker is a synonym.

Areas are matched against the published coordinates: rounded ones for approximate locations, none for hidden ones. Approximate properties can match an area up to about 1 km away from their real position, and properties with a hidden location never match an area. Elements without a recognised geometry — for example { "name": "Madrid" } — are ignored, and so is the whole parameter if it is not valid JSON. The filters.locations field of the response echoes the areas that were applied, so you can check what was understood.

Example request

curl "https://api.vestta.app/v1/ext/properties?limit=20" \
  -H "X-Api-Key: $VESTTA_API_KEY"

Authorization

  • X-Api-Keystringheaderrequired

    Your API key, AC_LIVE_<key_id>.<secret>. Authorization: ApiKey <key> is also accepted.

Query parameters

  • limitinteger≥ 1≤ 1000 default: 100

    Maximum number of properties to return.

  • offsetinteger≥ 0 default: 0

    Number of matching properties to skip before returning results.

  • statusstring

    Exact status match. Only disponible and reservada can match: sold, rented and withdrawn properties are never returned.

  • operationstring

    Operation: venta, alquiler or traspaso. Case-insensitive partial match, so properties offered for several operations match each of them. Also selects which price min_price, max_price and sort use.

  • rental_typestring

    Rental type: temporal for temporary rentals, anual for long-term rentals that are neither temporary nor holiday rentals.

    One oftemporalanual

  • typestring

    Exact property type: apartamento, casa, local, nave, almacenaje, oficina, terreno, aparcamiento or edificio.

  • subtypestring

    Exact subtype key as stored in Vestta, for example atico, duplex, chalet or villa. Responses return the subtype as a display label.

  • citystring

    City name. Case-insensitive exact match.

  • locationsstring

    URL-encoded JSON array of map areas. Supports circle (center + radius in metres), polygon/rectangle (coordinates) and point/marker (500 m default radius). Invalid JSON is ignored.

  • min_pricenumber≥ 0

    Minimum price, inclusive. Uses the rent or transfer price when operation is alquiler or traspaso.

  • max_pricenumber≥ 0

    Maximum price, inclusive. Uses the rent or transfer price when operation is alquiler or traspaso.

  • min_bedroomsinteger≥ 0

    Minimum number of bedrooms, inclusive.

  • is_featuredboolean

    true returns only featured properties; false only non-featured ones.

  • sortstring

    Sort by price (properties without a price go last). When omitted, results are ordered by last update, newest first.

    One ofprice_ascprice_desc

Response

200 Successful response.

Example response
{
  "status": "ok",
  "data": [
    {
      "id": 1355,
      "operation": "traspaso,alquiler",
      "type": "local",
      "subtype": "Local Comercial",
      "title": "Local comercial en el centro",
      "price": 0,
      "size_total": 120,
      "bedrooms": 0,
      "bathrooms": 1,
      "postal_code": "07820",
      "description": "<h2>Características del local</h2><p>Superficie total de 120 m² en planta baja…</p>",
      "images": [
        {
          "id": "63cfd9acfb62c728a6721ca0dd4afdcb_1784627270",
          "is_primary": true,
          "order": 1,
          "url": "https://cdn.vestta.app/images/caa459b11e9f/73121a89c611/63cfd9acfb62c728a6721ca0dd4afdcb_1784627270.jpeg"
        }
      ],
      "videos": [],
      "specs": {
        "address_privacy": "approximate",
        "holiday_renting": false,
        "price_calc": {
          "price_alq": 2000,
          "price_trasp": 25000
        },
        "temporal_renting": false
      },
      "features": [
        {
          "isextra": false,
          "key": "air_conditioning",
          "label": "Aire Acondicionado",
          "value": "Sí"
        }
      ],
      "status": "disponible",
      "address": "San Antonio",
      "city": "San Antonio",
      "province": "Islas Baleares",
      "country": "España",
      "lat": 38.98,
      "lon": 1.3,
      "is_featured": false,
      "created_at": "2026-07-21T11:42:51.820440+02:00",
      "updated_at": "2026-09-26T19:38:41.390976+02:00"
    }
  ],
  "count": 78,
  "limit": 20,
  "offset": 0,
  "filters": {
    "locations": [],
    "operation": "alquiler"
  },
  "authenticated_as": "Inmobiliaria Ejemplo"
}

Response fields

  • statusstringrequired always ok
  • dataarray of objectsrequired

    The requested page of properties.

  • countintegerrequired

    Total number of properties matching the filters, across all pages.

  • limitintegerrequired

    The limit that was applied.

  • offsetintegerrequired

    The offset that was applied.

  • filtersobjectrequired

    Echo of the filters that were applied; null for filters that were not sent. locations contains only the areas that were understood.

  • authenticated_asstring

    Name of the business that owns the API key.

Errors

StatusWhen
401 UnauthorizedThe API key is missing, malformed, unknown, revoked or expired, or lacks the required scope.
422 Unprocessable ContentA path parameter, query parameter or body field is invalid.
500 Internal Server ErrorUnexpected server error while processing the request.

Error bodies and how to handle each case: Errors.