{
  "openapi": "3.1.0",
  "info": {
    "title": "Catastro GPS API",
    "version": "2026-10-01",
    "summary": "Cadastral parcels of Spain and 25 other European countries as a JSON API: reference, coordinates, outline and area; address search in Spain, France and Italy; fincas and dwellings in Spain.",
    "description": "Public API of Catastro GPS / Parcel GPS. Spanish data comes from our own copy of the Dirección General del Catastro (dataSource `clone`/`local_clone`) and, when the copy does not have a finca, from the Catastro live (`catastro`). Attribution to the Dirección General del Catastro is mandatory and is returned in `attribution` where it applies.\n\nQuota: every 2xx response costs 1 unit of the monthly quota, except `GET /api/catastro/{refcat14}/units`, which costs one unit per unit (dwelling) served in that page (minimum 1). 304 Not Modified, 300, 4xx and 5xx responses are free, and so are 2xx answers that carry no data (`disponible: false` from `/market` or `/solar`, an empty `/agro`, a `/score` without data).\n\nError bodies always carry a stable machine code in `code` and an English text in `error`.\n\n## Coverage by country\n\nWhat each country answers today (measured against production on 1 October 2026; address search with five real addresses per country). Every country returns the reference, the GPS point (`latitud`, `longitud`), the outline (`poligono`) and the area (`superficieParcela`), by reference and by coordinates, unless the row says otherwise. `availableFields` in each response says which of the optional fields that response really carries.\n\n| Country | `country` | By reference | By coordinates | By address (`/search/address/candidates`) | Extra data |\n|---|---|---|---|---|---|\n| Spain, common territory | `ES` | yes | yes | yes (CartoCiudad) | address, use, class, built area, year, units/dwellings; `/units` |\n| Spain, Basque Country / Navarre | `PV` / `NA` | yes | yes | yes, with `country=ES` | address, use; no units per finca |\n| France | `FR` | yes | yes | yes (Base Adresse Nationale) | by reference also use, built area, year, dwellings and floors (BDNB) |\n| Italy | `IT` | yes | yes | yes (OpenStreetMap) | municipality, province |\n| Germany (15 of 16 Länder, **no Bavaria**) | `DE` | yes | yes | yes (OpenStreetMap), not in Bavaria | municipality, Land |\n| Austria | `AT` | yes | yes | yes (OpenStreetMap) | municipality, use |\n| Netherlands | `NL` | yes | yes | yes (PDOK Locatieserver) | municipality |\n| Belgium | `BE` | yes | yes (3-7 s, slow source) | yes (Digitaal Vlaanderen + OpenStreetMap), 5-15 s | — |\n| Poland | `PL` | yes | yes | yes (GUGiK) | municipality, voivodeship |\n| Switzerland | `CH` | yes | yes, except where the canton publishes no parcels (e.g. Vaud) | yes (swisstopo) | canton |\n| Czechia | `CZ` | yes | yes | yes (RÚIAN) | — |\n| Denmark | `DK` | yes | yes | yes (Dataforsyningen) | municipality |\n| Norway | `NO` | yes | yes | yes (OpenStreetMap) | municipality |\n| Finland | `FI` | yes | yes | yes (OpenStreetMap) | — |\n| Estonia | `EE` | yes | yes | yes (In-ADS) | municipality |\n| Latvia | `LV` | yes; bare digits need `?country=LV` | yes | yes (OpenStreetMap) | — |\n| Lithuania, Slovenia, Slovakia, Bulgaria | `LT`, `SI`, `SK`, `BG` | yes | yes | yes (OpenStreetMap; Cyrillic accepted in `BG`) | municipality in `SI` |\n| Luxembourg, Liechtenstein, Iceland | `LU`, `LI`, `IS` | yes | yes | yes (OpenStreetMap) | — |\n| Greece | `GR` | only with `?country=GR` | yes | yes (OpenStreetMap; Greek script) | — |\n| Cyprus | `CY` | yes | yes | yes (OpenStreetMap), low `confianza`: few house numbers mapped | — |\n| Portugal | `PT` | yes | partial: the cadastre does not cover Lisbon, Porto or Coimbra | partial, same limit; the DGT source is often down | municipality |\n| Ireland | `IE` | only with `?country=` (the numeric SP_ID) | partial | partial (OpenStreetMap) | county |\n| United Kingdom | `UK` | no | Scotland only | Scotland only (OpenStreetMap) | — |\n| Croatia | `HR` | no | partial | no (422) | municipality |\n| Sweden | `SE` | agricultural blocks | agricultural blocks | no (422): no parcels at urban addresses | land use |\n\nNot covered: Hungary, Romania and the rest. A reference from a country without coverage answers **422 `CNV_COVERAGE`**; bare digits that could belong to several countries answer **300 `CNV_AMBIGUOUS`** with the candidate countries — repeat the call with `?country=`. `/units` and dwellings are Spain only.\n\nThe analysis endpoints (`/solar`, `/agro`, `/score`) cover `ES`, `PV`, `NA`, `PT`, `FR`, `IT` and `DE`; other countries answer 422 `CNV_COVERAGE`. Human-readable coverage and pricing: https://parcelgps.com/developers.",
    "contact": {
      "name": "Catastro GPS",
      "email": "soporte@catastrogps.es",
      "url": "https://parcelgps.com/developers"
    }
  },
  "servers": [
    {
      "url": "https://api.parcelgps.com",
      "description": "Production"
    }
  ],
  "security": [
    {
      "ApiKey": []
    }
  ],
  "tags": [
    {
      "name": "Fincas",
      "description": "Import a building (comunidad de propietarios): address to finca, then all of its units."
    },
    {
      "name": "Parcels",
      "description": "Look a parcel or a unit up by reference or by coordinates."
    },
    {
      "name": "Hazards",
      "description": "Natural hazards and terrain of a parcel measured from satellite data."
    }
  ],
  "paths": {
    "/api/search/address/candidates": {
      "get": {
        "tags": [
          "Fincas"
        ],
        "operationId": "searchAddressCandidates",
        "summary": "Address to parcel in Spain and 25 other European countries, with ranked candidates",
        "description": "Turns a postal address into cadastral parcels, ranked by `confianza` (0 to 1).\n\n- **Spain** (default, `country=ES`): geocodes against CartoCiudad (Instituto Geográfico Nacional) and returns the building entrances (portales) that match, each with its 14-character cadastral reference. Does not depend on the Catastro being up. Candidates in the Basque Country (`pais: PV`) and Navarra (`pais: NA`) carry the foral reference.\n- **Other countries** (`country=FR`, `IT`, `DE`, `AT`, `NL`, `BE`, `PL`, `CH`, `CZ`, `DK`, `NO`, `FI`, `EE`, `LV`, `LT`, `SI`, `SK`, `BG`, `GR`, `CY`, `LU`, `LI`, `IS`, `IE`, `UK`, `PT`): the address is geocoded with the official national address register where there is a free one (France: Base Adresse Nationale; Netherlands: PDOK Locatieserver; Switzerland: swisstopo; Poland: GUGiK; Czechia: RÚIAN; Estonia: In-ADS; Denmark: Dataforsyningen; Flanders: Digitaal Vlaanderen) and with OpenStreetMap (Photon, Nominatim as backup) elsewhere. The parcel under each address point comes from that country's official cadastre, the same source as `/search/coordinates`. In Italy streets and waters (`STRADA…`, `ACQUA…`) are never returned. Sweden and Croatia answer 422: their sources have no parcels at urban addresses.\n\nOutside Spain `confianza` combines the geocoder score with whether the house number, the municipality (or postcode) and the street match: 0.75 or more means the number and the municipality match; when the geocoder only knows the street, `coincideNumero` is false and the parcel is one on that street. Use the reference with `GET /api/catastro/{refcat}` for the outline and area.\n\nCosts 1 quota unit when it returns candidates; 404 (nothing found), 422 and 304 are free.",
        "parameters": [
          {
            "name": "country",
            "in": "query",
            "description": "Country of the address. `ES` (default) also returns Basque Country and Navarra entrances. A country without address search (`SE`, `HR`, or one that is not covered) answers 422 `CNV_COVERAGE` with `data.supportedCountries`.",
            "schema": {
              "type": "string",
              "enum": [
                "ES",
                "FR",
                "IT",
                "DE",
                "AT",
                "NL",
                "BE",
                "PL",
                "CH",
                "CZ",
                "DK",
                "NO",
                "FI",
                "EE",
                "LV",
                "LT",
                "SI",
                "SK",
                "BG",
                "GR",
                "CY",
                "LU",
                "LI",
                "IS",
                "IE",
                "UK",
                "PT"
              ],
              "default": "ES"
            },
            "examples": {
              "FR": {
                "value": "FR"
              },
              "NL": {
                "value": "NL"
              },
              "DE": {
                "value": "DE"
              }
            }
          },
          {
            "name": "q",
            "in": "query",
            "description": "Free-text address: street and number, then municipality (and optionally postcode). Required unless `street` is given. Examples: `Calle Gran Vía 31, Madrid`, `8 boulevard du Port, Amiens`, `Via Toledo 256, Napoli`, `Damrak 1, 1012 LG Amsterdam`, `Floriańska 15, 31-019 Kraków`, `Unter den Linden 77, 10117 Berlin`.",
            "schema": {
              "type": "string",
              "minLength": 3,
              "maxLength": 200
            },
            "example": "Avenida José Rodríguez de la Borbolla Camoyán 10, Dos Hermanas"
          },
          {
            "name": "street",
            "in": "query",
            "description": "Street with its type, when the address is structured.",
            "schema": {
              "type": "string"
            },
            "example": "Calle Gran Vía"
          },
          {
            "name": "number",
            "in": "query",
            "description": "House number. Overrides the number found in `q`.",
            "schema": {
              "type": "integer",
              "minimum": 1
            },
            "example": 31
          },
          {
            "name": "municipality",
            "in": "query",
            "description": "Municipality. Overrides the one found in `q`.",
            "schema": {
              "type": "string"
            },
            "example": "Madrid"
          },
          {
            "name": "postcode",
            "in": "query",
            "description": "Postcode in the country's own format: five digits in Spain, France, Italy, Germany, Finland, Estonia; four in Austria, Belgium, Switzerland, Denmark, Norway, Slovenia, Bulgaria, Cyprus, Liechtenstein, Luxembourg (`L-1660` accepted) and Latvia (`LV-1012` accepted); `1012 LG` in the Netherlands, `31-019` in Poland, `2510-191` in Portugal, `110 00` in Czechia, Slovakia and Greece, UK postcodes and Irish Eircodes. A postcode in another format answers 400.",
            "schema": {
              "type": "string"
            },
            "example": "28013"
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum candidates returned.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 10,
              "default": 5
            }
          },
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "description": "Candidates ordered by confidence (best first).",
            "headers": {
              "X-Quota-Limit": {
                "$ref": "#/components/headers/XQuotaLimit"
              },
              "X-Quota-Remaining": {
                "$ref": "#/components/headers/XQuotaRemaining"
              },
              "X-Quota-Reset": {
                "$ref": "#/components/headers/XQuotaReset"
              },
              "X-Quota-Tier": {
                "$ref": "#/components/headers/XQuotaTier"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/XRateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/XRateLimitRemaining"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControl"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AddressCandidatesResponse"
                }
              }
            }
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "description": "`country` is not one of ES, FR, IT (`CNV_COVERAGE`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/api/catastro/{refcat14}/units": {
      "get": {
        "tags": [
          "Fincas"
        ],
        "operationId": "getFincaUnits",
        "summary": "All units (dwellings, shops, garages, storage) of a finca",
        "description": "Returns every unit of a finca from its 14-character reference, up to 200 per page, ordered by reference. Follow `nextCursor` while `truncated` is true. Served from our copy of the Catastro (`dataSource: clone`); when the copy lacks the finca, or has fewer dwellings than the building declares, it is read live from the Catastro (`dataSource: catastro`). A finca that is a single property (a hotel, a detached house) is returned as one unit with its 20-character reference, and its building elements go in `construcciones`. Costs one quota unit per unit served in the page (minimum 1); a 304 on refresh is free. Requires an organisation API key or a signed-in user. Common territory only: Basque Country and Navarra fincas answer 422.",
        "parameters": [
          {
            "name": "refcat14",
            "in": "path",
            "required": true,
            "description": "14-character finca reference (a 20-character one is cut to 14).",
            "schema": {
              "type": "string",
              "minLength": 14,
              "maxLength": 20
            },
            "example": "0745901TG4304N"
          },
          {
            "name": "cursor",
            "in": "query",
            "description": "`nextCursor` of the previous page (a 20-character reference of the same finca).",
            "schema": {
              "type": "string",
              "pattern": "^[0-9A-Z]{20}$"
            }
          },
          {
            "name": "country",
            "in": "query",
            "description": "Only common territory has units per finca. `PV` and `NA` answer 422 CNV_COVERAGE.",
            "schema": {
              "type": "string",
              "enum": [
                "ES",
                "PV",
                "NA"
              ]
            }
          },
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "description": "One page of units.",
            "headers": {
              "X-Quota-Limit": {
                "$ref": "#/components/headers/XQuotaLimit"
              },
              "X-Quota-Remaining": {
                "$ref": "#/components/headers/XQuotaRemaining"
              },
              "X-Quota-Reset": {
                "$ref": "#/components/headers/XQuotaReset"
              },
              "X-Quota-Tier": {
                "$ref": "#/components/headers/XQuotaTier"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/XRateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/XRateLimitRemaining"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControl"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UnitsResponse"
                }
              }
            }
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "description": "The finca is in the Basque Country or Navarra (code CNV_COVERAGE): their foral cadastres are not served per finca. Free.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/api/catastro/{refcat}": {
      "get": {
        "tags": [
          "Parcels"
        ],
        "operationId": "getParcel",
        "summary": "Parcel or unit by cadastral reference",
        "description": "With a 20-character Spanish reference it returns that unit (dwelling), with the same per-unit fields as the units list: `uso`, `participacion` (number, %), `escalera`, `planta`, `puerta`. `superficieConstruida` here is `superficie` in the units list. The country is detected from the reference format unless `country` is given. Costs 1 quota unit.",
        "parameters": [
          {
            "name": "refcat",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "0745901TG4304N0002KH"
          },
          {
            "name": "country",
            "in": "query",
            "description": "ISO code of the country: ES, PV, NA, FR, IT, DE, AT, PT, PL, NL, CH, BE, CZ, DK, FI, EE, SI, LT, LU, SK, BG, LI, IS, CY, GR, LV, IE, SE. Detected from the reference when omitted; required for GR, LV and IE. Coverage table in the description of this API and at https://parcelgps.com/developers.",
            "schema": {
              "type": "string",
              "minLength": 2,
              "maxLength": 2
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The parcel or unit.",
            "headers": {
              "X-Quota-Limit": {
                "$ref": "#/components/headers/XQuotaLimit"
              },
              "X-Quota-Remaining": {
                "$ref": "#/components/headers/XQuotaRemaining"
              },
              "X-Quota-Reset": {
                "$ref": "#/components/headers/XQuotaReset"
              },
              "X-Quota-Tier": {
                "$ref": "#/components/headers/XQuotaTier"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/XRateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/XRateLimitRemaining"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ParcelResponse"
                }
              }
            }
          },
          "300": {
            "description": "CNV_AMBIGUOUS: bare digits that could be a reference of several countries. `data.candidates` lists them; repeat with `?country=`. Free.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "description": "CNV_COVERAGE: the reference belongs to a country without coverage (`data.country`). CNV_PLACE_NAME: the text is a place name, not a reference. Free.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/api/search/coordinates": {
      "get": {
        "tags": [
          "Parcels"
        ],
        "operationId": "searchByCoordinates",
        "summary": "Parcel at a point (WGS84)",
        "parameters": [
          {
            "name": "lat",
            "in": "query",
            "required": true,
            "schema": {
              "type": "number"
            },
            "example": 40.41998
          },
          {
            "name": "lng",
            "in": "query",
            "required": true,
            "schema": {
              "type": "number"
            },
            "example": -3.70377
          },
          {
            "name": "country",
            "in": "query",
            "description": "ISO code of the country: ES, PV, NA, FR, IT, DE, AT, PT, PL, NL, CH, BE, CZ, DK, FI, EE, SI, LT, LU, SK, BG, LI, IS, CY, GR, LV, IE, HR, UK, SE. Detected from the point when omitted.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The parcel at that point.",
            "headers": {
              "X-Quota-Limit": {
                "$ref": "#/components/headers/XQuotaLimit"
              },
              "X-Quota-Remaining": {
                "$ref": "#/components/headers/XQuotaRemaining"
              },
              "X-Quota-Reset": {
                "$ref": "#/components/headers/XQuotaReset"
              },
              "X-Quota-Tier": {
                "$ref": "#/components/headers/XQuotaTier"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/XRateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/XRateLimitRemaining"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CoordinatesResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      },
      "post": {
        "tags": [
          "Parcels"
        ],
        "operationId": "searchByCoordinatesPost",
        "summary": "Parcel at a point (WGS84), JSON body",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "latitude",
                  "longitude"
                ],
                "properties": {
                  "latitude": {
                    "type": "number"
                  },
                  "longitude": {
                    "type": "number"
                  },
                  "country": {
                    "type": "string",
                    "description": "ISO code of the country: ES, PV, NA, FR, IT, DE, AT, PT, PL, NL, CH, BE, CZ, DK, FI, EE, SI, LT, LU, SK, BG, LI, IS, CY, GR, LV, IE, HR, UK, SE. Detected from the point when omitted."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The parcel at that point.",
            "headers": {
              "X-Quota-Limit": {
                "$ref": "#/components/headers/XQuotaLimit"
              },
              "X-Quota-Remaining": {
                "$ref": "#/components/headers/XQuotaRemaining"
              },
              "X-Quota-Reset": {
                "$ref": "#/components/headers/XQuotaReset"
              },
              "X-Quota-Tier": {
                "$ref": "#/components/headers/XQuotaTier"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/XRateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/XRateLimitRemaining"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CoordinatesResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/api/search/address": {
      "post": {
        "tags": [
          "Parcels"
        ],
        "operationId": "searchByStructuredAddress",
        "summary": "Structured Spanish address to reference (Catastro callejero, live)",
        "description": "Asks the Catastro street index live, so it fails with 404 when the Catastro is saturated. Prefer `GET /api/search/address/candidates`.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "provincia",
                  "municipio",
                  "nombreVia",
                  "numero"
                ],
                "properties": {
                  "provincia": {
                    "type": "string"
                  },
                  "municipio": {
                    "type": "string"
                  },
                  "tipoVia": {
                    "type": "string",
                    "description": "Catastro street type code, e.g. CL, AV, PZ."
                  },
                  "nombreVia": {
                    "type": "string"
                  },
                  "numero": {
                    "type": "integer",
                    "minimum": 1
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The reference at that address.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LegacyAddressResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/api/search/address/parse": {
      "post": {
        "tags": [
          "Parcels"
        ],
        "operationId": "searchByFreeAddress",
        "summary": "Free-text Spanish address to reference (Catastro callejero, live)",
        "description": "Parses the text and asks the Catastro street index live. Prefer `GET /api/search/address/candidates`, which does not depend on the Catastro and returns several candidates.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "direccion"
                ],
                "properties": {
                  "direccion": {
                    "type": "string",
                    "example": "Calle Gran Vía 31, Madrid"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The reference at that address.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LegacyAddressResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/api/catastro/{refcat}/ground-motion": {
      "get": {
        "tags": [
          "Hazards"
        ],
        "operationId": "getGroundMotion",
        "summary": "Ground motion (subsidence or uplift, mm/year) of a parcel, 2020-2024",
        "description": "Satellite-measured vertical and east-west ground velocity over the parcel, its class, the fastest-sinking cell and the yearly displacement, for every country with a parcel outline inside EGMS coverage (EEA-39). Data: Copernicus Land Monitoring Service, European Ground Motion Service (free, commercial use allowed); the `source.attribution` string must be shown next to the data. Costs 1 unit of the monthly quota.",
        "parameters": [
          {
            "name": "refcat",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "0745901TG4304N0002KH"
          },
          {
            "name": "country",
            "in": "query",
            "description": "ISO code of the country: ES, PV, NA, FR, IT, DE, AT, PT, PL, NL, CH, BE, CZ, DK, FI, EE, SI, LT, LU, SK, BG, LI, IS, CY, GR, LV, IE, SE. Detected from the reference when omitted; required for GR, LV and IE. Coverage table in the description of this API and at https://parcelgps.com/developers.",
            "schema": {
              "type": "string",
              "minLength": 2,
              "maxLength": 2
            }
          }
        ],
        "responses": {
          "300": {
            "description": "CNV_AMBIGUOUS: bare digits that could be a reference of several countries. `data.candidates` lists them; repeat with `?country=`. Free.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "description": "CNV_COVERAGE: the reference belongs to a country without coverage (`data.country`). CNV_PLACE_NAME: the text is a place name, not a reference. Free.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          },
          "200": {
            "description": "Ground motion of the parcel, or `status: no_data` with the reason.",
            "headers": {
              "X-Quota-Limit": {
                "$ref": "#/components/headers/XQuotaLimit"
              },
              "X-Quota-Remaining": {
                "$ref": "#/components/headers/XQuotaRemaining"
              },
              "X-Quota-Reset": {
                "$ref": "#/components/headers/XQuotaReset"
              },
              "X-Quota-Tier": {
                "$ref": "#/components/headers/XQuotaTier"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/XRateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/XRateLimitRemaining"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GroundMotionResponse"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "ApiKey": {
        "type": "apiKey",
        "in": "header",
        "name": "X-API-Key",
        "description": "Create keys at https://www.catastrogps.es/app/developer"
      }
    },
    "parameters": {
      "IfNoneMatch": {
        "name": "If-None-Match",
        "in": "header",
        "description": "ETag of a previous response. When nothing changed the answer is 304 with no body and costs no quota.",
        "schema": {
          "type": "string"
        }
      }
    },
    "headers": {
      "XQuotaLimit": {
        "description": "Monthly quota of your plan.",
        "schema": {
          "type": "integer"
        }
      },
      "XQuotaRemaining": {
        "description": "Quota left this month, after this response.",
        "schema": {
          "type": "integer"
        }
      },
      "XQuotaReset": {
        "description": "When the monthly quota resets (ISO 8601, UTC).",
        "schema": {
          "type": "string",
          "format": "date-time"
        }
      },
      "XQuotaTier": {
        "description": "Plan of the organisation.",
        "schema": {
          "type": "string"
        }
      },
      "XRateLimitLimit": {
        "description": "Requests allowed per minute for your key.",
        "schema": {
          "type": "integer"
        }
      },
      "XRateLimitRemaining": {
        "description": "Requests left in the current minute.",
        "schema": {
          "type": "integer"
        }
      },
      "ETag": {
        "description": "Entity tag of the body. Send it back in If-None-Match.",
        "schema": {
          "type": "string"
        }
      },
      "CacheControl": {
        "description": "private, max-age in seconds (6 h for units, 24 h for address candidates).",
        "schema": {
          "type": "string"
        }
      },
      "RetryAfter": {
        "description": "Seconds to wait before retrying.",
        "schema": {
          "type": "integer"
        }
      }
    },
    "responses": {
      "NotModified": {
        "description": "Unchanged since the ETag you sent. No body, no quota spent."
      },
      "ValidationError": {
        "description": "Malformed parameters (code VALIDATION_ERROR).",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Unauthorized": {
        "description": "Missing, malformed or unknown API key (KEY_AUTH_001, KEY_AUTH_002, KEY_AUTH_003, UNAUTHORIZED).",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "NotFound": {
        "description": "The reference or address does not exist (code NOT_FOUND). Never used for outages.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "TooManyRequests": {
        "description": "KEY_AUTH_004: monthly quota spent (see X-Quota-*). KEY_RATE_002 or RATE_LIMIT_EXCEEDED: per-minute limit, wait Retry-After seconds.",
        "headers": {
          "Retry-After": {
            "$ref": "#/components/headers/RetryAfter"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "ServiceUnavailable": {
        "description": "The official source of that country is down or saturated and our copy cannot answer (code SERVICE_UNAVAILABLE). Retry after Retry-After seconds. Free.",
        "headers": {
          "Retry-After": {
            "$ref": "#/components/headers/RetryAfter"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "required": [
          "success",
          "code",
          "error"
        ],
        "properties": {
          "success": {
            "type": "boolean",
            "const": false
          },
          "code": {
            "type": "string",
            "description": "Stable machine code.",
            "examples": [
              "NOT_FOUND",
              "SERVICE_UNAVAILABLE",
              "KEY_AUTH_004"
            ]
          },
          "error": {
            "type": "string",
            "description": "English text for humans. May change; route on `code`."
          }
        }
      },
      "AddressCandidatesResponse": {
        "type": "object",
        "required": [
          "success",
          "data"
        ],
        "properties": {
          "success": {
            "type": "boolean",
            "const": true
          },
          "data": {
            "type": "object",
            "required": [
              "consulta",
              "candidatos",
              "attribution"
            ],
            "properties": {
              "consulta": {
                "type": "object",
                "description": "How the address was read.",
                "properties": {
                  "texto": {
                    "type": "string"
                  },
                  "calle": {
                    "type": "string"
                  },
                  "numero": {
                    "type": "integer"
                  },
                  "municipio": {
                    "type": "string"
                  },
                  "codigoPostal": {
                    "type": "string"
                  }
                }
              },
              "candidatos": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/AddressCandidate"
                }
              },
              "attribution": {
                "type": "string"
              }
            }
          }
        }
      },
      "AddressCandidate": {
        "type": "object",
        "required": [
          "refCatastral",
          "pais",
          "direccion",
          "municipio",
          "provincia",
          "latitud",
          "longitud",
          "confianza",
          "coincideNumero",
          "coincideMunicipio",
          "enCopia"
        ],
        "properties": {
          "refCatastral": {
            "type": "string",
            "description": "Spain: 14-character finca reference in common territory, the foral reference in PV and NA. France: 14-character parcel IDU. Italy: particella reference (Belfiore code, sheet and number, e.g. `F839_019800.166`)."
          },
          "pais": {
            "type": "string",
            "enum": [
              "ES",
              "PV",
              "NA",
              "FR",
              "IT"
            ],
            "description": "ES: common territory, use the units endpoint. PV and NA: foral cadastre, units per finca are not available; look units up with GET /api/catastro/{refcat}?country=PV|NA. FR and IT: look the parcel up with GET /api/catastro/{refcat}?country=FR|IT."
          },
          "direccion": {
            "type": "string",
            "description": "Spain: address as the IGN writes it. France and Italy: the normalised address the geocoder matched."
          },
          "numero": {
            "type": "integer"
          },
          "codigoPostal": {
            "type": "string"
          },
          "municipio": {
            "type": "string"
          },
          "provincia": {
            "type": "string",
            "description": "Province (Spain), département (France) or province (Italy)."
          },
          "latitud": {
            "type": "number",
            "description": "Point of the address (entrance in Spain, address point in France and Italy)."
          },
          "longitud": {
            "type": "number"
          },
          "confianza": {
            "type": "number",
            "minimum": 0,
            "maximum": 1,
            "description": "0.75 or more: number and municipality match."
          },
          "coincideNumero": {
            "type": "boolean"
          },
          "coincideMunicipio": {
            "type": "boolean"
          },
          "enCopia": {
            "type": "boolean",
            "description": "The finca is in our copy of the Catastro (Spain only; always false in France and Italy)."
          },
          "direccionCatastro": {
            "type": "string",
            "description": "Address as the Catastro writes it (when enCopia)."
          },
          "uso": {
            "type": "string"
          },
          "viviendas": {
            "type": "integer",
            "description": "Dwellings the building declares (when enCopia)."
          },
          "anioConstruccion": {
            "type": "integer"
          }
        }
      },
      "UnitsResponse": {
        "type": "object",
        "required": [
          "success",
          "data"
        ],
        "properties": {
          "success": {
            "type": "boolean",
            "const": true
          },
          "data": {
            "$ref": "#/components/schemas/UnitsPage"
          },
          "searchesRemaining": {
            "type": "integer",
            "description": "Daily web searches left; -1 for API keys."
          }
        }
      },
      "UnitsPage": {
        "type": "object",
        "required": [
          "refCatastral",
          "totalUnidades",
          "totalUnidadesFinca",
          "unidades",
          "truncated",
          "dataSource",
          "dataDate",
          "attribution"
        ],
        "properties": {
          "refCatastral": {
            "type": "string"
          },
          "direccion": {
            "type": "string"
          },
          "codigoPostal": {
            "type": "string"
          },
          "municipio": {
            "type": "string"
          },
          "provincia": {
            "type": "string"
          },
          "usoGeneral": {
            "type": "string"
          },
          "superficieTotal": {
            "type": "integer",
            "description": "Sum of the unit areas in this page (m²)."
          },
          "anioConstruccion": {
            "type": "integer"
          },
          "participacion": {
            "type": "string",
            "description": "Finca-level coefficient as text; only meaningful for single-unit fincas. Use the per-unit number."
          },
          "totalUnidades": {
            "type": "integer",
            "description": "Units in this page."
          },
          "totalUnidadesFinca": {
            "type": "integer",
            "description": "Units in the whole finca."
          },
          "unidades": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Unit"
            }
          },
          "construcciones": {
            "type": "array",
            "description": "Building elements of a single-property finca.",
            "items": {
              "$ref": "#/components/schemas/Construction"
            }
          },
          "truncated": {
            "type": "boolean",
            "description": "More pages follow."
          },
          "nextCursor": {
            "type": "string",
            "description": "Pass as `cursor` to get the next page."
          },
          "dataSource": {
            "type": "string",
            "enum": [
              "clone",
              "catastro"
            ]
          },
          "dataDate": {
            "type": "string",
            "format": "date",
            "description": "Catastro publication the rows come from (clone) or the query date (catastro)."
          },
          "attribution": {
            "type": "string"
          }
        }
      },
      "Unit": {
        "type": "object",
        "required": [
          "refCatastral",
          "escalera",
          "planta",
          "puerta",
          "uso",
          "superficie",
          "descripcion"
        ],
        "properties": {
          "refCatastral": {
            "type": "string",
            "description": "20-character unit reference."
          },
          "escalera": {
            "type": "string"
          },
          "planta": {
            "type": "string",
            "description": "Floor as the Catastro writes it (01, 00, -1, OD = whole building…)."
          },
          "puerta": {
            "type": "string"
          },
          "uso": {
            "type": "string",
            "examples": [
              "Residencial",
              "Almacén-Estacionamiento",
              "Comercial"
            ]
          },
          "superficie": {
            "type": "integer",
            "description": "Built area of the unit, m²."
          },
          "descripcion": {
            "type": "string"
          },
          "participacion": {
            "type": "number",
            "description": "Participation coefficient in %, full precision. Absent when the source does not have it."
          },
          "anio": {
            "type": "integer"
          },
          "direccion": {
            "type": "string"
          }
        }
      },
      "Construction": {
        "type": "object",
        "properties": {
          "escalera": {
            "type": "string"
          },
          "planta": {
            "type": "string"
          },
          "puerta": {
            "type": "string"
          },
          "uso": {
            "type": "string"
          },
          "superficie": {
            "type": "integer"
          },
          "descripcion": {
            "type": "string"
          }
        }
      },
      "ParcelResponse": {
        "type": "object",
        "required": [
          "success",
          "data"
        ],
        "properties": {
          "success": {
            "type": "boolean",
            "const": true
          },
          "data": {
            "$ref": "#/components/schemas/Parcel"
          },
          "searchesRemaining": {
            "type": "integer"
          }
        }
      },
      "Parcel": {
        "type": "object",
        "required": [
          "refCatastral",
          "latitud",
          "longitud",
          "googleMapsUrl"
        ],
        "properties": {
          "dataSource": {
            "type": "string",
            "description": "`local_clone` when it came from our copy."
          },
          "refCatastral": {
            "type": "string"
          },
          "pais": {
            "type": "string"
          },
          "direccion": {
            "type": "string"
          },
          "codigoPostal": {
            "type": "string"
          },
          "municipio": {
            "type": "string"
          },
          "provincia": {
            "type": "string"
          },
          "latitud": {
            "type": "number"
          },
          "longitud": {
            "type": "number"
          },
          "googleMapsUrl": {
            "type": "string"
          },
          "uso": {
            "type": "string"
          },
          "clase": {
            "type": "string"
          },
          "superficieConstruida": {
            "type": "integer",
            "description": "Built area (m²). Same value as `superficie` in the units list."
          },
          "superficieParcela": {
            "type": "integer",
            "description": "Plot area (m²)."
          },
          "anioConstruccion": {
            "type": "integer"
          },
          "coefParticipacion": {
            "type": "string",
            "description": "Coefficient rounded to 2 decimals, as text. Kept for compatibility; use `participacion`."
          },
          "participacion": {
            "type": "number",
            "description": "Participation coefficient in %, full precision (20-character references)."
          },
          "escalera": {
            "type": "string"
          },
          "planta": {
            "type": "string"
          },
          "puerta": {
            "type": "string"
          },
          "viviendas": {
            "type": "integer"
          },
          "plantas": {
            "type": "integer"
          },
          "poligono": {
            "type": "array",
            "items": {
              "type": "array",
              "items": {
                "type": "number"
              },
              "minItems": 2,
              "maxItems": 2
            },
            "description": "Outline as [lat, lng] pairs."
          },
          "availableFields": {
            "type": "object",
            "additionalProperties": {
              "type": "boolean"
            }
          }
        }
      },
      "CoordinatesResponse": {
        "type": "object",
        "required": [
          "success",
          "data"
        ],
        "properties": {
          "success": {
            "type": "boolean",
            "const": true
          },
          "data": {
            "type": "object",
            "properties": {
              "referenciaCatastral": {
                "type": "string"
              },
              "refCat14": {
                "type": "string"
              },
              "direccion": {
                "type": "string"
              },
              "codigoPostal": {
                "type": "string"
              },
              "municipio": {
                "type": "string"
              },
              "tipoInmueble": {
                "type": "string"
              },
              "coordenadas": {
                "type": "object",
                "properties": {
                  "latitud": {
                    "type": "number"
                  },
                  "longitud": {
                    "type": "number"
                  }
                }
              },
              "googleMapsUrl": {
                "type": "string"
              },
              "pais": {
                "type": "string"
              }
            }
          },
          "searchesRemaining": {
            "type": "integer"
          }
        }
      },
      "LegacyAddressResponse": {
        "type": "object",
        "required": [
          "success",
          "data"
        ],
        "properties": {
          "success": {
            "type": "boolean",
            "const": true
          },
          "data": {
            "type": "object",
            "properties": {
              "referenciaCatastral": {
                "type": "string"
              },
              "refCat14": {
                "type": "string"
              },
              "direccion": {
                "type": "string"
              },
              "provincia": {
                "type": "string"
              },
              "municipio": {
                "type": "string"
              },
              "tipoVia": {
                "type": "string"
              },
              "nombreVia": {
                "type": "string"
              },
              "numero": {
                "type": "integer"
              },
              "planta": {
                "type": "string"
              },
              "puerta": {
                "type": "string"
              },
              "codigoPostal": {
                "type": "string"
              }
            }
          },
          "searchesRemaining": {
            "type": "integer"
          }
        }
      },
      "GroundMotionResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "data": {
            "$ref": "#/components/schemas/GroundMotion"
          }
        }
      },
      "GroundMotion": {
        "type": "object",
        "description": "Ground motion of the parcel measured by satellite radar (Sentinel-1 InSAR), from the Copernicus European Ground Motion Service (EGMS) L3 Ortho product, 100 m grid, 2020-2024. Velocities are the mean over the 100 m cells whose centre falls inside the parcel outline; when no centre does (parcels under ~1 ha) or there is no outline, the 3 x 3 cells around the parcel point are used and `basis` says `surroundings`. Negative vertical velocity = the ground sinks. Fields with no measurement are left out instead of estimated.",
        "required": [
          "refcat",
          "country",
          "status",
          "period",
          "source",
          "calculated_at"
        ],
        "properties": {
          "refcat": {
            "type": "string"
          },
          "country": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "ok",
              "no_data",
              "unavailable"
            ],
            "description": "`no_data`: there is no measurement for this parcel (see `reason`). `unavailable`: our copy of the data could not be read; retry later."
          },
          "reason": {
            "type": "string",
            "enum": [
              "no_reflectors",
              "outside_coverage",
              "parcel_too_large"
            ],
            "description": "Only with `no_data`. `no_reflectors`: the satellite found no stable reflectors here (fields, forest, water, snow); typical outside towns. `outside_coverage`: the location is outside EGMS coverage (EEA-39). `parcel_too_large`: the outline spans more than 2,500 km2."
          },
          "period": {
            "type": "object",
            "properties": {
              "from": {
                "type": "string",
                "example": "2020-01"
              },
              "to": {
                "type": "string",
                "example": "2024-12"
              },
              "label": {
                "type": "string",
                "example": "2020-2024"
              }
            }
          },
          "ground_motion": {
            "type": "object",
            "properties": {
              "class": {
                "type": "string",
                "enum": [
                  "severe_subsidence",
                  "notable_subsidence",
                  "slow_subsidence",
                  "stable",
                  "slow_uplift",
                  "notable_uplift"
                ],
                "description": "From the mean vertical velocity v (mm/year): v <= -10 severe_subsidence; -10 < v <= -5 notable_subsidence; -5 < v <= -2 slow_subsidence; -2 < v < 2 stable; 2 <= v < 5 slow_uplift; v >= 5 notable_uplift."
              },
              "worst_class": {
                "type": "string",
                "description": "Same scale applied to the fastest-sinking cell."
              },
              "vertical": {
                "type": "object",
                "properties": {
                  "mean_mm_year": {
                    "type": "number"
                  },
                  "max_subsidence_mm_year": {
                    "type": "number"
                  },
                  "max_uplift_mm_year": {
                    "type": "number"
                  },
                  "std_mm_year": {
                    "type": "number"
                  },
                  "acceleration_mm_year2": {
                    "type": "number"
                  },
                  "rmse_mm": {
                    "type": "number"
                  }
                }
              },
              "east_west": {
                "type": "object",
                "description": "Positive = moving east.",
                "properties": {
                  "mean_mm_year": {
                    "type": "number"
                  },
                  "std_mm_year": {
                    "type": "number"
                  }
                }
              },
              "yearly_displacement": {
                "type": "array",
                "description": "Mean vertical displacement of each year relative to January 2020, in mm.",
                "items": {
                  "type": "object",
                  "properties": {
                    "year": {
                      "type": "integer"
                    },
                    "mm": {
                      "type": "number"
                    }
                  }
                }
              },
              "cells_with_data": {
                "type": "integer"
              },
              "cells_considered": {
                "type": "integer"
              },
              "coverage_pct": {
                "type": "number"
              },
              "basis": {
                "type": "string",
                "enum": [
                  "parcel",
                  "surroundings"
                ]
              },
              "cell_size_m": {
                "type": "integer",
                "example": 100
              }
            }
          },
          "source": {
            "type": "object",
            "description": "Name, provider, licence and the attribution that must be shown with the data.",
            "properties": {
              "name": {
                "type": "string"
              },
              "provider": {
                "type": "string"
              },
              "license": {
                "type": "string"
              },
              "attribution": {
                "type": "string"
              },
              "url": {
                "type": "string"
              },
              "resolution": {
                "type": "string"
              },
              "edition": {
                "type": "string"
              }
            }
          },
          "calculated_at": {
            "type": "string",
            "format": "date-time"
          },
          "provenance": {
            "type": "string"
          }
        }
      }
    }
  }
}
