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
# 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')" 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')