openapi: 3.1.0
info:
  title: Urnario — API de resultados electorales
  version: "1.0.0"
  summary: Cómo ha votado cada municipio de España en todas las elecciones generales al Congreso desde 1977.
  description: |
    API de solo lectura, en JSON, con los resultados oficiales de las 16 elecciones generales al Congreso
    (1977–2023) de los 8.132 municipios de España, sus provincias, sus comunidades y el conjunto de España.

    **Origen de los datos: Ministerio del Interior.** El Ministerio no participa, patrocina ni apoya este proyecto.
    La unión de los municipios a lo largo del tiempo es elaboración propia con datos extraídos del sitio web
    del INE (www.ine.es). Cada respuesta lleva todo esto en `meta`, con la fecha de actualización de los datos.

    **Reglas:**
    - Los nombres de las candidaturas son los que registra Interior para cada elección, tal cual.
    - Cada candidatura tiene un identificador propio de su elección (`AAAAMM-código`, por ejemplo
      `202307-000047`). **Ningún identificador une candidaturas de elecciones distintas** y no hay bloques ni
      agrupaciones propias.
    - En municipio y provincia, cada candidatura es la de la papeleta de esa provincia. En comunidad y España se
      dan las cifras oficiales de Interior, que acumulan algunas candidaturas en su cabecera; `incluye` dice cuáles.
    - Resultados ordenados por votos. Porcentajes sobre votos válidos (a candidaturas y en blanco). Participación =
      votantes / electores.
    - El voto de los residentes en el extranjero (CERA) va aparte, por provincia, y no se reparte entre municipios.
    - Los municipios de hoy que no existían en una elección no tienen un cero: tienen `sin_dato` y una nota.

    **Uso:** libre, sin clave. Solo lectura, con CORS abierto. Licencia CC BY 4.0: cita «Origen de los datos:
    Ministerio del Interior» y el proyecto.
  license:
    name: CC BY 4.0
    url: https://creativecommons.org/licenses/by/4.0/deed.es
servers:
  - url: /
    description: La misma dirección de la web, https://urnario.nuvolastudiogroup.com
paths:
  /v1/elecciones:
    get:
      summary: Lista de elecciones
      description: Las 16 elecciones generales al Congreso, de 1977 a 2023.
      responses:
        "200":
          description: Elecciones
          content:
            application/json:
              schema:
                type: object
                properties:
                  meta: { $ref: "#/components/schemas/Meta" }
                  elecciones:
                    type: array
                    items: { $ref: "#/components/schemas/Eleccion" }
  /v1/elecciones/{id}:
    get:
      summary: Una elección y sus candidaturas
      parameters:
        - $ref: "#/components/parameters/IdEleccion"
      responses:
        "200":
          description: Elección con todas sus candidaturas, con siglas y denominación tal como las registra Interior.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: "#/components/schemas/Eleccion"
                  - type: object
                    properties:
                      meta: { $ref: "#/components/schemas/Meta" }
                      candidaturas:
                        type: array
                        items: { $ref: "#/components/schemas/Candidatura" }
        "404": { description: No existe esa elección }
  /v1/elecciones/{id}/participacion:
    get:
      summary: Participación de todos los municipios en una elección
      description: Los 8.132 municipios en una elección, para el mapa de participación y su tabla. Los que no tienen dato propio llevan `sin_dato`.
      parameters:
        - $ref: "#/components/parameters/IdEleccion"
      responses:
        "200":
          description: Participación por municipio
          content:
            application/json:
              schema:
                type: object
                properties:
                  meta: { $ref: "#/components/schemas/Meta" }
                  eleccion: { type: string, example: "202307" }
                  municipios:
                    type: array
                    items:
                      type: object
                      properties:
                        ine: { type: string, example: "09059" }
                        participacion: { type: [number, "null"], description: "Votantes / electores, en %." }
                        electores: { type: [integer, "null"] }
                        votantes: { type: [integer, "null"] }
                        diferencia_espana:
                          type: [number, "null"]
                          description: Puntos por encima (+) o por debajo (−) de la participación de los residentes en España.
                        sin_dato: { type: boolean }
                        avisos: { type: array, items: { type: string } }
        "404": { description: No existe esa elección }
  /v1/municipios:
    get:
      summary: Índice de municipios
      description: Los 8.132 municipios vigentes, con los otros nombres con los que aparecen en las elecciones (para buscar).
      responses:
        "200":
          description: Índice
          content:
            application/json:
              schema:
                type: object
                properties:
                  meta: { $ref: "#/components/schemas/Meta" }
                  municipios:
                    type: array
                    items:
                      type: object
                      properties:
                        ine: { type: string, example: "07026" }
                        nombre: { type: string, example: Eivissa }
                        provincia: { type: string, example: "07" }
                        otros_nombres: { type: array, items: { type: string }, example: [IBIZA] }
                        participacion_media: { type: [number, "null"], description: Media de las elecciones con dato propio. }
  /v1/municipios/{ine}:
    get:
      summary: Serie completa de un municipio
      description: Las 16 elecciones de un municipio de hoy, con participación, contexto, notas, avisos de la fuente y resultados.
      parameters:
        - $ref: "#/components/parameters/Ine"
      responses:
        "200":
          description: Municipio
          content:
            application/json:
              schema:
                allOf:
                  - $ref: "#/components/schemas/CabeceraMunicipio"
                  - type: object
                    properties:
                      elecciones:
                        type: array
                        items: { $ref: "#/components/schemas/MunicipioEnEleccion" }
        "404": { description: No existe ese municipio }
  /v1/elecciones/{id}/secciones/{provincia}:
    get:
      summary: Todas las secciones censales de una provincia en una elección (formato compacto)
      description: |
        Las secciones censales de una provincia, desde 1982. Para no ocupar de más, va en **formato compacto**: cada
        sección es una lista de valores en el orden de `campos`, y el último, `votos`, es una lista de pares
        [código de candidatura sin la elección, votos], ordenados por votos. El identificador completo de una
        candidatura es `{eleccion}-{código}` y su nombre está en `/v1/elecciones/{id}`. Los porcentajes se calculan
        sobre los votos válidos (candidaturas más blancos), como hace Interior.
      parameters:
        - $ref: "#/components/parameters/IdEleccion"
        - name: provincia
          in: path
          required: true
          schema: { type: string, pattern: "^[0-9]{2}$", example: "09" }
      responses:
        "200":
          description: Secciones de la provincia
          content:
            application/json:
              schema:
                type: object
                properties:
                  meta: { $ref: "#/components/schemas/Meta" }
                  eleccion: { type: string }
                  provincia: { type: string }
                  nota: { type: string }
                  formato: { type: string, enum: [compacto] }
                  campos:
                    type: array
                    items: { type: string }
                    example: [ine, mesas, electores, votantes, votos_blanco, votos_nulos, seccion_no_estandar, renta_anio,
                              renta_neta_media_persona, renta_neta_media_hogar, renta_mediana_unidad_consumo, votos]
                  secciones:
                    type: object
                    description: Código de sección → lista de valores en el orden de `campos`.
                    additionalProperties: { type: array }
        "404": { description: No hay datos por sección de esa elección y provincia }
  /v1/curiosidades:
    get:
      summary: Curiosidades oficiales y neutras
      description: |
        Hechos de los datos oficiales, con su criterio en `criterios`: municipios con una sola mesa (recuento por
        elección), récords de participación de cada elección, mayor participación media desde 1977 y mesas más
        pequeñas. **Solo máximos**, sin listas de «los que menos votan». Se excluyen los pares con avisos de
        calidad de la fuente y, en los récords, los municipios con menos de 100 electores.
      responses:
        "200":
          description: Curiosidades
          content:
            application/json:
              schema:
                type: object
                properties:
                  meta: { $ref: "#/components/schemas/Meta" }
                  criterios: { type: object, additionalProperties: { type: string } }
                  municipios_con_una_sola_mesa:
                    type: array
                    items: { type: object, properties: { eleccion: { type: string }, municipios: { type: integer }, de: { type: integer } } }
                  records_participacion: { type: array, items: { type: object } }
                  mayor_participacion_media: { type: array, items: { type: object } }
                  mesas_mas_pequenas: { type: array, items: { type: object } }
  /v1/mapa/municipios:
    get:
      summary: Geometría del mapa de municipios
      description: |
        Los 8.132 municipios como trazados SVG ya proyectados y simplificados (límites del IGN, CC BY 4.0;
        atribución en `meta.limites`), en orden de código INE, con los territorios compartidos aparte y el
        recuadro de Canarias. Método en calculo/README.md (`generar_mapa.py`).
      responses:
        "200":
          description: Geometría
          content:
            application/json:
              schema:
                type: object
                properties:
                  meta: { $ref: "#/components/schemas/Meta" }
                  viewBox: { type: array, items: { type: number }, example: [0, 0, 1000, 1055] }
                  proyeccion: { type: string }
                  municipios:
                    type: array
                    description: "Pares [código INE, trazado SVG (atributo d)]."
                    items: { type: array, items: { type: string } }
                  compartidos: { type: array, items: { type: string }, description: "Trazados de los territorios compartidos, sin municipio propio." }
                  recuadro_canarias: { type: array, items: { type: number }, description: "[x, y, ancho, alto]" }
  /v1/mapa/participacion:
    get:
      summary: Tramos de participación de cada municipio en cada elección
      description: |
        Una cadena por elección, con una cifra por municipio en el orden de /v1/mapa/municipios: de «0» (menos
        del 65 %) a «4» (80 % o más); «-» si no tiene dato propio. Además, el recuento por tramo de cada elección.
      responses:
        "200":
          description: Tramos
          content:
            application/json:
              schema:
                type: object
                properties:
                  meta: { $ref: "#/components/schemas/Meta" }
                  tramos:
                    type: object
                    properties:
                      cortes: { type: array, items: { type: number }, example: [65, 70, 75, 80] }
                      etiquetas: { type: array, items: { type: string } }
                      nota: { type: string }
                  orden: { type: string }
                  elecciones: { type: array, items: { type: string } }
                  tramo: { type: array, items: { type: string } }
                  resumen:
                    type: array
                    items:
                      type: object
                      properties:
                        eleccion: { type: string }
                        por_tramo: { type: array, items: { type: integer } }
                        sin_dato: { type: integer }
  /v1/candidaturas/{eleccion}:
    get:
      summary: Candidaturas proclamadas al Congreso y al Senado (BOE)
      description: |
        Las candidaturas proclamadas por las Juntas Electorales Provinciales, tal como las publica el BOE y con sus
        correcciones de errores aplicadas (calculo/candidaturas_boe.py): por provincia, el número, la denominación y
        las siglas de cada candidatura, si fue proclamada y sus titulares y suplentes en orden (en el Senado, cada
        candidato con sus suplentes, y la isla en Baleares y Canarias). Solo el nombre de cada persona, como en el
        BOE. Solo se publica la elección en curso (202611, desde que lo publique el BOE, hacia el 3/11/2026).
      parameters:
        - { name: eleccion, in: path, required: true, schema: { type: string, example: "202611" } }
      responses:
        "200":
          description: Candidaturas proclamadas
          content:
            application/json:
              schema:
                type: object
                properties:
                  meta:
                    type: object
                    properties:
                      fuente: { type: string, example: "Fuente de los datos: Agencia Estatal Boletín Oficial del Estado (https://www.boe.es)" }
                      eleccion: { type: string }
                      documento: { type: object, description: "Identificador, título, número y fecha del BOE, fecha de actualización y enlace." }
                      correcciones_aplicadas: { type: array, items: { type: object } }
                      avisos: { type: array, items: { type: string }, description: "Correcciones aplicadas con una tolerancia, para revisarlas a mano." }
                      nota: { type: string }
                  resumen: { type: object }
                  provincias:
                    type: array
                    items:
                      type: object
                      properties:
                        provincia: { type: string, example: "49" }
                        junta: { type: string, example: "ZAMORA" }
                        congreso: { type: array, items: { type: object } }
                        senado: { type: array, items: { type: object } }
        "404":
          description: Aún no publicadas
  /v1/provincias:
    get:
      summary: Lista de provincias
      responses:
        "200":
          description: Las 52 provincias, con su código, su nombre y su comunidad.
          content:
            application/json:
              schema:
                type: object
                properties:
                  meta: { $ref: "#/components/schemas/Meta" }
                  provincias:
                    type: array
                    items: { type: object, properties: { codigo: { type: string }, nombre: { type: string }, comunidad: { type: string } } }
  /v1/comunidades:
    get:
      summary: Lista de comunidades y ciudades autónomas
      responses:
        "200":
          description: Las 19, con su código y su nombre.
          content:
            application/json:
              schema:
                type: object
                properties:
                  meta: { $ref: "#/components/schemas/Meta" }
                  comunidades:
                    type: array
                    items: { type: object, properties: { codigo: { type: string }, nombre: { type: string } } }
  /v1/provincias/{codigo}:
    get:
      summary: Serie completa de una provincia (cifras oficiales, con escaños y voto CERA)
      parameters:
        - name: codigo
          in: path
          required: true
          description: Código INE de la provincia (2 cifras).
          schema: { type: string, pattern: "^[0-9]{2}$", example: "09" }
      responses:
        "200":
          description: Provincia
          content:
            application/json:
              schema: { $ref: "#/components/schemas/Ambito" }
        "404": { description: No existe esa provincia }
  /v1/comunidades/{codigo}:
    get:
      summary: Serie completa de una comunidad (cifras oficiales)
      parameters:
        - name: codigo
          in: path
          required: true
          description: Código de comunidad de Interior (2 cifras; 01 Andalucía … 19 Melilla).
          schema: { type: string, pattern: "^[0-9]{2}$", example: "08" }
      responses:
        "200":
          description: Comunidad
          content:
            application/json:
              schema: { $ref: "#/components/schemas/Ambito" }
        "404": { description: No existe esa comunidad }
  /v1/espana:
    get:
      summary: Serie completa de España (cifras oficiales)
      responses:
        "200":
          description: España
          content:
            application/json:
              schema: { $ref: "#/components/schemas/Ambito" }
components:
  parameters:
    Ine:
      name: ine
      in: path
      required: true
      description: Código INE del municipio (5 cifras, provincia + municipio).
      schema: { type: string, pattern: "^[0-9]{5}$", example: "09059" }
    IdEleccion:
      name: id
      in: path
      required: true
      description: Elección, como año y mes (AAAAMM).
      schema:
        type: string
        enum: ["197706", "197903", "198210", "198606", "198910", "199306", "199603", "200003", "200403",
               "200803", "201111", "201512", "201606", "201904", "201911", "202307"]
  schemas:
    Meta:
      type: object
      description: Atribución obligatoria. Viaja con cada respuesta.
      properties:
        fuente: { type: string, example: "Origen de los datos: Ministerio del Interior" }
        fecha_actualizacion_fuente:
          type: object
          description: Fecha de actualización de los datos de Interior de cada elección incluida (AAAAMM → fecha).
          additionalProperties: { type: string, format: date }
          example: { "202307": "2023-12-27" }
        aviso: { type: string, example: "El Ministerio del Interior no participa, patrocina ni apoya este proyecto." }
        union_de_municipios: { type: string, example: "Elaboración propia con datos extraídos del sitio web del INE: www.ine.es" }
        licencia: { type: string }
        cita: { type: string }
        generado: { type: string, format: date }
        documentacion: { type: string, example: /v1/openapi.yaml }
    Eleccion:
      type: object
      properties:
        id: { type: string, example: "202307" }
        fecha: { type: string, format: date, example: "2023-07-23" }
        datos_municipales_oficiales:
          type: boolean
          description: Falso hasta 1996, cuando Interior publica los datos municipales como «no oficiales».
    Candidatura:
      type: object
      properties:
        id: { type: string, example: "202307-000047" }
        siglas: { type: string, example: PSC }
        denominacion: { type: string, example: "PARTIT DELS SOCIALISTES DE CATALUNYA (PSC-PSOE)" }
        cabecera_autonomica: { type: string, description: Candidatura en la que Interior la acumula en la comunidad. }
        cabecera_nacional: { type: string, description: Candidatura en la que Interior la acumula en España. }
    Resultado:
      type: object
      properties:
        candidatura: { type: string, example: "202307-000047" }
        siglas: { type: string, example: PSC }
        votos: { type: integer }
        porcentaje: { type: number, description: Sobre votos válidos. }
        escanos: { type: integer, description: Solo en provincia, comunidad y España. }
        incluye:
          type: array
          items: { type: string }
          description: Solo en comunidad y España, si Interior acumula varias candidaturas en esta.
    DatosGenerales:
      type: object
      properties:
        electores: { type: integer, description: Censo de escrutinio. }
        mesas: { type: integer }
        votantes: { type: integer, description: Votos a candidaturas + en blanco + nulos. }
        participacion: { type: number, description: "Votantes / electores, en %." }
        votos_candidaturas: { type: integer }
        votos_blanco: { type: integer }
        votos_nulos: { type: integer }
        votos_validos: { type: integer }
    CabeceraMunicipio:
      type: object
      properties:
        meta: { $ref: "#/components/schemas/Meta" }
        ine: { type: string, example: "09059" }
        nombre: { type: string, example: Burgos }
        provincia: { type: object, properties: { codigo: { type: string }, nombre: { type: string } } }
        comunidad: { type: object, properties: { codigo: { type: string }, nombre: { type: string } } }
    MunicipioEnEleccion:
      allOf:
        - $ref: "#/components/schemas/DatosGenerales"
        - type: object
          properties:
            eleccion: { type: string, example: "202307" }
            sin_dato:
              type: boolean
              description: Verdadero si el municipio no tiene dato propio en esa elección (no existía, o la fuente no lo trae). Va con `notas`.
            codigos_electorales:
              type: array
              items: { type: string }
              description: Códigos de municipio de esa elección de los que sale el dato (varios si hoy forman un solo municipio).
            componentes:
              type: array
              description: |
                Solo si el dato es la suma de varios municipios de entonces (fusiones): cada uno por separado, con su
                nombre de entonces, electores, votantes y participación.
              items:
                type: object
                properties:
                  codigo: { type: string, example: "15026" }
                  nombre: { type: string, example: Cesuras }
                  electores: { type: integer }
                  votantes: { type: integer }
                  participacion: { type: number }
            notas:
              type: object
              properties:
                municipios:
                  type: array
                  description: Municipios de hoy relacionados con la nota (en el que votaba, o cuyo territorio incluía), para enlazar sus fichas.
                  items: { type: object, properties: { ine: { type: string }, nombre: { type: string } } }
                tipos:
                  type: array
                  items:
                    type: string
                    enum: [suma_de_municipios_historicos, votaba_como_parte_de, incluia_territorio_de,
                           sin_dato_en_la_fuente, otra_circunscripcion]
                texto: { type: string }
            diferencia_participacion:
              type: object
              description: |
                Puntos por encima (+) o por debajo (−) de la participación de los residentes (sin CERA) de su
                provincia, su comunidad y España. Se compara con residentes porque un municipio no tiene voto CERA.
              properties:
                provincia: { type: [number, "null"] }
                comunidad: { type: [number, "null"] }
                espana: { type: [number, "null"] }
            avisos:
              type: array
              description: Avisos de calidad de la fuente (no se corrige el dato).
              items: { type: string, enum: [participacion_mayor_100, participacion_menor_25, sin_votos] }
            resultados:
              type: array
              items: { $ref: "#/components/schemas/Resultado" }
    Seccion:
      type: object
      properties:
        seccion: { type: string, example: "0905901001" }
        ine: { type: [string, "null"], description: Municipio vigente al que pertenece hoy el municipio de la sección. }
        mesas: { type: integer }
        electores: { type: integer }
        votantes: { type: integer }
        participacion: { type: number }
        votos_blanco: { type: integer }
        votos_nulos: { type: integer }
        votos_validos: { type: integer }
        seccion_no_estandar: { type: boolean, description: El código de sección de la fuente no tiene el formato habitual; no se une a la renta. }
        renta:
          type: [object, "null"]
          description: Atlas de Distribución de Renta de los Hogares (INE), del año de la elección. Euros. Null si no hay o no casa.
          properties:
            anio: { type: integer }
            renta_neta_media_persona: { type: [number, "null"] }
            renta_neta_media_hogar: { type: [number, "null"] }
            renta_mediana_unidad_consumo: { type: [number, "null"] }
        resultados:
          type: array
          items:
            type: object
            properties:
              candidatura: { type: string }
              siglas: { type: string }
              votos: { type: integer }
              porcentaje: { type: number, description: Sobre votos válidos. }
    Ambito:
      type: object
      properties:
        meta: { $ref: "#/components/schemas/Meta" }
        tipo: { type: string, enum: [provincia, comunidad, espana] }
        codigo: { type: string }
        nombre: { type: string }
        nota_resultados: { type: string }
        nota_residentes: { type: string }
        municipios:
          type: array
          description: Solo en provincias. Sus municipios de hoy, con su participación media en las elecciones con dato propio.
          items:
            type: object
            properties:
              ine: { type: string }
              nombre: { type: string }
              participacion_media: { type: [number, "null"] }
              elecciones_con_dato: { type: integer }
        elecciones:
          type: array
          items:
            allOf:
              - $ref: "#/components/schemas/DatosGenerales"
              - type: object
                properties:
                  eleccion: { type: string }
                  escanos: { type: integer, description: Escaños repartidos en el ámbito. }
                  residentes:
                    type: object
                    description: |
                      Electores, votantes y participación de los residentes en España (sin CERA). Es la referencia
                      para comparar municipios. Hasta 1982 Interior no separa el CERA (`cera_separado`: false).
                    properties:
                      electores: { type: integer }
                      votantes: { type: integer }
                      participacion: { type: number }
                      cera_separado: { type: boolean }
                  numero_candidaturas:
                    type: integer
                    description: Solo en provincias. Candidaturas con votos en la papeleta de la provincia.
                  municipios:
                    type: array
                    description: Solo en provincias. Sus municipios con dato propio en esa elección (los nombres, en `municipios` de la raíz).
                    items: { type: object, properties: { ine: { type: string }, electores: { type: integer }, participacion: { type: number } } }
                  provincias:
                    type: array
                    description: Solo en comunidades. Sus provincias en esa elección.
                    items:
                      type: object
                      properties:
                        codigo: { type: string }
                        nombre: { type: string }
                        municipios: { type: integer, description: Municipios de hoy. }
                        participacion: { type: number, description: Oficial. }
                        escanos: { type: integer }
                  resultados:
                    type: array
                    items: { $ref: "#/components/schemas/Resultado" }
                  cera:
                    type: object
                    description: Solo en provincias, desde 1986. Voto de los residentes en el extranjero, incluido en las cifras de la provincia.
