{
  "openapi": "3.1.0",
  "info": {
    "title": "API de Licitaciones365",
    "version": "1.0.0",
    "summary": "Licitaciones públicas de España para tus aplicaciones e integraciones.",
    "description": "API REST para consultar las licitaciones públicas de España (Plataforma de Contratación del Sector Público y plataformas autonómicas) y los datos de tu equipo en Licitaciones365.\n\n- **Autenticación:** API key en la cabecera `Authorization: Bearer l365_…` (o en `X-API-Key`). Las API keys están incluidas en los planes Pro y Enterprise y las crea el propietario del equipo.\n- **Equipos:** cada clave trabaja con su equipo. Las claves para todos los equipos del propietario eligen equipo en cada petición con la cabecera `X-Equipo: <id>`; los ids salen en `GET /cuenta`.\n- **Formato:** JSON. Las respuestas van en `{data, meta}` y los errores en `{error: {code, message}}`.\n- **Guía, límites y ejemplos:** https://licitaciones365.es/desarrolladores",
    "termsOfService": "https://licitaciones365.es/policy-docs/terms",
    "license": {
      "name": "Uso según las condiciones de la API de Licitaciones365",
      "url": "https://licitaciones365.es/desarrolladores/guia#condiciones"
    },
    "contact": {
      "name": "Licitaciones365",
      "url": "https://licitaciones365.es/desarrolladores",
      "email": "contact-us@licitaciones365.es"
    }
  },
  "servers": [
    {
      "url": "https://api.licitaciones365.es/v1",
      "description": "Producción"
    }
  ],
  "security": [
    {
      "apiKey": []
    },
    {
      "apiKeyHeader": []
    }
  ],
  "tags": [
    {
      "name": "Cuenta",
      "description": "Quién está detrás de la API key: usuario, equipo, plan, límites y cuotas de hoy."
    },
    {
      "name": "Licitaciones",
      "description": "Búsqueda y ficha de licitaciones, contratos menores y anuncios previos de toda España, con sus documentos como enlaces al portal oficial."
    },
    {
      "name": "Favoritas",
      "description": "Las favoritas del equipo («Mis concursos» en la app), con sus grupos, que hacen de etapas. Se aplican las reglas de la app: límite de favoritas del plan, grupos desde Plus, y al añadir una favorita se le quita la marca «No me interesa» y se preparan sus documentos para la IA. Al quitarla se desactivan sus recordatorios pendientes; la nota y las tareas se conservan."
    },
    {
      "name": "Descartadas",
      "description": "Licitaciones que el equipo ha marcado como «No me interesa»: dejan de salir en las búsquedas de todo el equipo (salvo con `descartadas=incluir` o `descartadas=solo`)."
    },
    {
      "name": "Catálogos",
      "description": "Códigos que usan los filtros de búsqueda: CPV, provincias, comunidades autónomas, estados, tipos de contrato y otros."
    },
    {
      "name": "IA",
      "description": "La IA de Licitaciones365 sobre cada licitación: preguntas sobre los pliegos, checklist de tareas, informe PDF, análisis de competencia y recomendación de CPV.\n\nTodo lo que **gasta presupuesto de IA** del equipo es un `POST` y necesita una API key con permiso de escritura; consultar lo ya generado (`GET`) no gasta. Las tareas largas son asíncronas: responden `202` con `estado: \"en_curso\"` y se recogen después (o se espera hasta `esperar` segundos en la misma llamada). Solo puede haber una ejecución de IA en curso a la vez por clave."
    },
    {
      "name": "Espacio de trabajo",
      "description": "Lo del equipo en cada licitación: la nota, el checklist de tareas y los recordatorios por email, con las reglas de la app. Las tareas y los recordatorios solo existen en las favoritas; la nota, en cualquier licitación. Asignar tareas es de los planes Pro y Enterprise. Los cambios se ven al momento en la app de todo el equipo."
    },
    {
      "name": "Agenda",
      "description": "Plazos de presentación y vencimientos de las favoritas del equipo, y las tareas asignadas a cada uno («Mis tareas», planes Pro y Enterprise)."
    },
    {
      "name": "Alertas",
      "description": "Las alertas del equipo: búsquedas que el correo de resumen ejecuta cada mañana para enviar por email las licitaciones nuevas que encajan, y el propio correo (su historial y sus ajustes).\n\nSe aplican las reglas de la app: leer y probar, cualquier miembro del equipo; crear, cambiar y borrar, solo el propietario del equipo; el límite de alertas del plan; y los ajustes del correo y los destinatarios por alerta, en Pro y Enterprise. Una alerta creada por la API es idéntica a una creada en la app.\n\n**Palabras clave:** cada una es una palabra suelta de 3 letras o más que funciona como prefijo y sin distinguir tildes (`jardin` encuentra jardín, jardines y jardinería). En las alertas basta con que aparezca **una** (`modo_palabras: cualquiera`, por defecto) salvo que se pida `todas`; el buscador (`GET /licitaciones`) exige siempre todas."
    },
    {
      "name": "Vencimientos",
      "description": "Contratos adjudicados que vencen pronto, con su fecha estimada por Licitaciones365 (no oficial), para anticiparse a su nueva licitación. Solo planes Pro y Enterprise."
    },
    {
      "name": "Órganos y adjudicatarios",
      "description": "Directorios de órganos de contratación y de empresas adjudicatarias, con sus estadísticas. Por privacidad, las personas físicas no aparecen con nombre ni NIF."
    },
    {
      "name": "Estadísticas",
      "description": "Estadísticas agregadas de un mercado: volumen, importes, territorios, competencia, bajas y principales órganos y empresas."
    }
  ],
  "paths": {
    "/cuenta": {
      "get": {
        "tags": [
          "Cuenta"
        ],
        "operationId": "verCuenta",
        "summary": "Ver la cuenta de la API key",
        "description": "Usuario, equipo y plan de la API key, límites del plan, presupuesto de IA del mes, cuotas diarias de la API consumidas hoy y fecha de la última carga de datos.\n\nEs la llamada más sencilla para comprobar que tu clave funciona y no consume cuota diaria.",
        "responses": {
          "200": {
            "description": "Contexto de la cuenta.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Cuenta"
                    }
                  }
                },
                "example": {
                  "data": {
                    "usuario": {
                      "id": 1234,
                      "email": "ana@empresa.es",
                      "nombre": "Ana García"
                    },
                    "equipo": {
                      "id": 567,
                      "nombre": "Licitaciones",
                      "plan": "Pro",
                      "rol": "owner"
                    },
                    "credencial": {
                      "tipo": "api_key",
                      "nombre": "ERP de ofertas",
                      "escritura": false,
                      "todos_los_equipos": false
                    },
                    "limites_plan": {
                      "favoritas": {
                        "usados": 84,
                        "maximo": null,
                        "puede_anadir": true
                      },
                      "grupos_favoritas": {
                        "usados": 4,
                        "maximo": 20,
                        "puede_anadir": true
                      },
                      "busquedas_guardadas": {
                        "usados": 6,
                        "maximo": null,
                        "puede_anadir": true
                      },
                      "alertas": {
                        "usados": 9,
                        "maximo": null,
                        "puede_anadir": true
                      }
                    },
                    "presupuesto_ia": {
                      "unidad": "créditos (1 € = 1.000 créditos, como en la app)",
                      "mensual": 8000,
                      "usado": 1250,
                      "disponible": 6750,
                      "periodo_inicio": "2026-10-01T00:00:00+02:00",
                      "periodo_fin": "2026-10-31T23:59:59+01:00"
                    },
                    "cuotas_api_hoy": {
                      "busquedas_dia": {
                        "limite": 1000,
                        "usado": 37
                      },
                      "fichas_dia": {
                        "limite": 2000,
                        "usado": 112
                      },
                      "filas_csv_dia": {
                        "limite": 30000,
                        "usado": 0
                      },
                      "favoritas_nuevas_dia": {
                        "limite": 300,
                        "usado": 0
                      },
                      "alertas_nuevas_dia": {
                        "limite": 20,
                        "usado": 0
                      },
                      "previsualizaciones_dia": {
                        "limite": 60,
                        "usado": 0
                      },
                      "consultas_ia_dia": {
                        "limite": 40,
                        "usado": 0
                      }
                    },
                    "datos_actualizados": "2026-10-13T21:47:12+02:00",
                    "app_url": "https://app.licitaciones365.es"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/NoAutenticado"
          },
          "403": {
            "$ref": "#/components/responses/SinAcceso"
          },
          "429": {
            "$ref": "#/components/responses/LimiteSuperado"
          },
          "500": {
            "$ref": "#/components/responses/ErrorInterno"
          }
        },
        "parameters": [
          {
            "$ref": "#/components/parameters/Equipo"
          }
        ]
      }
    },
    "/licitaciones": {
      "get": {
        "tags": [
          "Licitaciones"
        ],
        "operationId": "buscarLicitaciones",
        "summary": "Buscar licitaciones",
        "description": "Busca licitaciones, contratos menores y anuncios previos con los mismos criterios que el buscador de la app. Todos los filtros son opcionales y se combinan entre sí (Y); dentro de un filtro de lista basta con que coincida uno de los valores (O).\n\nSin filtros devuelve todas las categorías y todos los estados salvo las anuladas, de la más reciente a la más antigua, sin las que tu equipo ha descartado. Para «abiertas ahora», usa `estado=PUB`; para «que cierran antes de una fecha», `plazo_hasta`.\n\nCada resultado es un resumen. Para la ficha completa usa `GET /licitaciones/{id}`.",
        "x-cuota-diaria": "busquedas_dia",
        "x-ejemplo-peticion": {
          "query": {
            "cpv": [
              "77310000"
            ],
            "estado": [
              "PUB"
            ],
            "provincia": [
              "ES523"
            ],
            "por_pagina": 2
          }
        },
        "parameters": [
          {
            "name": "texto",
            "in": "query",
            "description": "Palabras a buscar. Tienen que aparecer **todas**, en el título, en el objeto de algún lote o en la descripción de alguno de sus CPV. Cada palabra encuentra también las que empiezan por ella: `jardin` encuentra «jardines» y «jardinería». Se ignoran las palabras de menos de 3 letras y los operadores (`+`, `-`, comillas…), y se usan como mucho 10 palabras. Para un sector suele ser más preciso filtrar por `cpv`.",
            "schema": {
              "type": "string",
              "maxLength": 200
            },
            "example": "mantenimiento jardines"
          },
          {
            "name": "cpv",
            "in": "query",
            "description": "Códigos CPV de 8 dígitos, con o sin dígito de control (`45000000` o `45000000-7`), separados por comas; se usan los 50 primeros. Un código acabado en ceros incluye sus subcódigos: `45000000` es toda la división 45 (construcción). Búscalos con `GET /catalogos/cpv`.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string",
                "pattern": "^\\d{8}(-\\d)?$"
              }
            },
            "style": "form",
            "explode": false,
            "example": [
              "77310000",
              "45112710"
            ]
          },
          {
            "name": "provincia",
            "in": "query",
            "description": "Provincias por su código NUTS3, separadas por comas: `ES523` (Valencia), `ES300` (Madrid), `ES511` (Barcelona)… Lista completa en `GET /catalogos/provincias`.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "style": "form",
            "explode": false,
            "example": [
              "ES523"
            ]
          },
          {
            "name": "comunidad",
            "in": "query",
            "description": "Comunidades autónomas por su código NUTS2, separadas por comas: `ES52` (Comunitat Valenciana), `ES61` (Andalucía), `ES51` (Cataluña)… Incluye sus provincias y también lo que se publica asignado a la comunidad entera. Lista completa en `GET /catalogos/comunidades`.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "style": "form",
            "explode": false,
            "example": [
              "ES52"
            ]
          },
          {
            "name": "estado",
            "in": "query",
            "description": "Estados, separados por comas:\n\n- `PUB`: en plazo de presentación.\n- `EV`: pendiente de adjudicación.\n- `ADJ`: adjudicada.\n- `RES`: resuelta.\n- `PRE`: anuncio previo.\n- `CERR`: cerrada.\n- `ANUL`: anulada.\n\nPor defecto, todos menos `ANUL`.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string",
                "enum": [
                  "PUB",
                  "EV",
                  "ADJ",
                  "RES",
                  "PRE",
                  "CERR",
                  "ANUL"
                ]
              }
            },
            "style": "form",
            "explode": false,
            "example": [
              "PUB"
            ]
          },
          {
            "name": "categoria",
            "in": "query",
            "description": "Categorías, separadas por comas: `licitacion` (Plataforma de Contratación del Sector Público), `agregada` (plataformas autonómicas) o `menor` (contratos menores). Por defecto, las tres.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string",
                "enum": [
                  "licitacion",
                  "agregada",
                  "menor"
                ]
              }
            },
            "style": "form",
            "explode": false,
            "example": [
              "licitacion",
              "agregada"
            ]
          },
          {
            "name": "tipo_contrato",
            "in": "query",
            "description": "Tipos de contrato por su código, separados por comas: `1` suministros, `2` servicios, `3` obras, `21` gestión de servicios públicos, `22` concesión de servicios, `31` concesión de obras públicas, `32` concesión de obras, `40` colaboración entre el sector público y el privado, `50` patrimonial, `7` administrativo especial, `8` privado. Lista en `GET /catalogos/tipos_contrato`.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "style": "form",
            "explode": false,
            "example": [
              "2"
            ]
          },
          {
            "name": "subtipo_contrato",
            "in": "query",
            "description": "Subtipos con el formato `tipo::subtipo`, separados por comas: `2::7` es «Servicios de informática y servicios conexos». Lista en `GET /catalogos/subtipos_contrato`.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string",
                "pattern": "^\\d+::\\d+$"
              }
            },
            "style": "form",
            "explode": false,
            "example": [
              "2::7"
            ]
          },
          {
            "name": "sistema_contratacion",
            "in": "query",
            "description": "Sistemas de contratación, separados por comas: `0` no aplica, `1` establecimiento del acuerdo marco, `2` establecimiento del sistema dinámico de adquisición, `3` contrato basado en un acuerdo marco, `4` contrato basado en un sistema dinámico de adquisición.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string",
                "enum": [
                  "0",
                  "1",
                  "2",
                  "3",
                  "4"
                ]
              }
            },
            "style": "form",
            "explode": false,
            "example": [
              "1",
              "3"
            ]
          },
          {
            "name": "importe_min",
            "in": "query",
            "description": "Importe base de licitación mínimo, sin IVA, en euros.",
            "schema": {
              "type": "number",
              "minimum": 0
            },
            "example": 50000
          },
          {
            "name": "importe_max",
            "in": "query",
            "description": "Importe base de licitación máximo, sin IVA, en euros. Si es menor que `importe_min`, se intercambian.",
            "schema": {
              "type": "number",
              "minimum": 0
            },
            "example": 500000
          },
          {
            "name": "publicada_desde",
            "in": "query",
            "description": "Publicada desde esta fecha, incluida.",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "example": "2026-10-01"
          },
          {
            "name": "publicada_hasta",
            "in": "query",
            "description": "Publicada hasta esta fecha, incluida.",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "example": "2026-10-31"
          },
          {
            "name": "plazo_desde",
            "in": "query",
            "description": "El plazo de presentación termina desde esta fecha, incluida. Se usa el plazo de ofertas o, si no lo hay, el de solicitudes de participación.",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "example": "2026-10-15"
          },
          {
            "name": "plazo_hasta",
            "in": "query",
            "description": "El plazo de presentación termina hasta esta fecha, incluida.",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "example": "2026-10-31"
          },
          {
            "name": "organo",
            "in": "query",
            "description": "Identificador del órgano de contratación en la plataforma: el campo `organo.id` de los resultados.",
            "schema": {
              "type": "string",
              "maxLength": 64
            },
            "example": "10000000000001"
          },
          {
            "name": "adjudicatario",
            "in": "query",
            "description": "NIF de una empresa adjudicataria: devuelve las licitaciones con algún lote adjudicado a ella.",
            "schema": {
              "type": "string",
              "maxLength": 32
            },
            "example": "B00000000"
          },
          {
            "name": "orden",
            "in": "query",
            "description": "Ordenar por fecha de publicación (`fecha`) o por importe sin IVA (`importe`).",
            "schema": {
              "type": "string",
              "enum": [
                "fecha",
                "importe"
              ],
              "default": "fecha"
            }
          },
          {
            "name": "direccion",
            "in": "query",
            "description": "Sentido del orden: descendente (`desc`) o ascendente (`asc`).",
            "schema": {
              "type": "string",
              "enum": [
                "desc",
                "asc"
              ],
              "default": "desc"
            }
          },
          {
            "name": "descartadas",
            "in": "query",
            "description": "Qué hacer con las licitaciones que tu equipo ha descartado («No me interesa»): ocultarlas, devolver solo esas o incluirlas.",
            "schema": {
              "type": "string",
              "enum": [
                "ocultar",
                "solo",
                "incluir"
              ],
              "default": "ocultar"
            }
          },
          {
            "$ref": "#/components/parameters/Pagina"
          },
          {
            "$ref": "#/components/parameters/PorPagina"
          },
          {
            "$ref": "#/components/parameters/Equipo"
          }
        ],
        "responses": {
          "200": {
            "description": "Una página de resultados.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/LicitacionResumen"
                      }
                    },
                    "meta": {
                      "type": "object",
                      "required": [
                        "paginacion",
                        "filtros"
                      ],
                      "properties": {
                        "paginacion": {
                          "$ref": "#/components/schemas/Paginacion"
                        },
                        "filtros": {
                          "$ref": "#/components/schemas/FiltrosAplicados"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "data": [
                    {
                      "id": 4815162,
                      "expediente": "CON-2026-0142",
                      "titulo": "Servicio de mantenimiento de zonas verdes y arbolado del término municipal",
                      "categoria": "licitacion",
                      "estado": {
                        "codigo": "PUB",
                        "nombre": "En plazo"
                      },
                      "tipo_contrato": {
                        "codigo": "2",
                        "nombre": "Servicios"
                      },
                      "subtipo_contrato": {
                        "codigo": "2::1",
                        "nombre": "Servicios de mantenimiento y reparación"
                      },
                      "organo": {
                        "id": "10000000000001",
                        "nombre": "Ayuntamiento de Ejemplo"
                      },
                      "lugar_ejecucion": {
                        "codigo": "ES523",
                        "nombre": "Valencia/València"
                      },
                      "importe_sin_iva": 240000.0,
                      "importe_con_iva": 290400.0,
                      "numero_lotes": 2,
                      "publicada": "2026-10-02T09:15:00+02:00",
                      "actualizada": "2026-10-06T12:40:00+02:00",
                      "plazo_presentacion": {
                        "fecha": "2026-10-30",
                        "hora": "14:00",
                        "tipo": "ofertas"
                      },
                      "sistema_contratacion": {
                        "codigo": "0",
                        "nombre": "No aplica"
                      },
                      "favorita": false,
                      "descartada": false,
                      "url_app": "https://app.licitaciones365.es/licitaciones/4815162",
                      "url_origen": "https://contrataciondelestado.es/wps/poc?uri=deeplink:detalle_licitacion&idEvl=EjemploAbc%3D%3D"
                    },
                    {
                      "id": 4812007,
                      "expediente": "2026/SER/0087",
                      "titulo": "Conservación de jardines y espacios verdes de los centros educativos",
                      "categoria": "licitacion",
                      "estado": {
                        "codigo": "PUB",
                        "nombre": "En plazo"
                      },
                      "tipo_contrato": {
                        "codigo": "2",
                        "nombre": "Servicios"
                      },
                      "subtipo_contrato": {
                        "codigo": "2::1",
                        "nombre": "Servicios de mantenimiento y reparación"
                      },
                      "organo": {
                        "id": "10000000000002",
                        "nombre": "Consejería de Ejemplo"
                      },
                      "lugar_ejecucion": {
                        "codigo": "ES523",
                        "nombre": "Valencia/València"
                      },
                      "importe_sin_iva": 86500.0,
                      "importe_con_iva": 104665.0,
                      "numero_lotes": 0,
                      "publicada": "2026-09-29T11:02:00+02:00",
                      "actualizada": "2026-09-29T11:02:00+02:00",
                      "plazo_presentacion": {
                        "fecha": "2026-10-20",
                        "hora": "23:59",
                        "tipo": "ofertas"
                      },
                      "sistema_contratacion": {
                        "codigo": "0",
                        "nombre": "No aplica"
                      },
                      "favorita": true,
                      "descartada": false,
                      "url_app": "https://app.licitaciones365.es/licitaciones/4812007",
                      "url_origen": "https://contrataciondelestado.es/wps/poc?uri=deeplink:detalle_licitacion&idEvl=EjemploXyz%3D%3D"
                    }
                  ],
                  "meta": {
                    "paginacion": {
                      "pagina": 1,
                      "por_pagina": 2,
                      "total": 14,
                      "total_es_minimo": false,
                      "hay_mas": true
                    },
                    "filtros": {
                      "estados": [
                        "PUB"
                      ],
                      "categorias": [
                        "licitacion",
                        "agregada",
                        "menor"
                      ],
                      "territorios": [
                        "ES523"
                      ],
                      "cpv": [
                        "77310000"
                      ],
                      "orden": "fecha desc",
                      "descartadas": "ocultar"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/NoAutenticado"
          },
          "403": {
            "$ref": "#/components/responses/SinAcceso"
          },
          "422": {
            "$ref": "#/components/responses/ParametrosInvalidos"
          },
          "429": {
            "$ref": "#/components/responses/LimiteSuperado"
          },
          "500": {
            "$ref": "#/components/responses/ErrorInterno"
          }
        }
      }
    },
    "/licitaciones/{id}": {
      "get": {
        "tags": [
          "Licitaciones"
        ],
        "operationId": "verLicitacion",
        "summary": "Ver la ficha de una licitación",
        "description": "Ficha de una licitación por su `id` (el de los resultados de búsqueda). Se pide por secciones para no traer más de lo necesario. Además de las secciones, la respuesta incluye todos los campos del resumen y la `fuente` de los datos.\n\nNo cuenta como una apertura de la ficha en la app.",
        "x-cuota-diaria": "fichas_dia",
        "x-ejemplo-peticion": {
          "path": {
            "id": 4815162
          },
          "query": {
            "secciones": [
              "general",
              "lotes",
              "condiciones",
              "documentos",
              "vencimiento",
              "equipo"
            ]
          }
        },
        "parameters": [
          {
            "$ref": "#/components/parameters/IdLicitacion"
          },
          {
            "name": "secciones",
            "in": "query",
            "description": "Secciones de la ficha, separadas por comas. Por defecto: `general,lotes,condiciones,equipo`. Las que no existen se ignoran.\n\n- `general`: objeto, valor estimado, procedimiento, tramitación, órgano, plazos, duración y CPV.\n- `lotes`: cada lote con importes, resultado, ofertas recibidas, adjudicatarios y CPV.\n- `condiciones`: criterios de adjudicación con su peso, solvencia, garantías, condiciones de ejecución, modificaciones y financiación.\n- `historial`: anuncios publicados (licitación, adjudicación, formalización…).\n- `documentos`: enlaces a pliegos y anuncios, como en `GET /licitaciones/{id}/documentos`.\n- `vencimiento`: fecha estimada de fin del contrato y si admite prórroga.\n- `equipo`: si es favorita de tu equipo, en qué grupo y si tiene nota, tareas o recordatorios.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string",
                "enum": [
                  "general",
                  "lotes",
                  "condiciones",
                  "historial",
                  "documentos",
                  "vencimiento",
                  "equipo"
                ]
              }
            },
            "style": "form",
            "explode": false,
            "example": [
              "general",
              "lotes",
              "documentos"
            ]
          },
          {
            "$ref": "#/components/parameters/Equipo"
          }
        ],
        "responses": {
          "200": {
            "description": "Ficha de la licitación con las secciones pedidas.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Licitacion"
                    }
                  }
                },
                "example": {
                  "data": {
                    "id": 4815162,
                    "expediente": "CON-2026-0142",
                    "titulo": "Servicio de mantenimiento de zonas verdes y arbolado del término municipal",
                    "categoria": "licitacion",
                    "estado": {
                      "codigo": "ADJ",
                      "nombre": "Adjudicada"
                    },
                    "tipo_contrato": {
                      "codigo": "2",
                      "nombre": "Servicios"
                    },
                    "subtipo_contrato": {
                      "codigo": "2::1",
                      "nombre": "Servicios de mantenimiento y reparación"
                    },
                    "organo": {
                      "id": "10000000000001",
                      "nombre": "Ayuntamiento de Ejemplo"
                    },
                    "lugar_ejecucion": {
                      "codigo": "ES523",
                      "nombre": "Valencia/València"
                    },
                    "importe_sin_iva": 240000.0,
                    "importe_con_iva": 290400.0,
                    "publicada": "2026-10-02T09:15:00+02:00",
                    "actualizada": "2026-12-11T10:05:00+01:00",
                    "plazo_presentacion": {
                      "fecha": "2026-10-30",
                      "hora": "14:00",
                      "tipo": "ofertas"
                    },
                    "sistema_contratacion": {
                      "codigo": "0",
                      "nombre": "No aplica"
                    },
                    "favorita": true,
                    "descartada": false,
                    "url_app": "https://app.licitaciones365.es/licitaciones/4815162",
                    "url_origen": "https://contrataciondelestado.es/wps/poc?uri=deeplink:detalle_licitacion&idEvl=EjemploAbc%3D%3D",
                    "general": {
                      "objeto": "Mantenimiento de las zonas verdes, el arbolado viario y el riego de los parques municipales.",
                      "valor_estimado": 528000.0,
                      "procedimiento": {
                        "codigo": "1",
                        "nombre": "Abierto"
                      },
                      "tramitacion": {
                        "codigo": "1",
                        "nombre": "Ordinaria"
                      },
                      "presentacion_ofertas": {
                        "codigo": "1",
                        "nombre": "Electrónica"
                      },
                      "subasta_electronica": false,
                      "lugar_ejecucion": {
                        "pais": "ES",
                        "territorio": "Valencia/València"
                      },
                      "organo": {
                        "id": "10000000000001",
                        "nombre": "Ayuntamiento de Ejemplo",
                        "perfil_contratante": "https://contrataciondelestado.es/wps/poc?uri=deeplink:perfilContratante&idBp=EjemploPerfil%3D%3D"
                      },
                      "plazos": {
                        "ofertas": {
                          "fecha": "2026-10-30",
                          "hora": "14:00"
                        }
                      },
                      "duracion": {
                        "valor": "2",
                        "unidades": "ANN"
                      },
                      "cpv": [
                        {
                          "codigo": "77310000",
                          "descripcion": "Servicios de plantación y mantenimiento de zonas verdes."
                        }
                      ]
                    },
                    "numero_lotes": 2,
                    "lotes": [
                      {
                        "lote": 1,
                        "objeto": "Parques y jardines del casco urbano",
                        "importe_sin_iva": 150000.0,
                        "importe_con_iva": 181500.0,
                        "lugar_ejecucion": "Valencia/València",
                        "resultado": {
                          "codigo": "8",
                          "nombre": "Adjudicado"
                        },
                        "fecha_adjudicacion": "2026-12-10",
                        "ofertas": {
                          "recibidas": 6,
                          "de_pymes": 5,
                          "mas_baja": 121500.0,
                          "mas_alta": 148200.0
                        },
                        "adjudicatarios": [
                          {
                            "nombre": "Jardinería Ejemplo, S.L.",
                            "nif": "B00000000",
                            "persona_fisica_protegida": false,
                            "importe_ofertado_sin_iva": 126000.0,
                            "importe_ofertado_con_iva": 152460.0,
                            "baja_porcentaje": 16.0
                          }
                        ],
                        "cpv": [
                          {
                            "codigo": "77311000",
                            "descripcion": "Servicios de mantenimiento de jardines y parques."
                          }
                        ]
                      },
                      {
                        "lote": 2,
                        "objeto": "Arbolado viario",
                        "importe_sin_iva": 90000.0,
                        "importe_con_iva": 108900.0,
                        "lugar_ejecucion": "Valencia/València",
                        "resultado": {
                          "codigo": "8",
                          "nombre": "Adjudicado"
                        },
                        "fecha_adjudicacion": "2026-12-10",
                        "ofertas": {
                          "recibidas": 3,
                          "de_pymes": 3
                        },
                        "adjudicatarios": [
                          {
                            "nombre": "Persona física",
                            "nif": null,
                            "persona_fisica_protegida": true,
                            "importe_ofertado_sin_iva": 83250.0,
                            "importe_ofertado_con_iva": 100732.5,
                            "baja_porcentaje": 7.5
                          }
                        ],
                        "cpv": []
                      }
                    ],
                    "condiciones": {
                      "criterios_adjudicacion": [
                        {
                          "descripcion": "Oferta económica",
                          "peso": 60.0
                        },
                        {
                          "descripcion": "Memoria técnica del servicio",
                          "peso": 40.0
                        }
                      ],
                      "garantias": [
                        {
                          "tipo": "Definitiva",
                          "porcentaje": 5.0
                        }
                      ],
                      "otras": {
                        "subcontratacion_porcentaje": 30.0,
                        "admite_variantes": false
                      }
                    },
                    "documentos": [
                      {
                        "id": "pliego_tec:88140",
                        "tipo": "Pliego de prescripciones técnicas",
                        "nombre": "PPT_zonas_verdes.pdf",
                        "fecha": "2026-10-02",
                        "fuente": "contrataciondelestado.es",
                        "retirado": false,
                        "url": "https://contrataciondelestado.es/FileSystem/servlet/GetDocumentByIdServlet?DocumentIdParam=Ejemplo2"
                      }
                    ],
                    "vencimiento": {
                      "disponible": true,
                      "estimado": true,
                      "fecha_vencimiento": "2028-12-31",
                      "dias_restantes": 808,
                      "confianza": "alta",
                      "estado": "ADJ",
                      "prorroga_posible": true,
                      "fecha_fin_base": "2028-12-31",
                      "fecha_fin_maxima": "2029-12-31",
                      "fuente": "calculo_formalizacion_duracion"
                    },
                    "equipo": {
                      "favorita": true,
                      "grupo": {
                        "id": 12,
                        "nombre": "En estudio"
                      },
                      "tiene_nota": true,
                      "tareas": 3,
                      "recordatorios": 1
                    },
                    "fuente": "Plataforma de Contratación del Sector Público y plataformas autonómicas (reutilización de la información del sector público, RISP), vía licitaciones365."
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/NoAutenticado"
          },
          "403": {
            "$ref": "#/components/responses/SinAcceso"
          },
          "404": {
            "$ref": "#/components/responses/NoEncontrado"
          },
          "429": {
            "$ref": "#/components/responses/LimiteSuperado"
          },
          "500": {
            "$ref": "#/components/responses/ErrorInterno"
          }
        }
      }
    },
    "/licitaciones/{id}/documentos": {
      "get": {
        "tags": [
          "Licitaciones"
        ],
        "operationId": "listarDocumentos",
        "summary": "Listar los documentos de una licitación",
        "description": "Pliegos de cláusulas administrativas y de prescripciones técnicas, anexos, documentos generales y anuncios de la licitación, del más reciente al más antiguo.\n\nSon **enlaces al portal oficial** (Plataforma de Contratación del Sector Público o el portal autonómico): Licitaciones365 no guarda copias ni sirve su contenido. Algunos portales piden un navegador para abrirlos. Si un documento se publicó varias veces, solo sale su última versión; los retirados del expediente vienen marcados.",
        "x-cuota-diaria": "fichas_dia",
        "x-ejemplo-peticion": {
          "path": {
            "id": 4815162
          }
        },
        "parameters": [
          {
            "$ref": "#/components/parameters/IdLicitacion"
          },
          {
            "$ref": "#/components/parameters/Equipo"
          }
        ],
        "responses": {
          "200": {
            "description": "Documentos de la licitación.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Documento"
                      }
                    },
                    "meta": {
                      "type": "object",
                      "required": [
                        "licitacion"
                      ],
                      "properties": {
                        "licitacion": {
                          "type": "object",
                          "description": "La licitación a la que pertenecen los documentos.",
                          "required": [
                            "id",
                            "titulo"
                          ],
                          "properties": {
                            "id": {
                              "type": "integer"
                            },
                            "titulo": {
                              "type": [
                                "string",
                                "null"
                              ]
                            }
                          }
                        }
                      }
                    }
                  }
                },
                "example": {
                  "data": [
                    {
                      "id": "anuncio:73311",
                      "tipo": "Anuncio de licitación",
                      "nombre": "anuncio_licitacion.pdf",
                      "fecha": "2026-10-02",
                      "fuente": "contrataciondelestado.es",
                      "retirado": false,
                      "url": "https://contrataciondelestado.es/FileSystem/servlet/GetDocumentByIdServlet?DocumentIdParam=Ejemplo3"
                    },
                    {
                      "id": "pliego_adm:90211",
                      "tipo": "Pliego de cláusulas administrativas",
                      "nombre": "PCAP_zonas_verdes.pdf",
                      "fecha": "2026-10-02",
                      "fuente": "contrataciondelestado.es",
                      "retirado": false,
                      "url": "https://contrataciondelestado.es/FileSystem/servlet/GetDocumentByIdServlet?DocumentIdParam=Ejemplo1"
                    },
                    {
                      "id": "pliego_tec:88140",
                      "tipo": "Pliego de prescripciones técnicas",
                      "nombre": "PPT_zonas_verdes.pdf",
                      "fecha": "2026-10-02",
                      "fuente": "contrataciondelestado.es",
                      "retirado": false,
                      "url": "https://contrataciondelestado.es/FileSystem/servlet/GetDocumentByIdServlet?DocumentIdParam=Ejemplo2"
                    }
                  ],
                  "meta": {
                    "licitacion": {
                      "id": 4815162,
                      "titulo": "Servicio de mantenimiento de zonas verdes y arbolado del término municipal"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/NoAutenticado"
          },
          "403": {
            "$ref": "#/components/responses/SinAcceso"
          },
          "404": {
            "$ref": "#/components/responses/NoEncontrado"
          },
          "429": {
            "$ref": "#/components/responses/LimiteSuperado"
          },
          "500": {
            "$ref": "#/components/responses/ErrorInterno"
          }
        }
      }
    },
    "/favoritas": {
      "get": {
        "tags": [
          "Favoritas"
        ],
        "operationId": "listarFavoritas",
        "summary": "Listar las favoritas",
        "description": "Favoritas del equipo, de la última añadida a la primera, con su grupo. Con los planes Pro y Enterprise, cada una trae además el vencimiento estimado del contrato, como en «Mis concursos» de la app.",
        "x-ejemplo-peticion": {
          "query": {
            "grupo_id": 12
          }
        },
        "parameters": [
          {
            "name": "grupo_id",
            "in": "query",
            "description": "Solo las de este grupo (los id salen en `GET /favoritas/grupos`).",
            "schema": {
              "type": "integer",
              "minimum": 1
            },
            "example": 12
          },
          {
            "name": "sin_grupo",
            "in": "query",
            "description": "Solo las que no están en ningún grupo. No se combina con `grupo_id`.",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "texto",
            "in": "query",
            "description": "Palabras que tienen que aparecer todas en el título, el objeto, el expediente, el órgano o los CPV (con varios lotes, también en los de los lotes).",
            "schema": {
              "type": "string",
              "maxLength": 200
            },
            "example": "jardines"
          },
          {
            "name": "estado",
            "in": "query",
            "description": "Estados, separados por comas (los mismos que en `GET /licitaciones`).",
            "schema": {
              "type": "array",
              "items": {
                "type": "string",
                "enum": [
                  "PUB",
                  "EV",
                  "ADJ",
                  "RES",
                  "PRE",
                  "CERR",
                  "ANUL"
                ]
              }
            },
            "style": "form",
            "explode": false,
            "example": [
              "PUB",
              "EV"
            ]
          },
          {
            "name": "categoria",
            "in": "query",
            "description": "Categorías, separadas por comas: `licitacion`, `agregada` o `menor`.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string",
                "enum": [
                  "licitacion",
                  "agregada",
                  "menor"
                ]
              }
            },
            "style": "form",
            "explode": false
          },
          {
            "name": "tipo_contrato",
            "in": "query",
            "description": "Tipos de contrato por su código, separados por comas (ver `GET /catalogos/tipos_contrato`).",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "style": "form",
            "explode": false
          },
          {
            "$ref": "#/components/parameters/Pagina"
          },
          {
            "$ref": "#/components/parameters/PorPagina"
          },
          {
            "$ref": "#/components/parameters/Equipo"
          }
        ],
        "responses": {
          "200": {
            "description": "Una página de favoritas.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Favorita"
                      }
                    },
                    "meta": {
                      "type": "object",
                      "required": [
                        "paginacion",
                        "filtros"
                      ],
                      "properties": {
                        "paginacion": {
                          "$ref": "#/components/schemas/Paginacion"
                        },
                        "filtros": {
                          "type": "object",
                          "description": "Filtros aplicados; solo aparecen los que tienen valor.",
                          "properties": {
                            "grupo": {
                              "$ref": "#/components/schemas/GrupoDeFavorita"
                            },
                            "sin_grupo": {
                              "type": "boolean"
                            },
                            "texto": {
                              "type": "string"
                            },
                            "estados": {
                              "type": "array",
                              "items": {
                                "type": "string"
                              }
                            },
                            "categorias": {
                              "type": "array",
                              "items": {
                                "type": "string"
                              }
                            },
                            "tipos_contrato": {
                              "type": "array",
                              "items": {
                                "type": "string"
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                },
                "example": {
                  "data": [
                    {
                      "id": 4815162,
                      "expediente": "CON-2026-0142",
                      "titulo": "Servicio de mantenimiento de zonas verdes y arbolado del término municipal",
                      "categoria": "licitacion",
                      "estado": {
                        "codigo": "PUB",
                        "nombre": "En plazo"
                      },
                      "tipo_contrato": {
                        "codigo": "2",
                        "nombre": "Servicios"
                      },
                      "subtipo_contrato": {
                        "codigo": "2::1",
                        "nombre": "Servicios de mantenimiento y reparación"
                      },
                      "organo": {
                        "id": "10000000000001",
                        "nombre": "Ayuntamiento de Ejemplo"
                      },
                      "lugar_ejecucion": {
                        "codigo": "ES523",
                        "nombre": "Valencia/València"
                      },
                      "importe_sin_iva": 240000.0,
                      "importe_con_iva": 290400.0,
                      "numero_lotes": 2,
                      "publicada": "2026-10-02T09:15:00+02:00",
                      "actualizada": "2026-10-06T12:40:00+02:00",
                      "plazo_presentacion": {
                        "fecha": "2026-10-30",
                        "hora": "14:00",
                        "tipo": "ofertas"
                      },
                      "sistema_contratacion": {
                        "codigo": "0",
                        "nombre": "No aplica"
                      },
                      "favorita": true,
                      "descartada": false,
                      "url_app": "https://app.licitaciones365.es/licitaciones/4815162",
                      "url_origen": "https://contrataciondelestado.es/wps/poc?uri=deeplink:detalle_licitacion&idEvl=EjemploAbc%3D%3D",
                      "grupo": {
                        "id": 12,
                        "nombre": "En estudio"
                      },
                      "anadida_a_favoritas": "2026-10-07T08:41:16+02:00",
                      "vencimiento": null
                    }
                  ],
                  "meta": {
                    "paginacion": {
                      "pagina": 1,
                      "por_pagina": 25,
                      "total": 1,
                      "hay_mas": false
                    },
                    "filtros": {
                      "grupo": {
                        "id": 12,
                        "nombre": "En estudio"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/NoAutenticado"
          },
          "403": {
            "$ref": "#/components/responses/SinAcceso"
          },
          "404": {
            "$ref": "#/components/responses/NoEncontrado"
          },
          "422": {
            "$ref": "#/components/responses/ParametrosInvalidos"
          },
          "429": {
            "$ref": "#/components/responses/LimiteSuperado"
          },
          "500": {
            "$ref": "#/components/responses/ErrorInterno"
          }
        }
      },
      "post": {
        "tags": [
          "Favoritas"
        ],
        "operationId": "anadirFavorita",
        "summary": "Añadir una favorita",
        "description": "Añade una licitación a las favoritas del equipo, si quieres en un grupo. Si estaba descartada («No me interesa»), deja de estarlo. Si estaba bloqueada por el plan, se reactiva.\n\nErrores propios: `409 ya_es_favorita` si ya lo es (para cambiarla de grupo, usa `PATCH`) y `403 limite_del_plan` si el equipo ha llegado al máximo de favoritas de su plan.",
        "x-cuota-diaria": "favoritas_nuevas_dia",
        "x-ejemplo-peticion": {
          "body": {
            "licitacion_id": 4815162,
            "grupo_id": 12
          }
        },
        "requestBody": {
          "description": "La licitación y, si quieres, el grupo.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "licitacion_id": {
                    "type": "integer",
                    "minimum": 1,
                    "description": "Id de la licitación (el campo `id` de `GET /licitaciones`)."
                  },
                  "grupo_id": {
                    "type": "integer",
                    "minimum": 1,
                    "description": "Grupo en el que guardarla (los grupos son desde el plan Plus). Sin él, queda sin grupo."
                  }
                },
                "required": [
                  "licitacion_id"
                ]
              },
              "example": {
                "licitacion_id": 4815162,
                "grupo_id": 12
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Favorita añadida.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Favorita"
                    },
                    "meta": {
                      "type": "object",
                      "required": [
                        "reactivada",
                        "descarte_retirado",
                        "limite_favoritas"
                      ],
                      "properties": {
                        "reactivada": {
                          "type": "boolean",
                          "description": "Si ya era favorita pero estaba bloqueada por el plan."
                        },
                        "descarte_retirado": {
                          "type": "boolean",
                          "description": "Si estaba marcada como «No me interesa» y se ha quitado la marca."
                        },
                        "limite_favoritas": {
                          "$ref": "#/components/schemas/LimitePlan"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "data": {
                    "id": 4815162,
                    "expediente": "CON-2026-0142",
                    "titulo": "Servicio de mantenimiento de zonas verdes y arbolado del término municipal",
                    "categoria": "licitacion",
                    "estado": {
                      "codigo": "PUB",
                      "nombre": "En plazo"
                    },
                    "tipo_contrato": {
                      "codigo": "2",
                      "nombre": "Servicios"
                    },
                    "subtipo_contrato": {
                      "codigo": "2::1",
                      "nombre": "Servicios de mantenimiento y reparación"
                    },
                    "organo": {
                      "id": "10000000000001",
                      "nombre": "Ayuntamiento de Ejemplo"
                    },
                    "lugar_ejecucion": {
                      "codigo": "ES523",
                      "nombre": "Valencia/València"
                    },
                    "importe_sin_iva": 240000.0,
                    "importe_con_iva": 290400.0,
                    "numero_lotes": 2,
                    "publicada": "2026-10-02T09:15:00+02:00",
                    "actualizada": "2026-10-06T12:40:00+02:00",
                    "plazo_presentacion": {
                      "fecha": "2026-10-30",
                      "hora": "14:00",
                      "tipo": "ofertas"
                    },
                    "sistema_contratacion": {
                      "codigo": "0",
                      "nombre": "No aplica"
                    },
                    "favorita": true,
                    "descartada": false,
                    "url_app": "https://app.licitaciones365.es/licitaciones/4815162",
                    "url_origen": "https://contrataciondelestado.es/wps/poc?uri=deeplink:detalle_licitacion&idEvl=EjemploAbc%3D%3D",
                    "grupo": {
                      "id": 12,
                      "nombre": "En estudio"
                    },
                    "anadida_a_favoritas": "2026-10-07T08:41:16+02:00",
                    "vencimiento": null
                  },
                  "meta": {
                    "reactivada": false,
                    "descarte_retirado": false,
                    "limite_favoritas": {
                      "usados": 85,
                      "maximo": null,
                      "puede_anadir": true
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/NoAutenticado"
          },
          "403": {
            "$ref": "#/components/responses/SinAcceso"
          },
          "404": {
            "$ref": "#/components/responses/NoEncontrado"
          },
          "409": {
            "$ref": "#/components/responses/Conflicto"
          },
          "422": {
            "$ref": "#/components/responses/ParametrosInvalidos"
          },
          "429": {
            "$ref": "#/components/responses/LimiteSuperado"
          },
          "500": {
            "$ref": "#/components/responses/ErrorInterno"
          }
        },
        "parameters": [
          {
            "$ref": "#/components/parameters/Equipo"
          }
        ]
      }
    },
    "/favoritas/grupos": {
      "get": {
        "tags": [
          "Favoritas"
        ],
        "operationId": "listarGruposFavoritas",
        "summary": "Listar los grupos de favoritas",
        "description": "Grupos del equipo (las etapas de «Mis concursos») con cuántas favoritas tiene cada uno, cuántas van sin grupo, el reparto entre licitaciones y contratos menores y los límites del plan.",
        "responses": {
          "200": {
            "description": "Grupos y límites.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "required": [
                          "id",
                          "nombre",
                          "orden",
                          "favoritas"
                        ],
                        "properties": {
                          "id": {
                            "type": "integer"
                          },
                          "nombre": {
                            "type": "string"
                          },
                          "orden": {
                            "type": "integer",
                            "description": "Posición del grupo en la app."
                          },
                          "favoritas": {
                            "type": "integer",
                            "description": "Favoritas del grupo."
                          }
                        }
                      }
                    },
                    "meta": {
                      "type": "object",
                      "required": [
                        "sin_grupo",
                        "por_categoria",
                        "limites"
                      ],
                      "properties": {
                        "sin_grupo": {
                          "type": "integer",
                          "description": "Favoritas que no están en ningún grupo."
                        },
                        "por_categoria": {
                          "type": "object",
                          "required": [
                            "licitaciones",
                            "contratos_menores"
                          ],
                          "properties": {
                            "licitaciones": {
                              "type": "integer"
                            },
                            "contratos_menores": {
                              "type": "integer"
                            }
                          }
                        },
                        "limites": {
                          "type": "object",
                          "required": [
                            "favoritas",
                            "grupos"
                          ],
                          "properties": {
                            "favoritas": {
                              "allOf": [
                                {
                                  "$ref": "#/components/schemas/LimitePlan"
                                },
                                {
                                  "type": "object",
                                  "properties": {
                                    "bloqueadas_por_plan": {
                                      "type": "integer",
                                      "description": "Favoritas que se conservan pero no se muestran porque el plan actual no las permite."
                                    }
                                  }
                                }
                              ]
                            },
                            "grupos": {
                              "$ref": "#/components/schemas/LimitePlan"
                            }
                          }
                        }
                      }
                    }
                  }
                },
                "example": {
                  "data": [
                    {
                      "id": 12,
                      "nombre": "En estudio",
                      "orden": 1,
                      "favoritas": 9
                    },
                    {
                      "id": 13,
                      "nombre": "Presentadas",
                      "orden": 2,
                      "favoritas": 4
                    }
                  ],
                  "meta": {
                    "sin_grupo": 72,
                    "por_categoria": {
                      "licitaciones": 80,
                      "contratos_menores": 5
                    },
                    "limites": {
                      "favoritas": {
                        "usados": 85,
                        "maximo": null,
                        "puede_anadir": true,
                        "bloqueadas_por_plan": 0
                      },
                      "grupos": {
                        "usados": 2,
                        "maximo": 20,
                        "puede_anadir": true
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/NoAutenticado"
          },
          "403": {
            "$ref": "#/components/responses/SinAcceso"
          },
          "429": {
            "$ref": "#/components/responses/LimiteSuperado"
          },
          "500": {
            "$ref": "#/components/responses/ErrorInterno"
          }
        },
        "parameters": [
          {
            "$ref": "#/components/parameters/Equipo"
          }
        ]
      }
    },
    "/favoritas/{id}": {
      "patch": {
        "tags": [
          "Favoritas"
        ],
        "operationId": "moverFavorita",
        "summary": "Mover una favorita de grupo",
        "description": "Cambia de grupo una favorita (`{id}` es el id de la licitación). Con `grupo_id: null` o `sin_grupo: true` la deja sin grupo. Hay que indicar una de las dos cosas.",
        "x-ejemplo-peticion": {
          "path": {
            "id": 4815162
          },
          "body": {
            "grupo_id": 13
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Id de la licitación (no de la favorita).",
            "schema": {
              "type": "integer",
              "minimum": 1
            },
            "example": 4815162
          },
          {
            "$ref": "#/components/parameters/Equipo"
          }
        ],
        "requestBody": {
          "description": "Grupo de destino.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "grupo_id": {
                    "type": [
                      "integer",
                      "null"
                    ],
                    "minimum": 1,
                    "description": "Grupo de destino, o `null` para dejarla sin grupo."
                  },
                  "sin_grupo": {
                    "type": "boolean",
                    "description": "`true` para dejarla sin grupo. No se combina con `grupo_id`."
                  }
                }
              },
              "example": {
                "grupo_id": 13
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Favorita en su grupo nuevo.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Favorita"
                    },
                    "meta": {
                      "type": "object",
                      "required": [
                        "grupo_anterior"
                      ],
                      "properties": {
                        "grupo_anterior": {
                          "oneOf": [
                            {
                              "$ref": "#/components/schemas/GrupoDeFavorita"
                            },
                            {
                              "type": "null"
                            }
                          ]
                        }
                      }
                    }
                  }
                },
                "example": {
                  "data": {
                    "id": 4815162,
                    "expediente": "CON-2026-0142",
                    "titulo": "Servicio de mantenimiento de zonas verdes y arbolado del término municipal",
                    "categoria": "licitacion",
                    "estado": {
                      "codigo": "PUB",
                      "nombre": "En plazo"
                    },
                    "tipo_contrato": {
                      "codigo": "2",
                      "nombre": "Servicios"
                    },
                    "subtipo_contrato": {
                      "codigo": "2::1",
                      "nombre": "Servicios de mantenimiento y reparación"
                    },
                    "organo": {
                      "id": "10000000000001",
                      "nombre": "Ayuntamiento de Ejemplo"
                    },
                    "lugar_ejecucion": {
                      "codigo": "ES523",
                      "nombre": "Valencia/València"
                    },
                    "importe_sin_iva": 240000.0,
                    "importe_con_iva": 290400.0,
                    "numero_lotes": 2,
                    "publicada": "2026-10-02T09:15:00+02:00",
                    "actualizada": "2026-10-06T12:40:00+02:00",
                    "plazo_presentacion": {
                      "fecha": "2026-10-30",
                      "hora": "14:00",
                      "tipo": "ofertas"
                    },
                    "sistema_contratacion": {
                      "codigo": "0",
                      "nombre": "No aplica"
                    },
                    "favorita": true,
                    "descartada": false,
                    "url_app": "https://app.licitaciones365.es/licitaciones/4815162",
                    "url_origen": "https://contrataciondelestado.es/wps/poc?uri=deeplink:detalle_licitacion&idEvl=EjemploAbc%3D%3D",
                    "grupo": {
                      "id": 13,
                      "nombre": "Presentadas"
                    },
                    "anadida_a_favoritas": "2026-10-07T08:41:16+02:00",
                    "vencimiento": null
                  },
                  "meta": {
                    "grupo_anterior": {
                      "id": 12,
                      "nombre": "En estudio"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/NoAutenticado"
          },
          "403": {
            "$ref": "#/components/responses/SinAcceso"
          },
          "404": {
            "$ref": "#/components/responses/NoEncontrado"
          },
          "422": {
            "$ref": "#/components/responses/ParametrosInvalidos"
          },
          "429": {
            "$ref": "#/components/responses/LimiteSuperado"
          },
          "500": {
            "$ref": "#/components/responses/ErrorInterno"
          }
        }
      },
      "delete": {
        "tags": [
          "Favoritas"
        ],
        "operationId": "quitarFavorita",
        "summary": "Quitar una favorita",
        "description": "Quita una licitación de las favoritas del equipo (`{id}` es el id de la licitación), también si estaba bloqueada por el plan. Desactiva sus recordatorios que aún no se han enviado; la nota y las tareas de la licitación se conservan.",
        "x-ejemplo-peticion": {
          "path": {
            "id": 4815162
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Id de la licitación (no de la favorita).",
            "schema": {
              "type": "integer",
              "minimum": 1
            },
            "example": 4815162
          },
          {
            "$ref": "#/components/parameters/Equipo"
          }
        ],
        "responses": {
          "200": {
            "description": "Favorita quitada.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {
                      "type": "object",
                      "required": [
                        "licitacion_id",
                        "titulo",
                        "recordatorios_desactivados"
                      ],
                      "properties": {
                        "licitacion_id": {
                          "type": "integer"
                        },
                        "titulo": {
                          "type": [
                            "string",
                            "null"
                          ]
                        },
                        "recordatorios_desactivados": {
                          "type": "integer"
                        }
                      }
                    },
                    "meta": {
                      "type": "object",
                      "required": [
                        "limite_favoritas"
                      ],
                      "properties": {
                        "limite_favoritas": {
                          "$ref": "#/components/schemas/LimitePlan"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "data": {
                    "licitacion_id": 4815162,
                    "titulo": "Servicio de mantenimiento de zonas verdes y arbolado del término municipal",
                    "recordatorios_desactivados": 1
                  },
                  "meta": {
                    "limite_favoritas": {
                      "usados": 84,
                      "maximo": null,
                      "puede_anadir": true
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/NoAutenticado"
          },
          "403": {
            "$ref": "#/components/responses/SinAcceso"
          },
          "404": {
            "$ref": "#/components/responses/NoEncontrado"
          },
          "429": {
            "$ref": "#/components/responses/LimiteSuperado"
          },
          "500": {
            "$ref": "#/components/responses/ErrorInterno"
          }
        }
      }
    },
    "/descartadas": {
      "get": {
        "tags": [
          "Descartadas"
        ],
        "operationId": "listarDescartadas",
        "summary": "Listar las descartadas",
        "description": "Licitaciones que el equipo ha marcado como «No me interesa», de la última a la primera.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Pagina"
          },
          {
            "$ref": "#/components/parameters/PorPagina"
          },
          {
            "$ref": "#/components/parameters/Equipo"
          }
        ],
        "responses": {
          "200": {
            "description": "Una página de descartadas.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Descartada"
                      }
                    },
                    "meta": {
                      "type": "object",
                      "required": [
                        "paginacion"
                      ],
                      "properties": {
                        "paginacion": {
                          "$ref": "#/components/schemas/Paginacion"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "data": [
                    {
                      "id": 4790031,
                      "expediente": "CON-2026-0142",
                      "titulo": "Suministro de vestuario para el personal de jardinería",
                      "categoria": "licitacion",
                      "estado": {
                        "codigo": "PUB",
                        "nombre": "En plazo"
                      },
                      "tipo_contrato": {
                        "codigo": "1",
                        "nombre": "Suministros"
                      },
                      "subtipo_contrato": {
                        "codigo": "1::2",
                        "nombre": "Adquisición"
                      },
                      "organo": {
                        "id": "10000000000001",
                        "nombre": "Ayuntamiento de Ejemplo"
                      },
                      "lugar_ejecucion": {
                        "codigo": "ES523",
                        "nombre": "Valencia/València"
                      },
                      "importe_sin_iva": 18000.0,
                      "importe_con_iva": 21780.0,
                      "numero_lotes": 0,
                      "publicada": "2026-10-02T09:15:00+02:00",
                      "actualizada": "2026-10-06T12:40:00+02:00",
                      "plazo_presentacion": {
                        "fecha": "2026-10-30",
                        "hora": "14:00",
                        "tipo": "ofertas"
                      },
                      "sistema_contratacion": {
                        "codigo": "0",
                        "nombre": "No aplica"
                      },
                      "favorita": false,
                      "descartada": true,
                      "url_app": "https://app.licitaciones365.es/licitaciones/4790031",
                      "url_origen": "https://contrataciondelestado.es/wps/poc?uri=deeplink:detalle_licitacion&idEvl=EjemploDef%3D%3D",
                      "descartada_el": "2026-10-03T17:22:05+02:00"
                    }
                  ],
                  "meta": {
                    "paginacion": {
                      "pagina": 1,
                      "por_pagina": 25,
                      "total": 1,
                      "hay_mas": false
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/NoAutenticado"
          },
          "403": {
            "$ref": "#/components/responses/SinAcceso"
          },
          "422": {
            "$ref": "#/components/responses/ParametrosInvalidos"
          },
          "429": {
            "$ref": "#/components/responses/LimiteSuperado"
          },
          "500": {
            "$ref": "#/components/responses/ErrorInterno"
          }
        }
      },
      "post": {
        "tags": [
          "Descartadas"
        ],
        "operationId": "descartarLicitacion",
        "summary": "Descartar una licitación",
        "description": "Marca una licitación como «No me interesa» para todo el equipo. Responde `201` si la marca es nueva y `200` si ya estaba descartada. Una favorita no se puede descartar (`409 es_favorita`): quítala antes de favoritas.",
        "x-ejemplo-peticion": {
          "body": {
            "licitacion_id": 4790031
          }
        },
        "requestBody": {
          "description": "La licitación.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "licitacion_id": {
                    "type": "integer",
                    "minimum": 1,
                    "description": "Id de la licitación (el campo `id` de `GET /licitaciones`)."
                  }
                },
                "required": [
                  "licitacion_id"
                ]
              },
              "example": {
                "licitacion_id": 4790031
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Licitación descartada.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/LicitacionResumen"
                    },
                    "meta": {
                      "type": "object",
                      "required": [
                        "ya_estaba_descartada"
                      ],
                      "properties": {
                        "ya_estaba_descartada": {
                          "type": "boolean"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "data": {
                    "id": 4790031,
                    "expediente": "CON-2026-0142",
                    "titulo": "Suministro de vestuario para el personal de jardinería",
                    "categoria": "licitacion",
                    "estado": {
                      "codigo": "PUB",
                      "nombre": "En plazo"
                    },
                    "tipo_contrato": {
                      "codigo": "1",
                      "nombre": "Suministros"
                    },
                    "subtipo_contrato": {
                      "codigo": "1::2",
                      "nombre": "Adquisición"
                    },
                    "organo": {
                      "id": "10000000000001",
                      "nombre": "Ayuntamiento de Ejemplo"
                    },
                    "lugar_ejecucion": {
                      "codigo": "ES523",
                      "nombre": "Valencia/València"
                    },
                    "importe_sin_iva": 18000.0,
                    "importe_con_iva": 21780.0,
                    "numero_lotes": 0,
                    "publicada": "2026-10-02T09:15:00+02:00",
                    "actualizada": "2026-10-06T12:40:00+02:00",
                    "plazo_presentacion": {
                      "fecha": "2026-10-30",
                      "hora": "14:00",
                      "tipo": "ofertas"
                    },
                    "sistema_contratacion": {
                      "codigo": "0",
                      "nombre": "No aplica"
                    },
                    "favorita": false,
                    "descartada": true,
                    "url_app": "https://app.licitaciones365.es/licitaciones/4790031",
                    "url_origen": "https://contrataciondelestado.es/wps/poc?uri=deeplink:detalle_licitacion&idEvl=EjemploDef%3D%3D"
                  },
                  "meta": {
                    "ya_estaba_descartada": false
                  }
                }
              }
            }
          },
          "200": {
            "description": "Ya estaba descartada (`ya_estaba_descartada: true`).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/LicitacionResumen"
                    },
                    "meta": {
                      "type": "object",
                      "required": [
                        "ya_estaba_descartada"
                      ],
                      "properties": {
                        "ya_estaba_descartada": {
                          "type": "boolean"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/NoAutenticado"
          },
          "403": {
            "$ref": "#/components/responses/SinAcceso"
          },
          "404": {
            "$ref": "#/components/responses/NoEncontrado"
          },
          "409": {
            "$ref": "#/components/responses/Conflicto"
          },
          "422": {
            "$ref": "#/components/responses/ParametrosInvalidos"
          },
          "429": {
            "$ref": "#/components/responses/LimiteSuperado"
          },
          "500": {
            "$ref": "#/components/responses/ErrorInterno"
          }
        },
        "parameters": [
          {
            "$ref": "#/components/parameters/Equipo"
          }
        ]
      }
    },
    "/descartadas/{id}": {
      "delete": {
        "tags": [
          "Descartadas"
        ],
        "operationId": "deshacerDescarte",
        "summary": "Deshacer un descarte",
        "description": "Quita la marca «No me interesa» (`{id}` es el id de la licitación): vuelve a salir en las búsquedas del equipo. Si no estaba descartada, no cambia nada.",
        "x-ejemplo-peticion": {
          "path": {
            "id": 4790031
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Id de la licitación (no de la favorita).",
            "schema": {
              "type": "integer",
              "minimum": 1
            },
            "example": 4815162
          },
          {
            "$ref": "#/components/parameters/Equipo"
          }
        ],
        "responses": {
          "200": {
            "description": "Descarte deshecho.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "type": "object",
                      "required": [
                        "licitacion_id",
                        "estaba_descartada"
                      ],
                      "properties": {
                        "licitacion_id": {
                          "type": "integer"
                        },
                        "estaba_descartada": {
                          "type": "boolean"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "data": {
                    "licitacion_id": 4790031,
                    "estaba_descartada": true
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/NoAutenticado"
          },
          "403": {
            "$ref": "#/components/responses/SinAcceso"
          },
          "429": {
            "$ref": "#/components/responses/LimiteSuperado"
          },
          "500": {
            "$ref": "#/components/responses/ErrorInterno"
          }
        }
      }
    },
    "/catalogos/{tipo}": {
      "get": {
        "tags": [
          "Catálogos"
        ],
        "operationId": "consultarCatalogo",
        "summary": "Consultar un catálogo de códigos",
        "description": "Traduce lo que buscas a los códigos de los filtros de `GET /licitaciones`.\n\n- `cpv`: por texto (todas las palabras de 3 letras o más, sin importar tildes ni el final de la palabra: «jardines» encuentra «jardinería») o por código o prefijo (`4521` devuelve sus subcódigos). Sin texto, devuelve las divisiones (los dos primeros dígitos).\n- `provincias` (NUTS3) y `comunidades` (NUTS2), por nombre.\n- `estados`, `categorias`, `tipos_contrato`, `subtipos_contrato` (formato `tipo::subtipo`), `sistemas_contratacion` y `procedimientos`, por nombre o código.\n\nLa forma de cada elemento depende del catálogo (ver el esquema).",
        "x-ejemplo-peticion": {
          "path": {
            "tipo": "cpv"
          },
          "query": {
            "texto": "zonas verdes"
          }
        },
        "parameters": [
          {
            "name": "tipo",
            "in": "path",
            "required": true,
            "description": "Catálogo que quieres consultar.",
            "schema": {
              "type": "string",
              "enum": [
                "cpv",
                "provincias",
                "comunidades",
                "estados",
                "categorias",
                "tipos_contrato",
                "subtipos_contrato",
                "sistemas_contratacion",
                "procedimientos"
              ]
            },
            "example": "cpv"
          },
          {
            "name": "texto",
            "in": "query",
            "description": "Texto o código que buscar. Opcional salvo para afinar los CPV.",
            "schema": {
              "type": "string",
              "maxLength": 100
            },
            "example": "zonas verdes"
          },
          {
            "name": "limite",
            "in": "query",
            "description": "Máximo de resultados.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 50
            }
          },
          {
            "$ref": "#/components/parameters/Equipo"
          }
        ],
        "responses": {
          "200": {
            "description": "Códigos que coinciden.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/ElementoCatalogo"
                      }
                    },
                    "meta": {
                      "type": "object",
                      "required": [
                        "tipo",
                        "total"
                      ],
                      "properties": {
                        "tipo": {
                          "type": "string",
                          "description": "El catálogo consultado."
                        },
                        "total": {
                          "type": "integer",
                          "description": "Número de elementos devueltos."
                        }
                      }
                    }
                  }
                },
                "example": {
                  "data": [
                    {
                      "codigo": "45112710",
                      "descripcion": "Trabajos de paisajismo en zonas verdes."
                    },
                    {
                      "codigo": "77310000",
                      "descripcion": "Servicios de plantación y mantenimiento de zonas verdes."
                    }
                  ],
                  "meta": {
                    "tipo": "cpv",
                    "total": 2
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/NoAutenticado"
          },
          "403": {
            "$ref": "#/components/responses/SinAcceso"
          },
          "422": {
            "$ref": "#/components/responses/ParametrosInvalidos"
          },
          "429": {
            "$ref": "#/components/responses/LimiteSuperado"
          },
          "500": {
            "$ref": "#/components/responses/ErrorInterno"
          }
        }
      }
    },
    "/licitaciones/{id}/ia/preguntas": {
      "post": {
        "tags": [
          "IA"
        ],
        "operationId": "preguntarLicitacion",
        "summary": "Preguntar a la IA sobre una licitación",
        "description": "Envía una pregunta a la IA de Licitaciones365, que la responde leyendo los pliegos y documentos de esa licitación: solvencia, criterios, documentación que presentar, garantías, penalidades…\n\nLa conversación queda guardada en la app, visible para el equipo (o solo para ti con `privada: true`), y gasta presupuesto de IA del equipo. La primera pregunta sobre una licitación puede tardar unos minutos, mientras la IA lee los pliegos: si la respuesta no llega a tiempo, recibes `202` con un `run_id` para recogerla con `GET /ia/consultas/{run}`.\n\nLos contratos menores solo se pueden consultar mientras están en fase de ofertas.",
        "x-cuota-diaria": "consultas_ia_dia",
        "x-presupuesto-ia": true,
        "x-ejemplo-peticion": {
          "path": {
            "id": 4815162
          },
          "body": {
            "pregunta": "¿Qué solvencia técnica piden y cómo se acredita?",
            "esperar": 20
          }
        },
        "parameters": [
          {
            "$ref": "#/components/parameters/IdLicitacion"
          },
          {
            "$ref": "#/components/parameters/Equipo"
          }
        ],
        "requestBody": {
          "description": "La pregunta y, si quieres, la conversación que continúa.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "pregunta": {
                    "type": "string",
                    "minLength": 3,
                    "maxLength": 5000,
                    "description": "La pregunta, en lenguaje natural."
                  },
                  "conversacion_id": {
                    "type": "integer",
                    "minimum": 1,
                    "description": "Conversación anterior que quieres continuar (el `conversacion_id` de una respuesta). Sin él, empieza una nueva."
                  },
                  "privada": {
                    "type": "boolean",
                    "default": false,
                    "description": "Si la conversación es solo para ti. Por defecto la ve todo el equipo."
                  },
                  "esperar": {
                    "type": "integer",
                    "minimum": 0,
                    "maximum": 25,
                    "default": 0,
                    "description": "Segundos que la llamada espera a que termine la IA antes de responder (como mucho 25). Con 0 responde enseguida con `estado=en_curso`."
                  }
                },
                "required": [
                  "pregunta"
                ]
              },
              "example": {
                "pregunta": "¿Qué solvencia técnica piden y cómo se acredita?",
                "esperar": 20
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "La IA ha respondido (`estado: \"completada\"`) o no ha podido hacerlo (`estado: \"error\"`).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/RespuestaIa"
                    }
                  }
                },
                "example": {
                  "data": {
                    "run_id": 98231,
                    "conversacion_id": 5512,
                    "licitacion_id": 4815162,
                    "url_app": "https://app.licitaciones365.es/licitaciones/4815162",
                    "estado": "completada",
                    "respuesta": "El pliego de cláusulas administrativas pide como solvencia técnica una relación de los principales servicios de igual o similar naturaleza realizados en los últimos tres años…"
                  }
                }
              }
            }
          },
          "202": {
            "description": "La IA sigue trabajando (`estado: \"en_curso\"`). Recoge la respuesta con `GET /ia/consultas/{run}`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/RespuestaIa"
                    }
                  }
                },
                "example": {
                  "data": {
                    "run_id": 98231,
                    "conversacion_id": 5512,
                    "licitacion_id": 4815162,
                    "url_app": "https://app.licitaciones365.es/licitaciones/4815162",
                    "estado": "en_curso",
                    "fase": "cargando los pliegos",
                    "mensaje": "La IA sigue trabajando (la primera vez lee los pliegos y puede tardar unos minutos). Vuelve a consultarla con este run_id."
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/NoAutenticado"
          },
          "403": {
            "$ref": "#/components/responses/SinAcceso"
          },
          "404": {
            "$ref": "#/components/responses/NoEncontrado"
          },
          "409": {
            "$ref": "#/components/responses/Conflicto"
          },
          "422": {
            "$ref": "#/components/responses/ParametrosInvalidos"
          },
          "429": {
            "$ref": "#/components/responses/LimiteSuperado"
          },
          "500": {
            "$ref": "#/components/responses/ErrorInterno"
          }
        }
      }
    },
    "/ia/consultas/{run}": {
      "get": {
        "tags": [
          "IA"
        ],
        "operationId": "consultarRespuestaIa",
        "summary": "Recoger la respuesta de una pregunta",
        "description": "Devuelve la respuesta de una pregunta que estaba en curso, a partir de su `run_id`. Responde `200` también si la IA sigue trabajando: mira el campo `estado`. No gasta presupuesto de IA.",
        "x-ejemplo-peticion": {
          "path": {
            "run": 98231
          },
          "query": {
            "esperar": 10
          }
        },
        "parameters": [
          {
            "name": "run",
            "in": "path",
            "required": true,
            "description": "El `run_id` que devolvió la pregunta.",
            "schema": {
              "type": "integer",
              "minimum": 1
            },
            "example": 98231
          },
          {
            "name": "esperar",
            "in": "query",
            "description": "Segundos que la llamada espera a que termine la IA antes de responder (como mucho 25). Con 0 responde enseguida con `estado=en_curso`.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 25,
              "default": 0
            }
          },
          {
            "$ref": "#/components/parameters/Equipo"
          }
        ],
        "responses": {
          "200": {
            "description": "Estado de la consulta y, si ha terminado, la respuesta.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/RespuestaIa"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/NoAutenticado"
          },
          "403": {
            "$ref": "#/components/responses/SinAcceso"
          },
          "404": {
            "$ref": "#/components/responses/NoEncontrado"
          },
          "422": {
            "$ref": "#/components/responses/ParametrosInvalidos"
          },
          "429": {
            "$ref": "#/components/responses/LimiteSuperado"
          },
          "500": {
            "$ref": "#/components/responses/ErrorInterno"
          }
        }
      }
    },
    "/licitaciones/{id}/ia/checklist": {
      "get": {
        "tags": [
          "IA"
        ],
        "operationId": "verChecklistIa",
        "summary": "Ver el checklist IA de una licitación",
        "description": "La última propuesta de tareas de la IA para presentarse a la licitación, o su estado si aún no existe o se está generando. No gasta presupuesto de IA. Planes Pro y Enterprise.",
        "x-ejemplo-peticion": {
          "path": {
            "id": 4815162
          }
        },
        "parameters": [
          {
            "$ref": "#/components/parameters/IdLicitacion"
          },
          {
            "$ref": "#/components/parameters/Equipo"
          }
        ],
        "responses": {
          "200": {
            "description": "La propuesta o su estado (`sin_generar`, `en_curso`, `error`).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/ChecklistIa"
                    }
                  }
                },
                "example": {
                  "data": {
                    "licitacion_id": 4815162,
                    "estado": "completado",
                    "tareas": [
                      {
                        "indice": 0,
                        "tarea": "Preparar el certificado de estar al corriente con la Seguridad Social",
                        "prioridad": "alta",
                        "ya_en_el_checklist": false
                      },
                      {
                        "indice": 1,
                        "tarea": "Redactar la memoria técnica del servicio",
                        "descripcion": "Máximo 30 páginas; se valora con 40 puntos.",
                        "prioridad": "alta",
                        "ya_en_el_checklist": true
                      },
                      {
                        "indice": 2,
                        "tarea": "Constituir la garantía definitiva del 5 %",
                        "prioridad": "media",
                        "ya_en_el_checklist": false
                      }
                    ],
                    "generado": "2026-10-06T10:12:44+02:00",
                    "mensaje": "Propuesta de la IA a partir de los pliegos. Revísala antes de importarla al checklist del equipo."
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/NoAutenticado"
          },
          "403": {
            "$ref": "#/components/responses/SinAcceso"
          },
          "404": {
            "$ref": "#/components/responses/NoEncontrado"
          },
          "429": {
            "$ref": "#/components/responses/LimiteSuperado"
          },
          "500": {
            "$ref": "#/components/responses/ErrorInterno"
          }
        }
      },
      "post": {
        "tags": [
          "IA"
        ],
        "operationId": "generarChecklistIa",
        "summary": "Generar el checklist IA de una licitación",
        "description": "La IA lee los pliegos y propone las tareas para presentarse: documentación, garantías, plazos… Gasta presupuesto de IA la primera vez; si ya hay una propuesta para esos mismos documentos, se reutiliza. Las tareas no pasan al checklist del equipo hasta que las importas. Planes Pro y Enterprise.",
        "x-cuota-diaria": "consultas_ia_dia",
        "x-presupuesto-ia": true,
        "x-ejemplo-peticion": {
          "path": {
            "id": 4815162
          },
          "body": {
            "esperar": 20
          }
        },
        "parameters": [
          {
            "$ref": "#/components/parameters/IdLicitacion"
          },
          {
            "$ref": "#/components/parameters/Equipo"
          }
        ],
        "requestBody": {
          "description": "Opcional.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "esperar": {
                    "type": "integer",
                    "minimum": 0,
                    "maximum": 25,
                    "default": 0,
                    "description": "Segundos que la llamada espera a que termine la IA antes de responder (como mucho 25). Con 0 responde enseguida con `estado=en_curso`."
                  }
                }
              },
              "example": {
                "esperar": 20
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Propuesta lista (`estado: \"completado\"`).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/ChecklistIa"
                    }
                  }
                },
                "example": {
                  "data": {
                    "licitacion_id": 4815162,
                    "estado": "completado",
                    "tareas": [
                      {
                        "indice": 0,
                        "tarea": "Preparar el certificado de estar al corriente con la Seguridad Social",
                        "prioridad": "alta",
                        "ya_en_el_checklist": false
                      },
                      {
                        "indice": 1,
                        "tarea": "Redactar la memoria técnica del servicio",
                        "descripcion": "Máximo 30 páginas; se valora con 40 puntos.",
                        "prioridad": "alta",
                        "ya_en_el_checklist": true
                      },
                      {
                        "indice": 2,
                        "tarea": "Constituir la garantía definitiva del 5 %",
                        "prioridad": "media",
                        "ya_en_el_checklist": false
                      }
                    ],
                    "generado": "2026-10-06T10:12:44+02:00",
                    "mensaje": "Propuesta de la IA a partir de los pliegos. Revísala antes de importarla al checklist del equipo."
                  }
                }
              }
            }
          },
          "202": {
            "description": "La IA sigue leyendo los pliegos (`estado: \"en_curso\"`). Consúltalo después con `GET`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/ChecklistIa"
                    }
                  }
                },
                "example": {
                  "data": {
                    "licitacion_id": 4815162,
                    "estado": "en_curso",
                    "mensaje": "La IA está leyendo los pliegos para proponer el checklist. Vuelve a consultarlo en un minuto."
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/NoAutenticado"
          },
          "403": {
            "$ref": "#/components/responses/SinAcceso"
          },
          "404": {
            "$ref": "#/components/responses/NoEncontrado"
          },
          "409": {
            "$ref": "#/components/responses/Conflicto"
          },
          "422": {
            "$ref": "#/components/responses/ParametrosInvalidos"
          },
          "429": {
            "$ref": "#/components/responses/LimiteSuperado"
          },
          "500": {
            "$ref": "#/components/responses/ErrorInterno"
          }
        }
      }
    },
    "/licitaciones/{id}/ia/checklist/importar": {
      "post": {
        "tags": [
          "IA"
        ],
        "operationId": "importarChecklistIa",
        "summary": "Importar el checklist IA al checklist del equipo",
        "description": "Añade al checklist del equipo en esa licitación las tareas de la última propuesta de la IA: todas o solo las de `indices`. Las que ya existen no se duplican. No gasta presupuesto de IA. Planes Pro y Enterprise.",
        "x-ejemplo-peticion": {
          "path": {
            "id": 4815162
          },
          "body": {
            "indices": [
              0,
              2
            ]
          }
        },
        "parameters": [
          {
            "$ref": "#/components/parameters/IdLicitacion"
          },
          {
            "$ref": "#/components/parameters/Equipo"
          }
        ],
        "requestBody": {
          "description": "Opcional: sin `indices` se importan todas.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "indices": {
                    "type": "array",
                    "maxItems": 100,
                    "items": {
                      "type": "integer",
                      "minimum": 0
                    },
                    "description": "Posiciones (`indice`) de las tareas que quieres importar."
                  }
                }
              },
              "example": {
                "indices": [
                  0,
                  2
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Tareas añadidas.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/ImportacionChecklistIa"
                    }
                  }
                },
                "example": {
                  "data": {
                    "licitacion_id": 4815162,
                    "importadas": 2,
                    "tareas_creadas": [
                      70412,
                      70413
                    ],
                    "mensaje": "Tareas añadidas al checklist del equipo (las que ya existían no se duplican)."
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/NoAutenticado"
          },
          "403": {
            "$ref": "#/components/responses/SinAcceso"
          },
          "404": {
            "$ref": "#/components/responses/NoEncontrado"
          },
          "409": {
            "$ref": "#/components/responses/Conflicto"
          },
          "422": {
            "$ref": "#/components/responses/ParametrosInvalidos"
          },
          "429": {
            "$ref": "#/components/responses/LimiteSuperado"
          },
          "500": {
            "$ref": "#/components/responses/ErrorInterno"
          }
        }
      }
    },
    "/licitaciones/{id}/informe-pdf": {
      "get": {
        "tags": [
          "IA"
        ],
        "operationId": "verInformePdf",
        "summary": "Ver el informe PDF de una licitación",
        "description": "Estado del informe PDF de tu equipo para la licitación y, si está listo, un enlace de descarga que **caduca a los 15 minutos** (si caduca, vuelve a pedir el estado). No gasta presupuesto de IA. Solo licitaciones, no contratos menores.",
        "x-ejemplo-peticion": {
          "path": {
            "id": 4815162
          }
        },
        "parameters": [
          {
            "$ref": "#/components/parameters/IdLicitacion"
          },
          {
            "$ref": "#/components/parameters/Equipo"
          }
        ],
        "responses": {
          "200": {
            "description": "Estado del informe (`sin_generar`, `en_curso`, `listo` o `error`).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/InformePdf"
                    }
                  }
                },
                "example": {
                  "data": {
                    "licitacion_id": 4815162,
                    "estado": "listo",
                    "version": 2,
                    "generado": "2026-10-06T10:20:03+02:00",
                    "hay_version_mas_nueva": false,
                    "enlace": "https://api.licitaciones365.es/v1/descargas/informes/3321?expires=1792483200&signature=5f2b8c7d1e0a9b3c4d6e7f8091a2b3c4d5e6f708192a3b4c5d6e7f8091a2b3c4",
                    "enlace_caduca_en_minutos": 15,
                    "mensaje": "Informe listo. El enlace caduca en 15 minutos; si caduca, vuelve a pedir el estado para obtener otro."
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/NoAutenticado"
          },
          "403": {
            "$ref": "#/components/responses/SinAcceso"
          },
          "404": {
            "$ref": "#/components/responses/NoEncontrado"
          },
          "422": {
            "$ref": "#/components/responses/ParametrosInvalidos"
          },
          "429": {
            "$ref": "#/components/responses/LimiteSuperado"
          },
          "500": {
            "$ref": "#/components/responses/ErrorInterno"
          }
        }
      },
      "post": {
        "tags": [
          "IA"
        ],
        "operationId": "generarInformePdf",
        "summary": "Generar el informe PDF de una licitación",
        "description": "Genera el informe PDF de Licitaciones365 sobre la licitación (un resumen de los pliegos y los datos clave, listo para compartir) o una versión nueva si los documentos han cambiado. Gasta presupuesto de IA del equipo. Suele tardar uno o dos minutos: si no está listo dentro de `esperar`, recibes `202` y lo consultas con `GET`. Solo licitaciones, no contratos menores.",
        "x-cuota-diaria": "consultas_ia_dia",
        "x-presupuesto-ia": true,
        "x-ejemplo-peticion": {
          "path": {
            "id": 4815162
          },
          "body": {
            "esperar": 25
          }
        },
        "parameters": [
          {
            "$ref": "#/components/parameters/IdLicitacion"
          },
          {
            "$ref": "#/components/parameters/Equipo"
          }
        ],
        "requestBody": {
          "description": "Opcional.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "esperar": {
                    "type": "integer",
                    "minimum": 0,
                    "maximum": 25,
                    "default": 0,
                    "description": "Segundos que la llamada espera a que termine la IA antes de responder (como mucho 25). Con 0 responde enseguida con `estado=en_curso`."
                  }
                }
              },
              "example": {
                "esperar": 25
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Informe listo (o con error).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/InformePdf"
                    }
                  }
                },
                "example": {
                  "data": {
                    "licitacion_id": 4815162,
                    "estado": "listo",
                    "version": 2,
                    "generado": "2026-10-06T10:20:03+02:00",
                    "hay_version_mas_nueva": false,
                    "enlace": "https://api.licitaciones365.es/v1/descargas/informes/3321?expires=1792483200&signature=5f2b8c7d1e0a9b3c4d6e7f8091a2b3c4d5e6f708192a3b4c5d6e7f8091a2b3c4",
                    "enlace_caduca_en_minutos": 15,
                    "mensaje": "Informe listo. El enlace caduca en 15 minutos; si caduca, vuelve a pedir el estado para obtener otro."
                  }
                }
              }
            }
          },
          "202": {
            "description": "El informe se está generando (`estado: \"en_curso\"`).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/InformePdf"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/NoAutenticado"
          },
          "403": {
            "$ref": "#/components/responses/SinAcceso"
          },
          "404": {
            "$ref": "#/components/responses/NoEncontrado"
          },
          "409": {
            "$ref": "#/components/responses/Conflicto"
          },
          "422": {
            "$ref": "#/components/responses/ParametrosInvalidos"
          },
          "429": {
            "$ref": "#/components/responses/LimiteSuperado"
          },
          "500": {
            "$ref": "#/components/responses/ErrorInterno"
          }
        }
      }
    },
    "/licitaciones/{id}/competencia": {
      "get": {
        "tags": [
          "IA"
        ],
        "operationId": "verCompetencia",
        "summary": "Ver el análisis de competencia de un lote",
        "description": "El último análisis de competencia que hizo tu equipo para un lote: qué empresas suelen ganar contratos parecidos (mismo segmento de CPV), cuántas veces, con qué bajas, y la estimación del importe de adjudicación. No gasta presupuesto de IA. Si tu equipo aún no lo ha calculado, responde `404`. Planes Pro y Enterprise; solo licitaciones.",
        "x-ejemplo-peticion": {
          "path": {
            "id": 4815162
          },
          "query": {
            "lote": "1"
          }
        },
        "parameters": [
          {
            "$ref": "#/components/parameters/IdLicitacion"
          },
          {
            "name": "lote",
            "in": "query",
            "description": "Número del lote. Si la licitación tiene un solo lote, se puede omitir.",
            "schema": {
              "type": "string",
              "maxLength": 20
            },
            "example": "1"
          },
          {
            "$ref": "#/components/parameters/Equipo"
          }
        ],
        "responses": {
          "200": {
            "description": "Último análisis del equipo para el lote.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Competencia"
                    }
                  }
                },
                "example": {
                  "data": {
                    "licitacion_id": 4815162,
                    "lote": {
                      "numero": 1,
                      "objeto": "Parques y jardines del casco urbano"
                    },
                    "generado": "2026-10-05T18:31:10+02:00",
                    "desde_ultimo_analisis": true,
                    "conclusion": {
                      "texto": "Competencia moderada: la mitad de las adjudicaciones parecidas se ganaron con bajas de entre el 9 y el 17 %.",
                      "puntos_clave": [
                        "Mediana de baja: 12,8 %",
                        "El competidor con más presencia gana 1 de cada 10 adjudicaciones del segmento"
                      ],
                      "alertas": [
                        "Conclusión orientativa, no determinista."
                      ],
                      "generada_con_ia": true
                    },
                    "estimacion": {
                      "adjudicaciones_comparables": 80,
                      "confianza": "media",
                      "baja_pct": {
                        "percentil_25": 9.25,
                        "mediana": 12.8,
                        "percentil_75": 16.75,
                        "percentil_90": 21.1,
                        "media": 13.98,
                        "minima": 1.0,
                        "maxima": 42.0
                      },
                      "importe_sin_iva": {
                        "presupuesto_lote": 120000.0,
                        "oferta_conservadora": 108900.0,
                        "oferta_media": 104640.0,
                        "oferta_agresiva": 99900.0,
                        "oferta_muy_agresiva": 94680.0
                      },
                      "histograma_bajas": [
                        {
                          "desde_pct": 0.0,
                          "hasta_pct": 9.5,
                          "adjudicaciones": 12,
                          "porcentaje": 15.0
                        }
                      ]
                    },
                    "competidores": [
                      {
                        "nombre": "Jardinería Ejemplo, S.L.",
                        "nif": "B00000000",
                        "persona_fisica_protegida": false,
                        "adjudicaciones_en_el_segmento": 14,
                        "presencia_en_el_segmento_pct": 9.3,
                        "baja_media_pct": 12.4,
                        "baja_maxima_pct": 21.0,
                        "ultima_baja_pct": 16.0
                      },
                      {
                        "nombre": "Persona física",
                        "persona_fisica_protegida": true,
                        "adjudicaciones_en_el_segmento": 3,
                        "baja_media_pct": 7.1
                      }
                    ],
                    "competidores_total": 2,
                    "mensaje": "Último análisis del equipo. Para actualizarlo hay que volver a generarlo (consume presupuesto de IA)."
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/NoAutenticado"
          },
          "403": {
            "$ref": "#/components/responses/SinAcceso"
          },
          "404": {
            "$ref": "#/components/responses/NoEncontrado"
          },
          "422": {
            "$ref": "#/components/responses/ParametrosInvalidos"
          },
          "429": {
            "$ref": "#/components/responses/LimiteSuperado"
          },
          "500": {
            "$ref": "#/components/responses/ErrorInterno"
          }
        }
      },
      "post": {
        "tags": [
          "IA"
        ],
        "operationId": "analizarCompetencia",
        "summary": "Calcular el análisis de competencia de un lote",
        "description": "Calcula (o vuelve a calcular) el análisis de competencia de un lote. Gasta presupuesto de IA del equipo. Planes Pro y Enterprise; solo licitaciones.",
        "x-cuota-diaria": "consultas_ia_dia",
        "x-presupuesto-ia": true,
        "x-ejemplo-peticion": {
          "path": {
            "id": 4815162
          },
          "body": {
            "lote": "1"
          }
        },
        "parameters": [
          {
            "$ref": "#/components/parameters/IdLicitacion"
          },
          {
            "$ref": "#/components/parameters/Equipo"
          }
        ],
        "requestBody": {
          "description": "Opcional si la licitación tiene un solo lote.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "lote": {
                    "type": "string",
                    "maxLength": 20,
                    "description": "Número del lote."
                  }
                }
              },
              "example": {
                "lote": "1"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Análisis recién calculado (`desde_ultimo_analisis: false`).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Competencia"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/NoAutenticado"
          },
          "403": {
            "$ref": "#/components/responses/SinAcceso"
          },
          "404": {
            "$ref": "#/components/responses/NoEncontrado"
          },
          "409": {
            "$ref": "#/components/responses/Conflicto"
          },
          "422": {
            "$ref": "#/components/responses/ParametrosInvalidos"
          },
          "429": {
            "$ref": "#/components/responses/LimiteSuperado"
          },
          "500": {
            "$ref": "#/components/responses/ErrorInterno"
          }
        }
      }
    },
    "/ia/recomendar-cpv": {
      "post": {
        "tags": [
          "IA"
        ],
        "operationId": "recomendarCpv",
        "summary": "Recomendar códigos CPV para una empresa",
        "description": "A partir de la descripción de la actividad de una empresa, la IA recomienda los 10 códigos CPV más adecuados, con su relevancia. Útil para preparar búsquedas y alertas. Gasta presupuesto de IA del equipo; para buscar un CPV por su nombre, sin coste, usa `GET /catalogos/cpv`.",
        "x-cuota-diaria": "consultas_ia_dia",
        "x-presupuesto-ia": true,
        "x-ejemplo-peticion": {
          "body": {
            "descripcion": "Empresa de mantenimiento de zonas verdes, poda de arbolado y sistemas de riego para ayuntamientos."
          }
        },
        "requestBody": {
          "description": "Descripción de la actividad.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "descripcion": {
                    "type": "string",
                    "minLength": 20,
                    "maxLength": 1000,
                    "description": "A qué se dedica la empresa, en lenguaje natural."
                  }
                },
                "required": [
                  "descripcion"
                ]
              },
              "example": {
                "descripcion": "Empresa de mantenimiento de zonas verdes, poda de arbolado y sistemas de riego para ayuntamientos."
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Códigos recomendados.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/RecomendacionCpv"
                    }
                  }
                },
                "example": {
                  "data": {
                    "cpv": [
                      {
                        "codigo": "77310000",
                        "descripcion": "Servicios de plantación y mantenimiento de zonas verdes.",
                        "relevancia": "alta"
                      },
                      {
                        "codigo": "77311000",
                        "descripcion": "Servicios de mantenimiento de jardines y parques.",
                        "relevancia": "alta"
                      },
                      {
                        "codigo": "77211400",
                        "descripcion": "Servicios de tala de árboles.",
                        "relevancia": "media"
                      }
                    ],
                    "mensaje": "CPV recomendados por la IA a partir de la descripción."
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/NoAutenticado"
          },
          "403": {
            "$ref": "#/components/responses/SinAcceso"
          },
          "409": {
            "$ref": "#/components/responses/Conflicto"
          },
          "422": {
            "$ref": "#/components/responses/ParametrosInvalidos"
          },
          "429": {
            "$ref": "#/components/responses/LimiteSuperado"
          },
          "500": {
            "$ref": "#/components/responses/ErrorInterno"
          }
        },
        "parameters": [
          {
            "$ref": "#/components/parameters/Equipo"
          }
        ]
      }
    },
    "/licitaciones/{id}/espacio": {
      "get": {
        "tags": [
          "Espacio de trabajo"
        ],
        "operationId": "verEspacioLicitacion",
        "summary": "Ver el espacio de trabajo de una licitación",
        "description": "Si es favorita y en qué grupo, la nota del equipo, el checklist de tareas, los recordatorios y las conversaciones con la IA (sin los mensajes), como en la ficha de la app. Con los planes Pro y Enterprise, también el responsable de cada tarea y los miembros a los que se pueden asignar. Si la licitación no es favorita, la consulta cuenta como una ficha en la cuota diaria.",
        "x-ejemplo-peticion": {
          "path": {
            "id": 4815162
          }
        },
        "parameters": [
          {
            "$ref": "#/components/parameters/IdLicitacion"
          },
          {
            "$ref": "#/components/parameters/Equipo"
          }
        ],
        "responses": {
          "200": {
            "description": "Espacio de trabajo de la licitación.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/EspacioLicitacion"
                    }
                  }
                },
                "example": {
                  "data": {
                    "licitacion": {
                      "id": 4815162,
                      "expediente": "CON-2026-0142",
                      "titulo": "Servicio de mantenimiento de zonas verdes y arbolado del término municipal",
                      "categoria": "licitacion",
                      "estado": {
                        "codigo": "PUB",
                        "nombre": "En plazo"
                      },
                      "tipo_contrato": {
                        "codigo": "2",
                        "nombre": "Servicios"
                      },
                      "subtipo_contrato": {
                        "codigo": "2::1",
                        "nombre": "Servicios de mantenimiento y reparación"
                      },
                      "organo": {
                        "id": "10000000000001",
                        "nombre": "Ayuntamiento de Ejemplo"
                      },
                      "lugar_ejecucion": {
                        "codigo": "ES523",
                        "nombre": "Valencia/València"
                      },
                      "importe_sin_iva": 240000.0,
                      "importe_con_iva": 290400.0,
                      "numero_lotes": 2,
                      "publicada": "2026-10-02T09:15:00+02:00",
                      "actualizada": "2026-10-06T12:40:00+02:00",
                      "plazo_presentacion": {
                        "fecha": "2026-10-30",
                        "hora": "14:00",
                        "tipo": "ofertas"
                      },
                      "sistema_contratacion": {
                        "codigo": "0",
                        "nombre": "No aplica"
                      },
                      "favorita": true,
                      "descartada": false,
                      "url_app": "https://app.licitaciones365.es/licitaciones/4815162",
                      "url_origen": "https://contrataciondelestado.es/wps/poc?uri=deeplink:detalle_licitacion&idEvl=EjemploAbc%3D%3D"
                    },
                    "favorita": true,
                    "grupo": {
                      "id": 12,
                      "nombre": "En estudio"
                    },
                    "nota": {
                      "texto": "Llamar al órgano para aclarar la solvencia técnica.\n\n- Pedir certificados de buena ejecución",
                      "html": "<p>Llamar al órgano para aclarar la solvencia técnica.</p><ul><li><p>Pedir certificados de buena ejecución</p></li></ul>",
                      "creada_por": {
                        "id": 2,
                        "nombre": "Ana García",
                        "email": "ana@empresa.es",
                        "rol": "miembro"
                      },
                      "modificada_por": {
                        "id": 3,
                        "nombre": "Luis Pérez",
                        "email": "luis@empresa.es",
                        "rol": "miembro"
                      },
                      "creada": "2026-10-07T09:00:00+02:00",
                      "actualizada": "2026-10-09T18:02:00+02:00"
                    },
                    "tareas": [
                      {
                        "id": 5120,
                        "licitacion_id": 4815162,
                        "titulo": "Preparar la garantía provisional",
                        "descripcion": "Aval bancario del 3 % del presupuesto.",
                        "estado": "en_curso",
                        "prioridad": "alta",
                        "fecha_limite": "2026-10-24",
                        "vencida": false,
                        "responsable": {
                          "id": 3,
                          "nombre": "Luis Pérez",
                          "email": "luis@empresa.es",
                          "rol": "miembro"
                        },
                        "completada": null,
                        "completada_por": null,
                        "creada_por": {
                          "id": 2,
                          "nombre": "Ana García",
                          "email": "ana@empresa.es",
                          "rol": "miembro"
                        },
                        "creada": "2026-10-08T10:12:00+02:00",
                        "actualizada": "2026-10-09T17:30:00+02:00",
                        "orden": 1
                      }
                    ],
                    "resumen_tareas": {
                      "total": 1,
                      "pendientes": 0,
                      "en_curso": 1,
                      "completadas": 0,
                      "canceladas": 0,
                      "vencidas": 0
                    },
                    "recordatorios": [
                      {
                        "id": 881,
                        "licitacion_id": 4815162,
                        "referencia": "plazo",
                        "dias_antes": 3,
                        "hora": "09:00",
                        "fecha_aviso": "2026-10-27",
                        "activo": true,
                        "enviado": false,
                        "enviado_a": [],
                        "modificable": true,
                        "creado_por": {
                          "id": 2,
                          "nombre": "Ana García",
                          "email": "ana@empresa.es",
                          "rol": "miembro"
                        },
                        "creado": "2026-10-08T10:15:00+02:00"
                      }
                    ],
                    "recordatorios_disponibles": 2,
                    "conversaciones_ia": [
                      {
                        "id": 311,
                        "titulo": "¿Qué solvencia económica piden?",
                        "visibilidad": "equipo",
                        "creada_por": {
                          "id": 2,
                          "nombre": "Ana García",
                          "email": "ana@empresa.es",
                          "rol": "miembro"
                        },
                        "mensajes": 4,
                        "creada": "2026-10-08T11:00:00+02:00",
                        "ultimo_mensaje": "2026-10-08T11:03:00+02:00"
                      }
                    ],
                    "miembros": [
                      {
                        "id": 2,
                        "nombre": "Ana García",
                        "email": "ana@empresa.es",
                        "rol": "miembro"
                      },
                      {
                        "id": 3,
                        "nombre": "Luis Pérez",
                        "email": "luis@empresa.es",
                        "rol": "miembro"
                      }
                    ]
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/NoAutenticado"
          },
          "403": {
            "$ref": "#/components/responses/SinAcceso"
          },
          "404": {
            "$ref": "#/components/responses/NoEncontrado"
          },
          "429": {
            "$ref": "#/components/responses/LimiteSuperado"
          },
          "500": {
            "$ref": "#/components/responses/ErrorInterno"
          }
        }
      }
    },
    "/licitaciones/{id}/nota": {
      "put": {
        "tags": [
          "Espacio de trabajo"
        ],
        "operationId": "reemplazarNota",
        "summary": "Reemplazar la nota",
        "description": "Sustituye la nota entera del equipo sobre la licitación (con `texto` vacío, la deja en blanco); si no había, la crea. No hace falta que sea favorita. La respuesta trae en `nota_anterior` lo que había, para poder restaurarlo.",
        "x-ejemplo-peticion": {
          "path": {
            "id": 4815162
          },
          "body": {
            "texto": "Llamar al órgano para aclarar la solvencia técnica.\n\n- Pedir certificados de buena ejecución"
          }
        },
        "parameters": [
          {
            "$ref": "#/components/parameters/IdLicitacion"
          },
          {
            "$ref": "#/components/parameters/Equipo"
          }
        ],
        "requestBody": {
          "description": "Nuevo contenido completo de la nota.",
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "texto": {
                    "type": "string",
                    "maxLength": 60000,
                    "description": "En texto plano, una línea en blanco separa párrafos y las líneas que empiezan por «- » o «1. » forman listas. Con `formato: html`, HTML del editor de la app (se quitan imágenes y scripts)."
                  },
                  "formato": {
                    "type": "string",
                    "enum": [
                      "texto",
                      "html"
                    ],
                    "default": "texto"
                  }
                },
                "required": [
                  "texto"
                ]
              },
              "example": {
                "texto": "Llamar al órgano para aclarar la solvencia técnica.\n\n- Pedir certificados de buena ejecución"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Nota guardada.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/NotaGuardada"
                    }
                  }
                },
                "example": {
                  "data": {
                    "modo": "reemplazar",
                    "nota": {
                      "texto": "Llamar al órgano para aclarar la solvencia técnica.\n\n- Pedir certificados de buena ejecución",
                      "html": "<p>Llamar al órgano para aclarar la solvencia técnica.</p><ul><li><p>Pedir certificados de buena ejecución</p></li></ul>",
                      "creada_por": {
                        "id": 2,
                        "nombre": "Ana García",
                        "email": "ana@empresa.es",
                        "rol": "miembro"
                      },
                      "modificada_por": {
                        "id": 3,
                        "nombre": "Luis Pérez",
                        "email": "luis@empresa.es",
                        "rol": "miembro"
                      },
                      "creada": "2026-10-07T09:00:00+02:00",
                      "actualizada": "2026-10-09T18:02:00+02:00"
                    },
                    "nota_anterior": {
                      "texto": "Llamar al órgano.",
                      "html": "<p>Llamar al órgano.</p>"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/NoAutenticado"
          },
          "403": {
            "$ref": "#/components/responses/SinAcceso"
          },
          "404": {
            "$ref": "#/components/responses/NoEncontrado"
          },
          "422": {
            "$ref": "#/components/responses/ParametrosInvalidos"
          },
          "429": {
            "$ref": "#/components/responses/LimiteSuperado"
          },
          "500": {
            "$ref": "#/components/responses/ErrorInterno"
          }
        }
      },
      "post": {
        "tags": [
          "Espacio de trabajo"
        ],
        "operationId": "anadirANota",
        "summary": "Añadir texto al final de la nota",
        "description": "Añade el texto al final de la nota del equipo, sin tocar lo que ya hay (si no había nota, la crea). La nota completa no puede pasar de unos 65.000 caracteres.",
        "x-ejemplo-peticion": {
          "path": {
            "id": 4815162
          },
          "body": {
            "texto": "- Pedir certificados de buena ejecución"
          }
        },
        "parameters": [
          {
            "$ref": "#/components/parameters/IdLicitacion"
          },
          {
            "$ref": "#/components/parameters/Equipo"
          }
        ],
        "requestBody": {
          "description": "Texto que se añade.",
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "texto": {
                    "type": "string",
                    "maxLength": 60000,
                    "description": "En texto plano, una línea en blanco separa párrafos y las líneas que empiezan por «- » o «1. » forman listas. Con `formato: html`, HTML del editor de la app (se quitan imágenes y scripts)."
                  },
                  "formato": {
                    "type": "string",
                    "enum": [
                      "texto",
                      "html"
                    ],
                    "default": "texto"
                  }
                },
                "required": [
                  "texto"
                ]
              },
              "example": {
                "texto": "- Pedir certificados de buena ejecución"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Nota con el texto añadido.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/NotaGuardada"
                    }
                  }
                },
                "example": {
                  "data": {
                    "modo": "anadir_al_final",
                    "nota": {
                      "texto": "Llamar al órgano para aclarar la solvencia técnica.\n\n- Pedir certificados de buena ejecución",
                      "html": "<p>Llamar al órgano para aclarar la solvencia técnica.</p><ul><li><p>Pedir certificados de buena ejecución</p></li></ul>",
                      "creada_por": {
                        "id": 2,
                        "nombre": "Ana García",
                        "email": "ana@empresa.es",
                        "rol": "miembro"
                      },
                      "modificada_por": {
                        "id": 3,
                        "nombre": "Luis Pérez",
                        "email": "luis@empresa.es",
                        "rol": "miembro"
                      },
                      "creada": "2026-10-07T09:00:00+02:00",
                      "actualizada": "2026-10-09T18:02:00+02:00"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/NoAutenticado"
          },
          "403": {
            "$ref": "#/components/responses/SinAcceso"
          },
          "404": {
            "$ref": "#/components/responses/NoEncontrado"
          },
          "422": {
            "$ref": "#/components/responses/ParametrosInvalidos"
          },
          "429": {
            "$ref": "#/components/responses/LimiteSuperado"
          },
          "500": {
            "$ref": "#/components/responses/ErrorInterno"
          }
        }
      }
    },
    "/licitaciones/{id}/tareas": {
      "post": {
        "tags": [
          "Espacio de trabajo"
        ],
        "operationId": "crearTarea",
        "summary": "Crear una tarea",
        "description": "Añade una tarea pendiente al final del checklist de una licitación favorita (`no_es_favorita` si no lo es). Con `responsable`, queda asignada a ese miembro del equipo (planes Pro y Enterprise). El equipo la ve al momento en la app.",
        "x-ejemplo-peticion": {
          "path": {
            "id": 4815162
          },
          "body": {
            "titulo": "Preparar la garantía provisional",
            "prioridad": "alta",
            "fecha_limite": "2026-10-24",
            "responsable": "luis@empresa.es"
          }
        },
        "parameters": [
          {
            "$ref": "#/components/parameters/IdLicitacion"
          },
          {
            "$ref": "#/components/parameters/Equipo"
          }
        ],
        "requestBody": {
          "description": "La tarea.",
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "titulo": {
                    "type": "string",
                    "maxLength": 255
                  },
                  "descripcion": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "maxLength": 20000
                  },
                  "prioridad": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "enum": [
                      "baja",
                      "media",
                      "alta",
                      null
                    ]
                  },
                  "fecha_limite": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "format": "date"
                  },
                  "responsable": {
                    "type": [
                      "string",
                      "integer",
                      "null"
                    ],
                    "description": "Id o email de un miembro del equipo (planes Pro y Enterprise)."
                  }
                },
                "required": [
                  "titulo"
                ]
              },
              "example": {
                "titulo": "Preparar la garantía provisional",
                "prioridad": "alta",
                "fecha_limite": "2026-10-24",
                "responsable": "luis@empresa.es"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Tarea creada.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Tarea"
                    }
                  }
                },
                "example": {
                  "data": {
                    "id": 5120,
                    "licitacion_id": 4815162,
                    "titulo": "Preparar la garantía provisional",
                    "descripcion": null,
                    "estado": "pendiente",
                    "prioridad": "alta",
                    "fecha_limite": "2026-10-24",
                    "vencida": false,
                    "responsable": {
                      "id": 3,
                      "nombre": "Luis Pérez",
                      "email": "luis@empresa.es",
                      "rol": "miembro"
                    },
                    "completada": null,
                    "completada_por": null,
                    "creada_por": {
                      "id": 2,
                      "nombre": "Ana García",
                      "email": "ana@empresa.es",
                      "rol": "miembro"
                    },
                    "creada": "2026-10-08T10:12:00+02:00",
                    "actualizada": "2026-10-09T17:30:00+02:00",
                    "orden": 1
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/NoAutenticado"
          },
          "403": {
            "$ref": "#/components/responses/SinAcceso"
          },
          "404": {
            "$ref": "#/components/responses/NoEncontrado"
          },
          "409": {
            "$ref": "#/components/responses/Conflicto"
          },
          "422": {
            "$ref": "#/components/responses/ParametrosInvalidos"
          },
          "429": {
            "$ref": "#/components/responses/LimiteSuperado"
          },
          "500": {
            "$ref": "#/components/responses/ErrorInterno"
          }
        }
      }
    },
    "/licitaciones/{id}/tareas/{tarea}": {
      "patch": {
        "tags": [
          "Espacio de trabajo"
        ],
        "operationId": "modificarTarea",
        "summary": "Cambiar una tarea",
        "description": "Cambia solo los campos que se envían. `estado: completada` guarda quién y cuándo la completó; desde completada, cualquier otro estado la reabre. `responsable` la asigna a un miembro del equipo y `null` la deja sin responsable (planes Pro y Enterprise). El equipo ve el cambio al momento en la app.",
        "x-ejemplo-peticion": {
          "path": {
            "id": 4815162,
            "tarea": 5120
          },
          "body": {
            "estado": "completada"
          }
        },
        "parameters": [
          {
            "$ref": "#/components/parameters/IdLicitacion"
          },
          {
            "name": "tarea",
            "in": "path",
            "required": true,
            "description": "Id de la tarea (sale en `GET /licitaciones/{id}/espacio`).",
            "schema": {
              "type": "integer",
              "minimum": 1
            },
            "example": 5120
          },
          {
            "$ref": "#/components/parameters/Equipo"
          }
        ],
        "requestBody": {
          "description": "Campos que cambian (al menos uno).",
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "titulo": {
                    "type": "string",
                    "maxLength": 255
                  },
                  "descripcion": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "maxLength": 20000
                  },
                  "prioridad": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "enum": [
                      "baja",
                      "media",
                      "alta",
                      null
                    ]
                  },
                  "fecha_limite": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "format": "date"
                  },
                  "responsable": {
                    "type": [
                      "string",
                      "integer",
                      "null"
                    ],
                    "description": "Id o email de un miembro del equipo (planes Pro y Enterprise)."
                  },
                  "estado": {
                    "type": "string",
                    "enum": [
                      "pendiente",
                      "en_curso",
                      "completada",
                      "cancelada"
                    ]
                  }
                }
              },
              "example": {
                "estado": "completada"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Tarea como queda.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Tarea"
                    }
                  }
                },
                "example": {
                  "data": {
                    "id": 5120,
                    "licitacion_id": 4815162,
                    "titulo": "Preparar la garantía provisional",
                    "descripcion": "Aval bancario del 3 % del presupuesto.",
                    "estado": "completada",
                    "prioridad": "alta",
                    "fecha_limite": "2026-10-24",
                    "vencida": false,
                    "responsable": {
                      "id": 3,
                      "nombre": "Luis Pérez",
                      "email": "luis@empresa.es",
                      "rol": "miembro"
                    },
                    "completada": "2026-10-10T12:00:00+02:00",
                    "completada_por": {
                      "id": 3,
                      "nombre": "Luis Pérez",
                      "email": "luis@empresa.es",
                      "rol": "miembro"
                    },
                    "creada_por": {
                      "id": 2,
                      "nombre": "Ana García",
                      "email": "ana@empresa.es",
                      "rol": "miembro"
                    },
                    "creada": "2026-10-08T10:12:00+02:00",
                    "actualizada": "2026-10-09T17:30:00+02:00",
                    "orden": 1
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/NoAutenticado"
          },
          "403": {
            "$ref": "#/components/responses/SinAcceso"
          },
          "404": {
            "$ref": "#/components/responses/NoEncontrado"
          },
          "409": {
            "$ref": "#/components/responses/Conflicto"
          },
          "422": {
            "$ref": "#/components/responses/ParametrosInvalidos"
          },
          "429": {
            "$ref": "#/components/responses/LimiteSuperado"
          },
          "500": {
            "$ref": "#/components/responses/ErrorInterno"
          }
        }
      },
      "delete": {
        "tags": [
          "Espacio de trabajo"
        ],
        "operationId": "borrarTarea",
        "summary": "Borrar una tarea",
        "description": "Borra la tarea para todo el equipo y recoloca el resto del checklist. No se puede deshacer.",
        "x-ejemplo-peticion": {
          "path": {
            "id": 4815162,
            "tarea": 5120
          }
        },
        "parameters": [
          {
            "$ref": "#/components/parameters/IdLicitacion"
          },
          {
            "name": "tarea",
            "in": "path",
            "required": true,
            "description": "Id de la tarea (sale en `GET /licitaciones/{id}/espacio`).",
            "schema": {
              "type": "integer",
              "minimum": 1
            },
            "example": 5120
          },
          {
            "$ref": "#/components/parameters/Equipo"
          }
        ],
        "responses": {
          "200": {
            "description": "Tarea borrada.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "type": "object",
                      "required": [
                        "id",
                        "licitacion_id",
                        "borrada"
                      ],
                      "properties": {
                        "id": {
                          "type": "integer"
                        },
                        "licitacion_id": {
                          "type": "integer"
                        },
                        "borrada": {
                          "type": "boolean",
                          "const": true
                        }
                      }
                    }
                  }
                },
                "example": {
                  "data": {
                    "id": 5120,
                    "licitacion_id": 4815162,
                    "borrada": true
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/NoAutenticado"
          },
          "403": {
            "$ref": "#/components/responses/SinAcceso"
          },
          "404": {
            "$ref": "#/components/responses/NoEncontrado"
          },
          "409": {
            "$ref": "#/components/responses/Conflicto"
          },
          "429": {
            "$ref": "#/components/responses/LimiteSuperado"
          },
          "500": {
            "$ref": "#/components/responses/ErrorInterno"
          }
        }
      }
    },
    "/licitaciones/{id}/recordatorios": {
      "post": {
        "tags": [
          "Espacio de trabajo"
        ],
        "operationId": "crearRecordatorio",
        "summary": "Crear un recordatorio",
        "description": "Programa un recordatorio por email, para todo el equipo, en una licitación favorita: de 1 a 30 días antes del fin del plazo de presentación o, con `referencia: vencimiento` (planes Pro y Enterprise), de 1 a 365 días antes del vencimiento estimado del contrato. Como mucho 3 por licitación (`limite_recordatorios`), sin repetir los días (`recordatorio_repetido`), a una hora entre las 06:00 y las 22:00 en tramos de 15 minutos, y el aviso tiene que caer en el futuro.",
        "x-ejemplo-peticion": {
          "path": {
            "id": 4815162
          },
          "body": {
            "dias_antes": 3,
            "hora": "09:00"
          }
        },
        "parameters": [
          {
            "$ref": "#/components/parameters/IdLicitacion"
          },
          {
            "$ref": "#/components/parameters/Equipo"
          }
        ],
        "requestBody": {
          "description": "El recordatorio.",
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "dias_antes": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 365
                  },
                  "hora": {
                    "type": "string",
                    "default": "09:00",
                    "description": "HH:MM, hora de Madrid."
                  },
                  "referencia": {
                    "type": "string",
                    "enum": [
                      "plazo",
                      "vencimiento"
                    ],
                    "default": "plazo"
                  }
                },
                "required": [
                  "dias_antes"
                ]
              },
              "example": {
                "dias_antes": 3,
                "hora": "09:00"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Recordatorio creado.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Recordatorio"
                    }
                  }
                },
                "example": {
                  "data": {
                    "id": 881,
                    "licitacion_id": 4815162,
                    "referencia": "plazo",
                    "dias_antes": 3,
                    "hora": "09:00",
                    "fecha_aviso": "2026-10-27",
                    "activo": true,
                    "enviado": false,
                    "enviado_a": [],
                    "modificable": true,
                    "creado_por": {
                      "id": 2,
                      "nombre": "Ana García",
                      "email": "ana@empresa.es",
                      "rol": "miembro"
                    },
                    "creado": "2026-10-08T10:15:00+02:00"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/NoAutenticado"
          },
          "403": {
            "$ref": "#/components/responses/SinAcceso"
          },
          "404": {
            "$ref": "#/components/responses/NoEncontrado"
          },
          "409": {
            "$ref": "#/components/responses/Conflicto"
          },
          "422": {
            "$ref": "#/components/responses/ParametrosInvalidos"
          },
          "429": {
            "$ref": "#/components/responses/LimiteSuperado"
          },
          "500": {
            "$ref": "#/components/responses/ErrorInterno"
          }
        }
      }
    },
    "/licitaciones/{id}/recordatorios/{recordatorio}": {
      "patch": {
        "tags": [
          "Espacio de trabajo"
        ],
        "operationId": "cambiarRecordatorio",
        "summary": "Pausar o reactivar un recordatorio",
        "description": "Con `activo: false` deja de enviarse sin borrarlo; con `true`, vuelve a avisar. Los que ya se han enviado no se pueden cambiar (`recordatorio_enviado`).",
        "x-ejemplo-peticion": {
          "path": {
            "id": 4815162,
            "recordatorio": 881
          },
          "body": {
            "activo": false
          }
        },
        "parameters": [
          {
            "$ref": "#/components/parameters/IdLicitacion"
          },
          {
            "name": "recordatorio",
            "in": "path",
            "required": true,
            "description": "Id del recordatorio (sale en `GET /licitaciones/{id}/espacio`).",
            "schema": {
              "type": "integer",
              "minimum": 1
            },
            "example": 881
          },
          {
            "$ref": "#/components/parameters/Equipo"
          }
        ],
        "requestBody": {
          "description": "Nuevo estado.",
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "activo": {
                    "type": "boolean"
                  }
                },
                "required": [
                  "activo"
                ]
              },
              "example": {
                "activo": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Recordatorio como queda.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Recordatorio"
                    }
                  }
                },
                "example": {
                  "data": {
                    "id": 881,
                    "licitacion_id": 4815162,
                    "referencia": "plazo",
                    "dias_antes": 3,
                    "hora": "09:00",
                    "fecha_aviso": "2026-10-27",
                    "activo": false,
                    "enviado": false,
                    "enviado_a": [],
                    "modificable": true,
                    "creado_por": {
                      "id": 2,
                      "nombre": "Ana García",
                      "email": "ana@empresa.es",
                      "rol": "miembro"
                    },
                    "creado": "2026-10-08T10:15:00+02:00"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/NoAutenticado"
          },
          "403": {
            "$ref": "#/components/responses/SinAcceso"
          },
          "404": {
            "$ref": "#/components/responses/NoEncontrado"
          },
          "409": {
            "$ref": "#/components/responses/Conflicto"
          },
          "422": {
            "$ref": "#/components/responses/ParametrosInvalidos"
          },
          "429": {
            "$ref": "#/components/responses/LimiteSuperado"
          },
          "500": {
            "$ref": "#/components/responses/ErrorInterno"
          }
        }
      },
      "delete": {
        "tags": [
          "Espacio de trabajo"
        ],
        "operationId": "borrarRecordatorio",
        "summary": "Borrar un recordatorio",
        "description": "Borra el recordatorio. Los que ya se han enviado no se pueden borrar (`recordatorio_enviado`).",
        "x-ejemplo-peticion": {
          "path": {
            "id": 4815162,
            "recordatorio": 881
          }
        },
        "parameters": [
          {
            "$ref": "#/components/parameters/IdLicitacion"
          },
          {
            "name": "recordatorio",
            "in": "path",
            "required": true,
            "description": "Id del recordatorio (sale en `GET /licitaciones/{id}/espacio`).",
            "schema": {
              "type": "integer",
              "minimum": 1
            },
            "example": 881
          },
          {
            "$ref": "#/components/parameters/Equipo"
          }
        ],
        "responses": {
          "200": {
            "description": "Recordatorio borrado.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "type": "object",
                      "required": [
                        "id",
                        "licitacion_id",
                        "borrado"
                      ],
                      "properties": {
                        "id": {
                          "type": "integer"
                        },
                        "licitacion_id": {
                          "type": "integer"
                        },
                        "borrado": {
                          "type": "boolean",
                          "const": true
                        }
                      }
                    }
                  }
                },
                "example": {
                  "data": {
                    "id": 881,
                    "licitacion_id": 4815162,
                    "borrado": true
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/NoAutenticado"
          },
          "403": {
            "$ref": "#/components/responses/SinAcceso"
          },
          "404": {
            "$ref": "#/components/responses/NoEncontrado"
          },
          "409": {
            "$ref": "#/components/responses/Conflicto"
          },
          "429": {
            "$ref": "#/components/responses/LimiteSuperado"
          },
          "500": {
            "$ref": "#/components/responses/ErrorInterno"
          }
        }
      }
    },
    "/agenda": {
      "get": {
        "tags": [
          "Agenda"
        ],
        "operationId": "verAgenda",
        "summary": "Plazos y vencimientos de las favoritas",
        "description": "Fin del plazo de presentación de las favoritas del equipo y, con los planes Pro y Enterprise, el vencimiento estimado de sus contratos, por fecha. Por defecto, de hoy a 30 días; el rango puede ser de hasta 2 años. Solo consulta: no crea ni cambia nada (tampoco la suscripción al calendario de la app).",
        "x-ejemplo-peticion": {
          "query": {
            "desde": "2026-10-15",
            "hasta": "2026-12-31"
          }
        },
        "parameters": [
          {
            "name": "desde",
            "in": "query",
            "description": "Primer día. Por defecto, hoy.",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "example": "2026-10-15"
          },
          {
            "name": "hasta",
            "in": "query",
            "description": "Último día. Por defecto, 30 días después de `desde`.",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "example": "2026-12-31"
          },
          {
            "name": "incluir",
            "in": "query",
            "description": "Qué incluir, separado por comas. Por defecto, las dos cosas.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string",
                "enum": [
                  "plazos",
                  "vencimientos"
                ]
              }
            },
            "style": "form",
            "explode": false
          },
          {
            "$ref": "#/components/parameters/Pagina"
          },
          {
            "$ref": "#/components/parameters/PorPagina"
          },
          {
            "$ref": "#/components/parameters/Equipo"
          }
        ],
        "responses": {
          "200": {
            "description": "Una página de eventos.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/EventoAgenda"
                      }
                    },
                    "meta": {
                      "type": "object",
                      "required": [
                        "desde",
                        "hasta",
                        "paginacion",
                        "vencimientos"
                      ],
                      "properties": {
                        "desde": {
                          "type": "string",
                          "format": "date"
                        },
                        "hasta": {
                          "type": "string",
                          "format": "date"
                        },
                        "paginacion": {
                          "$ref": "#/components/schemas/Paginacion"
                        },
                        "vencimientos": {
                          "type": "object",
                          "required": [
                            "incluidos"
                          ],
                          "properties": {
                            "incluidos": {
                              "type": "boolean"
                            },
                            "motivo": {
                              "type": "string",
                              "description": "Si se han pedido y no se incluyen: por qué."
                            }
                          }
                        }
                      }
                    }
                  }
                },
                "example": {
                  "data": [
                    {
                      "fecha": "2026-10-30",
                      "tipo": "plazo_presentacion",
                      "hora": "14:00",
                      "plazo_de": "ofertas",
                      "dias_restantes": 15,
                      "grupo": {
                        "id": 12,
                        "nombre": "En estudio"
                      },
                      "licitacion": {
                        "id": 4815162,
                        "expediente": "CON-2026-0142",
                        "titulo": "Servicio de mantenimiento de zonas verdes y arbolado del término municipal",
                        "categoria": "licitacion",
                        "estado": {
                          "codigo": "PUB",
                          "nombre": "En plazo"
                        },
                        "tipo_contrato": {
                          "codigo": "2",
                          "nombre": "Servicios"
                        },
                        "subtipo_contrato": {
                          "codigo": "2::1",
                          "nombre": "Servicios de mantenimiento y reparación"
                        },
                        "organo": {
                          "id": "10000000000001",
                          "nombre": "Ayuntamiento de Ejemplo"
                        },
                        "lugar_ejecucion": {
                          "codigo": "ES523",
                          "nombre": "Valencia/València"
                        },
                        "importe_sin_iva": 240000.0,
                        "importe_con_iva": 290400.0,
                        "numero_lotes": 2,
                        "publicada": "2026-10-02T09:15:00+02:00",
                        "actualizada": "2026-10-06T12:40:00+02:00",
                        "plazo_presentacion": {
                          "fecha": "2026-10-30",
                          "hora": "14:00",
                          "tipo": "ofertas"
                        },
                        "sistema_contratacion": {
                          "codigo": "0",
                          "nombre": "No aplica"
                        },
                        "favorita": true,
                        "descartada": false,
                        "url_app": "https://app.licitaciones365.es/licitaciones/4815162",
                        "url_origen": "https://contrataciondelestado.es/wps/poc?uri=deeplink:detalle_licitacion&idEvl=EjemploAbc%3D%3D"
                      }
                    }
                  ],
                  "meta": {
                    "desde": "2026-10-15",
                    "hasta": "2026-12-31",
                    "paginacion": {
                      "pagina": 1,
                      "por_pagina": 25,
                      "total": 1,
                      "hay_mas": false
                    },
                    "vencimientos": {
                      "incluidos": true
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/NoAutenticado"
          },
          "403": {
            "$ref": "#/components/responses/SinAcceso"
          },
          "422": {
            "$ref": "#/components/responses/ParametrosInvalidos"
          },
          "429": {
            "$ref": "#/components/responses/LimiteSuperado"
          },
          "500": {
            "$ref": "#/components/responses/ErrorInterno"
          }
        }
      }
    },
    "/tareas": {
      "get": {
        "tags": [
          "Agenda"
        ],
        "operationId": "misTareas",
        "summary": "Mis tareas",
        "description": "Las tareas asignadas al usuario de la API key en las favoritas del equipo, agrupadas por licitación y ordenadas por el fin del plazo, como «Mis tareas» de la app. Por defecto, las abiertas (pendientes y en curso).",
        "x-ejemplo-peticion": {
          "query": {
            "estado": "abiertas"
          }
        },
        "parameters": [
          {
            "name": "estado",
            "in": "query",
            "description": "Qué tareas.",
            "schema": {
              "type": "string",
              "enum": [
                "abiertas",
                "completadas",
                "canceladas",
                "todas"
              ],
              "default": "abiertas"
            }
          },
          {
            "$ref": "#/components/parameters/Pagina"
          },
          {
            "$ref": "#/components/parameters/PorPagina"
          },
          {
            "$ref": "#/components/parameters/Equipo"
          }
        ],
        "responses": {
          "200": {
            "description": "Una página de tareas, por licitación.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/TareasDeLicitacion"
                      }
                    },
                    "meta": {
                      "type": "object",
                      "required": [
                        "estado",
                        "contadores",
                        "paginacion"
                      ],
                      "properties": {
                        "estado": {
                          "type": "string",
                          "enum": [
                            "abiertas",
                            "completadas",
                            "canceladas",
                            "todas"
                          ]
                        },
                        "contadores": {
                          "type": "object",
                          "required": [
                            "abiertas",
                            "completadas",
                            "total"
                          ],
                          "description": "Como en la app: abiertas (pendientes y en curso), completadas y total sin las canceladas.",
                          "properties": {
                            "abiertas": {
                              "type": "integer"
                            },
                            "completadas": {
                              "type": "integer"
                            },
                            "total": {
                              "type": "integer"
                            }
                          }
                        },
                        "paginacion": {
                          "$ref": "#/components/schemas/Paginacion"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "data": [
                    {
                      "licitacion": {
                        "id": 4815162,
                        "expediente": "CON-2026-0142",
                        "titulo": "Servicio de mantenimiento de zonas verdes y arbolado del término municipal",
                        "categoria": "licitacion",
                        "estado": {
                          "codigo": "PUB",
                          "nombre": "En plazo"
                        },
                        "tipo_contrato": {
                          "codigo": "2",
                          "nombre": "Servicios"
                        },
                        "subtipo_contrato": {
                          "codigo": "2::1",
                          "nombre": "Servicios de mantenimiento y reparación"
                        },
                        "organo": {
                          "id": "10000000000001",
                          "nombre": "Ayuntamiento de Ejemplo"
                        },
                        "lugar_ejecucion": {
                          "codigo": "ES523",
                          "nombre": "Valencia/València"
                        },
                        "importe_sin_iva": 240000.0,
                        "importe_con_iva": 290400.0,
                        "numero_lotes": 2,
                        "publicada": "2026-10-02T09:15:00+02:00",
                        "actualizada": "2026-10-06T12:40:00+02:00",
                        "plazo_presentacion": {
                          "fecha": "2026-10-30",
                          "hora": "14:00",
                          "tipo": "ofertas"
                        },
                        "sistema_contratacion": {
                          "codigo": "0",
                          "nombre": "No aplica"
                        },
                        "favorita": true,
                        "descartada": false,
                        "url_app": "https://app.licitaciones365.es/licitaciones/4815162",
                        "url_origen": "https://contrataciondelestado.es/wps/poc?uri=deeplink:detalle_licitacion&idEvl=EjemploAbc%3D%3D"
                      },
                      "tareas": [
                        {
                          "id": 5120,
                          "licitacion_id": 4815162,
                          "titulo": "Preparar la garantía provisional",
                          "descripcion": "Aval bancario del 3 % del presupuesto.",
                          "estado": "en_curso",
                          "prioridad": "alta",
                          "fecha_limite": "2026-10-24",
                          "vencida": false,
                          "responsable": {
                            "id": 2,
                            "nombre": "Ana García",
                            "email": "ana@empresa.es",
                            "rol": "miembro"
                          },
                          "completada": null,
                          "completada_por": null,
                          "creada_por": {
                            "id": 2,
                            "nombre": "Ana García",
                            "email": "ana@empresa.es",
                            "rol": "miembro"
                          },
                          "creada": "2026-10-08T10:12:00+02:00",
                          "actualizada": "2026-10-09T17:30:00+02:00",
                          "orden": 1
                        }
                      ]
                    }
                  ],
                  "meta": {
                    "estado": "abiertas",
                    "contadores": {
                      "abiertas": 1,
                      "completadas": 3,
                      "total": 4
                    },
                    "paginacion": {
                      "pagina": 1,
                      "por_pagina": 25,
                      "total": 1,
                      "hay_mas": false
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/NoAutenticado"
          },
          "403": {
            "$ref": "#/components/responses/SinAcceso"
          },
          "422": {
            "$ref": "#/components/responses/ParametrosInvalidos"
          },
          "429": {
            "$ref": "#/components/responses/LimiteSuperado"
          },
          "500": {
            "$ref": "#/components/responses/ErrorInterno"
          }
        }
      }
    },
    "/alertas": {
      "get": {
        "tags": [
          "Alertas"
        ],
        "operationId": "listarAlertas",
        "summary": "Listar las alertas",
        "description": "Alertas del equipo, en el orden de la app, con sus criterios legibles, su estado y su último envío. Las bloqueadas por el plan no salen (como en la app).",
        "parameters": [
          {
            "name": "incluir_borradas",
            "in": "query",
            "description": "Incluir también las borradas (solo el propietario del equipo).",
            "schema": {
              "type": "boolean",
              "default": false
            }
          },
          {
            "$ref": "#/components/parameters/Equipo"
          }
        ],
        "responses": {
          "200": {
            "description": "Las alertas.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Alerta"
                      }
                    },
                    "meta": {
                      "type": "object",
                      "properties": {
                        "limite": {
                          "$ref": "#/components/schemas/LimiteAlertas"
                        },
                        "es_propietario": {
                          "type": "boolean"
                        },
                        "propietario": {
                          "oneOf": [
                            {
                              "$ref": "#/components/schemas/MiembroEquipo"
                            },
                            {
                              "type": "null"
                            }
                          ]
                        }
                      },
                      "required": [
                        "limite",
                        "es_propietario"
                      ]
                    }
                  }
                },
                "example": {
                  "data": [
                    {
                      "id": 275,
                      "nombre": "Limpieza viaria Valencia",
                      "descripcion": null,
                      "estado": "activa",
                      "activa": true,
                      "avisos_por_email": true,
                      "criterios": {
                        "tipo": {
                          "codigo": "nuevas",
                          "nombre": "Nuevas publicaciones (licitaciones en plazo y anuncios previos)"
                        },
                        "estados": [
                          "PUB",
                          "PRE"
                        ],
                        "ambito": {
                          "codigo": "ambos",
                          "nombre": "Licitaciones y contratos menores en fase de ofertas"
                        },
                        "palabras_clave": [
                          "limpieza",
                          "viaria"
                        ],
                        "modo_palabras": "todas",
                        "cpv": [
                          {
                            "codigo": "90600000",
                            "nombre": "Servicios de limpieza y saneamiento en zonas urbanas o rurales, y servicios conexos."
                          }
                        ],
                        "provincias": [
                          {
                            "codigo": "ES523",
                            "nombre": "Valencia/València"
                          }
                        ],
                        "organos": [],
                        "importe_min": 10000.0,
                        "importe_max": null
                      },
                      "criterios_texto": "Nuevas publicaciones · Licitaciones y contratos menores en fase de ofertas · Con todas estas palabras: limpieza, viaria · CPV: 90600000 (Servicios de limpieza y saneamiento en zonas urbanas o rurales, y servicios conexos) · En: Valencia/València · Importe sin IVA desde 10.000 €",
                      "orden": 2,
                      "busqueda_guardada_id": null,
                      "creada": "2026-10-14T10:00:00+02:00",
                      "creada_por": {
                        "id": 41,
                        "nombre": "Ana",
                        "email": "ana@empresa.es",
                        "rol": "propietario"
                      },
                      "actualizada": "2026-10-14T10:00:00+02:00",
                      "actualizada_por": {
                        "id": 41,
                        "nombre": "Ana",
                        "email": "ana@empresa.es",
                        "rol": "propietario"
                      },
                      "ultimo_envio": {
                        "fecha": "2026-10-13",
                        "licitaciones": 4,
                        "enviado": "2026-10-13T09:00:02+02:00"
                      },
                      "ultima_ejecucion": {
                        "fecha": "2026-10-13",
                        "resultado": "enviada",
                        "licitaciones": 4
                      },
                      "destinatarios": {
                        "personalizados": false,
                        "usuarios": []
                      }
                    }
                  ],
                  "meta": {
                    "limite": {
                      "usadas": 3,
                      "maximo": null,
                      "puede_crear": true,
                      "motivo": null
                    },
                    "es_propietario": true,
                    "propietario": {
                      "id": 41,
                      "nombre": "Ana",
                      "email": "ana@empresa.es",
                      "rol": "propietario"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/NoAutenticado"
          },
          "403": {
            "$ref": "#/components/responses/SinAcceso"
          },
          "429": {
            "$ref": "#/components/responses/LimiteSuperado"
          },
          "500": {
            "$ref": "#/components/responses/ErrorInterno"
          }
        }
      },
      "post": {
        "tags": [
          "Alertas"
        ],
        "operationId": "crearAlerta",
        "summary": "Crear una alerta",
        "description": "Crea una alerta (solo el propietario del equipo), igual que el editor de la app. Cuenta para el límite de alertas del plan (`limite_del_plan`) y para la cuota diaria `alertas_nuevas_dia`. Con `busqueda_guardada_id` la crea desde una búsqueda guardada (ver `GET /alertas/busquedas-guardadas`); entonces el nombre y los criterios salen de ella, y sus palabras siguen exigiéndose todas salvo que se indique `modo_palabras`.",
        "x-ejemplo-peticion": {
          "body": {
            "nombre": "Limpieza viaria Valencia",
            "palabras_clave": [
              "limpieza",
              "viaria"
            ],
            "modo_palabras": "todas",
            "cpv": [
              "90600000"
            ],
            "provincias": [
              "ES523"
            ],
            "importe_min": 10000
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/EntradaAlerta"
                  },
                  {
                    "type": "object",
                    "properties": {
                      "busqueda_guardada_id": {
                        "type": "integer",
                        "minimum": 1,
                        "description": "Crear la alerta desde esta búsqueda guardada."
                      }
                    }
                  }
                ]
              },
              "example": {
                "nombre": "Limpieza viaria Valencia",
                "palabras_clave": [
                  "limpieza",
                  "viaria"
                ],
                "modo_palabras": "todas",
                "cpv": [
                  "90600000"
                ],
                "provincias": [
                  "ES523"
                ],
                "importe_min": 10000
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Alerta creada.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Alerta"
                    },
                    "meta": {
                      "type": "object",
                      "properties": {
                        "mensaje": {
                          "type": "string"
                        },
                        "avisos": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          },
                          "description": "Lo que se ha ajustado o conviene saber."
                        },
                        "limite": {
                          "$ref": "#/components/schemas/LimiteAlertas"
                        }
                      },
                      "required": [
                        "mensaje",
                        "limite"
                      ]
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/NoAutenticado"
          },
          "403": {
            "$ref": "#/components/responses/SinAcceso"
          },
          "404": {
            "$ref": "#/components/responses/NoEncontrado"
          },
          "422": {
            "$ref": "#/components/responses/ParametrosInvalidos"
          },
          "429": {
            "$ref": "#/components/responses/LimiteSuperado"
          },
          "500": {
            "$ref": "#/components/responses/ErrorInterno"
          }
        },
        "parameters": [
          {
            "$ref": "#/components/parameters/Equipo"
          }
        ]
      }
    },
    "/alertas/previsualizar": {
      "get": {
        "tags": [
          "Alertas"
        ],
        "operationId": "probarCriteriosAlerta",
        "summary": "Probar unos criterios de alerta",
        "description": "Cuántas y cuáles licitaciones habría traído la alerta en los últimos 30 días, con **la misma búsqueda que el correo de resumen** (no la del buscador: en las alertas basta una palabra salvo con `modo_palabras: todas`). No guarda nada. Cada prueba cuenta en la cuota diaria `previsualizaciones_dia` del equipo y las muy amplias se cortan por tiempo (`busqueda_demasiado_amplia`). Va por `GET` para que sirva también con claves de solo lectura. Los criterios son los de `POST /alertas`, con las listas separadas por comas.",
        "x-ejemplo-peticion": {
          "query": {
            "palabras_clave": "limpieza,viaria",
            "provincias": "ES523"
          }
        },
        "parameters": [
          {
            "name": "palabras_clave",
            "in": "query",
            "description": "Palabras clave separadas por comas.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "style": "form",
            "explode": false,
            "example": [
              "limpieza",
              "viaria"
            ]
          },
          {
            "name": "modo_palabras",
            "in": "query",
            "description": "`cualquiera` (por defecto) o `todas`.",
            "schema": {
              "type": "string",
              "enum": [
                "cualquiera",
                "todas"
              ]
            }
          },
          {
            "name": "tipo",
            "in": "query",
            "description": "`nuevas` (por defecto) o `adjudicaciones`.",
            "schema": {
              "type": "string",
              "enum": [
                "nuevas",
                "adjudicaciones"
              ]
            }
          },
          {
            "name": "ambito",
            "in": "query",
            "description": "`licitaciones` (por defecto), `menores` o `ambos`.",
            "schema": {
              "type": "string",
              "enum": [
                "licitaciones",
                "menores",
                "ambos"
              ]
            }
          },
          {
            "name": "cpv",
            "in": "query",
            "description": "Códigos CPV separados por comas.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "style": "form",
            "explode": false
          },
          {
            "name": "provincias",
            "in": "query",
            "description": "Provincias NUTS3 separadas por comas.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "style": "form",
            "explode": false,
            "example": [
              "ES523"
            ]
          },
          {
            "name": "comunidades",
            "in": "query",
            "description": "Comunidades NUTS2 separadas por comas.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "style": "form",
            "explode": false
          },
          {
            "name": "organos",
            "in": "query",
            "description": "Ids de órgano separados por comas.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "style": "form",
            "explode": false
          },
          {
            "name": "importe_min",
            "in": "query",
            "description": "Importe mínimo sin IVA.",
            "schema": {
              "type": "number",
              "minimum": 0
            }
          },
          {
            "name": "importe_max",
            "in": "query",
            "description": "Importe máximo sin IVA.",
            "schema": {
              "type": "number",
              "minimum": 0
            }
          },
          {
            "name": "limite",
            "in": "query",
            "description": "Cuántas licitaciones devolver (por defecto 10).",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 25,
              "default": 10
            }
          },
          {
            "$ref": "#/components/parameters/Equipo"
          }
        ],
        "responses": {
          "200": {
            "description": "Las licitaciones más recientes que habría traído, y en `meta` el total, la media diaria, el desglose y una valoración.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "allOf": [
                          {
                            "$ref": "#/components/schemas/LicitacionResumen"
                          },
                          {
                            "type": "object",
                            "properties": {
                              "ya_enviada": {
                                "type": "boolean",
                                "description": "Ya se envió al equipo (el resumen no la repetiría)."
                              }
                            }
                          }
                        ]
                      }
                    },
                    "meta": {
                      "type": "object",
                      "properties": {
                        "alerta": {
                          "type": [
                            "object",
                            "null"
                          ],
                          "properties": {
                            "id": {
                              "type": "integer"
                            },
                            "nombre": {
                              "type": "string"
                            }
                          }
                        },
                        "criterios": {
                          "$ref": "#/components/schemas/CriteriosAlerta"
                        },
                        "criterios_texto": {
                          "type": "string"
                        },
                        "periodo": {
                          "type": "object",
                          "properties": {
                            "desde": {
                              "type": "string",
                              "format": "date"
                            },
                            "hasta": {
                              "type": "string",
                              "format": "date"
                            },
                            "dias": {
                              "type": "integer"
                            }
                          }
                        },
                        "total": {
                          "type": "integer",
                          "description": "Coincidencias en el periodo."
                        },
                        "media_diaria": {
                          "type": "number"
                        },
                        "desglose": {
                          "type": "object",
                          "description": "`nuevas` son las que enviaría el resumen. Si hay más de 5.000 coincidencias, se desglosan las 5.000 más recientes (`calculado_sobre`).",
                          "properties": {
                            "nuevas": {
                              "type": "integer"
                            },
                            "ya_enviadas": {
                              "type": "integer"
                            },
                            "favoritas": {
                              "type": "integer"
                            },
                            "descartadas": {
                              "type": "integer"
                            },
                            "calculado_sobre": {
                              "type": "integer"
                            }
                          }
                        },
                        "valoracion": {
                          "type": "string"
                        },
                        "como_funciona": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "total",
                        "desglose",
                        "periodo"
                      ]
                    }
                  }
                },
                "example": {
                  "data": [],
                  "meta": {
                    "alerta": null,
                    "periodo": {
                      "desde": "2026-09-14",
                      "hasta": "2026-10-14",
                      "dias": 30
                    },
                    "total": 37,
                    "media_diaria": 1.2,
                    "desglose": {
                      "nuevas": 30,
                      "ya_enviadas": 5,
                      "favoritas": 1,
                      "descartadas": 1
                    },
                    "valoracion": "Volumen razonable: unas 1,2 licitaciones al día."
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/NoAutenticado"
          },
          "403": {
            "$ref": "#/components/responses/SinAcceso"
          },
          "422": {
            "$ref": "#/components/responses/ParametrosInvalidos"
          },
          "429": {
            "$ref": "#/components/responses/LimiteSuperado"
          },
          "500": {
            "$ref": "#/components/responses/ErrorInterno"
          }
        }
      }
    },
    "/alertas/busquedas-guardadas": {
      "get": {
        "tags": [
          "Alertas"
        ],
        "operationId": "listarBusquedasGuardadas",
        "summary": "Listar las búsquedas guardadas",
        "description": "Las búsquedas guardadas del equipo, que se pueden convertir en alertas con `POST /alertas` y `busqueda_guardada_id`, con la alerta que ya salió de cada una.",
        "responses": {
          "200": {
            "description": "Las búsquedas guardadas.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/BusquedaGuardada"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/NoAutenticado"
          },
          "403": {
            "$ref": "#/components/responses/SinAcceso"
          },
          "429": {
            "$ref": "#/components/responses/LimiteSuperado"
          },
          "500": {
            "$ref": "#/components/responses/ErrorInterno"
          }
        },
        "parameters": [
          {
            "$ref": "#/components/parameters/Equipo"
          }
        ]
      }
    },
    "/alertas/historial": {
      "get": {
        "tags": [
          "Alertas"
        ],
        "operationId": "historialResumen",
        "summary": "Historial del correo de resumen",
        "description": "Sin `dia`: un resumen por días (los últimos 14, o de `desde` a `hasta`, como mucho 90) con lo enviado por cada alerta, los cambios en favoritas avisados y si salió el correo. Con `dia`: las licitaciones enviadas ese día por cada alerta, con los criterios que tenía al enviarlas y las palabras clave que aparecen en cada título, y los cambios en favoritas de ese día. `alerta_id` limita a una alerta (también borrada) y, con `dia`, `pagina` recorre sus licitaciones.",
        "x-ejemplo-peticion": {
          "query": {
            "dia": "2026-10-13"
          }
        },
        "parameters": [
          {
            "name": "dia",
            "in": "query",
            "description": "Un día concreto (AAAA-MM-DD).",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "example": "2026-10-13"
          },
          {
            "name": "desde",
            "in": "query",
            "description": "Sin `dia`: primer día del periodo.",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "hasta",
            "in": "query",
            "description": "Sin `dia`: último día del periodo (por defecto, hoy).",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "alerta_id",
            "in": "query",
            "description": "Solo esta alerta.",
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          },
          {
            "name": "incluir_vacios",
            "in": "query",
            "description": "Incluir también las alertas y los días sin envíos.",
            "schema": {
              "type": "boolean",
              "default": false
            }
          },
          {
            "$ref": "#/components/parameters/Pagina"
          },
          {
            "$ref": "#/components/parameters/PorPagina"
          },
          {
            "$ref": "#/components/parameters/Equipo"
          }
        ],
        "responses": {
          "200": {
            "description": "El historial (por días, o el detalle de un día con `fecha`, `alertas` y `favoritas`).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "periodo": {
                          "type": "object",
                          "properties": {
                            "desde": {
                              "type": "string",
                              "format": "date"
                            },
                            "hasta": {
                              "type": "string",
                              "format": "date"
                            }
                          }
                        },
                        "dias": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "fecha": {
                                "type": "string",
                                "format": "date"
                              },
                              "licitaciones_enviadas": {
                                "type": "integer"
                              },
                              "alertas": {
                                "type": "array",
                                "items": {
                                  "type": "object",
                                  "properties": {
                                    "alerta": {
                                      "type": "object"
                                    },
                                    "resultado": {
                                      "type": "string"
                                    },
                                    "licitaciones": {
                                      "type": "integer"
                                    }
                                  }
                                }
                              },
                              "cambios_en_favoritas": {
                                "type": [
                                  "integer",
                                  "null"
                                ]
                              },
                              "correo": {
                                "type": "object",
                                "properties": {
                                  "enviado": {
                                    "type": "boolean"
                                  },
                                  "hora": {
                                    "type": "string",
                                    "format": "date-time"
                                  },
                                  "destinatarios": {
                                    "type": "integer"
                                  }
                                }
                              }
                            }
                          }
                        },
                        "fecha": {
                          "type": "string",
                          "format": "date",
                          "description": "Con `dia`."
                        },
                        "alertas": {
                          "type": "array",
                          "description": "Con `dia`: lo enviado por cada alerta.",
                          "items": {
                            "type": "object",
                            "properties": {
                              "alerta": {
                                "type": "object"
                              },
                              "resultado": {
                                "type": "string"
                              },
                              "criterios_al_enviar": {
                                "type": [
                                  "string",
                                  "null"
                                ]
                              },
                              "total_licitaciones": {
                                "type": "integer"
                              },
                              "licitaciones": {
                                "type": "array",
                                "items": {
                                  "allOf": [
                                    {
                                      "$ref": "#/components/schemas/LicitacionResumen"
                                    },
                                    {
                                      "type": "object",
                                      "properties": {
                                        "enviada": {
                                          "type": "string",
                                          "format": "date-time"
                                        },
                                        "palabras_en_titulo": {
                                          "type": "array",
                                          "items": {
                                            "type": "string"
                                          }
                                        }
                                      }
                                    }
                                  ]
                                }
                              },
                              "hay_mas": {
                                "type": "boolean"
                              }
                            }
                          }
                        },
                        "favoritas": {
                          "type": "object",
                          "description": "Con `dia` y sin `alerta_id`: cambios en favoritas avisados (estado, plazo, importe, documentos nuevos)."
                        },
                        "paginacion": {
                          "$ref": "#/components/schemas/Paginacion"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/NoAutenticado"
          },
          "403": {
            "$ref": "#/components/responses/SinAcceso"
          },
          "404": {
            "$ref": "#/components/responses/NoEncontrado"
          },
          "422": {
            "$ref": "#/components/responses/ParametrosInvalidos"
          },
          "429": {
            "$ref": "#/components/responses/LimiteSuperado"
          },
          "500": {
            "$ref": "#/components/responses/ErrorInterno"
          }
        }
      }
    },
    "/alertas/ajustes": {
      "get": {
        "tags": [
          "Alertas"
        ],
        "operationId": "verAjustesResumen",
        "summary": "Ver los ajustes del correo de resumen",
        "description": "Hora, días, zona horaria, destinatarios y demás ajustes del correo de resumen (Pro y Enterprise). Cualquier miembro del equipo puede verlos.",
        "responses": {
          "200": {
            "description": "Los ajustes.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/AjustesResumen"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/NoAutenticado"
          },
          "403": {
            "$ref": "#/components/responses/SinAcceso"
          },
          "429": {
            "$ref": "#/components/responses/LimiteSuperado"
          },
          "500": {
            "$ref": "#/components/responses/ErrorInterno"
          }
        },
        "parameters": [
          {
            "$ref": "#/components/parameters/Equipo"
          }
        ]
      },
      "patch": {
        "tags": [
          "Alertas"
        ],
        "operationId": "cambiarAjustesResumen",
        "summary": "Cambiar los ajustes del correo de resumen",
        "description": "Solo el propietario del equipo (Pro y Enterprise). Solo cambia lo que se envía. La zona horaria se valida (identificador IANA). En `destinatarios` solo cambian los miembros indicados.",
        "x-ejemplo-peticion": {
          "body": {
            "hora": "10:30",
            "dias": [
              "lunes",
              "miércoles",
              "viernes"
            ],
            "destinatarios": [
              {
                "usuario": "luis@empresa.es",
                "recibe": true
              }
            ]
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "activo": {
                    "type": "boolean"
                  },
                  "hora": {
                    "type": "string",
                    "pattern": "^\\d{2}:\\d{2}$",
                    "description": "Entre 08:00 y 22:00."
                  },
                  "dias": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "enum": [
                        "lunes",
                        "martes",
                        "miércoles",
                        "jueves",
                        "viernes",
                        "sábado",
                        "domingo"
                      ]
                    },
                    "minItems": 1
                  },
                  "zona_horaria": {
                    "type": "string",
                    "examples": [
                      "Europe/Madrid",
                      "Atlantic/Canary"
                    ]
                  },
                  "enviar_si_no_hay_novedades": {
                    "type": "boolean"
                  },
                  "tipo_resumen": {
                    "type": "string",
                    "enum": [
                      "ninguno",
                      "basico",
                      "ia"
                    ]
                  },
                  "licitaciones_por_alerta": {
                    "type": "integer",
                    "enum": [
                      3,
                      10,
                      25,
                      50
                    ]
                  },
                  "un_correo_por_alerta": {
                    "type": "boolean"
                  },
                  "avisos_de_favoritas": {
                    "type": "boolean"
                  },
                  "destinatarios": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "required": [
                        "usuario",
                        "recibe"
                      ],
                      "properties": {
                        "usuario": {
                          "type": "string",
                          "description": "Email o id de un miembro."
                        },
                        "recibe": {
                          "type": "boolean"
                        }
                      }
                    }
                  }
                }
              },
              "example": {
                "hora": "10:30",
                "dias": [
                  "lunes",
                  "miércoles",
                  "viernes"
                ],
                "destinatarios": [
                  {
                    "usuario": "luis@empresa.es",
                    "recibe": true
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Los ajustes como quedan.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/AjustesResumen"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/NoAutenticado"
          },
          "403": {
            "$ref": "#/components/responses/SinAcceso"
          },
          "422": {
            "$ref": "#/components/responses/ParametrosInvalidos"
          },
          "429": {
            "$ref": "#/components/responses/LimiteSuperado"
          },
          "500": {
            "$ref": "#/components/responses/ErrorInterno"
          }
        },
        "parameters": [
          {
            "$ref": "#/components/parameters/Equipo"
          }
        ]
      }
    },
    "/alertas/{id}": {
      "get": {
        "tags": [
          "Alertas"
        ],
        "operationId": "verAlerta",
        "summary": "Ver una alerta",
        "description": "Una alerta del equipo. El propietario ve también las borradas.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Id de la alerta (el campo `id` de `GET /alertas`).",
            "schema": {
              "type": "integer",
              "minimum": 1
            },
            "example": 275
          },
          {
            "$ref": "#/components/parameters/Equipo"
          }
        ],
        "responses": {
          "200": {
            "description": "La alerta.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Alerta"
                    }
                  }
                },
                "example": {
                  "data": {
                    "id": 275,
                    "nombre": "Limpieza viaria Valencia",
                    "descripcion": null,
                    "estado": "activa",
                    "activa": true,
                    "avisos_por_email": true,
                    "criterios": {
                      "tipo": {
                        "codigo": "nuevas",
                        "nombre": "Nuevas publicaciones (licitaciones en plazo y anuncios previos)"
                      },
                      "estados": [
                        "PUB",
                        "PRE"
                      ],
                      "ambito": {
                        "codigo": "ambos",
                        "nombre": "Licitaciones y contratos menores en fase de ofertas"
                      },
                      "palabras_clave": [
                        "limpieza",
                        "viaria"
                      ],
                      "modo_palabras": "todas",
                      "cpv": [
                        {
                          "codigo": "90600000",
                          "nombre": "Servicios de limpieza y saneamiento en zonas urbanas o rurales, y servicios conexos."
                        }
                      ],
                      "provincias": [
                        {
                          "codigo": "ES523",
                          "nombre": "Valencia/València"
                        }
                      ],
                      "organos": [],
                      "importe_min": 10000.0,
                      "importe_max": null
                    },
                    "criterios_texto": "Nuevas publicaciones · Licitaciones y contratos menores en fase de ofertas · Con todas estas palabras: limpieza, viaria · CPV: 90600000 (Servicios de limpieza y saneamiento en zonas urbanas o rurales, y servicios conexos) · En: Valencia/València · Importe sin IVA desde 10.000 €",
                    "orden": 2,
                    "busqueda_guardada_id": null,
                    "creada": "2026-10-14T10:00:00+02:00",
                    "creada_por": {
                      "id": 41,
                      "nombre": "Ana",
                      "email": "ana@empresa.es",
                      "rol": "propietario"
                    },
                    "actualizada": "2026-10-14T10:00:00+02:00",
                    "actualizada_por": {
                      "id": 41,
                      "nombre": "Ana",
                      "email": "ana@empresa.es",
                      "rol": "propietario"
                    },
                    "ultimo_envio": {
                      "fecha": "2026-10-13",
                      "licitaciones": 4,
                      "enviado": "2026-10-13T09:00:02+02:00"
                    },
                    "ultima_ejecucion": {
                      "fecha": "2026-10-13",
                      "resultado": "enviada",
                      "licitaciones": 4
                    },
                    "destinatarios": {
                      "personalizados": false,
                      "usuarios": []
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/NoAutenticado"
          },
          "403": {
            "$ref": "#/components/responses/SinAcceso"
          },
          "404": {
            "$ref": "#/components/responses/NoEncontrado"
          },
          "429": {
            "$ref": "#/components/responses/LimiteSuperado"
          },
          "500": {
            "$ref": "#/components/responses/ErrorInterno"
          }
        }
      },
      "patch": {
        "tags": [
          "Alertas"
        ],
        "operationId": "modificarAlerta",
        "summary": "Modificar una alerta",
        "description": "Solo el propietario del equipo. Solo cambia lo que se envía; un criterio vacío (`[]` o `null`) se quita, y la alerta tiene que conservar alguno. `activa: false` la pone en pausa.",
        "x-ejemplo-peticion": {
          "path": {
            "id": 275
          },
          "body": {
            "activa": false
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Id de la alerta (el campo `id` de `GET /alertas`).",
            "schema": {
              "type": "integer",
              "minimum": 1
            },
            "example": 275
          },
          {
            "$ref": "#/components/parameters/Equipo"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EntradaAlerta"
              },
              "example": {
                "importe_min": null,
                "provincias": [
                  "ES523",
                  "ES521"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "La alerta como queda.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Alerta"
                    },
                    "meta": {
                      "type": "object",
                      "properties": {
                        "mensaje": {
                          "type": "string"
                        },
                        "avisos": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          },
                          "description": "Lo que se ha ajustado o conviene saber."
                        },
                        "limite": {
                          "$ref": "#/components/schemas/LimiteAlertas"
                        }
                      },
                      "required": [
                        "mensaje",
                        "limite"
                      ]
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/NoAutenticado"
          },
          "403": {
            "$ref": "#/components/responses/SinAcceso"
          },
          "404": {
            "$ref": "#/components/responses/NoEncontrado"
          },
          "422": {
            "$ref": "#/components/responses/ParametrosInvalidos"
          },
          "429": {
            "$ref": "#/components/responses/LimiteSuperado"
          },
          "500": {
            "$ref": "#/components/responses/ErrorInterno"
          }
        }
      },
      "delete": {
        "tags": [
          "Alertas"
        ],
        "operationId": "borrarAlerta",
        "summary": "Borrar una alerta",
        "description": "La cancela como la app (soft delete): deja de ejecutarse y libera su plaza en el límite del plan. Su historial se conserva. Solo el propietario del equipo.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Id de la alerta (el campo `id` de `GET /alertas`).",
            "schema": {
              "type": "integer",
              "minimum": 1
            },
            "example": 275
          },
          {
            "$ref": "#/components/parameters/Equipo"
          }
        ],
        "responses": {
          "200": {
            "description": "Alerta borrada.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "type": "object",
                      "required": [
                        "borrada",
                        "alerta"
                      ],
                      "properties": {
                        "borrada": {
                          "type": "boolean"
                        },
                        "alerta": {
                          "type": "object",
                          "properties": {
                            "id": {
                              "type": "integer"
                            },
                            "nombre": {
                              "type": "string"
                            }
                          }
                        }
                      }
                    },
                    "meta": {
                      "type": "object",
                      "properties": {
                        "mensaje": {
                          "type": "string"
                        },
                        "limite": {
                          "$ref": "#/components/schemas/LimiteAlertas"
                        }
                      },
                      "required": [
                        "mensaje",
                        "limite"
                      ]
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/NoAutenticado"
          },
          "403": {
            "$ref": "#/components/responses/SinAcceso"
          },
          "404": {
            "$ref": "#/components/responses/NoEncontrado"
          },
          "429": {
            "$ref": "#/components/responses/LimiteSuperado"
          },
          "500": {
            "$ref": "#/components/responses/ErrorInterno"
          }
        }
      }
    },
    "/alertas/{id}/previsualizar": {
      "get": {
        "tags": [
          "Alertas"
        ],
        "operationId": "probarAlerta",
        "summary": "Probar una alerta guardada",
        "description": "Cuántas y cuáles licitaciones habría traído la alerta en los últimos 30 días, con **la misma búsqueda que el correo de resumen** (no la del buscador: en las alertas basta una palabra salvo con `modo_palabras: todas`). No guarda nada. Cada prueba cuenta en la cuota diaria `previsualizaciones_dia` del equipo y las muy amplias se cortan por tiempo (`busqueda_demasiado_amplia`). Va por `GET` para que sirva también con claves de solo lectura.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Id de la alerta (el campo `id` de `GET /alertas`).",
            "schema": {
              "type": "integer",
              "minimum": 1
            },
            "example": 275
          },
          {
            "name": "limite",
            "in": "query",
            "description": "Cuántas licitaciones devolver (por defecto 10).",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 25,
              "default": 10
            }
          },
          {
            "$ref": "#/components/parameters/Equipo"
          }
        ],
        "responses": {
          "200": {
            "description": "Las licitaciones más recientes que habría traído, y en `meta` el total, la media diaria, el desglose y una valoración.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "allOf": [
                          {
                            "$ref": "#/components/schemas/LicitacionResumen"
                          },
                          {
                            "type": "object",
                            "properties": {
                              "ya_enviada": {
                                "type": "boolean",
                                "description": "Ya se envió al equipo (el resumen no la repetiría)."
                              }
                            }
                          }
                        ]
                      }
                    },
                    "meta": {
                      "type": "object",
                      "properties": {
                        "alerta": {
                          "type": [
                            "object",
                            "null"
                          ],
                          "properties": {
                            "id": {
                              "type": "integer"
                            },
                            "nombre": {
                              "type": "string"
                            }
                          }
                        },
                        "criterios": {
                          "$ref": "#/components/schemas/CriteriosAlerta"
                        },
                        "criterios_texto": {
                          "type": "string"
                        },
                        "periodo": {
                          "type": "object",
                          "properties": {
                            "desde": {
                              "type": "string",
                              "format": "date"
                            },
                            "hasta": {
                              "type": "string",
                              "format": "date"
                            },
                            "dias": {
                              "type": "integer"
                            }
                          }
                        },
                        "total": {
                          "type": "integer",
                          "description": "Coincidencias en el periodo."
                        },
                        "media_diaria": {
                          "type": "number"
                        },
                        "desglose": {
                          "type": "object",
                          "description": "`nuevas` son las que enviaría el resumen. Si hay más de 5.000 coincidencias, se desglosan las 5.000 más recientes (`calculado_sobre`).",
                          "properties": {
                            "nuevas": {
                              "type": "integer"
                            },
                            "ya_enviadas": {
                              "type": "integer"
                            },
                            "favoritas": {
                              "type": "integer"
                            },
                            "descartadas": {
                              "type": "integer"
                            },
                            "calculado_sobre": {
                              "type": "integer"
                            }
                          }
                        },
                        "valoracion": {
                          "type": "string"
                        },
                        "como_funciona": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "total",
                        "desglose",
                        "periodo"
                      ]
                    }
                  }
                },
                "example": {
                  "data": [],
                  "meta": {
                    "alerta": null,
                    "periodo": {
                      "desde": "2026-09-14",
                      "hasta": "2026-10-14",
                      "dias": 30
                    },
                    "total": 37,
                    "media_diaria": 1.2,
                    "desglose": {
                      "nuevas": 30,
                      "ya_enviadas": 5,
                      "favoritas": 1,
                      "descartadas": 1
                    },
                    "valoracion": "Volumen razonable: unas 1,2 licitaciones al día."
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/NoAutenticado"
          },
          "403": {
            "$ref": "#/components/responses/SinAcceso"
          },
          "404": {
            "$ref": "#/components/responses/NoEncontrado"
          },
          "422": {
            "$ref": "#/components/responses/ParametrosInvalidos"
          },
          "429": {
            "$ref": "#/components/responses/LimiteSuperado"
          },
          "500": {
            "$ref": "#/components/responses/ErrorInterno"
          }
        }
      }
    },
    "/vencimientos": {
      "get": {
        "tags": [
          "Vencimientos"
        ],
        "operationId": "buscarVencimientos",
        "summary": "Buscar contratos que vencen",
        "description": "Contratos públicos ya adjudicados que vencen pronto (licitaciones de la Plataforma de Contratación del Sector Público y de las plataformas autonómicas; sin contratos menores), para anticiparse a su nueva licitación. La fecha es una **estimación** de Licitaciones365 (fin indicado en el contrato, duración pactada, prórrogas registradas o leídas en los documentos), no un dato oficial.\n\nPor defecto: los que vencen de hoy a 12 meses con confianza alta o media, por fecha de vencimiento. Mismos filtros y reglas que el panel de Vencimientos de la app. Solo planes Pro y Enterprise.",
        "x-cuota-diaria": "busquedas_dia",
        "x-ejemplo-peticion": {
          "query": {
            "cpv": [
              "90910000"
            ],
            "comunidad": [
              "ES52"
            ],
            "ventana_meses": 6,
            "incluir": [
              "estadisticas"
            ],
            "por_pagina": 1
          }
        },
        "parameters": [
          {
            "name": "texto",
            "in": "query",
            "description": "Palabras que deben aparecer **todas** en el objeto o el título del contrato (las de menos de 3 letras se ignoran).",
            "schema": {
              "type": "string",
              "maxLength": 120
            },
            "example": "limpieza colegios"
          },
          {
            "name": "cpv",
            "in": "query",
            "description": "Códigos CPV de 8 dígitos sobre el **CPV principal** del contrato, separados por comas. Un código acabado en ceros incluye sus subcódigos (`90910000` = servicios de limpieza; nunca baja de la división: `90000000` no incluye la 92).",
            "schema": {
              "type": "array",
              "items": {
                "type": "string",
                "pattern": "^\\d{8}(-\\d)?$"
              }
            },
            "style": "form",
            "explode": false,
            "example": [
              "90910000"
            ]
          },
          {
            "name": "provincia",
            "in": "query",
            "description": "Provincias por su código NUTS3 (`ES523` Valencia, `ES300` Madrid…). Ver `GET /catalogos/provincias`.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "style": "form",
            "explode": false,
            "example": [
              "ES523"
            ]
          },
          {
            "name": "comunidad",
            "in": "query",
            "description": "Comunidades autónomas por su código NUTS2 (`ES52`, `ES61`…). Incluye sus provincias y lo asignado a la comunidad entera.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "style": "form",
            "explode": false,
            "example": [
              "ES52"
            ]
          },
          {
            "name": "sector",
            "in": "query",
            "description": "Sector de actividad del órgano de contratación (quién compra). También vale su nombre (`Sanidad`); como alguno lleva coma, en listas usa el código.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string",
                "enum": [
                  "servicios_publicos_generales",
                  "defensa",
                  "orden_publico_seguridad_e_interior",
                  "asuntos_economicos",
                  "industria_y_energia",
                  "medio_ambiente",
                  "vivienda_y_urbanismo",
                  "sanidad",
                  "cultura_ocio_y_religion",
                  "educacion",
                  "investigacion_e_i_d_i",
                  "proteccion_social",
                  "transporte_e_infraestructuras",
                  "agua",
                  "correos_y_comunicaciones",
                  "sin_clasificar"
                ]
              }
            },
            "style": "form",
            "explode": false,
            "example": [
              "sanidad",
              "educacion"
            ]
          },
          {
            "name": "tipo_contrato",
            "in": "query",
            "description": "Tipos de contrato por su código (`1` suministros, `2` servicios, `3` obras…). Ver `GET /catalogos/tipos_contrato`.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "style": "form",
            "explode": false,
            "example": [
              "2"
            ]
          },
          {
            "name": "organo",
            "in": "query",
            "description": "Id de plataforma del órgano de contratación (`organo.id` de las licitaciones o `GET /organos`).",
            "schema": {
              "type": "string",
              "maxLength": 64
            },
            "example": "10000000000001"
          },
          {
            "name": "adjudicatario",
            "in": "query",
            "description": "CIF de la empresa adjudicataria. Solo empresas: por privacidad no se filtra por el NIF de personas físicas.",
            "schema": {
              "type": "string",
              "maxLength": 32
            },
            "example": "B00000000"
          },
          {
            "name": "importe_min",
            "in": "query",
            "description": "Importe base mínimo del contrato, sin IVA, en euros.",
            "schema": {
              "type": "number",
              "minimum": 0
            }
          },
          {
            "name": "importe_max",
            "in": "query",
            "description": "Importe base máximo del contrato, sin IVA, en euros.",
            "schema": {
              "type": "number",
              "minimum": 0
            }
          },
          {
            "name": "confianza",
            "in": "query",
            "description": "Confianza de la fecha estimada. Por defecto `alta,media` (la baja suele ser ruido).",
            "schema": {
              "type": "array",
              "items": {
                "type": "string",
                "enum": [
                  "alta",
                  "media",
                  "baja"
                ]
              }
            },
            "style": "form",
            "explode": false
          },
          {
            "name": "ventana_meses",
            "in": "query",
            "description": "Vencen de hoy a 1, 3, 6 o 12 meses. Por defecto, 12.",
            "schema": {
              "type": "integer",
              "enum": [
                1,
                3,
                6,
                12
              ],
              "default": 12
            }
          },
          {
            "name": "vence_desde",
            "in": "query",
            "description": "Vencen desde esta fecha.",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "vence_hasta",
            "in": "query",
            "description": "Vencen hasta esta fecha: como mucho 366 días desde hoy. Sustituye a `ventana_meses`.",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "example": "2027-03-31"
          },
          {
            "name": "incluir_vencidos",
            "in": "query",
            "description": "Añade los vencidos en los últimos 90 días y los que siguen vivos por una posible prórroga.",
            "schema": {
              "type": "boolean",
              "default": false
            }
          },
          {
            "name": "prorroga",
            "in": "query",
            "description": "`prorrogable`: contempla posibles prórrogas. `prorrogado`: la fecha ya incluye una prórroga o modificación.",
            "schema": {
              "type": "string",
              "enum": [
                "prorrogable",
                "prorrogado"
              ]
            }
          },
          {
            "name": "orden",
            "in": "query",
            "description": "`fecha` de vencimiento (por defecto), `importe` o `prorroga` («prorrogable hasta»; los que no lo tienen, al final).",
            "schema": {
              "type": "string",
              "enum": [
                "fecha",
                "importe",
                "prorroga"
              ],
              "default": "fecha"
            }
          },
          {
            "name": "direccion",
            "in": "query",
            "description": "`asc` (por defecto) o `desc`.",
            "schema": {
              "type": "string",
              "enum": [
                "asc",
                "desc"
              ],
              "default": "asc"
            }
          },
          {
            "name": "incluir",
            "in": "query",
            "description": "Datos extra en `meta`: `estadisticas` (totales, importes, por mes y por territorio) y `facetas` (recuentos para afinar los filtros).",
            "schema": {
              "type": "array",
              "items": {
                "type": "string",
                "enum": [
                  "estadisticas",
                  "facetas"
                ]
              }
            },
            "style": "form",
            "explode": false,
            "example": [
              "estadisticas"
            ]
          },
          {
            "$ref": "#/components/parameters/Pagina"
          },
          {
            "$ref": "#/components/parameters/PorPagina"
          },
          {
            "$ref": "#/components/parameters/Equipo"
          }
        ],
        "responses": {
          "200": {
            "description": "Una página de contratos.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/ContratoQueVence"
                      }
                    },
                    "meta": {
                      "type": "object",
                      "required": [
                        "paginacion",
                        "filtros",
                        "atribucion"
                      ],
                      "properties": {
                        "paginacion": {
                          "$ref": "#/components/schemas/Paginacion"
                        },
                        "filtros": {
                          "type": "object",
                          "description": "Filtros aplicados, ya normalizados (incluye `hoy` y el final de la ventana en `vence_hasta`)."
                        },
                        "estadisticas": {
                          "$ref": "#/components/schemas/ResumenVencimientos"
                        },
                        "facetas": {
                          "$ref": "#/components/schemas/FacetasVencimientos"
                        },
                        "atribucion": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "data": [
                    {
                      "licitacion_id": 4521877,
                      "fecha_vencimiento": "2027-01-15",
                      "dias_restantes": 93,
                      "confianza": "media",
                      "origen_fecha": {
                        "codigo": "calculo_formalizacion_duracion",
                        "descripcion": "Formalización + duración pactada",
                        "leida_con_ia": false
                      },
                      "prorroga": {
                        "aplicada": false,
                        "prevista": "si",
                        "prorrogable_hasta": "2028-01-15",
                        "permitida_dias": 365,
                        "fin_sin_prorrogas": "2027-01-15"
                      },
                      "objeto": "Servicio de limpieza de los colegios públicos del municipio",
                      "cpv_principal": {
                        "codigo": "90911200",
                        "descripcion": "Servicios de limpieza de edificios"
                      },
                      "sector_organo": {
                        "codigo": "servicios_publicos_generales",
                        "nombre": "Servicios públicos generales"
                      },
                      "adjudicatarios": [
                        {
                          "nombre": "Limpiezas de Ejemplo SL",
                          "nif": "B00000000",
                          "ute": false,
                          "persona_fisica_protegida": false
                        }
                      ],
                      "adjudicatarios_no_mostrados": false,
                      "lotes_con_vencimientos_distintos": false,
                      "algun_lote_desierto": false,
                      "licitacion": {
                        "id": 4521877,
                        "expediente": "SER-2023-118",
                        "titulo": "Servicio de limpieza de los colegios públicos del municipio",
                        "categoria": "licitacion",
                        "estado": {
                          "codigo": "RES",
                          "nombre": "Resuelta"
                        },
                        "tipo_contrato": {
                          "codigo": "2",
                          "nombre": "Servicios"
                        },
                        "subtipo_contrato": null,
                        "organo": {
                          "id": "10000000000001",
                          "nombre": "Ayuntamiento de Ejemplo"
                        },
                        "lugar_ejecucion": {
                          "codigo": "ES523",
                          "nombre": "Valencia/València"
                        },
                        "importe_sin_iva": 480000.0,
                        "importe_con_iva": 580800.0,
                        "numero_lotes": 1,
                        "publicada": "2023-09-12T10:20:00+02:00",
                        "actualizada": "2024-01-30T13:05:00+01:00",
                        "plazo_presentacion": {
                          "fecha": "2023-10-10",
                          "hora": "14:00",
                          "tipo": "ofertas"
                        },
                        "sistema_contratacion": {
                          "codigo": "0",
                          "nombre": "No aplica"
                        },
                        "favorita": false,
                        "descartada": false,
                        "url_app": "https://app.licitaciones365.es/licitaciones/4521877",
                        "url_origen": "https://contrataciondelestado.es/wps/poc?uri=deeplink:detalle_licitacion&idEvl=EjemploXyz%3D%3D"
                      }
                    }
                  ],
                  "meta": {
                    "paginacion": {
                      "pagina": 1,
                      "por_pagina": 1,
                      "total": 37,
                      "hay_mas": true
                    },
                    "filtros": {
                      "hoy": "2026-10-14",
                      "vence_hasta": "2027-04-14",
                      "ventana_meses": 6,
                      "confianza": [
                        "alta",
                        "media"
                      ],
                      "cpv": [
                        "90910000"
                      ],
                      "territorios": [
                        "ES52"
                      ],
                      "orden": "fecha asc"
                    },
                    "estadisticas": {
                      "total": 37,
                      "importe_total": 9150000.0,
                      "importe_medio": 247297.3,
                      "con_importe": 37,
                      "por_confianza": {
                        "alta": 9,
                        "media": 28,
                        "baja": 0
                      },
                      "proximos_90_dias": 14,
                      "por_mes": [
                        {
                          "mes": "2026-11",
                          "vencimientos": 6,
                          "importe": 1210000.0
                        }
                      ],
                      "por_comunidad": [
                        {
                          "codigo": "ES52",
                          "nombre": "Comunitat Valenciana",
                          "vencimientos": 37,
                          "importe": 9150000.0
                        }
                      ],
                      "por_provincia": [
                        {
                          "codigo": "ES523",
                          "nombre": "Valencia/València",
                          "vencimientos": 21,
                          "importe": 5300000.0
                        }
                      ]
                    },
                    "atribucion": "Fuente: Plataforma de Contratación del Sector Público (datos reutilizados bajo licencia RISP / Ley 37/2007). Fecha de vencimiento ESTIMADA por licitaciones365, no oficial."
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/NoAutenticado"
          },
          "403": {
            "$ref": "#/components/responses/SinAcceso"
          },
          "422": {
            "$ref": "#/components/responses/ParametrosInvalidos"
          },
          "429": {
            "$ref": "#/components/responses/LimiteSuperado"
          },
          "500": {
            "$ref": "#/components/responses/ErrorInterno"
          },
          "503": {
            "description": "La funcionalidad de vencimientos está desactivada en este momento (`no_disponible`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "no_disponible",
                    "message": "Los vencimientos de contratos no están disponibles en este momento. Vuelve a intentarlo más tarde."
                  }
                }
              }
            }
          }
        }
      }
    },
    "/organos": {
      "get": {
        "tags": [
          "Órganos y adjudicatarios"
        ],
        "operationId": "buscarOrganos",
        "summary": "Buscar órganos de contratación",
        "description": "Directorio de órganos de contratación (quién licita), con su actividad. `texto` busca todas sus palabras en el nombre o el NIF. Por defecto, los que más licitan primero.",
        "x-cuota-diaria": "busquedas_dia",
        "x-ejemplo-peticion": {
          "query": {
            "texto": "ayuntamiento valencia",
            "por_pagina": 1
          }
        },
        "parameters": [
          {
            "name": "texto",
            "in": "query",
            "description": "Nombre o NIF (todas las palabras, sin distinguir mayúsculas ni tildes).",
            "schema": {
              "type": "string",
              "minLength": 2,
              "maxLength": 200
            },
            "example": "ayuntamiento valencia"
          },
          {
            "name": "codigo_postal",
            "in": "query",
            "description": "Prefijo del código postal: `46` es la provincia de Valencia.",
            "schema": {
              "type": "string",
              "pattern": "^\\d{1,5}$"
            },
            "example": "46"
          },
          {
            "name": "tipo_organo",
            "in": "query",
            "description": "Tipo de órgano: `1` autoridad estatal, `2` regional, `3` local, `4` organismo de derecho público, `5` otras entidades del sector público, `6`, `7` y `8` organismos bajo control estatal, regional o local, `9` empresa pública estatal.",
            "schema": {
              "type": "string",
              "enum": [
                "1",
                "2",
                "3",
                "4",
                "5",
                "6",
                "7",
                "8",
                "9"
              ]
            }
          },
          {
            "name": "activo",
            "in": "query",
            "description": "`true` solo los activos; `false`, solo los inactivos.",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "orden",
            "in": "query",
            "description": "`licitaciones` (por defecto), `contratos_menores`, `importe` o `nombre`.",
            "schema": {
              "type": "string",
              "enum": [
                "licitaciones",
                "contratos_menores",
                "importe",
                "nombre"
              ],
              "default": "licitaciones"
            }
          },
          {
            "name": "direccion",
            "in": "query",
            "description": "`desc` por defecto (`asc` al ordenar por nombre).",
            "schema": {
              "type": "string",
              "enum": [
                "asc",
                "desc"
              ]
            }
          },
          {
            "$ref": "#/components/parameters/Pagina"
          },
          {
            "$ref": "#/components/parameters/PorPagina"
          },
          {
            "$ref": "#/components/parameters/Equipo"
          }
        ],
        "responses": {
          "200": {
            "description": "Una página del directorio.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/OrganoContratacion"
                      }
                    },
                    "meta": {
                      "type": "object",
                      "properties": {
                        "paginacion": {
                          "$ref": "#/components/schemas/Paginacion"
                        },
                        "filtros": {
                          "type": "object"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "data": [
                    {
                      "id": "10000000000001",
                      "nombre": "Ayuntamiento de Ejemplo",
                      "nif": "P0000000A",
                      "dir3": "L01000000",
                      "tipo": {
                        "codigo": "3",
                        "nombre": "Autoridad local"
                      },
                      "ubicacion": "Valencia",
                      "dependencia": [
                        "Entidades Locales",
                        "Comunitat Valenciana"
                      ],
                      "codigo_postal": "46002",
                      "activo": true,
                      "licitaciones": 1245,
                      "contratos_menores": 3310,
                      "importe_total": 912345678.9,
                      "ultima_licitacion": "2026-10-10",
                      "ultimo_contrato_menor": "2026-10-08",
                      "url_publica": "https://licitaciones365.es/organos-contratacion/10000000000001-ayuntamiento-de-ejemplo"
                    }
                  ],
                  "meta": {
                    "paginacion": {
                      "pagina": 1,
                      "por_pagina": 1,
                      "total": 14,
                      "hay_mas": true
                    },
                    "filtros": {
                      "texto": "ayuntamiento valencia",
                      "orden": "licitaciones desc"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/NoAutenticado"
          },
          "403": {
            "$ref": "#/components/responses/SinAcceso"
          },
          "422": {
            "$ref": "#/components/responses/ParametrosInvalidos"
          },
          "429": {
            "$ref": "#/components/responses/LimiteSuperado"
          },
          "500": {
            "$ref": "#/components/responses/ErrorInterno"
          }
        }
      }
    },
    "/organos/{id}": {
      "get": {
        "tags": [
          "Órganos y adjudicatarios"
        ],
        "operationId": "verOrgano",
        "summary": "Ver un órgano de contratación",
        "description": "Ficha de un órgano: licitaciones y contratos menores, importes, evolución anual y de los últimos 12 meses, reparto por territorio, CPV principales, adjudicatarios más frecuentes (las personas físicas, sin nombre ni NIF), licitaciones en plazo y últimas publicadas. Las estadísticas se recalculan a diario.",
        "x-cuota-diaria": "fichas_dia",
        "x-ejemplo-peticion": {
          "path": {
            "id": "10000000000001"
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Id de plataforma del órgano (el `organo.id` de las licitaciones).",
            "schema": {
              "type": "string",
              "pattern": "^\\d+$"
            },
            "example": "10000000000001"
          },
          {
            "$ref": "#/components/parameters/Equipo"
          }
        ],
        "responses": {
          "200": {
            "description": "Ficha del órgano.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/FichaOrganoContratacion"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/NoAutenticado"
          },
          "403": {
            "$ref": "#/components/responses/SinAcceso"
          },
          "404": {
            "$ref": "#/components/responses/NoEncontrado"
          },
          "422": {
            "$ref": "#/components/responses/ParametrosInvalidos"
          },
          "429": {
            "$ref": "#/components/responses/LimiteSuperado"
          },
          "500": {
            "$ref": "#/components/responses/ErrorInterno"
          }
        }
      }
    },
    "/adjudicatarios": {
      "get": {
        "tags": [
          "Órganos y adjudicatarios"
        ],
        "operationId": "buscarAdjudicatarios",
        "summary": "Buscar empresas adjudicatarias",
        "description": "Directorio de empresas que ganan contratos públicos, con sus lotes, importes y bajas. Solo empresas con CIF: las personas físicas no aparecen y no se puede buscar por su NIF (responde `403`). Por defecto, las que más lotes ganan primero.",
        "x-cuota-diaria": "busquedas_dia",
        "x-ejemplo-peticion": {
          "query": {
            "texto": "limpiezas",
            "por_pagina": 1
          }
        },
        "parameters": [
          {
            "name": "texto",
            "in": "query",
            "description": "Nombre o CIF de la empresa (todas las palabras).",
            "schema": {
              "type": "string",
              "minLength": 2,
              "maxLength": 200
            },
            "example": "limpiezas"
          },
          {
            "name": "orden",
            "in": "query",
            "description": "`lotes` (por defecto), `licitaciones`, `contratos_menores`, `importe`, `baja_media` o `ultima_adjudicacion`.",
            "schema": {
              "type": "string",
              "enum": [
                "lotes",
                "licitaciones",
                "contratos_menores",
                "importe",
                "baja_media",
                "ultima_adjudicacion"
              ],
              "default": "lotes"
            }
          },
          {
            "name": "direccion",
            "in": "query",
            "description": "`desc` (por defecto) o `asc`.",
            "schema": {
              "type": "string",
              "enum": [
                "asc",
                "desc"
              ],
              "default": "desc"
            }
          },
          {
            "$ref": "#/components/parameters/Pagina"
          },
          {
            "$ref": "#/components/parameters/PorPagina"
          },
          {
            "$ref": "#/components/parameters/Equipo"
          }
        ],
        "responses": {
          "200": {
            "description": "Una página del directorio.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/EmpresaAdjudicataria"
                      }
                    },
                    "meta": {
                      "type": "object",
                      "properties": {
                        "paginacion": {
                          "$ref": "#/components/schemas/Paginacion"
                        },
                        "filtros": {
                          "type": "object"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "data": [
                    {
                      "nombre": "Limpiezas de Ejemplo SL",
                      "nif": "B00000000",
                      "ute": false,
                      "lotes": 412,
                      "licitaciones": 268,
                      "contratos_menores": 131,
                      "importe_adjudicado": 18750000.0,
                      "importe_medio_por_lote": 45509.71,
                      "baja_media": 12.4,
                      "primera_adjudicacion": null,
                      "ultima_adjudicacion": "2026-09-30"
                    }
                  ],
                  "meta": {
                    "paginacion": {
                      "pagina": 1,
                      "por_pagina": 1,
                      "total": 87,
                      "hay_mas": true
                    },
                    "filtros": {
                      "texto": "limpiezas",
                      "orden": "lotes desc"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/NoAutenticado"
          },
          "403": {
            "$ref": "#/components/responses/SinAcceso"
          },
          "422": {
            "$ref": "#/components/responses/ParametrosInvalidos"
          },
          "429": {
            "$ref": "#/components/responses/LimiteSuperado"
          },
          "500": {
            "$ref": "#/components/responses/ErrorInterno"
          }
        }
      }
    },
    "/adjudicatarios/{nif}": {
      "get": {
        "tags": [
          "Órganos y adjudicatarios"
        ],
        "operationId": "verAdjudicatario",
        "summary": "Ver una empresa adjudicataria",
        "description": "Ficha de una empresa por su CIF: lotes, licitaciones y contratos menores ganados, importe adjudicado, bajas, los órganos que más le adjudican, los CPV en los que más gana y sus últimas adjudicaciones. Con el NIF de una persona física (o de una comunidad de bienes o sociedad civil) responde `403`, exista o no.",
        "x-cuota-diaria": "fichas_dia",
        "x-ejemplo-peticion": {
          "path": {
            "nif": "B00000000"
          }
        },
        "parameters": [
          {
            "name": "nif",
            "in": "path",
            "required": true,
            "description": "CIF de la empresa (con o sin guiones).",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9.\\-]{2,32}$"
            },
            "example": "B00000000"
          },
          {
            "$ref": "#/components/parameters/Equipo"
          }
        ],
        "responses": {
          "200": {
            "description": "Ficha de la empresa.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/FichaEmpresaAdjudicataria"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/NoAutenticado"
          },
          "403": {
            "$ref": "#/components/responses/SinAcceso"
          },
          "404": {
            "$ref": "#/components/responses/NoEncontrado"
          },
          "422": {
            "$ref": "#/components/responses/ParametrosInvalidos"
          },
          "429": {
            "$ref": "#/components/responses/LimiteSuperado"
          },
          "500": {
            "$ref": "#/components/responses/ErrorInterno"
          }
        }
      }
    },
    "/estadisticas/mercado": {
      "get": {
        "tags": [
          "Estadísticas"
        ],
        "operationId": "estadisticasMercado",
        "summary": "Estadísticas de un mercado",
        "description": "Estadísticas agregadas de un mercado definido con los mismos filtros que `GET /licitaciones`: número de licitaciones e importes, serie mensual, reparto por estado, categoría, tipo, comunidad y provincia, los 10 CPV, órganos y empresas con más licitaciones, competencia media (ofertas por lote) y baja media.\n\nEl periodo es de publicación: por defecto, los últimos 12 meses; como mucho 36. Se calcula sobre 30.000 licitaciones como mucho: si el mercado es más amplio, responde `422` explicando cómo acotarlo. No excluye las descartadas del equipo. Los resultados se guardan 12 horas.",
        "x-cuota-diaria": "busquedas_dia",
        "x-ejemplo-peticion": {
          "query": {
            "cpv": [
              "90910000"
            ],
            "comunidad": [
              "ES52"
            ]
          }
        },
        "parameters": [
          {
            "name": "texto",
            "in": "query",
            "description": "Palabras a buscar. Tienen que aparecer **todas**, en el título, en el objeto de algún lote o en la descripción de alguno de sus CPV. Cada palabra encuentra también las que empiezan por ella: `jardin` encuentra «jardines» y «jardinería». Se ignoran las palabras de menos de 3 letras y los operadores (`+`, `-`, comillas…), y se usan como mucho 10 palabras. Para un sector suele ser más preciso filtrar por `cpv`.",
            "schema": {
              "type": "string",
              "maxLength": 200
            },
            "example": "mantenimiento jardines"
          },
          {
            "name": "cpv",
            "in": "query",
            "description": "Códigos CPV de 8 dígitos, con o sin dígito de control (`45000000` o `45000000-7`), separados por comas; se usan los 50 primeros. Un código acabado en ceros incluye sus subcódigos: `45000000` es toda la división 45 (construcción). Búscalos con `GET /catalogos/cpv`.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string",
                "pattern": "^\\d{8}(-\\d)?$"
              }
            },
            "style": "form",
            "explode": false,
            "example": [
              "77310000",
              "45112710"
            ]
          },
          {
            "name": "provincia",
            "in": "query",
            "description": "Provincias por su código NUTS3, separadas por comas: `ES523` (Valencia), `ES300` (Madrid), `ES511` (Barcelona)… Lista completa en `GET /catalogos/provincias`.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "style": "form",
            "explode": false,
            "example": [
              "ES523"
            ]
          },
          {
            "name": "comunidad",
            "in": "query",
            "description": "Comunidades autónomas por su código NUTS2, separadas por comas: `ES52` (Comunitat Valenciana), `ES61` (Andalucía), `ES51` (Cataluña)… Incluye sus provincias y también lo que se publica asignado a la comunidad entera. Lista completa en `GET /catalogos/comunidades`.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "style": "form",
            "explode": false,
            "example": [
              "ES52"
            ]
          },
          {
            "name": "estado",
            "in": "query",
            "description": "Estados, separados por comas:\n\n- `PUB`: en plazo de presentación.\n- `EV`: pendiente de adjudicación.\n- `ADJ`: adjudicada.\n- `RES`: resuelta.\n- `PRE`: anuncio previo.\n- `CERR`: cerrada.\n- `ANUL`: anulada.\n\nPor defecto, todos menos `ANUL`.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string",
                "enum": [
                  "PUB",
                  "EV",
                  "ADJ",
                  "RES",
                  "PRE",
                  "CERR",
                  "ANUL"
                ]
              }
            },
            "style": "form",
            "explode": false,
            "example": [
              "PUB"
            ]
          },
          {
            "name": "categoria",
            "in": "query",
            "description": "Categorías, separadas por comas: `licitacion` (Plataforma de Contratación del Sector Público), `agregada` (plataformas autonómicas) o `menor` (contratos menores). Por defecto, las tres.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string",
                "enum": [
                  "licitacion",
                  "agregada",
                  "menor"
                ]
              }
            },
            "style": "form",
            "explode": false,
            "example": [
              "licitacion",
              "agregada"
            ]
          },
          {
            "name": "tipo_contrato",
            "in": "query",
            "description": "Tipos de contrato por su código, separados por comas: `1` suministros, `2` servicios, `3` obras, `21` gestión de servicios públicos, `22` concesión de servicios, `31` concesión de obras públicas, `32` concesión de obras, `40` colaboración entre el sector público y el privado, `50` patrimonial, `7` administrativo especial, `8` privado. Lista en `GET /catalogos/tipos_contrato`.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "style": "form",
            "explode": false,
            "example": [
              "2"
            ]
          },
          {
            "name": "subtipo_contrato",
            "in": "query",
            "description": "Subtipos con el formato `tipo::subtipo`, separados por comas: `2::7` es «Servicios de informática y servicios conexos». Lista en `GET /catalogos/subtipos_contrato`.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string",
                "pattern": "^\\d+::\\d+$"
              }
            },
            "style": "form",
            "explode": false,
            "example": [
              "2::7"
            ]
          },
          {
            "name": "sistema_contratacion",
            "in": "query",
            "description": "Sistemas de contratación, separados por comas: `0` no aplica, `1` establecimiento del acuerdo marco, `2` establecimiento del sistema dinámico de adquisición, `3` contrato basado en un acuerdo marco, `4` contrato basado en un sistema dinámico de adquisición.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string",
                "enum": [
                  "0",
                  "1",
                  "2",
                  "3",
                  "4"
                ]
              }
            },
            "style": "form",
            "explode": false,
            "example": [
              "1",
              "3"
            ]
          },
          {
            "name": "importe_min",
            "in": "query",
            "description": "Importe base de licitación mínimo, sin IVA, en euros.",
            "schema": {
              "type": "number",
              "minimum": 0
            },
            "example": 50000
          },
          {
            "name": "importe_max",
            "in": "query",
            "description": "Importe base de licitación máximo, sin IVA, en euros. Si es menor que `importe_min`, se intercambian.",
            "schema": {
              "type": "number",
              "minimum": 0
            },
            "example": 500000
          },
          {
            "name": "publicada_desde",
            "in": "query",
            "description": "Inicio del periodo de publicación. Por defecto, el día 1 del mes de hace 11 meses.",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "publicada_hasta",
            "in": "query",
            "description": "Fin del periodo. Por defecto, hoy. Entre las dos fechas, 36 meses como mucho.",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "plazo_desde",
            "in": "query",
            "description": "El plazo de presentación termina desde esta fecha, incluida. Se usa el plazo de ofertas o, si no lo hay, el de solicitudes de participación.",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "example": "2026-10-15"
          },
          {
            "name": "plazo_hasta",
            "in": "query",
            "description": "El plazo de presentación termina hasta esta fecha, incluida.",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "example": "2026-10-31"
          },
          {
            "name": "organo",
            "in": "query",
            "description": "Identificador del órgano de contratación en la plataforma: el campo `organo.id` de los resultados.",
            "schema": {
              "type": "string",
              "maxLength": 64
            },
            "example": "10000000000001"
          },
          {
            "name": "adjudicatario",
            "in": "query",
            "description": "NIF de una empresa adjudicataria: devuelve las licitaciones con algún lote adjudicado a ella.",
            "schema": {
              "type": "string",
              "maxLength": 32
            },
            "example": "B00000000"
          },
          {
            "$ref": "#/components/parameters/Equipo"
          }
        ],
        "responses": {
          "200": {
            "description": "Estadísticas del mercado.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/EstadisticasMercado"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/NoAutenticado"
          },
          "403": {
            "$ref": "#/components/responses/SinAcceso"
          },
          "422": {
            "$ref": "#/components/responses/ParametrosInvalidos"
          },
          "429": {
            "$ref": "#/components/responses/LimiteSuperado"
          },
          "500": {
            "$ref": "#/components/responses/ErrorInterno"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "apiKey": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "l365_…",
        "description": "API key creada en la app (Perfil → Integraciones → API keys) por el propietario del equipo. Se envía en la cabecera `Authorization: Bearer l365_…`. Cada clave trabaja con un equipo, o con todos los del propietario si se creó así, y tiene permiso de solo lectura o de lectura y escritura."
      },
      "apiKeyHeader": {
        "type": "apiKey",
        "in": "header",
        "name": "X-API-Key",
        "description": "La misma API key en la cabecera `X-API-Key: l365_…`, para las herramientas que solo piden el nombre de una cabecera (Copilot Studio, Power Automate…). Si llegan las dos, vale la de `Authorization`."
      }
    },
    "parameters": {
      "Pagina": {
        "name": "pagina",
        "in": "query",
        "description": "Página que quieres, empezando por 1. `pagina × por_pagina` no puede pasar de 5.000: para ir más allá, acota la búsqueda.",
        "schema": {
          "type": "integer",
          "minimum": 1,
          "default": 1
        }
      },
      "PorPagina": {
        "name": "por_pagina",
        "in": "query",
        "description": "Resultados por página.",
        "schema": {
          "type": "integer",
          "minimum": 1,
          "maximum": 100,
          "default": 25
        }
      },
      "IdLicitacion": {
        "name": "id",
        "in": "path",
        "required": true,
        "description": "Identificador de la licitación en Licitaciones365 (el campo `id` de los resultados de búsqueda).",
        "schema": {
          "type": "integer",
          "minimum": 1
        },
        "example": 4815162
      },
      "Equipo": {
        "name": "X-Equipo",
        "in": "header",
        "required": false,
        "description": "Solo con una API key para todos los equipos: el id del equipo con el que trabaja esta petición (los ids salen en `GET /cuenta`, en `equipos`). Sin ella, la clave trabaja con su equipo.",
        "schema": {
          "type": "integer",
          "minimum": 1
        }
      }
    },
    "headers": {
      "RetryAfter": {
        "description": "Segundos que hay que esperar antes de volver a intentarlo.",
        "schema": {
          "type": "integer",
          "minimum": 1
        },
        "example": 42
      },
      "WwwAuthenticate": {
        "description": "Esquema de autenticación esperado.",
        "schema": {
          "type": "string"
        },
        "example": "Bearer realm=\"licitaciones365\""
      }
    },
    "responses": {
      "NoAutenticado": {
        "description": "Falta la API key (`no_autenticado`) o no es válida, ha caducado o se ha revocado (`credencial_invalida`).",
        "headers": {
          "WWW-Authenticate": {
            "$ref": "#/components/headers/WwwAuthenticate"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": {
                "code": "credencial_invalida",
                "message": "La credencial no es válida, ha caducado o se ha revocado."
              }
            }
          }
        }
      },
      "SinAcceso": {
        "description": "La clave es válida pero no puede hacer esto: `cuenta_no_disponible`, `plan_insuficiente`, `beta_cerrada`, `sin_equipo`, `equipo_bloqueado`, `solo_lectura`, `sin_permiso`, `limite_del_plan` (el equipo ha llegado a un límite de su plan) o, en la IA, `presupuesto_ia_agotado`.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": {
                "code": "plan_insuficiente",
                "message": "Las API keys están disponibles en los planes Pro y Enterprise. El plan actual del equipo no las incluye."
              }
            }
          }
        }
      },
      "NoEncontrado": {
        "description": "El recurso no existe o no tienes acceso a él (`no_encontrado`).",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": {
                "code": "no_encontrado",
                "message": "No existe ninguna licitación con el id 4815162."
              }
            }
          }
        }
      },
      "ParametrosInvalidos": {
        "description": "Algún parámetro no es válido (`parametros_invalidos`, con el detalle por campo en `details` cuando lo hay) o la búsqueda es tan amplia que ha superado el tiempo máximo (`busqueda_demasiado_amplia`).",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": {
                "code": "parametros_invalidos",
                "message": "El campo por_pagina debe ser como máximo 100.",
                "details": {
                  "por_pagina": [
                    "El campo por_pagina debe ser como máximo 100."
                  ]
                }
              }
            }
          }
        }
      },
      "LimiteSuperado": {
        "description": "Se ha superado el límite por minuto de la clave o una cuota diaria del equipo (`limite_superado`). La cabecera `Retry-After` dice cuántos segundos esperar.",
        "headers": {
          "Retry-After": {
            "$ref": "#/components/headers/RetryAfter"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": {
                "code": "limite_superado",
                "message": "Demasiadas peticiones: con el plan Pro cada credencial puede hacer 120 consultas por minuto. Vuelve a intentarlo en 42 s."
              }
            }
          }
        }
      },
      "ErrorInterno": {
        "description": "Error inesperado de nuestro lado (`error_interno`). Si se repite, escríbenos.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": {
                "code": "error_interno",
                "message": "Error interno. Si se repite, escríbenos a contact-us@licitaciones365.es."
              }
            }
          }
        }
      },
      "Conflicto": {
        "description": "La operación choca con el estado actual. Códigos: `ya_es_favorita` y `es_favorita` (favoritas y descartadas), `ia_en_curso` (ya hay una ejecución de IA en curso con esta clave) y `sin_checklist_ia` (hay que generar el checklist IA antes de importarlo). En el espacio de trabajo: `no_es_favorita` (las tareas y los recordatorios solo existen en las favoritas), `limite_recordatorios` (ya tiene 3), `recordatorio_repetido` (ya hay uno esos días antes) y `recordatorio_enviado` (ya se ha enviado: no se puede pausar ni borrar).",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": {
                "code": "ia_en_curso",
                "message": "Ya hay una consulta de IA en curso con esta credencial (pregunta sobre la licitación 4815162, consulta 98231). Espera a que termine antes de lanzar otra."
              }
            }
          }
        }
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "description": "Formato de todos los errores.",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "object",
            "required": [
              "code",
              "message"
            ],
            "properties": {
              "code": {
                "type": "string",
                "description": "Código estable del error, para tu código. La lista está en la guía.",
                "examples": [
                  "parametros_invalidos"
                ]
              },
              "message": {
                "type": "string",
                "description": "Explicación en español, pensada para una persona. Puede cambiar: no la compares en tu código."
              },
              "details": {
                "type": "object",
                "description": "Solo en algunos `parametros_invalidos`: los mensajes de cada campo.",
                "additionalProperties": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                }
              }
            }
          }
        }
      },
      "CodigoNombre": {
        "type": "object",
        "description": "Un código con su nombre legible.",
        "required": [
          "codigo",
          "nombre"
        ],
        "properties": {
          "codigo": {
            "type": "string",
            "examples": [
              "PUB"
            ]
          },
          "nombre": {
            "type": [
              "string",
              "null"
            ],
            "description": "null si el código no está en el catálogo.",
            "examples": [
              "En plazo"
            ]
          }
        }
      },
      "Cpv": {
        "type": "object",
        "required": [
          "codigo",
          "descripcion"
        ],
        "properties": {
          "codigo": {
            "type": "string",
            "description": "Código CPV de 8 dígitos.",
            "examples": [
              "77310000"
            ]
          },
          "descripcion": {
            "type": [
              "string",
              "null"
            ],
            "examples": [
              "Servicios de plantación y mantenimiento de zonas verdes."
            ]
          }
        }
      },
      "Paginacion": {
        "type": "object",
        "required": [
          "pagina",
          "por_pagina",
          "total",
          "hay_mas"
        ],
        "properties": {
          "pagina": {
            "type": "integer"
          },
          "por_pagina": {
            "type": "integer"
          },
          "total": {
            "type": "integer",
            "description": "Total de resultados. Si `total_es_minimo` es `true`, es un mínimo («al menos N»)."
          },
          "total_es_minimo": {
            "type": "boolean",
            "description": "Solo en la búsqueda de licitaciones: en búsquedas de texto muy amplias el recuento se corta y `total` es solo un mínimo."
          },
          "hay_mas": {
            "type": "boolean",
            "description": "Si hay más páginas después de esta."
          }
        }
      },
      "FiltrosAplicados": {
        "type": "object",
        "description": "Resumen de los filtros que se han aplicado, ya normalizados. Solo aparecen los que tienen valor.",
        "properties": {
          "texto": {
            "type": "string",
            "description": "Palabras que se han buscado."
          },
          "estados": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "categorias": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "territorios": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Códigos NUTS con los que se ha filtrado, tras sumar a cada comunidad su ámbito autonómico."
          },
          "tipos_contrato": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "subtipos_contrato": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "sistemas_contratacion": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "cpv": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "importe_min": {
            "type": "number"
          },
          "importe_max": {
            "type": "number"
          },
          "publicada_desde": {
            "type": "string",
            "format": "date"
          },
          "publicada_hasta": {
            "type": "string",
            "format": "date"
          },
          "plazo_desde": {
            "type": "string",
            "format": "date"
          },
          "plazo_hasta": {
            "type": "string",
            "format": "date"
          },
          "organo": {
            "type": "string"
          },
          "adjudicatario": {
            "type": "string"
          },
          "orden": {
            "type": "string",
            "description": "Campo y sentido, p. ej. `fecha desc`."
          },
          "descartadas": {
            "type": "string"
          }
        }
      },
      "PlazoPresentacion": {
        "type": "object",
        "description": "Fin del plazo de presentación: el de ofertas o, si no lo hay, el de solicitudes de participación.",
        "required": [
          "fecha",
          "hora",
          "tipo"
        ],
        "properties": {
          "fecha": {
            "type": "string",
            "format": "date"
          },
          "hora": {
            "type": [
              "string",
              "null"
            ],
            "description": "Hora local de Madrid (HH:MM).",
            "examples": [
              "14:00"
            ]
          },
          "tipo": {
            "type": "string",
            "enum": [
              "ofertas",
              "solicitudes"
            ]
          }
        }
      },
      "LicitacionResumen": {
        "description": "Resumen de una licitación, el que devuelve la búsqueda.",
        "allOf": [
          {
            "$ref": "#/components/schemas/LicitacionBase"
          },
          {
            "type": "object",
            "required": [
              "numero_lotes"
            ],
            "properties": {
              "numero_lotes": {
                "type": "integer",
                "description": "Número de lotes."
              }
            }
          }
        ]
      },
      "LicitacionBase": {
        "type": "object",
        "description": "Campos comunes al resumen y a la ficha de una licitación.",
        "required": [
          "id",
          "titulo",
          "categoria",
          "estado",
          "organo",
          "favorita",
          "descartada",
          "url_app"
        ],
        "properties": {
          "id": {
            "type": "integer",
            "description": "Identificador en Licitaciones365."
          },
          "expediente": {
            "type": [
              "string",
              "null"
            ],
            "description": "Número de expediente del órgano de contratación."
          },
          "titulo": {
            "type": [
              "string",
              "null"
            ]
          },
          "categoria": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "licitacion",
              "agregada",
              "menor",
              null
            ],
            "description": "`licitacion` (Plataforma de Contratación del Sector Público), `agregada` (plataformas autonómicas) o `menor` (contrato menor)."
          },
          "estado": {
            "description": "Estado del expediente (`PUB`, `EV`, `ADJ`, `RES`, `PRE`, `CERR`, `ANUL`).",
            "oneOf": [
              {
                "$ref": "#/components/schemas/CodigoNombre"
              },
              {
                "type": "null"
              }
            ]
          },
          "tipo_contrato": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/CodigoNombre"
              },
              {
                "type": "null"
              }
            ]
          },
          "subtipo_contrato": {
            "description": "El código va con el formato `tipo::subtipo`.",
            "oneOf": [
              {
                "$ref": "#/components/schemas/CodigoNombre"
              },
              {
                "type": "null"
              }
            ]
          },
          "organo": {
            "type": "object",
            "description": "Órgano de contratación.",
            "required": [
              "id",
              "nombre"
            ],
            "properties": {
              "id": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Identificador en la plataforma; sirve para el filtro `organo`."
              },
              "nombre": {
                "type": [
                  "string",
                  "null"
                ]
              }
            }
          },
          "lugar_ejecucion": {
            "description": "Territorio de ejecución por su código NUTS (país, comunidad o provincia).",
            "oneOf": [
              {
                "$ref": "#/components/schemas/CodigoNombre"
              },
              {
                "type": "null"
              }
            ]
          },
          "importe_sin_iva": {
            "type": [
              "number",
              "null"
            ],
            "description": "Presupuesto base de licitación sin IVA, en euros."
          },
          "importe_con_iva": {
            "type": [
              "number",
              "null"
            ],
            "description": "Presupuesto base de licitación con IVA, en euros."
          },
          "publicada": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "Primera publicación (hora de Madrid)."
          },
          "actualizada": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "Última actualización en origen (hora de Madrid)."
          },
          "plazo_presentacion": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/PlazoPresentacion"
              },
              {
                "type": "null"
              }
            ]
          },
          "sistema_contratacion": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/CodigoNombre"
              },
              {
                "type": "null"
              }
            ]
          },
          "favorita": {
            "type": "boolean",
            "description": "Si es favorita de tu equipo."
          },
          "descartada": {
            "type": "boolean",
            "description": "Si tu equipo la ha descartado."
          },
          "url_app": {
            "type": "string",
            "format": "uri",
            "description": "Ficha en la app de Licitaciones365 (pide iniciar sesión)."
          },
          "url_origen": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri",
            "description": "Ficha en el portal oficial de origen."
          }
        }
      },
      "Licitacion": {
        "description": "Ficha de una licitación: los campos del resumen, las secciones pedidas y la fuente.",
        "allOf": [
          {
            "$ref": "#/components/schemas/LicitacionBase"
          },
          {
            "type": "object",
            "required": [
              "numero_lotes",
              "fuente"
            ],
            "properties": {
              "numero_lotes": {
                "type": "integer",
                "description": "Número de lotes."
              },
              "general": {
                "$ref": "#/components/schemas/SeccionGeneral"
              },
              "lotes": {
                "type": "array",
                "description": "Sección `lotes` (incluida por defecto): cada lote con su objeto, importes, resultado, ofertas y adjudicatarios.",
                "items": {
                  "$ref": "#/components/schemas/Lote"
                }
              },
              "condiciones": {
                "description": "Sección `condiciones`. null si la licitación no publica estos datos.",
                "oneOf": [
                  {
                    "$ref": "#/components/schemas/Condiciones"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "historial": {
                "type": "array",
                "description": "Sección `historial`: anuncios publicados, del más reciente al más antiguo.",
                "items": {
                  "$ref": "#/components/schemas/AnuncioHistorial"
                }
              },
              "documentos": {
                "type": "array",
                "description": "Sección `documentos`.",
                "items": {
                  "$ref": "#/components/schemas/Documento"
                }
              },
              "vencimiento": {
                "description": "Sección `vencimiento`. null si no se ha podido consultar.",
                "oneOf": [
                  {
                    "$ref": "#/components/schemas/Vencimiento"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "equipo": {
                "$ref": "#/components/schemas/EquipoLicitacion"
              },
              "fuente": {
                "type": "string",
                "description": "Origen de los datos, para la atribución (reutilización de la información del sector público)."
              }
            }
          }
        ]
      },
      "SeccionGeneral": {
        "type": "object",
        "description": "Sección `general`. Las claves sin dato se omiten.",
        "properties": {
          "objeto": {
            "type": [
              "string",
              "null"
            ],
            "description": "Objeto del contrato."
          },
          "valor_estimado": {
            "type": [
              "number",
              "null"
            ],
            "description": "Valor estimado del contrato, sin IVA, en euros."
          },
          "procedimiento": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/CodigoNombre"
              },
              {
                "type": "null"
              }
            ]
          },
          "tramitacion": {
            "description": "Ordinaria, urgente o de emergencia.",
            "oneOf": [
              {
                "$ref": "#/components/schemas/CodigoNombre"
              },
              {
                "type": "null"
              }
            ]
          },
          "presentacion_ofertas": {
            "description": "Electrónica, manual o ambas.",
            "oneOf": [
              {
                "$ref": "#/components/schemas/CodigoNombre"
              },
              {
                "type": "null"
              }
            ]
          },
          "subasta_electronica": {
            "type": [
              "boolean",
              "null"
            ]
          },
          "lugar_ejecucion": {
            "type": "object",
            "properties": {
              "pais": {
                "type": "string",
                "examples": [
                  "ES"
                ]
              },
              "territorio": {
                "type": "string"
              },
              "poblacion": {
                "type": "string"
              }
            }
          },
          "organo": {
            "type": "object",
            "description": "Órgano de contratación.",
            "properties": {
              "id": {
                "type": "string"
              },
              "nombre": {
                "type": "string"
              },
              "dir3": {
                "type": "string",
                "description": "Código DIR3."
              },
              "web": {
                "type": "string"
              },
              "perfil_contratante": {
                "type": "string",
                "description": "URL del perfil del contratante."
              },
              "direccion": {
                "type": "string"
              }
            }
          },
          "plazos": {
            "type": "object",
            "properties": {
              "ofertas": {
                "$ref": "#/components/schemas/PlazoDetalle"
              },
              "solicitudes_participacion": {
                "$ref": "#/components/schemas/PlazoDetalle"
              }
            }
          },
          "duracion": {
            "type": "object",
            "description": "Duración del contrato.",
            "properties": {
              "inicio": {
                "type": "string",
                "format": "date"
              },
              "fin": {
                "type": "string",
                "format": "date"
              },
              "valor": {
                "type": "string",
                "description": "Cantidad, en las unidades de `unidades`.",
                "examples": [
                  "2"
                ]
              },
              "unidades": {
                "type": "string",
                "description": "`DAY` días, `MON` meses o `ANN` años.",
                "examples": [
                  "ANN"
                ]
              }
            }
          },
          "cpv": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Cpv"
            }
          }
        }
      },
      "PlazoDetalle": {
        "type": "object",
        "required": [
          "fecha"
        ],
        "properties": {
          "fecha": {
            "type": "string",
            "format": "date"
          },
          "hora": {
            "type": "string",
            "description": "Hora local de Madrid (HH:MM)."
          },
          "observaciones": {
            "type": "string"
          }
        }
      },
      "Lote": {
        "type": "object",
        "properties": {
          "lote": {
            "type": "integer",
            "description": "Número de lote."
          },
          "objeto": {
            "type": [
              "string",
              "null"
            ]
          },
          "importe_sin_iva": {
            "type": [
              "number",
              "null"
            ]
          },
          "importe_con_iva": {
            "type": [
              "number",
              "null"
            ]
          },
          "lugar_ejecucion": {
            "type": [
              "string",
              "null"
            ],
            "description": "Nombre del territorio."
          },
          "resultado": {
            "description": "Resultado del lote: adjudicado, formalizado, desierto…",
            "oneOf": [
              {
                "$ref": "#/components/schemas/CodigoNombre"
              },
              {
                "type": "null"
              }
            ]
          },
          "fecha_adjudicacion": {
            "type": [
              "string",
              "null"
            ],
            "format": "date"
          },
          "ofertas": {
            "type": "object",
            "description": "Ofertas recibidas. Las claves sin dato se omiten.",
            "properties": {
              "recibidas": {
                "type": "integer"
              },
              "de_pymes": {
                "type": "integer"
              },
              "de_otros_paises_ue": {
                "type": "integer"
              },
              "de_fuera_ue": {
                "type": "integer"
              },
              "mas_baja": {
                "type": "number",
                "description": "Importe de la oferta más baja, en euros."
              },
              "mas_alta": {
                "type": "number",
                "description": "Importe de la oferta más alta, en euros."
              }
            }
          },
          "adjudicatarios": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Adjudicatario"
            }
          },
          "cpv": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Cpv"
            }
          }
        }
      },
      "Adjudicatario": {
        "type": "object",
        "description": "Empresa adjudicataria de un lote. Las personas físicas salen sin nombre ni NIF.",
        "required": [
          "nombre",
          "nif",
          "persona_fisica_protegida"
        ],
        "properties": {
          "nombre": {
            "type": "string",
            "description": "Razón social, o «Persona física» si está protegida."
          },
          "nif": {
            "type": [
              "string",
              "null"
            ],
            "description": "NIF de la empresa; null si es una persona física o no se puede publicar."
          },
          "persona_fisica_protegida": {
            "type": "boolean"
          },
          "importe_ofertado_sin_iva": {
            "type": [
              "number",
              "null"
            ]
          },
          "importe_ofertado_con_iva": {
            "type": [
              "number",
              "null"
            ]
          },
          "baja_porcentaje": {
            "type": [
              "number",
              "null"
            ],
            "description": "Baja sobre el presupuesto, en porcentaje."
          }
        }
      },
      "Condiciones": {
        "type": "object",
        "description": "Sección `condiciones`, con los datos estructurados que publica el órgano. Las listas vacías se omiten.",
        "properties": {
          "criterios_adjudicacion": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "descripcion": {
                  "type": "string"
                },
                "tipo": {
                  "type": "string"
                },
                "peso": {
                  "type": "number",
                  "description": "Peso o puntuación del criterio."
                },
                "lote": {
                  "type": "integer"
                }
              }
            }
          },
          "solvencia": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "ambito": {
                  "type": "string"
                },
                "criterio": {
                  "type": "string"
                },
                "descripcion": {
                  "type": "string"
                },
                "lote": {
                  "type": "integer"
                }
              }
            }
          },
          "garantias": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "tipo": {
                  "type": "string",
                  "examples": [
                    "Definitiva"
                  ]
                },
                "porcentaje": {
                  "type": "number"
                },
                "importe": {
                  "type": "number"
                },
                "lote": {
                  "type": "integer"
                }
              }
            }
          },
          "condiciones_ejecucion": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "tipo": {
                  "type": "string"
                },
                "nombre": {
                  "type": "string"
                },
                "descripcion": {
                  "type": "string"
                }
              }
            }
          },
          "modificaciones": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "numero": {
                  "type": "string"
                },
                "nota": {
                  "type": "string"
                },
                "importe_modificacion": {
                  "type": "number"
                },
                "importe_final": {
                  "type": "number"
                }
              }
            }
          },
          "financiacion": {
            "type": "array",
            "description": "Programas de financiación (por ejemplo, fondos europeos).",
            "items": {
              "type": "string"
            }
          },
          "otras": {
            "type": "object",
            "properties": {
              "subcontratacion_porcentaje": {
                "type": "number"
              },
              "subcontratacion": {
                "type": "string"
              },
              "admite_variantes": {
                "type": "boolean"
              },
              "exige_cv": {
                "type": "boolean"
              },
              "revision_precios": {
                "type": "string"
              },
              "prorroga_plazo": {
                "type": "string"
              },
              "prorroga": {
                "type": "string"
              },
              "solvencia": {
                "type": "string"
              },
              "financiacion": {
                "type": "string"
              }
            }
          }
        }
      },
      "AnuncioHistorial": {
        "type": "object",
        "properties": {
          "tipo": {
            "type": [
              "string",
              "null"
            ],
            "examples": [
              "Anuncio de licitación"
            ]
          },
          "codigo": {
            "type": [
              "string",
              "null"
            ],
            "examples": [
              "DOC_CN"
            ]
          },
          "fecha": {
            "type": [
              "string",
              "null"
            ],
            "format": "date"
          },
          "medio": {
            "type": [
              "string",
              "null"
            ],
            "description": "Medio de publicación."
          }
        }
      },
      "Documento": {
        "type": "object",
        "description": "Documento de la licitación, como enlace al portal oficial.",
        "required": [
          "id",
          "tipo",
          "nombre",
          "fecha",
          "fuente",
          "retirado",
          "url"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Identificador compuesto por el tipo y un número: `pliego_adm:…`, `pliego_tec:…`, `anexo:…`, `general:…`, `anuncio:…` o `modweb:…`.",
            "examples": [
              "pliego_adm:90211"
            ]
          },
          "tipo": {
            "type": "string",
            "examples": [
              "Pliego de cláusulas administrativas"
            ]
          },
          "nombre": {
            "type": "string",
            "description": "Nombre del fichero o, si no lo tiene, el tipo."
          },
          "fecha": {
            "type": [
              "string",
              "null"
            ],
            "format": "date"
          },
          "fuente": {
            "type": [
              "string",
              "null"
            ],
            "description": "Dominio del portal de origen.",
            "examples": [
              "contrataciondelestado.es"
            ]
          },
          "retirado": {
            "type": "boolean",
            "description": "Si se ha retirado del expediente."
          },
          "url": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri",
            "description": "Enlace al documento en el portal de origen."
          }
        }
      },
      "Vencimiento": {
        "type": "object",
        "description": "Vencimiento estimado del contrato. Si `disponible` o `estimado` son `false`, `motivo` explica por qué; el resto de claves solo aparecen con datos.",
        "required": [
          "disponible"
        ],
        "properties": {
          "disponible": {
            "type": "boolean"
          },
          "estimado": {
            "type": "boolean",
            "description": "Si hay una fecha estimada para este contrato."
          },
          "motivo": {
            "type": "string"
          },
          "fecha_vencimiento": {
            "type": "string",
            "format": "date"
          },
          "dias_restantes": {
            "type": "integer",
            "description": "Días hasta el vencimiento; negativo si ya ha vencido."
          },
          "confianza": {
            "type": "string",
            "enum": [
              "alta",
              "media"
            ]
          },
          "estado": {
            "type": "string",
            "description": "Estado del expediente."
          },
          "prorroga_posible": {
            "type": "boolean"
          },
          "fecha_fin_base": {
            "type": "string",
            "format": "date",
            "description": "Fin del contrato sin prórrogas."
          },
          "fecha_fin_maxima": {
            "type": "string",
            "format": "date",
            "description": "Fin con todas las prórrogas permitidas."
          },
          "fuente": {
            "type": "string",
            "description": "Cómo se ha calculado la fecha."
          },
          "cita": {
            "type": "string",
            "description": "Texto del documento en el que se basa la estimación, cuando lo hay."
          },
          "cita_documento": {
            "type": "string",
            "format": "uri",
            "description": "Documento de la cita."
          }
        }
      },
      "EquipoLicitacion": {
        "type": "object",
        "description": "Sección `equipo`: lo de tu equipo sobre esta licitación.",
        "required": [
          "favorita",
          "grupo",
          "tiene_nota",
          "tareas",
          "recordatorios"
        ],
        "properties": {
          "favorita": {
            "type": "boolean"
          },
          "grupo": {
            "description": "Grupo de favoritas en el que está.",
            "oneOf": [
              {
                "type": "object",
                "required": [
                  "id",
                  "nombre"
                ],
                "properties": {
                  "id": {
                    "type": "integer"
                  },
                  "nombre": {
                    "type": "string"
                  }
                }
              },
              {
                "type": "null"
              }
            ]
          },
          "tiene_nota": {
            "type": "boolean"
          },
          "tareas": {
            "type": "integer",
            "description": "Tareas del checklist."
          },
          "recordatorios": {
            "type": "integer"
          }
        }
      },
      "Cuenta": {
        "type": "object",
        "required": [
          "usuario",
          "equipo",
          "credencial",
          "limites_plan",
          "presupuesto_ia",
          "cuotas_api_hoy",
          "datos_actualizados",
          "app_url"
        ],
        "properties": {
          "usuario": {
            "type": "object",
            "required": [
              "id",
              "email",
              "nombre"
            ],
            "properties": {
              "id": {
                "type": "integer"
              },
              "email": {
                "type": "string",
                "format": "email"
              },
              "nombre": {
                "type": "string"
              }
            }
          },
          "equipo": {
            "type": "object",
            "required": [
              "id",
              "nombre",
              "plan",
              "rol"
            ],
            "properties": {
              "id": {
                "type": "integer"
              },
              "nombre": {
                "type": "string"
              },
              "plan": {
                "type": "string",
                "description": "Plan del equipo. Con API key, `Pro` o `Enterprise`.",
                "examples": [
                  "Pro"
                ]
              },
              "rol": {
                "type": [
                  "string",
                  "null"
                ],
                "enum": [
                  "owner",
                  "member",
                  null
                ],
                "description": "Tu rol en el equipo: propietario (`owner`) o miembro (`member`)."
              }
            }
          },
          "credencial": {
            "type": "object",
            "required": [
              "tipo",
              "nombre",
              "escritura",
              "todos_los_equipos"
            ],
            "properties": {
              "tipo": {
                "type": "string",
                "enum": [
                  "api_key",
                  "conector"
                ],
                "description": "`api_key` en la API; `conector` en los asistentes conectados por OAuth."
              },
              "nombre": {
                "type": "string",
                "description": "Nombre que le diste a la clave."
              },
              "escritura": {
                "type": "boolean",
                "description": "Si la clave puede hacer cambios."
              },
              "todos_los_equipos": {
                "type": "boolean",
                "description": "Si la clave vale para todos los equipos de su propietario (elige equipo con `X-Equipo`)."
              }
            }
          },
          "limites_plan": {
            "type": "object",
            "description": "Lo que tu equipo usa de cada límite del plan.",
            "properties": {
              "favoritas": {
                "$ref": "#/components/schemas/LimitePlan"
              },
              "grupos_favoritas": {
                "$ref": "#/components/schemas/LimitePlan"
              },
              "busquedas_guardadas": {
                "$ref": "#/components/schemas/LimitePlan"
              },
              "alertas": {
                "$ref": "#/components/schemas/LimitePlan"
              }
            }
          },
          "presupuesto_ia": {
            "description": "Presupuesto mensual de IA del equipo. null si no se ha podido consultar.",
            "oneOf": [
              {
                "$ref": "#/components/schemas/PresupuestoIa"
              },
              {
                "type": "null"
              }
            ]
          },
          "cuotas_api_hoy": {
            "type": "object",
            "description": "Cuotas diarias de la API y del MCP para tu equipo, con lo usado hoy. Se renuevan a medianoche (hora de Madrid).",
            "properties": {
              "busquedas_dia": {
                "$ref": "#/components/schemas/CuotaDiaria"
              },
              "fichas_dia": {
                "$ref": "#/components/schemas/CuotaDiaria"
              },
              "filas_csv_dia": {
                "$ref": "#/components/schemas/CuotaDiaria"
              },
              "favoritas_nuevas_dia": {
                "$ref": "#/components/schemas/CuotaDiaria"
              },
              "alertas_nuevas_dia": {
                "$ref": "#/components/schemas/CuotaDiaria"
              },
              "previsualizaciones_dia": {
                "$ref": "#/components/schemas/CuotaDiaria"
              },
              "consultas_ia_dia": {
                "$ref": "#/components/schemas/CuotaDiaria"
              }
            }
          },
          "datos_actualizados": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "Fin de la última carga diaria de datos."
          },
          "app_url": {
            "type": "string",
            "format": "uri"
          },
          "equipos": {
            "type": "array",
            "description": "Solo con una API key para todos los equipos: los equipos del usuario y si la clave puede trabajar con cada uno (los ids de `X-Equipo`).",
            "items": {
              "type": "object",
              "required": [
                "id",
                "nombre",
                "plan",
                "actual",
                "disponible"
              ],
              "properties": {
                "id": {
                  "type": "integer"
                },
                "nombre": {
                  "type": "string"
                },
                "personal": {
                  "type": "boolean",
                  "description": "Si es su espacio personal."
                },
                "rol": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "plan": {
                  "type": "string"
                },
                "actual": {
                  "type": "boolean",
                  "description": "Si es el equipo con el que trabaja esta petición."
                },
                "disponible": {
                  "type": "boolean",
                  "description": "Si la clave puede trabajar con él (propietario y plan Pro o Enterprise)."
                },
                "motivo": {
                  "type": [
                    "string",
                    "null"
                  ],
                  "description": "Por qué no, si no está disponible."
                }
              }
            }
          }
        }
      },
      "LimitePlan": {
        "type": "object",
        "required": [
          "usados",
          "maximo",
          "puede_anadir"
        ],
        "properties": {
          "usados": {
            "type": "integer"
          },
          "maximo": {
            "type": [
              "integer",
              "null"
            ],
            "description": "null si el plan no tiene límite."
          },
          "puede_anadir": {
            "type": "boolean"
          }
        }
      },
      "CuotaDiaria": {
        "type": "object",
        "required": [
          "limite",
          "usado"
        ],
        "properties": {
          "limite": {
            "type": "integer"
          },
          "usado": {
            "type": "integer"
          }
        }
      },
      "PresupuestoIa": {
        "type": "object",
        "properties": {
          "unidad": {
            "type": "string"
          },
          "mensual": {
            "type": "integer"
          },
          "usado": {
            "type": "integer"
          },
          "disponible": {
            "type": "integer"
          },
          "periodo_inicio": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "periodo_fin": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          }
        }
      },
      "ElementoCatalogo": {
        "description": "Un elemento del catálogo. La forma depende del `tipo` consultado.",
        "anyOf": [
          {
            "title": "CPV (tipo cpv)",
            "type": "object",
            "required": [
              "codigo",
              "descripcion"
            ],
            "properties": {
              "codigo": {
                "type": "string",
                "examples": [
                  "77310000"
                ]
              },
              "descripcion": {
                "type": "string"
              }
            }
          },
          {
            "title": "Provincia (tipo provincias)",
            "type": "object",
            "required": [
              "codigo",
              "nombre",
              "comunidad"
            ],
            "properties": {
              "codigo": {
                "type": "string",
                "description": "NUTS3.",
                "examples": [
                  "ES523"
                ]
              },
              "nombre": {
                "type": "string"
              },
              "comunidad": {
                "type": "string",
                "description": "NUTS2 de su comunidad.",
                "examples": [
                  "ES52"
                ]
              }
            }
          },
          {
            "title": "Comunidad autónoma (tipo comunidades)",
            "type": "object",
            "required": [
              "codigo",
              "nombre",
              "provincias"
            ],
            "properties": {
              "codigo": {
                "type": "string",
                "description": "NUTS2.",
                "examples": [
                  "ES52"
                ]
              },
              "nombre": {
                "type": "string"
              },
              "provincias": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "description": "Códigos NUTS3 de sus provincias."
              }
            }
          },
          {
            "title": "Código con nombre (resto de catálogos)",
            "$ref": "#/components/schemas/CodigoNombre"
          }
        ]
      },
      "RespuestaIa": {
        "type": "object",
        "description": "Una pregunta a la IA y, cuando termina, su respuesta.",
        "required": [
          "run_id",
          "conversacion_id",
          "licitacion_id",
          "url_app",
          "estado"
        ],
        "properties": {
          "run_id": {
            "type": "integer",
            "description": "Identificador de la consulta, para recogerla con `GET /ia/consultas/{run}`."
          },
          "conversacion_id": {
            "type": "integer",
            "description": "Conversación de la app donde queda la pregunta; pásalo en `conversacion_id` para continuarla."
          },
          "licitacion_id": {
            "type": "integer"
          },
          "url_app": {
            "type": "string",
            "format": "uri",
            "description": "Ficha de la licitación en la app, donde también se ve la conversación."
          },
          "estado": {
            "type": "string",
            "enum": [
              "en_curso",
              "completada",
              "error"
            ]
          },
          "fase": {
            "type": "string",
            "description": "Solo en curso: en cola, cargando los pliegos, preparando la documentación o pensando la respuesta."
          },
          "respuesta": {
            "type": "string",
            "description": "Solo si está completada: la respuesta de la IA."
          },
          "fuentes": {
            "type": "array",
            "items": {
              "type": "object"
            },
            "description": "Si están activadas, los fragmentos de los documentos en los que se basa la respuesta."
          },
          "mensaje": {
            "type": "string",
            "description": "Explicación del estado, cuando no está completada."
          }
        }
      },
      "ChecklistIa": {
        "type": "object",
        "description": "Propuesta de tareas de la IA para presentarse a una licitación, o su estado.",
        "required": [
          "licitacion_id",
          "estado"
        ],
        "properties": {
          "licitacion_id": {
            "type": "integer"
          },
          "estado": {
            "type": "string",
            "enum": [
              "sin_generar",
              "en_curso",
              "completado",
              "error"
            ]
          },
          "tareas": {
            "type": "array",
            "description": "Solo si está completado.",
            "items": {
              "type": "object",
              "required": [
                "indice",
                "ya_en_el_checklist"
              ],
              "properties": {
                "indice": {
                  "type": "integer",
                  "description": "Posición en la propuesta; sirve para importar solo algunas."
                },
                "tarea": {
                  "type": "string"
                },
                "descripcion": {
                  "type": "string"
                },
                "prioridad": {
                  "type": "string",
                  "enum": [
                    "alta",
                    "media",
                    "baja"
                  ]
                },
                "fecha_limite": {
                  "type": "string",
                  "description": "Fecha límite propuesta, si la hay."
                },
                "ya_en_el_checklist": {
                  "type": "boolean",
                  "description": "Si el equipo ya tiene esa tarea."
                }
              }
            }
          },
          "generado": {
            "type": "string",
            "format": "date-time",
            "description": "Cuándo se generó la propuesta."
          },
          "mensaje": {
            "type": "string"
          }
        }
      },
      "ImportacionChecklistIa": {
        "type": "object",
        "required": [
          "licitacion_id",
          "importadas",
          "tareas_creadas",
          "mensaje"
        ],
        "properties": {
          "licitacion_id": {
            "type": "integer"
          },
          "importadas": {
            "type": "integer",
            "description": "Tareas nuevas añadidas al checklist."
          },
          "tareas_creadas": {
            "type": "array",
            "items": {
              "type": "integer"
            },
            "description": "Identificadores de las tareas creadas."
          },
          "mensaje": {
            "type": "string"
          }
        }
      },
      "InformePdf": {
        "type": "object",
        "description": "Estado del informe PDF del equipo para una licitación. Las claves sin dato no aparecen.",
        "required": [
          "licitacion_id",
          "estado",
          "hay_version_mas_nueva",
          "mensaje"
        ],
        "properties": {
          "licitacion_id": {
            "type": "integer"
          },
          "estado": {
            "type": "string",
            "enum": [
              "sin_generar",
              "en_curso",
              "listo",
              "error"
            ]
          },
          "version": {
            "type": "integer",
            "description": "Versión del informe del equipo."
          },
          "generado": {
            "type": "string",
            "format": "date-time"
          },
          "hay_version_mas_nueva": {
            "type": "boolean",
            "description": "Si los documentos han cambiado y se puede generar una versión nueva."
          },
          "enlace": {
            "type": "string",
            "format": "uri",
            "description": "Solo si está listo: enlace de descarga, sin credencial, que caduca a los 15 minutos."
          },
          "enlace_caduca_en_minutos": {
            "type": "integer",
            "examples": [
              15
            ]
          },
          "mensaje": {
            "type": "string"
          }
        }
      },
      "Competencia": {
        "type": "object",
        "description": "Análisis de competencia de un lote.",
        "required": [
          "licitacion_id",
          "lote",
          "desde_ultimo_analisis",
          "competidores",
          "competidores_total",
          "mensaje"
        ],
        "properties": {
          "licitacion_id": {
            "type": "integer"
          },
          "lote": {
            "type": "object",
            "properties": {
              "numero": {
                "type": "integer"
              },
              "objeto": {
                "type": [
                  "string",
                  "null"
                ]
              }
            }
          },
          "generado": {
            "type": [
              "string",
              "null"
            ],
            "description": "Cuándo se calculó."
          },
          "desde_ultimo_analisis": {
            "type": "boolean",
            "description": "`true` si es el último análisis guardado; `false` si se acaba de calcular."
          },
          "conclusion": {
            "type": [
              "object",
              "null"
            ],
            "description": "Conclusión del análisis para decidir la oferta. null si aún no hay.",
            "required": [
              "texto",
              "puntos_clave",
              "alertas",
              "generada_con_ia"
            ],
            "properties": {
              "texto": {
                "type": "string"
              },
              "puntos_clave": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "alertas": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "description": "Avisos de prudencia (muestra pequeña, dispersión…)."
              },
              "generada_con_ia": {
                "type": "boolean",
                "description": "false si es el resumen automático sin IA."
              }
            }
          },
          "estimacion": {
            "type": [
              "object",
              "null"
            ],
            "description": "Estimación del importe de adjudicación del lote a partir de las bajas de adjudicaciones parecidas (mismo segmento de CPV e importe). Orientativa. null si no hay muestra suficiente.",
            "properties": {
              "adjudicaciones_comparables": {
                "type": [
                  "integer",
                  "null"
                ],
                "description": "Tamaño de la muestra."
              },
              "confianza": {
                "type": [
                  "string",
                  "null"
                ],
                "enum": [
                  "alta",
                  "media",
                  "baja",
                  null
                ]
              },
              "baja_pct": {
                "type": "object",
                "description": "Bajas de la muestra, en porcentaje.",
                "properties": {
                  "percentil_25": {
                    "type": "number",
                    "description": "Percentil 25."
                  },
                  "mediana": {
                    "type": "number",
                    "description": "Mediana."
                  },
                  "percentil_75": {
                    "type": "number",
                    "description": "Percentil 75."
                  },
                  "percentil_90": {
                    "type": "number",
                    "description": "Percentil 90."
                  },
                  "media": {
                    "type": "number",
                    "description": "Media."
                  },
                  "minima": {
                    "type": "number",
                    "description": "Mínima."
                  },
                  "maxima": {
                    "type": "number",
                    "description": "Máxima."
                  }
                }
              },
              "importe_sin_iva": {
                "type": "object",
                "description": "Ofertas según la baja: conservadora (percentil 25), media (mediana), agresiva (percentil 75) y muy agresiva (percentil 90).",
                "properties": {
                  "presupuesto_lote": {
                    "type": "number",
                    "description": "Presupuesto base del lote."
                  },
                  "oferta_conservadora": {
                    "type": "number"
                  },
                  "oferta_media": {
                    "type": "number"
                  },
                  "oferta_agresiva": {
                    "type": "number"
                  },
                  "oferta_muy_agresiva": {
                    "type": "number"
                  }
                }
              },
              "histograma_bajas": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "desde_pct": {
                      "type": "number"
                    },
                    "hasta_pct": {
                      "type": "number"
                    },
                    "adjudicaciones": {
                      "type": "integer"
                    },
                    "porcentaje": {
                      "type": [
                        "number",
                        "null"
                      ]
                    }
                  }
                }
              }
            }
          },
          "competidores": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Competidor"
            }
          },
          "competidores_total": {
            "type": "integer"
          },
          "mensaje": {
            "type": "string"
          }
        }
      },
      "Competidor": {
        "type": "object",
        "description": "Empresa que suele ganar en el segmento del lote. Las personas físicas salen protegidas, sin nombre ni NIF. Las claves sin dato no aparecen.",
        "required": [
          "nombre",
          "persona_fisica_protegida"
        ],
        "properties": {
          "nombre": {
            "type": "string"
          },
          "nif": {
            "type": "string",
            "description": "Solo si es una empresa que se puede identificar con certeza."
          },
          "persona_fisica_protegida": {
            "type": "boolean"
          },
          "adjudicaciones_en_el_segmento": {
            "type": "integer"
          },
          "presencia_en_el_segmento_pct": {
            "type": "number"
          },
          "baja_media_pct": {
            "type": "number",
            "description": "En porcentaje."
          },
          "baja_maxima_pct": {
            "type": "number",
            "description": "En porcentaje."
          },
          "ultima_baja_pct": {
            "type": "number",
            "description": "En porcentaje."
          }
        }
      },
      "RecomendacionCpv": {
        "type": "object",
        "required": [
          "cpv",
          "mensaje"
        ],
        "properties": {
          "cpv": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "codigo": {
                  "type": "string"
                },
                "descripcion": {
                  "type": "string"
                },
                "relevancia": {
                  "type": "string",
                  "enum": [
                    "alta",
                    "media",
                    "baja"
                  ]
                }
              }
            }
          },
          "mensaje": {
            "type": "string"
          }
        }
      },
      "GrupoDeFavorita": {
        "type": "object",
        "description": "Grupo de favoritas (una etapa de «Mis concursos»).",
        "required": [
          "id",
          "nombre"
        ],
        "properties": {
          "id": {
            "type": "integer"
          },
          "nombre": {
            "type": "string"
          },
          "bloqueado_por_plan": {
            "type": "boolean",
            "description": "Solo aparece (con `true`) si el grupo está bloqueado porque el plan actual no lo permite."
          }
        }
      },
      "Favorita": {
        "description": "Una favorita: el resumen de la licitación, su grupo y cuándo se añadió.",
        "allOf": [
          {
            "$ref": "#/components/schemas/LicitacionResumen"
          },
          {
            "type": "object",
            "required": [
              "grupo",
              "anadida_a_favoritas"
            ],
            "properties": {
              "grupo": {
                "oneOf": [
                  {
                    "$ref": "#/components/schemas/GrupoDeFavorita"
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "null si no está en ningún grupo."
              },
              "anadida_a_favoritas": {
                "type": [
                  "string",
                  "null"
                ],
                "format": "date-time"
              },
              "vencimiento": {
                "description": "Solo con los planes Pro y Enterprise: vencimiento estimado del contrato, o null si no lo hay.",
                "oneOf": [
                  {
                    "type": "object",
                    "properties": {
                      "fecha_vencimiento": {
                        "type": [
                          "string",
                          "null"
                        ],
                        "format": "date"
                      },
                      "dias_restantes": {
                        "type": [
                          "integer",
                          "null"
                        ],
                        "description": "Negativo si ya ha vencido."
                      },
                      "confianza": {
                        "type": [
                          "string",
                          "null"
                        ],
                        "enum": [
                          "alta",
                          "media",
                          null
                        ]
                      },
                      "prorroga_posible": {
                        "type": "boolean"
                      }
                    }
                  },
                  {
                    "type": "null"
                  }
                ]
              }
            }
          }
        ]
      },
      "Descartada": {
        "description": "Una licitación descartada: su resumen y cuándo se descartó.",
        "allOf": [
          {
            "$ref": "#/components/schemas/LicitacionResumen"
          },
          {
            "type": "object",
            "required": [
              "descartada_el"
            ],
            "properties": {
              "descartada_el": {
                "type": [
                  "string",
                  "null"
                ],
                "format": "date-time"
              }
            }
          }
        ]
      },
      "MiembroEquipo": {
        "type": "object",
        "description": "Una persona del equipo: id, nombre, email y rol. De quien ya no está en el equipo (escribió una tarea y se fue) solo se da el id: nombre, email y rol a null y antiguo_miembro a true.",
        "required": [
          "id",
          "nombre",
          "email",
          "rol"
        ],
        "properties": {
          "id": {
            "type": "integer"
          },
          "nombre": {
            "type": [
              "string",
              "null"
            ]
          },
          "email": {
            "type": [
              "string",
              "null"
            ],
            "format": "email"
          },
          "rol": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "propietario",
              "miembro",
              null
            ]
          },
          "antiguo_miembro": {
            "type": "boolean",
            "description": "true si ya no es miembro del equipo."
          }
        }
      },
      "NotaLicitacion": {
        "type": "object",
        "description": "Nota del equipo sobre una licitación (una por licitación y equipo), en texto plano y en el HTML del editor de la app.",
        "required": [
          "texto",
          "html",
          "creada_por",
          "modificada_por",
          "creada",
          "actualizada"
        ],
        "properties": {
          "texto": {
            "type": "string",
            "description": "La nota en texto plano: párrafos separados por una línea en blanco y listas con guiones."
          },
          "html": {
            "type": "string",
            "description": "La nota en HTML saneado (sin imágenes ni scripts)."
          },
          "creada_por": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/MiembroEquipo"
              },
              {
                "type": "null"
              }
            ]
          },
          "modificada_por": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/MiembroEquipo"
              },
              {
                "type": "null"
              }
            ]
          },
          "creada": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "actualizada": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          }
        }
      },
      "NotaGuardada": {
        "type": "object",
        "required": [
          "modo",
          "nota"
        ],
        "properties": {
          "modo": {
            "type": "string",
            "enum": [
              "reemplazar",
              "anadir_al_final"
            ]
          },
          "nota": {
            "$ref": "#/components/schemas/NotaLicitacion"
          },
          "nota_anterior": {
            "type": "object",
            "description": "Solo al reemplazar una nota que tenía contenido: lo que había, para poder restaurarlo.",
            "required": [
              "texto",
              "html"
            ],
            "properties": {
              "texto": {
                "type": "string"
              },
              "html": {
                "type": "string"
              }
            }
          }
        }
      },
      "Tarea": {
        "type": "object",
        "description": "Una tarea del checklist del equipo en una licitación favorita.",
        "required": [
          "id",
          "licitacion_id",
          "titulo",
          "descripcion",
          "estado",
          "prioridad",
          "fecha_limite",
          "vencida",
          "completada",
          "completada_por",
          "creada_por",
          "creada",
          "actualizada",
          "orden"
        ],
        "properties": {
          "id": {
            "type": "integer"
          },
          "licitacion_id": {
            "type": "integer"
          },
          "titulo": {
            "type": "string",
            "maxLength": 255
          },
          "descripcion": {
            "type": [
              "string",
              "null"
            ]
          },
          "estado": {
            "type": "string",
            "enum": [
              "pendiente",
              "en_curso",
              "completada",
              "cancelada"
            ]
          },
          "prioridad": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "baja",
              "media",
              "alta",
              null
            ]
          },
          "fecha_limite": {
            "type": [
              "string",
              "null"
            ],
            "format": "date"
          },
          "vencida": {
            "type": "boolean",
            "description": "La fecha límite ya ha pasado y no está completada ni cancelada."
          },
          "responsable": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/MiembroEquipo"
              },
              {
                "type": "null"
              }
            ],
            "description": "Solo con los planes Pro y Enterprise (asignar tareas es de esos planes)."
          },
          "completada": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "completada_por": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/MiembroEquipo"
              },
              {
                "type": "null"
              }
            ]
          },
          "creada_por": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/MiembroEquipo"
              },
              {
                "type": "null"
              }
            ]
          },
          "creada": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "actualizada": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "orden": {
            "type": "integer",
            "description": "Posición en el checklist (empieza en 1)."
          }
        }
      },
      "Recordatorio": {
        "type": "object",
        "description": "Recordatorio por email de una licitación favorita: le llega a todo el equipo `dias_antes` días antes del fin del plazo de presentación (`referencia: plazo`) o del vencimiento estimado del contrato (`referencia: vencimiento`), a la `hora` indicada (hora de Madrid).",
        "required": [
          "id",
          "licitacion_id",
          "referencia",
          "dias_antes",
          "hora",
          "fecha_aviso",
          "activo",
          "enviado",
          "enviado_a",
          "modificable",
          "creado_por",
          "creado"
        ],
        "properties": {
          "id": {
            "type": "integer"
          },
          "licitacion_id": {
            "type": "integer"
          },
          "referencia": {
            "type": "string",
            "enum": [
              "plazo",
              "vencimiento"
            ]
          },
          "dias_antes": {
            "type": "integer",
            "minimum": 1,
            "maximum": 365
          },
          "hora": {
            "type": "string",
            "description": "HH:MM.",
            "examples": [
              "09:00"
            ]
          },
          "fecha_aviso": {
            "type": [
              "string",
              "null"
            ],
            "format": "date",
            "description": "Día en que se envía; null si no se puede calcular (sin plazo o sin vencimiento visible)."
          },
          "activo": {
            "type": "boolean",
            "description": "`false` si está en pausa."
          },
          "enviado": {
            "type": "boolean"
          },
          "enviado_a": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "persona",
                "enviado"
              ],
              "properties": {
                "persona": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/MiembroEquipo"
                    },
                    {
                      "type": "null"
                    }
                  ]
                },
                "enviado": {
                  "type": [
                    "string",
                    "null"
                  ],
                  "format": "date-time"
                }
              }
            }
          },
          "modificable": {
            "type": "boolean",
            "description": "Si aún se puede pausar o borrar: los ya enviados, no."
          },
          "creado_por": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/MiembroEquipo"
              },
              {
                "type": "null"
              }
            ]
          },
          "creado": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          }
        }
      },
      "ConversacionIa": {
        "type": "object",
        "description": "Conversación con la IA de Licitaciones365 sobre una licitación, sin los mensajes. Las privadas solo las ve quien las creó.",
        "required": [
          "id",
          "titulo",
          "visibilidad",
          "creada_por",
          "mensajes",
          "creada",
          "ultimo_mensaje"
        ],
        "properties": {
          "id": {
            "type": "integer"
          },
          "titulo": {
            "type": "string",
            "description": "El título puesto en la app o, si no tiene, el principio de la primera pregunta."
          },
          "visibilidad": {
            "type": "string",
            "enum": [
              "equipo",
              "privada"
            ]
          },
          "creada_por": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/MiembroEquipo"
              },
              {
                "type": "null"
              }
            ]
          },
          "mensajes": {
            "type": "integer"
          },
          "creada": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "ultimo_mensaje": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          }
        }
      },
      "EspacioLicitacion": {
        "type": "object",
        "description": "Lo que el equipo tiene sobre una licitación. Las tareas y los recordatorios solo existen en las favoritas: si no lo es, vienen a null y hay un `aviso`.",
        "required": [
          "licitacion",
          "favorita",
          "grupo",
          "nota",
          "tareas",
          "resumen_tareas",
          "recordatorios",
          "recordatorios_disponibles",
          "conversaciones_ia"
        ],
        "properties": {
          "licitacion": {
            "$ref": "#/components/schemas/LicitacionResumen"
          },
          "favorita": {
            "type": "boolean"
          },
          "grupo": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/GrupoDeFavorita"
              },
              {
                "type": "null"
              }
            ]
          },
          "nota": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/NotaLicitacion"
              },
              {
                "type": "null"
              }
            ]
          },
          "tareas": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "$ref": "#/components/schemas/Tarea"
            }
          },
          "resumen_tareas": {
            "type": [
              "object",
              "null"
            ],
            "properties": {
              "total": {
                "type": "integer"
              },
              "pendientes": {
                "type": "integer"
              },
              "en_curso": {
                "type": "integer"
              },
              "completadas": {
                "type": "integer"
              },
              "canceladas": {
                "type": "integer"
              },
              "vencidas": {
                "type": "integer"
              }
            }
          },
          "recordatorios": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "$ref": "#/components/schemas/Recordatorio"
            }
          },
          "recordatorios_disponibles": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Cuántos se pueden añadir todavía (como mucho 3 por licitación)."
          },
          "conversaciones_ia": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ConversacionIa"
            }
          },
          "miembros": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/MiembroEquipo"
            },
            "description": "Solo con los planes Pro y Enterprise: a quién se pueden asignar tareas."
          },
          "aviso": {
            "type": "string",
            "description": "Solo si la licitación no es favorita."
          }
        }
      },
      "EventoAgenda": {
        "type": "object",
        "description": "Un plazo de presentación (`plazo_presentacion`) o un vencimiento estimado de contrato (`vencimiento`, planes Pro y Enterprise) de una favorita del equipo.",
        "required": [
          "fecha",
          "tipo",
          "hora",
          "dias_restantes",
          "grupo",
          "licitacion"
        ],
        "properties": {
          "fecha": {
            "type": "string",
            "format": "date"
          },
          "tipo": {
            "type": "string",
            "enum": [
              "plazo_presentacion",
              "vencimiento"
            ]
          },
          "hora": {
            "type": [
              "string",
              "null"
            ],
            "description": "Hora límite de presentación (HH:MM, hora de Madrid); null si no consta o en los vencimientos."
          },
          "plazo_de": {
            "type": "string",
            "enum": [
              "ofertas",
              "solicitudes"
            ],
            "description": "Solo en los plazos: de ofertas o de solicitudes de participación."
          },
          "dias_restantes": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Días desde hoy; negativo si ya pasó."
          },
          "confianza": {
            "type": "string",
            "enum": [
              "alta",
              "media"
            ],
            "description": "Solo en los vencimientos."
          },
          "prorroga_posible": {
            "type": "boolean",
            "description": "Solo en los vencimientos."
          },
          "fecha_fin_maxima": {
            "type": [
              "string",
              "null"
            ],
            "format": "date",
            "description": "Solo en los vencimientos: fin con todas las prórrogas permitidas."
          },
          "grupo": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/GrupoDeFavorita"
              },
              {
                "type": "null"
              }
            ]
          },
          "licitacion": {
            "$ref": "#/components/schemas/LicitacionResumen"
          }
        }
      },
      "TareasDeLicitacion": {
        "type": "object",
        "description": "Las tareas de una licitación asignadas al usuario de la API key.",
        "required": [
          "licitacion",
          "tareas"
        ],
        "properties": {
          "licitacion": {
            "$ref": "#/components/schemas/LicitacionResumen"
          },
          "tareas": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Tarea"
            }
          }
        }
      },
      "CriteriosAlerta": {
        "type": "object",
        "description": "Los criterios de una alerta, legibles.",
        "properties": {
          "tipo": {
            "type": "object",
            "properties": {
              "codigo": {
                "type": "string",
                "enum": [
                  "nuevas",
                  "adjudicaciones",
                  "personalizado",
                  "sin_tipo"
                ]
              },
              "nombre": {
                "type": "string"
              }
            }
          },
          "estados": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Estados que vigila (`PUB,PRE` en las nuevas, `ADJ,RES` en las de adjudicaciones)."
          },
          "ambito": {
            "type": "object",
            "properties": {
              "codigo": {
                "type": "string",
                "enum": [
                  "licitaciones",
                  "menores",
                  "ambos"
                ]
              },
              "nombre": {
                "type": "string"
              }
            }
          },
          "palabras_clave": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "modo_palabras": {
            "type": "string",
            "enum": [
              "cualquiera",
              "todas"
            ]
          },
          "cpv": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CodigoNombre"
            }
          },
          "provincias": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CodigoNombre"
            }
          },
          "organos": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "nombre": {
                  "type": [
                    "string",
                    "null"
                  ]
                }
              }
            }
          },
          "importe_min": {
            "type": [
              "number",
              "null"
            ]
          },
          "importe_max": {
            "type": [
              "number",
              "null"
            ]
          }
        }
      },
      "Alerta": {
        "type": "object",
        "description": "Una alerta del equipo.",
        "required": [
          "id",
          "nombre",
          "estado",
          "activa",
          "avisos_por_email",
          "criterios",
          "criterios_texto"
        ],
        "properties": {
          "id": {
            "type": "integer"
          },
          "nombre": {
            "type": "string"
          },
          "descripcion": {
            "type": [
              "string",
              "null"
            ]
          },
          "estado": {
            "type": "string",
            "enum": [
              "activa",
              "pausada",
              "borrada"
            ]
          },
          "activa": {
            "type": "boolean",
            "description": "Si entra en el correo de resumen."
          },
          "avisos_por_email": {
            "type": "boolean",
            "description": "false: se ejecuta, pero no envía nada."
          },
          "criterios": {
            "$ref": "#/components/schemas/CriteriosAlerta"
          },
          "criterios_texto": {
            "type": "string",
            "description": "Los criterios en una línea."
          },
          "orden": {
            "type": "integer"
          },
          "busqueda_guardada_id": {
            "type": [
              "integer",
              "null"
            ],
            "description": "La búsqueda guardada de la que se creó, si es el caso."
          },
          "creada": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "creada_por": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/MiembroEquipo"
              },
              {
                "type": "null"
              }
            ],
            "description": "null si ya no está en el equipo."
          },
          "actualizada": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "actualizada_por": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/MiembroEquipo"
              },
              {
                "type": "null"
              }
            ]
          },
          "ultimo_envio": {
            "oneOf": [
              {
                "type": "object",
                "properties": {
                  "fecha": {
                    "type": "string",
                    "format": "date"
                  },
                  "licitaciones": {
                    "type": "integer"
                  },
                  "enviado": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "format": "date-time"
                  }
                }
              },
              {
                "type": "null"
              }
            ],
            "description": "El último día que envió licitaciones."
          },
          "ultima_ejecucion": {
            "oneOf": [
              {
                "type": "object",
                "properties": {
                  "fecha": {
                    "type": "string",
                    "format": "date"
                  },
                  "resultado": {
                    "type": "string",
                    "enum": [
                      "enviada",
                      "sin_novedades",
                      "fallida",
                      "pausada",
                      "en_curso"
                    ]
                  },
                  "licitaciones": {
                    "type": "integer"
                  }
                }
              },
              {
                "type": "null"
              }
            ]
          },
          "destinatarios": {
            "type": "object",
            "description": "Solo con Pro y Enterprise: miembros que reciben esta alerta en lugar de los destinatarios del resumen (`personalizados: false` = los del resumen).",
            "properties": {
              "personalizados": {
                "type": "boolean"
              },
              "usuarios": {
                "type": "array",
                "items": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/MiembroEquipo"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "recibe": {
                          "type": "boolean"
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "borrada": {
            "type": "string",
            "format": "date-time",
            "description": "Solo en las borradas."
          }
        }
      },
      "LimiteAlertas": {
        "type": "object",
        "description": "Límite de alertas del plan (las borradas y las bloqueadas por el plan no cuentan; las pausadas, sí).",
        "required": [
          "usadas",
          "maximo",
          "puede_crear"
        ],
        "properties": {
          "usadas": {
            "type": "integer"
          },
          "maximo": {
            "type": [
              "integer",
              "null"
            ],
            "description": "null si el plan no tiene límite."
          },
          "puede_crear": {
            "type": "boolean",
            "description": "Si quien usa la clave puede crear otra (es el propietario y queda hueco)."
          },
          "motivo": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "EntradaAlerta": {
        "type": "object",
        "description": "Datos de una alerta. Al crear, `nombre` es obligatorio y hace falta al menos uno de `palabras_clave`, `cpv`, `provincias` o `comunidades`, u `organos`. Al modificar solo cambia lo que se envía, y un criterio vacío (`[]` o `null`) se quita.",
        "properties": {
          "nombre": {
            "type": "string",
            "maxLength": 255
          },
          "descripcion": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 255
          },
          "palabras_clave": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "type": "string",
              "minLength": 3,
              "maxLength": 40
            },
            "maxItems": 40,
            "description": "Palabras sueltas (solo letras y números), cada una un prefijo sin tildes. Se buscan en el título, el objeto de los lotes y la descripción de los CPV. No se traducen: `limpieza` y `neteja` son palabras distintas."
          },
          "modo_palabras": {
            "type": "string",
            "enum": [
              "cualquiera",
              "todas"
            ],
            "description": "`cualquiera` (por defecto): basta una palabra. `todas`: deben aparecer todas."
          },
          "tipo": {
            "type": "string",
            "enum": [
              "nuevas",
              "adjudicaciones"
            ],
            "description": "`nuevas` (por defecto): en plazo y anuncios previos. `adjudicaciones`: adjudicadas y resueltas."
          },
          "ambito": {
            "type": "string",
            "enum": [
              "licitaciones",
              "menores",
              "ambos"
            ],
            "description": "`licitaciones` (por defecto), `menores` (contratos menores en fase de ofertas) o `ambos`. Los menores, solo con `tipo: nuevas`."
          },
          "cpv": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "type": "string",
              "pattern": "^\\d{8}(-\\d)?$"
            },
            "maxItems": 50,
            "description": "Códigos CPV de 8 dígitos; uno acabado en ceros incluye sus subcódigos (ver `GET /catalogos/cpv`)."
          },
          "provincias": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "type": "string"
            },
            "description": "Provincias por código NUTS3, p. ej. `ES523` (ver `GET /catalogos/provincias`)."
          },
          "comunidades": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "type": "string"
            },
            "description": "Comunidades por código NUTS2, p. ej. `ES51`. Se guardan como sus provincias (como el selector de la app) y traen también lo asignado a la comunidad entera. Al modificar, `provincias` y `comunidades` se sustituyen juntas."
          },
          "organos": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "type": "string"
            },
            "maxItems": 20,
            "description": "Órganos de contratación por su id de plataforma (el campo `organo.id` de las licitaciones)."
          },
          "importe_min": {
            "type": [
              "number",
              "null"
            ],
            "minimum": 0,
            "description": "Importe mínimo sin IVA, en euros."
          },
          "importe_max": {
            "type": [
              "number",
              "null"
            ],
            "minimum": 0,
            "description": "Importe máximo sin IVA, en euros."
          },
          "activa": {
            "type": "boolean",
            "description": "false = en pausa (sigue contando en el límite del plan)."
          },
          "avisos_por_email": {
            "type": "boolean"
          },
          "destinatarios": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "type": "string"
            },
            "description": "Solo Pro y Enterprise: miembros (email o id) que reciben esta alerta en lugar de los del resumen; `[]` vuelve a los del resumen y `null` no cambia nada."
          }
        }
      },
      "AjustesResumen": {
        "type": "object",
        "description": "Ajustes del correo de resumen. Sin Pro ni Enterprise solo vienen `configurable: false`, `motivo`, `activo` y `avisos_de_favoritas`.",
        "required": [
          "configurable"
        ],
        "properties": {
          "configurable": {
            "type": "boolean"
          },
          "motivo": {
            "type": "string"
          },
          "activo": {
            "type": "boolean",
            "description": "Resumen de alertas activado."
          },
          "hora": {
            "type": "string",
            "pattern": "^\\d{2}:\\d{2}$",
            "description": "Entre 08:00 y 22:00."
          },
          "dias": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "lunes",
                "martes",
                "miércoles",
                "jueves",
                "viernes",
                "sábado",
                "domingo"
              ]
            }
          },
          "zona_horaria": {
            "type": "string",
            "description": "Identificador IANA."
          },
          "enviar_si_no_hay_novedades": {
            "type": "boolean",
            "description": "Valor efectivo según el plan."
          },
          "tipo_resumen": {
            "type": "string",
            "enum": [
              "ninguno",
              "basico",
              "ia"
            ]
          },
          "licitaciones_por_alerta": {
            "type": "integer",
            "enum": [
              3,
              10,
              25,
              50
            ]
          },
          "un_correo_por_alerta": {
            "type": "boolean"
          },
          "avisos_de_favoritas": {
            "type": "boolean"
          },
          "destinatarios": {
            "type": "array",
            "items": {
              "allOf": [
                {
                  "$ref": "#/components/schemas/MiembroEquipo"
                },
                {
                  "type": "object",
                  "properties": {
                    "recibe": {
                      "type": "boolean"
                    }
                  }
                }
              ]
            }
          }
        }
      },
      "BusquedaGuardada": {
        "type": "object",
        "required": [
          "id",
          "nombre"
        ],
        "properties": {
          "id": {
            "type": "integer"
          },
          "nombre": {
            "type": "string"
          },
          "descripcion": {
            "type": [
              "string",
              "null"
            ]
          },
          "filtros": {
            "type": [
              "object",
              "null"
            ],
            "description": "Los filtros del buscador guardados (texto, estados, categorias, provincias, cpv, tipos_contrato…)."
          },
          "alerta_id": {
            "type": [
              "integer",
              "null"
            ],
            "description": "La alerta que ya se creó desde ella, si la hay."
          }
        }
      },
      "TotalTerritorial": {
        "type": "object",
        "description": "Total de un territorio (código NUTS, nombre, número e importe sin IVA).",
        "required": [
          "codigo",
          "nombre",
          "importe"
        ],
        "properties": {
          "codigo": {
            "type": "string",
            "examples": [
              "ES52"
            ]
          },
          "nombre": {
            "type": [
              "string",
              "null"
            ]
          },
          "vencimientos": {
            "type": "integer",
            "description": "En los vencimientos."
          },
          "licitaciones": {
            "type": "integer",
            "description": "En las estadísticas de mercado."
          },
          "importe": {
            "type": "number"
          }
        }
      },
      "ContratoQueVence": {
        "type": "object",
        "description": "Un contrato adjudicado y su vencimiento estimado por Licitaciones365 (no es un dato oficial).",
        "required": [
          "licitacion_id",
          "fecha_vencimiento",
          "dias_restantes",
          "confianza",
          "prorroga",
          "adjudicatarios",
          "adjudicatarios_no_mostrados",
          "licitacion"
        ],
        "properties": {
          "licitacion_id": {
            "type": "integer"
          },
          "fecha_vencimiento": {
            "type": "string",
            "format": "date"
          },
          "dias_restantes": {
            "type": "integer",
            "description": "Días desde hoy; negativo si ya ha vencido."
          },
          "confianza": {
            "type": "string",
            "enum": [
              "alta",
              "media",
              "baja"
            ]
          },
          "origen_fecha": {
            "type": [
              "object",
              "null"
            ],
            "description": "Cómo se ha estimado la fecha.",
            "properties": {
              "codigo": {
                "type": "string",
                "examples": [
                  "fin_explicito"
                ]
              },
              "descripcion": {
                "type": "string"
              },
              "leida_con_ia": {
                "type": "boolean",
                "description": "Si algún dato se leyó con IA de los documentos del expediente."
              }
            }
          },
          "prorroga": {
            "type": "object",
            "properties": {
              "aplicada": {
                "type": "boolean",
                "description": "La fecha ya incluye una prórroga o modificación."
              },
              "prevista": {
                "type": "string",
                "enum": [
                  "si",
                  "no",
                  "sin_confirmar"
                ],
                "description": "Si el contrato contempla prórrogas."
              },
              "prorrogable_hasta": {
                "type": [
                  "string",
                  "null"
                ],
                "format": "date",
                "description": "Fin con todas las prórrogas permitidas."
              },
              "permitida_dias": {
                "type": [
                  "integer",
                  "null"
                ]
              },
              "fin_sin_prorrogas": {
                "type": [
                  "string",
                  "null"
                ],
                "format": "date"
              }
            }
          },
          "objeto": {
            "type": [
              "string",
              "null"
            ],
            "description": "Objeto del contrato, recortado a 300 caracteres (completo en GET /licitaciones/{id})."
          },
          "cpv_principal": {
            "type": [
              "object",
              "null"
            ],
            "properties": {
              "codigo": {
                "type": "string"
              },
              "descripcion": {
                "type": [
                  "string",
                  "null"
                ]
              }
            }
          },
          "sector_organo": {
            "type": "object",
            "description": "Sector de actividad del órgano. `codigo` es el valor del filtro `sector` (null en «Otros»).",
            "properties": {
              "codigo": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "nombre": {
                "type": "string"
              }
            }
          },
          "adjudicatarios": {
            "type": "array",
            "description": "Empresas adjudicatarias. Las personas físicas y los dudosos salen como «Persona física», sin NIF.",
            "items": {
              "type": "object",
              "properties": {
                "nombre": {
                  "type": "string"
                },
                "nif": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "ute": {
                  "type": "boolean"
                },
                "persona_fisica_protegida": {
                  "type": "boolean"
                }
              }
            }
          },
          "adjudicatarios_no_mostrados": {
            "type": "boolean",
            "description": "Hubo adjudicatarios que no se enseñan (personas físicas, empresas extranjeras o datos dudosos)."
          },
          "lotes_con_vencimientos_distintos": {
            "type": "boolean"
          },
          "algun_lote_desierto": {
            "type": "boolean"
          },
          "licitacion": {
            "$ref": "#/components/schemas/LicitacionResumen",
            "description": "La licitación del contrato (si ya no existe, solo id, titulo, organo, lugar_ejecucion, importe_sin_iva y url_app)."
          }
        }
      },
      "ResumenVencimientos": {
        "type": "object",
        "description": "Resumen de los contratos que cumplen los filtros (como la barra de resultados del panel).",
        "properties": {
          "total": {
            "type": "integer"
          },
          "importe_total": {
            "type": [
              "number",
              "null"
            ]
          },
          "importe_medio": {
            "type": [
              "number",
              "null"
            ]
          },
          "con_importe": {
            "type": "integer"
          },
          "por_confianza": {
            "type": "object",
            "properties": {
              "alta": {
                "type": "integer"
              },
              "media": {
                "type": "integer"
              },
              "baja": {
                "type": "integer"
              }
            }
          },
          "proximos_90_dias": {
            "type": "integer"
          },
          "por_mes": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "mes": {
                  "type": "string",
                  "examples": [
                    "2027-01"
                  ]
                },
                "vencimientos": {
                  "type": "integer"
                },
                "importe": {
                  "type": "number"
                }
              }
            }
          },
          "por_comunidad": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TotalTerritorial"
            }
          },
          "por_provincia": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TotalTerritorial"
            }
          }
        }
      },
      "FacetasVencimientos": {
        "type": "object",
        "description": "Recuentos para afinar los filtros. Como en el panel, dependen solo de la ventana y la confianza (no del resto de filtros) y la de confianza no se filtra por confianza.",
        "properties": {
          "familias_cpv": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "codigo": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "nombre": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "vencimientos": {
                  "type": "integer"
                }
              }
            },
            "description": "Divisiones del CPV principal; el código vale tal cual en el filtro `cpv`."
          },
          "sectores": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "codigo": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "nombre": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "vencimientos": {
                  "type": "integer"
                }
              }
            },
            "description": "Todo el catálogo de sectores, también los que no tienen vencimientos."
          },
          "territorios": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "codigo": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "nombre": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "vencimientos": {
                  "type": "integer"
                }
              }
            }
          },
          "confianza": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "codigo": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "vencimientos": {
                  "type": "integer"
                }
              }
            }
          },
          "tipos_contrato": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "codigo": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "nombre": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "vencimientos": {
                  "type": "integer"
                }
              }
            }
          }
        }
      },
      "OrganoContratacion": {
        "type": "object",
        "description": "Un órgano de contratación del directorio.",
        "required": [
          "id",
          "nombre",
          "licitaciones",
          "contratos_menores"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Id de plataforma (el `organo.id` de las licitaciones)."
          },
          "nombre": {
            "type": [
              "string",
              "null"
            ]
          },
          "nif": {
            "type": [
              "string",
              "null"
            ]
          },
          "dir3": {
            "type": [
              "string",
              "null"
            ]
          },
          "tipo": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/CodigoNombre"
              },
              {
                "type": "null"
              }
            ],
            "description": "Tipo de órgano: 1 estatal, 2 regional, 3 local, 4 organismo de derecho público, 5 otras entidades del sector público, 6-8 organismos bajo control estatal, regional o local, 9 empresa pública estatal."
          },
          "ubicacion": {
            "type": [
              "string",
              "null"
            ]
          },
          "dependencia": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "De qué depende, del nivel más alto al más concreto."
          },
          "codigo_postal": {
            "type": [
              "string",
              "null"
            ]
          },
          "activo": {
            "type": [
              "boolean",
              "null"
            ]
          },
          "licitaciones": {
            "type": "integer"
          },
          "contratos_menores": {
            "type": "integer"
          },
          "importe_total": {
            "type": [
              "number",
              "null"
            ]
          },
          "ultima_licitacion": {
            "type": [
              "string",
              "null"
            ],
            "format": "date"
          },
          "ultimo_contrato_menor": {
            "type": [
              "string",
              "null"
            ],
            "format": "date"
          },
          "url_publica": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri",
            "description": "Su ficha pública en licitaciones365.es."
          }
        }
      },
      "FichaOrganoContratacion": {
        "description": "Ficha de un órgano con las estadísticas que se recalculan a diario (las de su página pública).",
        "allOf": [
          {
            "$ref": "#/components/schemas/OrganoContratacion"
          },
          {
            "type": "object",
            "properties": {
              "estadisticas": {
                "type": "object",
                "properties": {
                  "licitaciones": {
                    "type": "integer"
                  },
                  "contratos_menores": {
                    "type": "integer"
                  },
                  "lotes_licitaciones": {
                    "type": "integer"
                  },
                  "lotes_contratos_menores": {
                    "type": "integer"
                  },
                  "importe_licitaciones": {
                    "type": [
                      "number",
                      "null"
                    ]
                  },
                  "importe_contratos_menores": {
                    "type": [
                      "number",
                      "null"
                    ]
                  },
                  "importe_medio_licitacion": {
                    "type": [
                      "number",
                      "null"
                    ]
                  },
                  "importe_medio_contrato_menor": {
                    "type": [
                      "number",
                      "null"
                    ]
                  },
                  "primera_licitacion": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "format": "date"
                  },
                  "primer_contrato_menor": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "format": "date"
                  },
                  "calculadas": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "format": "date-time"
                  }
                }
              },
              "evolucion_anual": {
                "type": "array",
                "description": "Últimos 10 años.",
                "items": {
                  "allOf": [
                    {
                      "type": "object",
                      "properties": {
                        "anio": {
                          "type": "integer"
                        }
                      }
                    },
                    {
                      "type": "object",
                      "properties": {
                        "licitaciones": {
                          "type": "integer"
                        },
                        "contratos_menores": {
                          "type": "integer"
                        },
                        "importe": {
                          "type": "number"
                        }
                      }
                    }
                  ]
                }
              },
              "ultimos_12_meses": {
                "type": "array",
                "items": {
                  "allOf": [
                    {
                      "type": "object",
                      "properties": {
                        "mes": {
                          "type": "string"
                        }
                      }
                    },
                    {
                      "type": "object",
                      "properties": {
                        "licitaciones": {
                          "type": "integer"
                        },
                        "contratos_menores": {
                          "type": "integer"
                        },
                        "importe": {
                          "type": "number"
                        }
                      }
                    }
                  ]
                }
              },
              "territorios": {
                "type": "object",
                "properties": {
                  "comunidades": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "codigo": {
                          "type": "string"
                        },
                        "nombre": {
                          "type": [
                            "string",
                            "null"
                          ]
                        },
                        "licitaciones": {
                          "type": "integer"
                        },
                        "contratos_menores": {
                          "type": "integer"
                        },
                        "importe": {
                          "type": "number"
                        }
                      }
                    }
                  },
                  "provincias": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "codigo": {
                          "type": "string"
                        },
                        "nombre": {
                          "type": [
                            "string",
                            "null"
                          ]
                        },
                        "licitaciones": {
                          "type": "integer"
                        },
                        "contratos_menores": {
                          "type": "integer"
                        },
                        "importe": {
                          "type": "number"
                        }
                      }
                    }
                  }
                }
              },
              "cpv_principales": {
                "type": "object",
                "properties": {
                  "por_numero": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "codigo": {
                          "type": "string"
                        },
                        "descripcion": {
                          "type": [
                            "string",
                            "null"
                          ]
                        },
                        "licitaciones": {
                          "type": "integer"
                        },
                        "contratos_menores": {
                          "type": "integer"
                        },
                        "importe": {
                          "type": "number"
                        }
                      }
                    }
                  },
                  "por_importe": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "codigo": {
                          "type": "string"
                        },
                        "descripcion": {
                          "type": [
                            "string",
                            "null"
                          ]
                        },
                        "licitaciones": {
                          "type": "integer"
                        },
                        "contratos_menores": {
                          "type": "integer"
                        },
                        "importe": {
                          "type": "number"
                        }
                      }
                    }
                  }
                }
              },
              "adjudicatarios_frecuentes": {
                "type": "object",
                "description": "Las personas físicas salen como «Persona física», sin NIF.",
                "properties": {
                  "por_numero": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "nombre": {
                          "type": "string"
                        },
                        "nif": {
                          "type": [
                            "string",
                            "null"
                          ]
                        },
                        "persona_fisica_protegida": {
                          "type": "boolean"
                        },
                        "licitaciones": {
                          "type": "integer"
                        },
                        "contratos_menores": {
                          "type": "integer"
                        },
                        "importe_adjudicado": {
                          "type": "number"
                        }
                      }
                    }
                  },
                  "por_importe": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "nombre": {
                          "type": "string"
                        },
                        "nif": {
                          "type": [
                            "string",
                            "null"
                          ]
                        },
                        "persona_fisica_protegida": {
                          "type": "boolean"
                        },
                        "licitaciones": {
                          "type": "integer"
                        },
                        "contratos_menores": {
                          "type": "integer"
                        },
                        "importe_adjudicado": {
                          "type": "number"
                        }
                      }
                    }
                  }
                }
              },
              "licitaciones_en_plazo": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/LicitacionResumen"
                },
                "description": "Hasta 6, las que cierran antes primero."
              },
              "ultimas_licitaciones": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/LicitacionResumen"
                },
                "description": "Las 6 últimas publicadas."
              },
              "nota": {
                "type": "string"
              }
            }
          }
        ]
      },
      "EmpresaAdjudicataria": {
        "type": "object",
        "description": "Una empresa adjudicataria (solo empresas con CIF: nunca personas físicas).",
        "required": [
          "nombre",
          "nif"
        ],
        "properties": {
          "nombre": {
            "type": "string"
          },
          "nif": {
            "type": "string",
            "description": "CIF de la empresa."
          },
          "ute": {
            "type": "boolean",
            "description": "Es una unión temporal de empresas."
          },
          "lotes": {
            "type": "integer"
          },
          "licitaciones": {
            "type": "integer"
          },
          "contratos_menores": {
            "type": "integer"
          },
          "importe_adjudicado": {
            "type": [
              "number",
              "null"
            ]
          },
          "importe_medio_por_lote": {
            "type": [
              "number",
              "null"
            ]
          },
          "baja_media": {
            "type": [
              "number",
              "null"
            ],
            "description": "Porcentaje medio de baja (en la ficha va en `bajas`)."
          },
          "primera_adjudicacion": {
            "type": [
              "string",
              "null"
            ],
            "format": "date"
          },
          "ultima_adjudicacion": {
            "type": [
              "string",
              "null"
            ],
            "format": "date"
          }
        }
      },
      "FichaEmpresaAdjudicataria": {
        "description": "Ficha de una empresa adjudicataria.",
        "allOf": [
          {
            "$ref": "#/components/schemas/EmpresaAdjudicataria"
          },
          {
            "type": "object",
            "properties": {
              "bajas": {
                "type": "object",
                "description": "Porcentaje de baja sobre el presupuesto de cada lote, sin contratos menores ni valores fuera de 0-75 %.",
                "properties": {
                  "media": {
                    "type": [
                      "number",
                      "null"
                    ]
                  },
                  "minima": {
                    "type": [
                      "number",
                      "null"
                    ]
                  },
                  "maxima": {
                    "type": [
                      "number",
                      "null"
                    ]
                  },
                  "ultimos_12_meses": {
                    "type": [
                      "number",
                      "null"
                    ]
                  },
                  "ultimos_6_meses": {
                    "type": [
                      "number",
                      "null"
                    ]
                  },
                  "ultima": {
                    "type": [
                      "number",
                      "null"
                    ]
                  },
                  "nota": {
                    "type": "string"
                  }
                }
              },
              "organos_clientes": {
                "type": "array",
                "description": "Los 10 órganos que más contratos le han adjudicado.",
                "items": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "nombre": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "contratos": {
                      "type": "integer"
                    },
                    "importe_adjudicado": {
                      "type": "number"
                    }
                  }
                }
              },
              "cpv_principales": {
                "type": "array",
                "description": "Los 10 CPV en los que más contratos gana.",
                "items": {
                  "type": "object",
                  "properties": {
                    "codigo": {
                      "type": "string"
                    },
                    "descripcion": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "contratos": {
                      "type": "integer"
                    }
                  }
                }
              },
              "ultimas_adjudicaciones": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/LicitacionResumen"
                },
                "description": "Sus 6 adjudicaciones más recientes."
              },
              "nota": {
                "type": "string"
              }
            }
          }
        ]
      },
      "EstadisticasMercado": {
        "type": "object",
        "description": "Estadísticas de un mercado (los filtros de GET /licitaciones) en un periodo de publicación.",
        "properties": {
          "periodo": {
            "type": "object",
            "properties": {
              "desde": {
                "type": "string",
                "format": "date"
              },
              "hasta": {
                "type": "string",
                "format": "date"
              },
              "fecha": {
                "type": "string",
                "const": "publicación"
              }
            }
          },
          "filtros": {
            "$ref": "#/components/schemas/FiltrosAplicados"
          },
          "resumen": {
            "type": "object",
            "properties": {
              "licitaciones": {
                "type": "integer"
              },
              "con_importe": {
                "type": "integer"
              },
              "importe_total": {
                "type": "number"
              },
              "importe_medio": {
                "type": [
                  "number",
                  "null"
                ]
              },
              "importe_maximo": {
                "type": [
                  "number",
                  "null"
                ]
              },
              "importe_minimo": {
                "type": [
                  "number",
                  "null"
                ]
              }
            }
          },
          "por_mes": {
            "type": "array",
            "description": "Todos los meses del periodo (a cero si no hubo).",
            "items": {
              "type": "object",
              "properties": {
                "mes": {
                  "type": "string"
                },
                "licitaciones": {
                  "type": "integer"
                },
                "importe": {
                  "type": "number"
                }
              }
            }
          },
          "por_estado": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "codigo": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "nombre": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "licitaciones": {
                  "type": "integer"
                },
                "importe": {
                  "type": "number"
                }
              }
            }
          },
          "por_categoria": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "codigo": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "nombre": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "licitaciones": {
                  "type": "integer"
                },
                "importe": {
                  "type": "number"
                }
              }
            }
          },
          "por_tipo_contrato": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "codigo": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "nombre": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "licitaciones": {
                  "type": "integer"
                },
                "importe": {
                  "type": "number"
                }
              }
            }
          },
          "por_comunidad": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TotalTerritorial"
            }
          },
          "por_provincia": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TotalTerritorial"
            }
          },
          "sin_territorio": {
            "type": "integer",
            "description": "Asignadas a toda España, a varias comunidades o sin lugar de ejecución."
          },
          "cpv_principales": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "codigo": {
                  "type": "string"
                },
                "descripcion": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "licitaciones": {
                  "type": "integer"
                },
                "importe": {
                  "type": "number"
                }
              }
            }
          },
          "organos_principales": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "nombre": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "licitaciones": {
                  "type": "integer"
                },
                "importe": {
                  "type": "number"
                }
              }
            }
          },
          "adjudicatarios_principales": {
            "type": "array",
            "description": "Las 10 empresas que más licitaciones ganan (solo empresas con CIF).",
            "items": {
              "type": "object",
              "properties": {
                "nombre": {
                  "type": "string"
                },
                "nif": {
                  "type": "string"
                },
                "licitaciones": {
                  "type": "integer"
                },
                "importe_adjudicado": {
                  "type": "number"
                }
              }
            }
          },
          "adjudicatarios_distintos": {
            "type": "integer",
            "description": "Adjudicatarios distintos, personas físicas incluidas (que no salen en el ranking)."
          },
          "competencia": {
            "type": "object",
            "properties": {
              "ofertas_por_lote": {
                "type": [
                  "number",
                  "null"
                ]
              },
              "lotes_con_dato": {
                "type": "integer"
              }
            }
          },
          "bajas": {
            "type": "object",
            "properties": {
              "baja_media_porcentaje": {
                "type": [
                  "number",
                  "null"
                ]
              },
              "adjudicaciones_con_dato": {
                "type": "integer"
              },
              "nota": {
                "type": "string"
              }
            }
          },
          "calculado": {
            "type": "string",
            "format": "date-time"
          },
          "notas": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "fuente": {
            "type": "string"
          }
        }
      }
    }
  }
}
