# Catastro (`legaltech/catastro`) Actor

Este actor automatiza la búsqueda de notificaciones catastrales publicadas en el Tablón Edictal Único (TEU) del Boletín Oficial del Estado (BOE) y permite consultar los servicios web públicos de la Sede Electrónica del Catastro.

- **URL**: https://apify.com/legaltech/catastro.md
- **Developed by:** [Miguel González](https://apify.com/legaltech) (community)
- **Categories:** Automation
- **Stats:** 8 total users, 2 monthly users, 100.0% runs succeeded, 1 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.00 / 1,000 results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## 🏠 Búsqueda de anuncios de Catastro en el BOE (TEU)

Este actor automatiza la búsqueda de notificaciones catastrales publicadas en el Tablón Edictal Único (TEU) del Boletín Oficial del Estado (BOE) y permite consultar los servicios web públicos de la Sede Electrónica del Catastro.

Está enfocado en detectar comunicaciones del Catastro cuando no ha sido posible la notificación personal al interesado.

### 🧾 ¿Qué hace este actor?

El actor catastro revisa diariamente los anuncios publicados en el TEU del BOE y detecta notificaciones relacionadas con procedimientos catastrales, como:

Comunicaciones–propuesta de resolución

Procedimientos tributarios catastrales

Obligados tributarios

Titulares catastrales

Permite buscar fácilmente si existe alguna notificación publicada en el día actual para una lista de términos que tú indiques.

### 🔍 ¿Qué puedes buscar?

El actor permite buscar por cualquier texto que pueda aparecer en un anuncio del Catastro, por ejemplo:

🆔 NIF / DNI

🏢 Titulares catastrales

📄 Números de expediente

🧾 Números de documento

🏘️ Municipios

👤 Nombres de personas físicas

🏛️ Empresas o entidades

### 💡 ¿Por qué usar este actor?

Las notificaciones catastrales tienen efectos legales importantes, y muchas veces pasan desapercibidas porque se publican únicamente en el BOE.

Este actor te ahorra revisar manualmente el TEU todos los días.

#### Casos de uso habituales

🏛️ Gestorías y despachos profesionales
Monitoriza automáticamente las notificaciones catastrales de todos tus clientes.

🏠 Propietarios e inversores inmobiliarios
Detecta comunicaciones del Catastro antes de que generen sanciones o liquidaciones.

🧑‍⚖️ Abogados y asesores fiscales
Controla expedientes catastrales y propuestas de resolución en tiempo real.

#### 🤖 Automatización de avisos

Integra el actor con Zapier, Make o n8n para:

Enviar emails automáticos

Crear tareas

Enviar alertas a Slack o Teams

### 🚀 ¿Cómo se utiliza?

Buscar anuncios catastrales en el BOE es muy sencillo:

Haz clic en Try for free

Introduce tus términos de búsqueda en el campo searchTerms

Haz clic en Run

Cuando termine la ejecución, revisa la pestaña Dataset para ver o descargar los resultados

### 📝 Parámetros de Entrada

Parámetro	Tipo / Ejemplo	Descripción
searchTerms (Requerido)	\["01398642N", "MADRID", "455022.33/25"]	Lista de NIFs, nombres, municipios, nº de expediente o cualquier texto a buscar en los anuncios
timezone (Opcional)	"Europe/Madrid"	Zona horaria para asegurar la búsqueda por fecha correcta. Por defecto: Europe/Madrid
diasAtras (Opcional)	30	Amplía la búsqueda a los últimos N días además de hoy. Sin este campo se busca sólo el día actual
fechaDesde / fechaHasta (Opcional)	"2026-08-01" / "2026-09-09"	Ventana concreta en formato AAAA-MM-DD. Alternativa a `diasAtras` (no se pueden combinar). `fechaHasta` es opcional y por defecto es hoy
maxResultadosPorTermino (Opcional)	200	Presupuesto de anuncios por término. Por defecto 200, máximo 2000
extraerTexto (Opcional)	true	Descarga el PDF de cada anuncio y extrae su texto completo y las entidades que contiene. **Activado por defecto**; ponlo a false para quedarte sólo con el listado
maxTextosPorRun (Opcional)	50	Máximo de PDFs descargados por ejecución, repartido entre todos los términos. Por defecto 50, máximo 500
guardarPdf (Opcional)	true	Archiva además el PDF firmado de cada anuncio encontrado en la búsqueda. Desactivado por defecto
descargarNotificaciones (Opcional)	\["https://www.boe.es/boe/_n/dias/2026/08/12/not.php?id=BOE-N-2026-615482"]	Operación independiente: descarga y archiva el PDF de anuncios concretos, sin necesidad de buscar

#### 📥 Ejemplo de entrada

{
"searchTerms": \[
"12345678N",
"MADRID",
"455022.33/25"
],
"timezone": "Europe/Madrid",
"diasAtras": 30
}

### 🗓️ Ventana de búsqueda

Por defecto el actor busca **sólo en el día actual**, que es el uso normal: una ejecución diaria que avisa de lo que se ha publicado hoy. Con `diasAtras` o con `fechaDesde`/`fechaHasta` se puede consultar hacia atrás — útil para recuperar un día perdido si un run falló, o para comprobar si a alguien le notificaron algo durante el último trimestre.

El filtro de fecha del formulario del TEU tiene dos extremos (`dato[4][0]` y `dato[4][1]`), así que **una ventana entera se resuelve con la misma única petición HTTP que un solo día**: ampliar el rango no multiplica las peticiones al BOE.

El BOE sólo conserva los anuncios del TEU de los últimos **~92 días** — su propio formulario lo declara en el `min` de los campos de fecha. Las fechas anteriores a ese límite, o posteriores a hoy, se recortan automáticamente y el recorte se avisa en el log.

#### Cómo se evita convertir esto en un volcado del TEU

Ampliar la ventana no puede servir para vaciar el tablón, así que hay dos controles, y ninguno de los dos depende de adivinar intenciones:

1. **Presupuesto de resultados por término** (`maxResultadosPorTermino`, 200 por defecto). El BOE publica el número total de coincidencias junto al listado, así que el actor lo comprueba **antes de volcar nada**. Si un término lo supera, en vez de escribir los anuncios escribe una única fila con `busquedaDemasiadoAmplia: true`, el total encontrado y un aviso para afinar la búsqueda. Es el control decisivo: una consulta por NIF o por referencia catastral no se acerca al límite ni mirando el trimestre entero, y una de texto libre sobre una ventana ancha se para sola.
2. **Ventana escalonada según el término.** Un término que es un identificador (NIF, NIE, CIF, referencia catastral de 14/18/20 posiciones o un `BOE-N-…`) designa a una persona o a un inmueble concretos y admite la ventana completa. El texto libre ("AYUNTAMIENTO DE MADRID", "CATASTRO") se limita a **7 días**; el recorte no es silencioso: se avisa en el log y viaja en cada fila como `ventanaAjustada` y `aviso`.

Además, el actor nunca sigue los enlaces de paginación del BOE (sólo lee la primera página), pide el escalón de `page_hits` más pequeño que cubra el presupuesto en vez del máximo de 2000, y deja una pausa entre términos.

### 📊 Resultados

Cada anuncio del TEU se devuelve con `terminoBuscado`, `fecha`, `fechaDesde`, `fechaHasta`, `suplemento`, `publicador`, `descripcion`, `pdfUrl`, `pdfReferencia` e `identificador` (el código `BOE-N-AAAA-NNNNNN`, estable, útil para deduplicar entre ejecuciones). **Un término sin coincidencias no deja fila.** El dataset contiene anuncios y nada más, que es lo que esperan las integraciones ya montadas: se pueden recorrer las filas y avisar por cada una sin filtrar antes. A cambio, "no había anuncios" y "falló la búsqueda" no se distinguen mirando sólo el dataset: eso se ve en el status message del run (`TEU: N/M términos procesados`, que además indica los fallidos) y en el log.

`fecha` es la **fecha real de publicación del anuncio**, leída de la línea del suplemento, no la fecha en la que se lanzó la búsqueda: en una ventana de varios días cada fila lleva la suya. `fechaDesde` y `fechaHasta` describen la ventana que se consultó realmente para ese término (ya recortada, si se recortó).

Una búsqueda del TEU devuelve como mucho 2000 anuncios por término. Si el BOE informase de más coincidencias de las listadas, las filas se marcan con `resultadosTruncados` y `totalResultadosDisponibles`, en vez de recortarse en silencio.

### 📄 Texto de las notificaciones

**Activado por defecto.** El actor no se queda en el titular del listado: descarga cada anuncio y añade su **texto completo** en el campo `texto`, junto con `numPaginas`. Para volver al comportamiento de sólo-listado, `extraerTexto: false`.

Son campos **nuevos**: ninguno de los que ya devolvía el actor cambia de nombre ni de valor, así que una integración existente (Make, n8n, Zapier) sigue funcionando sin tocar nada — sólo recibe más datos por fila.

El enlace "PDF" del listado del TEU no lleva a una página HTML: devuelve directamente el **PDF firmado** del anuncio (`application/pdf`, ~200 KB). No existe versión en texto ni en XML — el TEU no está en la API de datos abiertos del BOE —, así que el cuerpo del anuncio se obtiene leyendo la capa de texto del PDF con [`unpdf`](https://github.com/unjs/unpdf) (pdf.js puro en JavaScript, sin dependencias nativas).

#### Entidades extraídas del texto

El listado del TEU no dice a qué inmueble afecta un anuncio; el cuerpo sí. Del texto se sacan automáticamente:

| Campo | Qué es |
| --- | --- |
| `referenciasCatastrales` | Referencias catastrales citadas en el anuncio (14, 18 o 20 posiciones), en orden de aparición |
| `nifs` | NIF, NIE y CIF que aparecen en el texto |
| `csv` | Código Seguro de Verificación, para comprobar el documento en la sede electrónica |
| `idNotificacion` | Identificador interno de la notificación (`N26…`) |

Las `referenciasCatastrales` se pueden encadenar directamente con las operaciones de Catastro de este mismo actor (`refCat`, `parcelGeometry`, `colindantes`): se pasa de "hay un anuncio que te menciona" a "estas son las parcelas afectadas y sus datos catastrales".

#### Coste y caché

Cada texto son ~200 KB descargados del BOE, así que la función está acotada por partida doble:

- Sólo se descargan los PDFs de anuncios que **ya han pasado el presupuesto por término**: una búsqueda demasiado amplia no descarga ni un PDF.
- `maxTextosPorRun` (50 por defecto) limita las descargas de todo el run, repartidas entre todos los términos. Las filas que se quedan fuera lo indican con `textoNoExtraido`.

Los textos extraídos se guardan en el key-value store con nombre **`teu-notificaciones`**, usando el identificador del BOE como clave. Como ese identificador es estable, **un anuncio ya leído no se vuelve a descargar nunca**, ni siquiera en ejecuciones posteriores: en un actor que corre a diario, es lo que más carga le ahorra al BOE. Los textos servidos desde la caché no consumen `maxTextosPorRun`.

Con `guardarPdf: true` se archiva además el PDF original en ese mismo store, como `<identificador>.pdf`. El PDF del TEU va firmado electrónicamente y es el documento con valor probatorio, pero el BOE lo retira a los ~92 días: esto deja una copia permanente con URL propia.

Si un PDF concreto no se puede leer, la fila se conserva igual con el resto de campos y un `errorTexto` explicando el motivo: un documento ilegible no invalida el anuncio. La librería de PDF se carga de forma perezosa y sólo dentro de esa protección, de modo que ni siquiera un fallo al cargarla puede tumbar un run que sólo quería el listado.

### 📥 Descargar el PDF de una notificación concreta

`descargarNotificaciones` es una **operación independiente**: no necesita búsqueda. Se le indican los anuncios que quieres y el actor descarga su PDF firmado, lo archiva en el key-value store `teu-notificaciones` y devuelve su enlace permanente (`pdfAlmacenado`) junto con el texto y las entidades.

```json
{
  "descargarNotificaciones": [
    "https://www.boe.es/boe_n/dias/2026/08/12/not.php?id=BOE-N-2026-615482",
    { "identificador": "BOE-N-2026-684298", "fecha": "2026-09-09" }
  ]
}
```

Cada elemento admite tres formas: la `pdfUrl` como texto suelto, `{"pdfUrl": "..."}`, o el par `{"identificador", "fecha"}`. Las tres salen tal cual de las filas del listado, así que encadenar "busca hoy" → "descárgame los PDFs" desde un flujo externo es mapeo directo.

**La fecha es obligatoria junto al identificador**, y no es un capricho del actor: forma parte de la ruta del PDF en el BOE (`/boe_n/dias/AAAA/MM/DD/not.php?id=…`), las variantes sin fecha devuelven 404, y el buscador del TEU no indexa el identificador (buscarlo como término da cero resultados). Un identificador suelto se rechaza con un mensaje que lo explica, en vez de fallar con un 404 opaco.

Un anuncio ya archivado no se vuelve a pedir al BOE: la fila sale de la caché marcada con `desdeCache`. Las filas de esta operación llevan `tipoResultado: "notificacion"`, así que se distinguen de las del listado con un filtro.

#### Cómo consulta el TEU este actor

El formulario del TEU es `method="GET"`, así que la vía normal es **una única petición HTTP** por término: sin navegador, sin arrancar Chromium. Si esa petición falla o el BOE devuelve algo que no es la página esperada (mantenimiento, bloqueo, un futuro requisito de JavaScript o cookies), el actor **recurre automáticamente a Playwright** solo para los términos afectados, rellenando el formulario en un navegador real. El campo `viaConsulta` de cada fila indica cuál se usó (`http` o `navegador`).

Ambas vías comparten el mismo parser **y la misma decisión de volcado**, así que producen exactamente los mismos campos y aplican el mismo presupuesto por término: si el control de volumen viviese sólo en la vía HTTP, bastaría con que el BOE fallase una petición para saltárselo. Playwright se importa de forma dinámica: en un run normal ni siquiera se carga.

También admite consultas directas a la API pública mediante `catastroQueries`. Este campo es opcional y puede combinarse con `searchTerms` o utilizarse de forma independiente.

```json
{
  "catastroQueries": [
    {
      "operation": "refCat",
      "parameters": {
        "RefCat": "2749704YJ0624N0001DI"
      }
    }
  ]
}
```

Operaciones disponibles: `province`, `municipality`, `municipalityCodes`, `via`, `viaCodes`, `number`, `numberCodes`, `location`, `locationCodes`, `refCat`, `refCatCodes`, `parcel`, `parcelCodes`, `coordinatesToRef`, `nearby`, `refToCoordinates`, `colindantes`, `parcelGeometry`.

La respuesta de cada consulta incluye `tipoResultado`, `operacion`, `parametros`, `url` y `respuesta`. Los errores remotos se devuelven en `error` y no cancelan las consultas siguientes.

#### Errores que Catastro devuelve con HTTP 200

Catastro responde HTTP 200 aunque la consulta falle por motivos de negocio (RC mal formada o inexistente, coordenadas sin parcela, etc.): el error viaja dentro del cuerpo como `control.cuerr` + `lerr`, en una ruta que además cambia según la operación. El actor lo detecta y lo expone en **`errorCatastro`**, en el primer nivel del resultado, sin tocar la respuesta original:

```json
{
  "operacion": "refCat",
  "errorCatastro": "[3] LA REFERENCIA CATASTRAL DEBE TENER 14,18 o 20 POSICIONES",
  "respuesta": { "consulta_dnprcResult": { "control": { "cuerr": 1 }, "lerr": [ ... ] } }
}
```

Estas consultas se contabilizan aparte en el mensaje de estado del run (`Catastro: N ok, M sin resultado`): no son un fallo del actor, pero tampoco un resultado aprovechable.

Durante sus ventanas de mantenimiento, Catastro llega a responder **HTTP 200 con un XML de aviso** en endpoints `/json/`. El actor rechaza cualquier respuesta que no sea JSON y la reporta en `error`, en vez de dejar que ese cuerpo se cuele como dato válido.

#### RefCat de 14, 18 o 20 posiciones

La mayoría de operaciones (`refCat`, `refCatCodes`, `location(Codigos)`, `parcel(Codigos)`, `coordinatesToRef`) aceptan la referencia catastral completa (18 o 20 posiciones, con cargo/finca y dígitos de control) o solo las 14 primeras. **`refToCoordinates` es la excepción**: el servicio remoto (`Consulta_CPMRC`) solo admite 14 posiciones y devuelve el error 18 si se le pasa la RC completa. El actor lo detecta y **trunca automáticamente** a los primeros 14 caracteres, así que puedes pasarle la RC tal cual venga de un recibo del IBI o de otra consulta.

#### `nearby`: el parámetro `Distancia` no existe

El servicio real (`Consulta_RCCOOR_Distancia`) no admite ningún parámetro de radio: cualquier `Distancia` que se envíe se ignora en silencio. El radio efectivo es fijo (~25 m) y solo entra en juego cuando el punto consultado no cae dentro de ninguna parcela; si cae dentro de una, `nearby` devuelve solo esa parcela con `dis: 0`. Para explorar un radio mayor hay que muestrear varios puntos por separado — que es justo lo que hace `colindantes` (ver más abajo).

#### Parcelas colindantes (aproximadas)

Catastro no expone una operación oficial de parcelas limítrofes. `colindantes` es una operación **compuesta y no oficial** que el actor reconstruye internamente en una sola llamada:

1. Consulta `refCat` para leer la superficie de la parcela y elegir un radio de muestreo razonable. Usa la superficie **gráfica** del recinto (`finca.dff.ss`), que es la que describe su tamaño real; la superficie *de uso* (`sfc`) solo se emplea si la respuesta no trae la gráfica, y el campo `origenSuperficie` del resultado indica cuál se ha usado.
2. Consulta `refToCoordinates` para obtener el centroide.
3. Lanza varias consultas `nearby` reales en un anillo de puntos alrededor del centroide (8-16 según el tamaño de la parcela) y deduplica las referencias catastrales devueltas, descartando la propia parcela.

```json
{
  "catastroQueries": [
    {
      "operation": "colindantes",
      "parameters": { "RefCat": "1784401VK4718D" }
    }
  ]
}
```

`radios` (array de metros) y `sectores` son opcionales e **independientes entre sí**: si no se indican se calculan a partir de la superficie de la parcela, y puedes indicar solo `sectores` para densificar el muestreo manteniendo los radios calculados. El resultado incluye `centro`, `superficieM2`, `origenSuperficie`, la lista `colindantes` (RC, dirección y distancia mínima en metros) y `consultasRealizadas`/`consultasOk`/`consultasError` para saber cuántos puntos del anillo se resolvieron.

`maxResultados` recorta la lista `colindantes` (y solo esa lista), añadiendo `resultadosTruncados` y `totalResultadosDisponibles` con el número real de vecinas encontradas.

**Esto aproxima proximidad, no adyacencia geométrica real**: puede incluir parcelas cercanas que no son colindantes (p. ej. al otro lado de una calle) y puede omitir alguna colindante de frente estrecho si ningún punto del anillo la roza. Para un uso jurídico riguroso (deslindes, notificaciones del art. 199 LH) haría falta geometría real vía el servicio INSPIRE de Catastro (WFS) — ver `parcelGeometry` más abajo, que sí lo cubre para la superficie del recinto (no para la geometría completa del polígono).

#### Enlace directo a la ficha de la Sede Electrónica (`enlaceSede`)

Cuando una consulta (`refCat`, `refCatCodes`, `parcel`, `parcelCodes`, `location`, `locationCodes`, o sus variantes `...Codigos`) devuelve uno o más bienes inmuebles completos, el actor añade automáticamente un campo `enlaceSede` **dentro de cada bien** (junto a sus propios datos en `respuesta`), con la URL que abre su ficha directamente en la Sede Electrónica:

```
https://www1.sedecatastro.gob.es/CYCBienInmueble/OVCConCiud.aspx?del={provincia}&mun={municipio}&UrbRus={R|U}&RefC={referencia de 20 posiciones}&...
```

`{municipio}` es el código de municipio de la **DGC** (`dt.cmc`), no el del **INE** (`dt.loine.cm`): para muchos municipios no coinciden — las capitales de provincia llevan el código DGC `900` (Madrid: INE 79 / DGC 900; Málaga capital: INE 67 / DGC 900) — y usar el del INE lleva la ficha a otro municipio sin dar ningún error. La referencia para comprobarlo es la URL que el propio Catastro devuelve para el mismo inmueble en `finca.infgraf.igraf`.

La referencia catastral **abreviada** (18 posiciones: polígono/parcela + carácter de bien) que devuelve la API no es válida en ese formulario — la Sede exige los 20 caracteres completos (incluye los dos dígitos de control). `enlaceSede` ya construye la referencia de 20 posiciones y decide `UrbRus` a partir de la propia forma de la respuesta (rústico si trae `dt.locs.lors`, urbano si trae `dt.locs.lous`). Si una parcela agrupa subparcelas de distinta naturaleza (p. ej. una agraria y otra residencial, caso real de la parcela 172 del polígono 11 de Nerja), cada bien recibe su propio enlace correcto.

Si a algún bien le falta algún campo necesario (RC incompleta, o una forma de respuesta que no incluya `dt.locs` ni un `luso` reconocible), simplemente no se le añade `enlaceSede`; el resto de la respuesta no se ve afectado.

#### Superficie gráfica de la parcela (`parcelGeometry`)

El resto de operaciones (Callejero/Coordenadas) solo devuelven la superficie **de uso** por bien inmueble (`sfc`: construida o de cultivo). La superficie **gráfica** real del recinto, medida sobre el plano catastral, es una magnitud distinta y solo la expone el servicio INSPIRE de Catastro (Cadastral Parcels, WFS) — no está disponible como campo en `Consulta_DNPRC`/`Consulta_DNPPP`. `parcelGeometry` es una operación adicional que consulta ese WFS directamente:

```json
{
  "catastroQueries": [
    {
      "operation": "parcelGeometry",
      "parameters": { "RefCat": "29075A011001720000EI" }
    }
  ]
}
```

`RefCat` se trunca automáticamente a 14 posiciones (el WFS, igual que `refToCoordinates`, no admite la referencia completa). El resultado incluye `areaGraficaM2` (superficie gráfica del recinto, en la unidad indicada en `unidad`) y, si el servicio la incluye, `etiqueta`. Para la parcela de ejemplo, `areaGraficaM2` es 2798, frente a los 432 m² (190 construidos + 242 de cultivo) que suman las superficies "de uso" de sus dos bienes — **no es un error, son dos magnitudes catastrales distintas**.

El WFS devuelve GML/XML, no JSON: sus errores viajan como `<ExceptionText>` en vez del `control.cuerr`/`lerr` habitual del resto de operaciones de este actor.

### Validación

La batería automatizada se ejecuta con:

```bash
npm test
npm run lint
```

Actualmente cubre la compatibilidad de `searchTerms`, la ejecución solo con Catastro, la construcción de URLs JSON, la normalización de parámetros y el rechazo de operaciones no soportadas.

También se validó una ejecución completa con ambas entradas en el mismo run:

```json
{
  "searchTerms": ["99999999R"],
  "timezone": "Europe/Madrid",
  "catastroQueries": [
    {
      "operation": "refCat",
      "parameters": {
        "RefCat": "29005A002002940000FB"
      }
    }
  ]
}
```

El run procesó la búsqueda TEU sin errores y guardó la respuesta real de Catastro. Si un término no tiene anuncios publicados en la fecha consultada, no se genera resultado TEU; esto no afecta a los resultados de la API de Catastro.

El actor devuelve un objeto por cada coincidencia encontrada.

Si un término no aparece en ningún anuncio, no se genera ningún resultado.

Cada resultado incluye la información relevante del anuncio catastral publicado en el BOE.

Los datos se entregan en un Dataset, listo para:

Descarga en JSON / CSV

Consumo por otros actores

Integración en flujos automatizados

# Actor input Schema

## `searchTerms` (type: `array`):

Introduce la lista de NIFs, referencias catastrales, nombres, etc. que quieres buscar. Por defecto se busca sólo en el día actual; con "diasAtras" o "fechaDesde"/"fechaHasta" se amplía la ventana. Los términos que son un identificador (NIF/NIE/CIF o referencia catastral de 14, 18 o 20 posiciones) admiten la ventana completa; los de texto libre (nombres de organismos, apellidos) se limitan a 7 días para no convertir el actor en un volcado del TEU — la fila resultante lo indica con "ventanaAjustada". El BOE sólo conserva los anuncios del TEU de los últimos ~92 días.

## `timezone` (type: `string`):

Tu zona horaria (ej. 'Europe/Madrid') para asegurar que la búsqueda por fecha se realiza en el día correcto. Si se deja en blanco, se usará UTC.

## `diasAtras` (type: `integer`):

Amplía la búsqueda a los últimos N días además de hoy. 0 (o dejarlo en blanco) busca sólo el día actual, que es el comportamiento por defecto. El TEU sólo conserva los anuncios de los últimos ~92 días, así que ése es el máximo real. No se puede combinar con "fechaDesde"/"fechaHasta".

## `fechaDesde` (type: `string`):

Inicio de la ventana de búsqueda, en formato AAAA-MM-DD. Alternativa a "diasAtras" para consultar un tramo concreto. Si se indica sin "fechaHasta", la ventana llega hasta hoy. Las fechas anteriores a los ~92 días de retención del TEU se recortan automáticamente.

## `fechaHasta` (type: `string`):

Fin de la ventana de búsqueda, en formato AAAA-MM-DD. Requiere "fechaDesde". Si es futura se recorta a hoy.

## `maxResultadosPorTermino` (type: `integer`):

Presupuesto de resultados por término de búsqueda. Por defecto 200 (máximo 2000). El BOE publica el número total de coincidencias junto al listado, así que el actor lo comprueba ANTES de volcar nada: si un término supera el límite, en vez de volcar los anuncios escribe una única fila con "busquedaDemasiadoAmplia": true y el total encontrado, para que afines el término o reduzcas la ventana. Una búsqueda por NIF o por referencia catastral no se acerca a este límite ni consultando el trimestre entero.

## `extraerTexto` (type: `boolean`):

Activado por defecto. Descarga el PDF de cada anuncio encontrado y extrae su texto completo al campo "texto". Además, del texto se sacan las entidades que el listado no da: "referenciasCatastrales", "nifs", "csv" e "idNotificacion" — las referencias catastrales se pueden encadenar directamente con las operaciones de Catastro de este mismo actor. Todos esos campos son NUEVOS: no cambian ni el nombre ni el valor de ninguno de los que ya devolvía el actor, así que una integración existente sigue funcionando igual. Ponlo a false si sólo quieres el listado y prefieres runs más rápidos. Los anuncios ya leídos en ejecuciones anteriores se reutilizan de una caché permanente y no se vuelven a descargar.

## `maxTextosPorRun` (type: `integer`):

Número máximo de PDFs que se descargan en un run, repartido entre todos los términos. Por defecto 50 (máximo 500). Los anuncios servidos desde la caché no consumen este límite. Es el tope que acota lo que un run puede tardar con "extraerTexto" activado.

## `guardarPdf` (type: `boolean`):

Archiva además el PDF original de cada notificación en el key-value store "teu-notificaciones". El PDF del TEU va firmado electrónicamente y es el documento con valor probatorio, pero el BOE lo retira a los ~92 días: esto deja una copia permanente con URL propia. Desactivado por defecto porque son ~200 KB por anuncio. Sólo tiene efecto con "extraerTexto" activado.

## `descargarNotificaciones` (type: `array`):

Operación independiente: descarga el PDF firmado de los anuncios del TEU que se indiquen y lo archiva en el key-value store "teu-notificaciones", devolviendo su enlace permanente y también su texto. No necesita búsqueda: el actor se puede invocar sólo para esto.

Cada elemento puede ser:
• La "pdfUrl" que devuelve el listado, como texto suelto o como {"pdfUrl": "..."} — es la forma más cómoda de encadenarlo con una búsqueda previa.
• El par {"identificador": "BOE-N-2026-615482", "fecha": "2026-08-12"}.

La fecha es obligatoria junto al identificador porque forma parte de la ruta del PDF en el BOE y no se puede deducir del código (el buscador del TEU no indexa el identificador). Los dos campos vienen en cada fila del listado, igual que "pdfUrl".

## `catastroQueries` (type: `array`):

Consultas opcionales a los servicios públicos de Catastro. Puede usarse junto con searchTerms o de forma independiente. Cada elemento usa una operación y sus parámetros oficiales.

## Actor input object example

```json
{
  "searchTerms": [
    "99999999R",
    "2043581VK4724C0001WU",
    "AYUNTAMIENTO DE MADRID"
  ],
  "timezone": "Europe/Madrid",
  "maxResultadosPorTermino": 200,
  "extraerTexto": true,
  "maxTextosPorRun": 50,
  "guardarPdf": false
}
```

# Actor output Schema

## `overview` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "searchTerms": [
        "99999999R",
        "2043581VK4724C0001WU",
        "AYUNTAMIENTO DE MADRID"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("legaltech/catastro").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "searchTerms": [
        "99999999R",
        "2043581VK4724C0001WU",
        "AYUNTAMIENTO DE MADRID",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("legaltech/catastro").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "searchTerms": [
    "99999999R",
    "2043581VK4724C0001WU",
    "AYUNTAMIENTO DE MADRID"
  ]
}' |
apify call legaltech/catastro --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,legaltech/catastro"
        }
    }
}

```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/iKnZls6MLDyPNGkBs/builds/gv4FVGiEsJDJpdopR/openapi.json
