# Cendoj (`legaltech/cendoj`) Actor

Automatiza la búsqueda de jurisprudencia en el CENDOJ. Permite buscar sentencias, autos y acuerdos por término de texto y filtrarlos por jurisdicción, tipo de órgano, tipo de resolución, comunidad autónoma y rango de fechas.

- **URL**: https://apify.com/legaltech/cendoj.md
- **Developed by:** [Miguel González](https://apify.com/legaltech) (community)
- **Categories:** Automation
- **Stats:** 315 total users, 83 monthly users, 92.3% runs succeeded, 9 bookmarks
- **User rating**: 5.00 out of 5 stars

## 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

## 🏛️ Cendoj - Buscador de sentencias

Actor de [Apify](https://apify.com) que automatiza la búsqueda de jurisprudencia en el **CENDOJ** (Centro de Documentación Judicial del Consejo General del Poder Judicial). Permite buscar sentencias, autos y acuerdos por término de texto y filtrarlos por jurisdicción, tipo de órgano, tipo de resolución, comunidad autónoma y rango de fechas.

Para cada resolución encontrada, el actor extrae sus metadatos (ECLI, ROJ, ponente, municipio, número de recurso, etc.), un resumen automático y la URL del PDF oficial. Además, en una segunda ejecución puedes pedirle que **descargue y extraiga el texto completo** de sentencias concretas (campo `pdfUrls`) para analizarlas.

### ✨ Características

- 🔎 Búsqueda por hasta **4 términos** por ejecución (usa operadores booleanos para cubrir más casos dentro de cada término).
- 🔣 Operadores booleanos en el término de búsqueda (`Y`, `O`, `NO`, `PROXn`).
- 🆔 Búsqueda directa **por ECLI o ROJ** para localizar una sentencia concreta.
- 🧰 Filtros avanzados: jurisdicción, tipo de órgano, tipo de resolución, comunidad autónoma y fechas.
- ↕️ Ordenación de resultados (relevancia, fecha, órgano).
- 📄 Extracción de metadatos completos (ECLI, ROJ, ponente, municipio, número de resolución y recurso).
- 📝 Resumen automático de cada sentencia.
- 🔗 URL de descarga del PDF oficial de cada resolución.
- 🔗 Enlace estable "ver sentencia" (`documentUrl`) sin parámetros, ideal para pinchar o compartir.
- 📑 Extracción bajo demanda del **texto completo** de sentencias concretas (campo `pdfUrls`).
- 🔏 **Anonimización automática** de nombres de personas: el campo `ponente` y los nombres detectados en el texto del PDF se sustituyen por sus iniciales.

### 📥 Entrada (Input)

La entrada se define mediante un objeto JSON. Debes indicar **al menos uno** de estos dos campos: `searchTerms` (para buscar jurisprudencia) o `pdfUrls` (para extraer el texto de sentencias concretas).

| Campo | Tipo | Obligatorio | Descripción |
| --- | --- | --- | --- |
| `searchTerms` | `array<string>` | ✅ Uno de los dos | Lista de términos a buscar en la jurisprudencia (**máx. 4**). Usa [operadores booleanos](#-operadores-de-búsqueda) para combinar conceptos dentro de un mismo término en lugar de multiplicar términos. |
| `pdfUrls` | `array<string>` | ✅ Uno de los dos | Lista de URLs de PDF (campo `pdfUrl` de resultados anteriores) de las que extraer el **texto completo** (máx. 50). Úselo en una segunda ejecución tras una búsqueda. Ver [Extracción de texto](#-extracción-de-texto-de-sentencias-concretas). |
| `jurisdictions` | `array<string>` | No | Jurisdicciones: `CIVIL`, `PENAL`, `CONTENCIOSO`, `SOCIAL`, `MILITAR`, `ESPECIAL`. Por defecto, todas. |
| `organoTypes` | `array<string>` | No | Tipos de órgano judicial / Sala (Tribunal Supremo, Audiencia Nacional, Audiencia Provincial, etc.). Por defecto, todos. |
| `resolutionTypes` | `array<string>` | No | Tipos de resolución: `SENTENCIA`, `AUTO` (todos los subtipos), `AUTOADMISION`, `AUTOINADMISION`, `AUTOACLARATORIO`, `AUTOOTROS`, `ACUERDO`. Por defecto, todos. |
| `section` | `string` | No | **Sección** dentro del órgano judicial (ej. Sección 1ª de una Audiencia Provincial). Es un campo **independiente** de `organoTypes`: ese filtra la Sala/tipo de órgano, este filtra la Sección dentro de ella. Por defecto, todas. |
| `admissionAutoSection` | `string` | No | Sección destino del Auto de Admisión del recurso de casación (Sala 3ª TS): `1`(Quinta), `2`(Segunda), `3`(Tercera), `4`(Cuarta). Solo tiene efecto si `resolutionTypes` incluye `AUTOADMISION` (o `AUTO`). Por defecto, todas. |
| `locations` | `array<string>` | No | Comunidades autónomas (ej. `MADRID`, `CATALUÑA`). Por defecto, todas. *Solo aplica en la vía HTTP.* |
| `dateFrom` | `string` | No | Fecha de resolución inicial (`YYYY-MM-DD` o `DD/MM/YYYY`). |
| `dateTo` | `string` | No | Fecha de resolución final (`YYYY-MM-DD` o `DD/MM/YYYY`). |
| `sortOrder` | `string` | No | Criterio de ordenación: `Relevance` (coincidencia, por defecto), `IN_FECHARESOLUCION:increasing` (fecha asc.), `IN_FECHARESOLUCION:decreasing` (fecha desc.), `IN_FECHAENTRADA:numberdecreasing` (lo más nuevo), `IP_TIPOORGANO:alphabetical` (órgano a–z), `IP_TIPOORGANO:reversealphabetical` (órgano z–a). |
| `maxResults` | `integer` | No | Máximo de sentencias por término (1–50). Por defecto, `10`. Con hasta 4 términos por ejecución, máximo 200 resultados. |
| `proxyConfiguration` | `object` | No | Configuración de proxy. Por defecto, proxy residencial de España. |

### 🧮 Operadores de búsqueda

El campo `searchTerms` admite **operadores booleanos** para construir consultas precisas. Puedes escribirlos tanto en su sintaxis nativa de CENDOJ (español) como en la estándar en inglés: el actor traduce automáticamente la versión en inglés a la que entiende el buscador.

| Operador (escribe) | Equivalente CENDOJ | Significado | Ejemplo |
| --- | --- | --- | --- |
| `AND` | `Y` | Ambos términos deben aparecer. | `abogacía AND responsabilidad` |
| `OR` | `O` | Basta con que aparezca uno de los términos. | `"Real Decreto 135/2021" OR "Real Decreto 658/2001"` |
| `NOT` | `NO` | Excluye las resoluciones con ese término. | `costas NOT "Ley 22/1988"` |
| `NEARn` | `PROXn` | Los términos están a menos de `n` palabras de distancia. | `estatuto NEAR5 abogacía` |

Notas:

- Los operadores deben escribirse en **MAYÚSCULAS** como palabra completa; los términos en minúsculas se tratan como texto literal.
- Puedes usar **comillas** para frases exactas: `"condena en costas"`.
- Si escribes directamente los operadores en español (`Y`, `O`, `NO`, `PROX20`), se envían tal cual.
- **Exclusión de frases con `NOT`/`NO`:** el buscador de CENDOJ solo excluye la **palabra inmediatamente siguiente** al operador. Por eso, para excluir una frase de varias palabras, **enciérrala entre comillas**: el actor la expande automáticamente a una exclusión por cada palabra (por ejemplo, `NOT "defectos constructivos"` se envía como `NO defectos NO constructivos`). Las palabras vacías (`de`, `la`, `el`...) se omiten para no vaciar los resultados.

> ⚠️ **No sobre-restrinjas la consulta con demasiadas frases exactas.** Las comillas buscan coincidencia **literal**: si encadenas 3-4 frases entre comillas con `AND`, **todas y cada una** deben aparecer textualmente en el mismo documento, lo que casi siempre da **0 resultados**, incluso sobre temas con mucha jurisprudencia real. Es un error frecuente: parafrasear una doctrina o un artículo en vez de citarlo tal cual aparecería en una sentencia (p. ej. `"actos contrarios a los propios actos"` en vez de la doctrina real, **"doctrina de los actos propios"**; o `"artículo 1258 Código Civil"` sin el `del` que casi siempre lleva: `"artículo 1258 del Código Civil"`). Reglas prácticas:
>
> - Máximo **2 frases exactas entre comillas** por término; el resto de conceptos, como **palabras sueltas** sin comillas.
> - Las frases entre comillas deben ser **citas textuales** previsibles (un artículo de ley con su redacción habitual, el nombre de una norma, una expresión jurídica estándar), nunca un parafraseo propio de un concepto o doctrina.
> - No encadenes más de **2-3 condiciones** (`AND`/`NEARn`/`NOT`) en un mismo término: cada condición adicional reduce drásticamente la intersección de resultados.
> - Ejemplo — ❌ `"validez del ejercicio de opción" AND "burofax" AND "notificación recepticia" AND "requerimiento de compraventa"` (4 frases exactas → 0 resultados) frente a ✅ `"opción de compra" AND burofax AND caducidad`.

#### 🆔 Buscar una sentencia concreta (ECLI o ROJ)

Si sabes **qué sentencia** quieres, no la busques por texto: pon su **ECLI** o su **ROJ** como término de búsqueda.

```json
{ "searchTerms": ["ECLI:ES:TS:2025:2382"] }
{ "searchTerms": ["STS 2382/2025"] }
```

CENDOJ tiene un **campo de formulario dedicado** para cada identificador, distinto del de texto libre. El actor detecta automáticamente de cuál se trata y lo envía al campo correcto. Detalles:

- **ECLI**: se aceptan `ECLI:ES:TS:2025:2382`, `ES:TS:2025:2382` y las formas entrecomilladas.
- **ROJ**: se aceptan `STS 2382/2025`, `ROJ: STS 2382/2025` y las formas entrecomilladas (`SAP B 1234/2020`, `ATIM M 31/2026`, etc.).
- El prefijo (`ECLI:` / `ROJ:`) se elimina antes de enviarlo: CENDOJ **no lo acepta dentro del valor** y devolvería 0 resultados.
- **El resto de filtros se ignoran** (jurisdicción, órgano, tipo de resolución, sección, comunidad, fechas): el identificador ya señala una resolución única, y un filtro que no case con la clasificación interna de CENDOJ dejaría fuera precisamente el documento buscado. Por eso el campo `jurisdiction` de la salida viene a `null` en este modo.
- Devuelve **1 resultado** (o ninguno, si el identificador no existe).

> ⚠️ **Nunca busques un ECLI o un ROJ como texto libre** (entre comillas o combinado con `AND`). Ninguno de los dos está en el índice de texto de CENDOJ: dan **siempre 0 resultados**. Pásalos solos, como término único, y el actor se encarga del resto.

#### 🤖 Uso con Claude Code / MCP de Apify (lenguaje natural)

Este actor está pensado para integrarse en **Claude Code** a través del **MCP de Apify**. La idea es que el usuario describa su necesidad en lenguaje natural y el asistente **construya automáticamente** el valor de `searchTerms` con los operadores adecuados, sin que el usuario tenga que conocerlos.

> 📖 Guía de integración: [Cómo enlazar Claude Code con Apify (MCP)](https://www.legaltechnologybootcamp.com/es/blog/claude-code-apify-mcp-registro-propiedad/).

> ⚠️ **Límite de términos: máximo 4 por ejecución.** Si el actor recibe más de 4 términos, cancela la ejecución con error. La estrategia correcta es **comprimir** la consulta usando operadores booleanos dentro de cada término (un `OR` une variantes, un `AND` exige co-ocurrencia, un `NOT` descarta ruido) en lugar de lanzar un término separado por cada variante o concepto.

Directrices para que el asistente (LLM) genere la query:

- Cuando el usuario quiera **varias alternativas equivalentes** (sinónimos, varias normas, varios nombres), únelas con `OR`.
- Cuando el usuario exija que aparezcan **varios conceptos a la vez**, únelos con `AND`.
- Cuando el usuario quiera **descartar ruido** (un tema, una ley o un sentido no deseado), usa `NOT`. Si lo que se excluye es una **frase de varias palabras**, ponla **entre comillas** (`NOT "defectos constructivos"`) para que el actor la expanda correctamente; de lo contrario CENDOJ solo excluiría la primera palabra.
- Cuando dos conceptos deban referirse **a lo mismo** (estar próximos en el texto), usa `NEARn` (por defecto `NEAR5`–`NEAR10`).
- Encierra entre **comillas** las expresiones de varias palabras que deban buscarse literalmente.
- ⚠️ **No uses más de 2 frases exactas entre comillas por término, ni encadenes más de 2-3 condiciones `AND`/`NEARn`/`NOT`.** Cada frase exacta adicional reduce drásticamente la probabilidad de intersección (ver la nota de arriba). Para cubrir más matices, usa varios `searchTerms` (hasta 4) en vez de sobrecargar uno solo, y reserva las comillas para citas textuales previsibles (artículos de ley, nombres de normas), no para parafraseos de doctrinas o conceptos jurídicos.

Ejemplos de traducción de lenguaje natural a query:

| El usuario pide... | `searchTerms` generado |
| --- | --- |
| "Sentencias sobre gastos hipotecarios pero que no traten de temas penales" | `"gastos hipotecarios" NOT penal` |
| "Obra nueva, pero excluyendo defectos constructivos y derecho de superficie" | `"obra nueva" NOT "defectos constructivos" NOT "derecho de superficie"` |
| "Casos del Real Decreto 135/2021 o del 658/2001" | `"Real Decreto 135/2021" OR "Real Decreto 658/2001"` |
| "Resoluciones sobre responsabilidad del abogado en relación con las costas" | `abogado AND costas` |
| "Que hablen del estatuto de la abogacía, no del de los trabajadores" | `estatuto NEAR5 abogacía` |
| "Validez del ejercicio de una opción de compra notificado por burofax antes de la caducidad del plazo" | ✅ `"opción de compra" AND burofax AND caducidad` — ❌ `"validez del ejercicio de opción" AND "burofax" AND "notificación recepticia" AND "requerimiento de compraventa"` (4 frases exactas, casi seguro 0 resultados) |

#### 🗂️ Mapeo de filtros desde lenguaje natural

Además del término de búsqueda, el asistente debe rellenar automáticamente los filtros estructurados cuando el usuario los menciona en lenguaje natural:

- **Jurisdicción** (`jurisdictions`): "civil" → `CIVIL`, "penal" → `PENAL`, "contencioso" / "contencioso-administrativo" → `CONTENCIOSO`, "social" / "laboral" → `SOCIAL`, "militar" → `MILITAR`, "especial" → `ESPECIAL`.
- **Tipo de resolución** (`resolutionTypes`): "sentencias" → `SENTENCIA`, "autos" → `AUTO`, "acuerdos" → `ACUERDO`. Si el usuario pide **específicamente** "autos de admisión" (p. ej. de un recurso de casación), usa `AUTOADMISION` en vez de `AUTO` genérico: `AUTO` trae también inadmisiones, aclaratorios y otros. Del mismo modo existen `AUTOINADMISION`, `AUTOACLARATORIO` y `AUTOOTROS` para pedir un subtipo concreto.
- **Tipo de órgano** (`organoTypes`): ⚠️ **los códigos son opacos y NO siguen el orden alfabético; NO los adivines, cópialos de la tabla de abajo.** Errores típicos: usar `12` (Sala Penal) para asuntos civiles, o `31` (TSJ) creyendo que es el Juzgado de Primera Instancia (que es `42`). Consulta la [tabla de referencia de órganos](#-tabla-de-referencia-organotypes).
- **Sección** (`section`): ⚠️ **no confundir con `organoTypes` (Sala).** Si el usuario pide "Sección 1ª", "Sección 2ª", etc. de un órgano concreto (p. ej. "Audiencia Provincial, Sección 3ª"), eso va en `section` (texto libre, ej. `"3"`), NUNCA en `organoTypes`. `organoTypes` selecciona el tipo de órgano/Sala; `section` filtra la Sección dentro de él.
- **Sección destino de Autos de Admisión** (`admissionAutoSection`): solo cuando el usuario pide autos de admisión del recurso de casación **de una sección concreta** de la Sala 3ª TS (ej. "autos de admisión de la Sección 2ª de la Sala Tercera"). Usa `resolutionTypes: ["AUTOADMISION"]` junto con `admissionAutoSection: "2"` (mapeo: `1`=Quinta, `2`=Segunda, `3`=Tercera, `4`=Cuarta — códigos opacos, no adivinar).
- **Comunidad autónoma** (`locations`): "Madrid" → `MADRID`, "Cataluña" → `CATALUÑA`, "Andalucía" → `ANDALUCÍA`, etc. *(solo aplica en la vía HTTP).*
- **Sentencia concreta por identificador**: si el usuario da un **ECLI** (`ECLI:ES:TS:2025:2382`) o un **ROJ** (`STS 2382/2025`), pásalo tal cual como término único y **no rellenes filtros** (se ignoran). Ver [Buscar una sentencia concreta](#-buscar-una-sentencia-concreta-ecli-o-roj). Nunca lo entrecomilles junto a otros conceptos con `AND`: como texto libre da 0 resultados.
- **Fechas** (`dateFrom` / `dateTo`): "desde 2020" → `dateFrom: "2020-01-01"`, "el último año", "entre enero y marzo de 2024", etc. Formato `YYYY-MM-DD`.
- **Ordenación** (`sortOrder`): "las más recientes" → `IN_FECHARESOLUCION:decreasing`, "las más antiguas" → `IN_FECHARESOLUCION:increasing`, "las más relevantes" → `Relevance` (por defecto).
- **Número de resultados** (`maxResults`): por defecto `10`. Súbelo (hasta `50` por término) cuando el usuario pida "todas", "un listado amplio", "un análisis exhaustivo" o similar; con 4 términos eso da hasta 200 resultados en la ejecución.
- **Número de términos** (`searchTerms`): **máximo 4**. Si necesitas cubrir más casos, combínalos dentro del mismo término con `OR`/`AND`/`NOT` en lugar de añadir más entradas al array. Superar el límite cancela la ejecución.
- **Texto completo** (`pdfUrls`): cuando el usuario pida "descarga/analiza el texto de estas sentencias" tras una búsqueda, relanza el actor pasando en `pdfUrls` los `pdfUrl` de las sentencias elegidas (ver [Extracción de texto](#-extracción-de-texto-de-sentencias-concretas)). No uses `fetch` ni otros actores para bajar el PDF.

> 💡 Para construir **tablas**, los campos más útiles de la salida son `organo`, `jurisdiction`, `resolutionDateISO`, `roj`, `ecli`, `title`, `ponente`, `summary` y `documentUrl` (enlace para "ver sentencia"). Usa **`documentUrl`** para los enlaces que el usuario va a pinchar; reserva `pdfUrl` para reenviarlo en `pdfUrls` cuando se pida extraer el texto.

> ⚠️ **Enlaces y el carácter `&` (MCP de Apify).** Al leer el dataset por el MCP, las URLs con parámetros (`pdfUrl`) pueden llegar con los `&` escapados como `&amp;`. Si publicas esa cadena cruda como enlace, da **404**. Para enlaces clicables usa siempre **`documentUrl`** (no tiene `&`). Si necesitas reenviar un `pdfUrl` en `pdfUrls`, pásalo tal cual aunque tenga `&amp;`: el actor lo **decodifica automáticamente** antes de descargar.

#### 🏛️ Tabla de referencia (`organoTypes`)

Mapea el órgano que pide el usuario a su **código exacto** de esta tabla (son los valores oficiales del `<select>` de CENDOJ). Para órganos con varias salas, usa el **código combinado** (primera fila de cada grupo) salvo que el usuario precise una sala concreta.

| Código (`organoTypes`) | Órgano (título oficial) |
| --- | --- |
| `11\|12\|13\|14\|15\|16` | **Tribunal Supremo** (todas las salas) |
| `11` | Tribunal Supremo. Sala de lo Civil |
| `12` | Tribunal Supremo. Sala de lo Penal |
| `13` | Tribunal Supremo. Sala de lo Contencioso |
| `14` | Tribunal Supremo. Sala de lo Social |
| `15` | Tribunal Supremo. Sala de lo Militar |
| `16` | Tribunal Supremo. Sala de lo Especial |
| `22\|2264\|23\|24\|25\|26\|27\|28\|29` | **Audiencia Nacional** (todas las salas) |
| `22` | Audiencia Nacional. Sala de lo Penal |
| `2264` | Sala de Apelación de la Audiencia Nacional |
| `23` | Audiencia Nacional. Sala de lo Contencioso |
| `24` | Audiencia Nacional. Sala de lo Social |
| `27` | Audiencia Nacional. Juzgados Centrales de Instrucción / Tribunal Central Instancia Sec. Instr. |
| `26` | Audiencia Nacional. Juzgado Central de Menores |
| `25` | Audiencia Nacional. Juzgado Central de Vigilancia Penitenciaria |
| `29` | Audiencia Nacional. Juzgados Centrales de lo Contencioso / Tribunal Central Instancia Sec. Contencioso |
| `28` | Audiencia Nacional. Juzgados Centrales de lo Penal |
| `31\|31201202\|33\|34` | **Tribunal Superior de Justicia** (todas las salas) |
| `31` | Tribunal Superior de Justicia. Sala de lo Civil y Penal |
| `31201202` | Sección de Apelación Penal. TSJ Sala de lo Civil y Penal |
| `33` | Tribunal Superior de Justicia. Sala de lo Contencioso |
| `34` | Tribunal Superior de Justicia. Sala de lo Social |
| `37` | **Audiencia Provincial** |
| `38` | Audiencia Provincial. Tribunal Jurado |
| `1001` | Tribunal de Marca de la UE |
| `42` | **Juzgado de Primera Instancia** / Tribunal Instancia Sec. Civil |
| `43` | Juzgado de Instrucción |
| `45` | Juzgado de lo Contencioso Administrativo / Tribunal Instancia Sec. Contencioso-Administrativo |
| `53` | Juzgado de Menores / Tribunal Instancia Sec. Menores |
| `41` | Juzgado de 1ª Inst. Instr. / Tribunal Instancia Sec. Civil Instr. |
| `47` | Juzgado de lo Mercantil / Tribunal Instancia Sec. Mercantil |
| `1002` | Juzgados de Marca de la UE |
| `51` | Juzgado de lo Penal / Tribunal Instancia Sec. Penal |
| `44` | Juzgado de lo Social / Tribunal Instancia Sec. Social |
| `52` | Juzgado de Vigilancia Penitenciaria / Tribunal Instancia Sec. Vigilancia Penitenciaria |
| `48` | Juzgado de Violencia sobre la Mujer |
| `83` | Tribunal Militar Territorial |
| `85` | Tribunal Militar Central |
| `75` | Consejo Supremo de Justicia Militar |
| `36` | Audiencia Territorial |

> ⚠️ **"Juzgado de Primera Instancia" = `42`**, **NO** `31` (que es el Tribunal Superior de Justicia). **"Sala de lo Civil del Supremo" = `11`**, **NO** `12` (que es Penal). **"Audiencia Provincial" = `37`**, **NO** `42`. Verifica siempre el código contra esta tabla antes de llamar al actor.

### 📤 Salida (Output)

Los resultados se almacenan en el **dataset** del actor. Cada elemento corresponde a una resolución con la siguiente estructura:

```json
{
    "searchTerm": "Gastos hipotecarios",
    "title": "ATIM Madrid, a 10 de junio de 2026 - ROJ: ATIM M 31/2026",
    "roj": "ATIM M 31/2026",
    "reference": "11755479",
    "ecli": "ECLI:ES:TIM:2026:31A",
    "jurisdiction": "Civil",
    "organo": "Tribunal de Instancia Mercantil",
    "resolutionDate": "20260610",
    "resolutionDateISO": "2026-06-10",
    "resolutionNumber": null,
    "municipality": "Madrid",
    "ponente": "P.J.V.T.",
    "appealNumber": "573/2025",
    "summary": "Resumen automático de la resolución...",
    "pdfUrl": "https://www.poderjudicial.es/search/contenidos.action?action=contentpdf&databasematch=AN&reference=11755479&optimize=20260612&publicinterface=true&tab=AN",
    "documentUrl": "https://www.poderjudicial.es/search/AN/openDocument/abc123.../20260612"
}
```

| Campo | Descripción |
| --- | --- |
| `searchTerm` | Término de búsqueda que originó el resultado. |
| `title` | Título de la resolución. |
| `roj` | Repositorio Oficial de Jurisprudencia (identificador ROJ). |
| `reference` | Referencia interna del documento en CENDOJ. |
| `ecli` | Identificador europeo de jurisprudencia (ECLI). |
| `jurisdiction` | Jurisdicción de la búsqueda en formato legible (p. ej. `Civil`). `null` si no se filtró por jurisdicción. |
| `organo` | Órgano judicial legible derivado del ROJ (p. ej. `Tribunal Supremo`, `Audiencia Provincial`). |
| `resolutionDate` | Fecha de resolución (formato `YYYYMMDD`). |
| `resolutionDateISO` | Fecha de resolución en formato legible `YYYY-MM-DD`. |
| `resolutionNumber` | Número de resolución (si está disponible). |
| `municipality` | Municipio del órgano judicial. |
| `ponente` | Magistrado ponente, **anonimizado** como iniciales (p. ej. `"P.J.V.T."`). Ver [Anonimización](#-anonimización). |
| `appealNumber` | Número de recurso. |
| `summary` | Resumen automático generado por el buscador. |
| `pdfUrl` | URL de descarga del PDF oficial (es también el documento online: el visor de CENDOJ muestra ese mismo PDF). Contiene parámetros con `&`; ver la nota sobre el MCP más abajo. |
| `documentUrl` | Enlace **estable** al visor de la sentencia (`openDocument`). No lleva parámetros de query (sin `&`), no caduca y es el enlace recomendado para mostrar o compartir ("ver sentencia"). |

### � Extracción de texto de sentencias concretas

El buscador devuelve metadatos y resumen, pero **no** el texto completo de los PDFs (descargarlos todos sería lento y CENDOJ bloquea las descargas masivas). Para analizar el contenido de sentencias concretas, sigue un flujo en **dos pasos**:

1. **Busca** con `searchTerms` y revisa los resultados en base al título y summary. Cada uno incluye su `pdfUrl`.
2. **Vuelve a ejecutar** el actor pasando en `pdfUrls` las URLs (`pdfUrl`) de las sentencias que te interesen. El actor descargará esos PDFs y extraerá su texto.

Cuando usas `pdfUrls`, **no es necesario** rellenar `searchTerms`. La salida de esta segunda ejecución tiene esta forma:

```json
{
    "pdfUrl": "https://www.poderjudicial.es/search/contenidos.action?action=contentpdf&databasematch=TS&reference=11753648&...",
    "reference": "11753648",
    "databasematch": "TS",
    "text": "Texto completo de la sentencia extraído del PDF..."
}
```

| Campo | Descripción |
| --- | --- |
| `pdfUrl` | URL del PDF procesado (la que pasaste en `pdfUrls`). |
| `reference` | Referencia interna del documento (extraída de la URL). |
| `databasematch` | Base de datos de origen (extraída de la URL). |
| `text` | Texto completo de la sentencia. Es `null` (con campo `error`) si no se pudo extraer. |

> 💡 Límite de **50 PDFs por ejecución**.

> ℹ️ Si el `pdfUrl` que reenvías llega con los `&` escapados como `&amp;` (lo hace el MCP de Apify al serializar el dataset), no pasa nada: el actor decodifica las URLs de `pdfUrls` automáticamente antes de descargar.

#### 🤖 Uso con Claude Code / MCP

El flujo encaja de forma natural con el MCP: primero el asistente lanza la búsqueda, muestra los resultados y, cuando le pides "descárgame el texto de estas dos sentencias para analizarlas", relanza el actor con el campo `pdfUrls` rellenado con los `pdfUrl` correspondientes del paso anterior. **No uses `fetch` ni otros actores** para bajar el PDF: usa este mismo actor con `pdfUrls`.

### 🔏 Anonimización

El actor aplica anonimización automática para proteger los datos personales de las personas que intervienen en los procedimientos judiciales. Los nombres se sustituyen por sus **iniciales en mayúscula seguidas de punto** (`"Pedro Manuel Torres"` → `"P.M.T."`).

#### Qué se anonimiza

| Dónde | Qué | Ejemplo |
| --- | --- | --- |
| Campo `ponente` (metadatos) | Nombre del magistrado ponente, en cualquier formato CENDOJ | `"GARCÍA MARTÍNEZ, Marta"` → `"G.M.M."` |
| Texto del PDF — cuerpo | Cualquier nombre precedido de título de cortesía | `"la letrada Doña Ana García López"` → `"la letrada Doña A.G.L."` |
| Texto del PDF — cuerpo | Cualquier nombre precedido de `Sr./Sra.`, `Ilmo./Excmo. Sr./Sra.` | `"Excmo. Sr. D. Pedro Sánchez Martínez"` → `"Excmo. Sr. D. P.S.M."` |
| Texto del PDF — cabecera de metadatos CENDOJ | Nombres en MAYÚSCULAS precedidos de rol (`Ponente:`, `Magistrado:`, `Letrado de la Administración de Justicia:`) | `"Ponente: PEDRO JOSE VELA TORRES"` → `"Ponente: P.J.V.T."` |

#### Quién queda anonimizado

La anonimización cubre **todos los roles** que aparecen con título de cortesía o etiqueta de rol en el texto de la resolución:

- Magistrado/a ponente y resto de magistrados de la sala
- Letrado/a (abogado/a) de cualquiera de las partes
- Procurador/a de cualquiera de las partes
- Letrado/a de la Administración de Justicia (secretario judicial)
- Cualquier otra persona mencionada con `Don`, `Doña`, `D.`, `Dª`, `Sr.`, `Sra.` u otros tratamientos protocolarios

#### Qué no se modifica

- **Nombres de organizaciones** (bancos, empresas, administraciones): no encajan en los patrones de nombre propio personal.

### 📝 Notas

- Número máximo de resultados: **200** por ejecución.

### Ecosistema legaltech — actores relacionados

Este actor forma parte de una colección de actores para búsqueda jurídica española y europea. Si la consulta del usuario requiere otras fuentes, usa el actor correspondiente sin pedirle que busque en Apify Store:

| Actor | Fuente | Tipo de documentos |
|-------|--------|--------------------|
| **`legaltech/aepd`** ← este actor | AEPD | Resoluciones y guías de protección de datos |
| **`legaltech/cendoj`** | CENDOJ (Consejo General del Poder Judicial) | Sentencias y autos del sistema judicial español |
| **`legaltech/tribunal-constitucional`** | Tribunal Constitucional de España | Sentencias del TC, recursos de amparo, cuestiones de inconstitucionalidad |
| **`legaltech/tjue`** | Tribunal de Justicia de la UE (CURIA) | Sentencias, autos y conclusiones del TJUE |

#### Guía de derivación

- **Protección de datos, RGPD, LOPDGDD, sanciones de la AEPD** → `legaltech/aepd`
- **Jurisprudencia civil, penal, laboral, contencioso-administrativa española** → `legaltech/cendoj`
- **Derechos fundamentales, inconstitucionalidad, recursos de amparo** → `legaltech/tribunal-constitucional`
- **Derecho europeo, directivas, reglamentos UE, cuestiones prejudiciales** → `legaltech/tjue`
- **Intersección RGPD + derecho europeo** → combinar `legaltech/aepd` y `legaltech/tjue`

# Actor input Schema

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

Lista de términos a buscar en la jurisprudencia de CENDOJ. Máximo 4 términos por ejecución. Usa operadores booleanos dentro de cada término para acotar la búsqueda: Y/AND (ambos), O/OR (cualquiera), NO/NOT (excluir) y PROXn/NEARn (proximidad, ej. PROX20). Ejemplo: "abogado Y costas O "condena en costas" NO penal". ⚠️ NO sobre-restrinjas: máximo 2 frases exactas entre comillas por término (las comillas buscan coincidencia LITERAL; encadenar 3-4 con Y/AND casi siempre da 0 resultados) y no más de 2-3 condiciones por término. Las frases entre comillas deben ser citas textuales previsibles (artículo de ley, nombre de norma), nunca un parafraseo de una doctrina o concepto (ej. usa la cita real 'doctrina de los actos propios', no una paráfrasis inventada). Para cubrir más matices, usa varios searchTerms en vez de sobrecargar uno solo. 🔎 BUSCAR UNA SENTENCIA CONCRETA: escribe su ECLI (ej. "ECLI:ES:TS:2025:2382") o su ROJ (ej. "STS 2382/2025") como término ÚNICO, sin comillas ni operadores. El actor lo detecta y lo envía al campo dedicado de CENDOJ, ignorando el resto de filtros (el identificador ya señala una resolución única). ⚠️ Nunca metas un ECLI o un ROJ dentro de una query de texto (entrecomillado o con AND): no están en el índice de texto y darían 0 resultados.

## `pdfUrls` (type: `array`):

Lista de URLs de PDF (campo `pdfUrl` de resultados anteriores) de las que quieres descargar y extraer el texto completo para analizarlas. Úsalo en una segunda ejecución tras una búsqueda: copia aquí las URLs de las sentencias que te interesen. Si rellenas este campo, el actor solo extrae el texto de esas sentencias (no es necesario rellenar 'Términos de Búsqueda'). Límite de 50 por ejecución para evitar bloqueos por descargas masivas.

## `jurisdictions` (type: `array`):

Selecciona una o más jurisdicciones. Si no se selecciona ninguna, se buscará en todas por defecto.

## `organoTypes` (type: `array`):

Tipo de órgano judicial. Los códigos son opacos: NO los adivines, lee el título (enumTitle) de cada opción y elige el que coincide exactamente con lo que pide el usuario. Para un órgano con varias salas (Tribunal Supremo, Audiencia Nacional, TSJ) usa el código combinado salvo que se precise una sala. Errores frecuentes a evitar: 'Juzgado de Primera Instancia' es el código 42 (NO 31, que es el Tribunal Superior de Justicia); la 'Sala de lo Civil del Tribunal Supremo' es 11 (NO 12, que es Penal); la 'Audiencia Provincial' es 37 (NO 42). Si no se indica ninguno, se busca en todos.

## `resolutionTypes` (type: `array`):

Selecciona uno o más tipos de resolución. Si no se selecciona ninguno, se buscará en todos. 'Auto' incluye los 4 subtipos (aclaratorio, admisión, inadmisión, otros); si solo te interesan los autos de admisión (p. ej. de un recurso de casación), usa 'Auto de admisión' en vez de 'Auto' para no traer también inadmisiones y otros autos.

## `section` (type: `string`):

Número de Sección DENTRO del órgano judicial (ej. Sección 1ª de una Audiencia Provincial). Es un campo INDEPENDIENTE de 'Tipo de Órgano': ese campo selecciona la Sala/tipo de órgano, este selecciona la Sección dentro de ella (el buscador de CENDOJ los trata como dos filtros distintos). Déjalo vacío para buscar en todas las secciones.

## `admissionAutoSection` (type: `string`):

Filtra los Autos de Admisión del recurso de casación de la Sala de lo Contencioso-Administrativo del Tribunal Supremo (Sala 3ª) por la Sección a la que se ha turnado el asunto. Solo tiene efecto si 'Tipo de Resolución' incluye 'Auto de admisión' (o 'Auto'); en cualquier otra combinación CENDOJ lo ignora. Si se deja vacío/Todas, se incluyen todas las secciones.

## `locations` (type: `array`):

Selecciona una o más Comunidades Autónomas. Si no se selecciona ninguna, se buscará en todas.

## `maxResults` (type: `integer`):

Define el número máximo de sentencias a extraer por cada término de búsqueda (hasta 4 términos por ejecución). Se pagina automáticamente de 50 en 50. Límite de 50 por término, es decir, 200 como máximo por ejecución (4 términos × 50).

## `paragraphs` (type: `integer`):

Si es mayor que 0, al extraer el texto de un PDF se devuelven solo ese número de PÁRRAFOS relevantes (los pasajes donde aparecen los términos buscados, en frases completas y priorizando los Fundamentos de Derecho) en lugar del texto íntegro. Ideal para análisis con un LLM (menos tokens). Aplica cuando se extrae texto (campo `pdfUrls`, o búsqueda con extracción de texto activada). 0 = texto completo.

## `paragraphTerms` (type: `string`):

Términos con los que localizar los pasajes en el modo párrafos. Si se deja vacío, se usa el propio término de búsqueda (en la vía `searchTerms`). Es recomendable rellenarlo cuando se usa `pdfUrls` (segunda ejecución), ya que ahí no hay término de búsqueda.

## `dateFrom` (type: `string`):

Fecha de resolución inicial (opcional). Se incluyen las sentencias dictadas a partir de esta fecha.

## `dateTo` (type: `string`):

Fecha de resolución final (opcional). Se incluyen las sentencias dictadas hasta esta fecha.

## `sortOrder` (type: `string`):

Criterio de ordenación de los resultados. Por defecto se ordena por coincidencia (relevancia).

## `proxyConfiguration` (type: `object`):

Configuración de proxy. CENDOJ bloquea las IP de datacenter, por lo que se recomienda usar proxy residencial de España (grupo RESIDENTIAL, país ES). El tráfico residencial se factura por GB consumido.

## Actor input object example

```json
{
  "searchTerms": [
    "Gastos hipotecarios"
  ],
  "pdfUrls": [],
  "jurisdictions": [],
  "organoTypes": [],
  "resolutionTypes": [],
  "admissionAutoSection": "",
  "locations": [],
  "maxResults": 10,
  "paragraphs": 0,
  "sortOrder": "Relevance",
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "ES"
  }
}
```

# 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": [
        "Gastos hipotecarios"
    ],
    "pdfUrls": [],
    "jurisdictions": [],
    "organoTypes": [],
    "resolutionTypes": [],
    "section": "",
    "locations": [],
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ],
        "apifyProxyCountry": "ES"
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("legaltech/cendoj").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": ["Gastos hipotecarios"],
    "pdfUrls": [],
    "jurisdictions": [],
    "organoTypes": [],
    "resolutionTypes": [],
    "section": "",
    "locations": [],
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
        "apifyProxyCountry": "ES",
    },
}

# Run the Actor and wait for it to finish
run = client.actor("legaltech/cendoj").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": [
    "Gastos hipotecarios"
  ],
  "pdfUrls": [],
  "jurisdictions": [],
  "organoTypes": [],
  "resolutionTypes": [],
  "section": "",
  "locations": [],
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "ES"
  }
}' |
apify call legaltech/cendoj --silent --output-dataset

```

## MCP server setup

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

```

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/BlnEP405nFDcDZDi2/builds/kbusMdX79ghzg6djg/openapi.json
