Regional Gobierno Vasco

País Vasco — Contratación pública

API REST de KontratazioA, la plataforma de contratación pública de Euskadi, con los contratos del Registro de Contratos (REVASCON). Unos 720.000 contratos, el 90 % menores. Acceso libre, sin clave, 50 resultados por página.

Ficha técnica

Formato
API REST (JSON)
Registros
~720.000
Cobertura
Desde 2014 (el grueso, desde 2018)
Actualización
Diaria
Licencia
Aviso legal de Open Data Euskadi
Entidad
Gobierno Vasco

Descripción

Open Data Euskadi ofrece una API REST sobre KontratazioA, la plataforma de contratación pública de Euskadi. Recoge el perfil de contratante y la parte pública del Registro de Contratos del Sector Público de Euskadi (REVASCON). No pide registro ni clave, la documentación está en formato OpenAPI y, según esa documentación, los datos se actualizan a diario.

La API tiene cuatro bloques: contratos (/procurements/contracts), anuncios de licitación (/procurements/contracting-notices, con datos desde 2015), poderes adjudicadores (/procurements/contracting-authorities) y empresas del Registro de Licitadores (/procurements/companies). Esta ficha se centra en contratos. La antigua dirección, opendata.euskadi.eus/webopd00-apicontract/api/contracts, ya no responde.

En octubre de 2026 había 720.072 contratos, de los que 647.537 eran menores. Por fecha de formalización hay unos mil en 2014, entre 5.000 y 11.000 al año de 2015 a 2017 y entre 74.000 y 102.000 al año de 2019 a 2025. Algunas fechas son claramente erróneas (años 0001 o 2031), así que conviene filtrar por rango.

La paginación usa currentPage e itemsOfPage, con un máximo de 50 resultados por página: descargar todo exige unas 14.400 peticiones, por lo que es mejor filtrar. Los filtros principales son award-date.gt y award-date.lt (fecha de formalización, ambos excluyentes), minor-contract, contract-type-id, contract-procedure-type-id, contracting-authority-id y contract-budget.gt/.lt. Cada respuesta trae totalItems, totalPages y un enlace _links.next. También hay rutas para consultar los contratos de una empresa por su NIF (/procurements/contracts/companies/{nif}) o de un poder adjudicador. Con lang=BASQUE las descripciones salen en euskera.

La API no indica licencia propia. El aviso legal de Open Data Euskadi remite a la licencia de cada conjunto, que puede ser CC BY 4.0 o una licencia libre de reutilización.

Estructura de datos

  • id — Identificador del contrato
  • object — Objeto del contrato
  • contractType — Tipo de contrato (id y nombre: Obras, Servicios, Suministros…)
  • contractProcedureType — Procedimiento (Abierto, Directo/Contrato Menor…)
  • contractProcedureStatus — Estado del expediente
  • CIF / socialReason — NIF y razón social del adjudicatario
  • awardDate — Fecha de formalización
  • companySignatureDate / administrationSignatureDate — Fechas de firma
  • contractEndDate / monthsContractDuration — Fin y duración (meses)
  • awardAmount / awardAmountWithoutVAT — Importe de adjudicación con y sin IVA
  • CPV — CPV principal
  • minorContract — true si es contrato menor
  • mainEntityOfPage — Anuncio en contratacion.euskadi.eus
  • _links — Enlaces al poder adjudicador, al anuncio, a la entidad y al órgano

Ejemplos de código

Consultar la API de contratos curl
# Los 5 contratos formalizados más recientes (orden por defecto: awardDate descendente)
curl -s "https://api.euskadi.eus/procurements/contracts?currentPage=1&itemsOfPage=5" | python3 -m json.tool

# Contratos no menores formalizados en septiembre de 2026 (los filtros de fecha son excluyentes)
curl -s "https://api.euskadi.eus/procurements/contracts?minor-contract=false&award-date.gt=2026-08-31&award-date.lt=2026-10-01&itemsOfPage=50" \
  | python3 -c "import json, sys; d = json.load(sys.stdin); print(d['totalItems'], 'contratos')"
Paginar resultados python
import pandas as pd
import requests

URL = 'https://api.euskadi.eus/procurements/contracts'
params = {
    'minor-contract': 'false',
    'award-date.gt': '2026-08-31',  # excluyente
    'award-date.lt': '2026-10-01',  # excluyente
    'itemsOfPage': 50,              # máximo permitido
    'currentPage': 1,
}

rows = []
while True:
    data = requests.get(URL, params=params, timeout=60).json()
    for c in data['items']:
        rows.append({
            'id': c['id'],
            'objeto': c.get('object'),
            'tipo': c.get('contractType', {}).get('name'),
            'nif': c.get('CIF'),
            'adjudicatario': c.get('socialReason'),
            'fecha': c.get('awardDate'),
            'importe': c.get('awardAmount'),
        })
    if params['currentPage'] >= data['totalPages']:
        break
    params['currentPage'] += 1

df = pd.DataFrame(rows)
print(f'{len(df)} contratos, {df["importe"].sum():,.2f} EUR con IVA')