API de licitaciones públicas de España
Todas las licitaciones que publica el sector público español, normalizadas, desde tu programa, tu CRM o un agente de IA. Incluida en la suscripción Pro; las claves se crean en tu panel.
- Referencia de todas las rutas
- OpenAPI 3.1 (JSON), para generar clientes o dárselo a un agente
- llms.txt, resumen del sitio y de la API para modelos de lenguaje
- Términos de uso
Qué puedes hacer
| Ruta | Para qué |
|---|---|
GET /api/public/v1/contracts | Buscar licitaciones con texto y filtros (CPV, provincia, comunidad, estado, tipo, procedimiento, presupuesto, fechas, solo abiertas). |
GET /api/public/v1/contracts/{id o slug} | Una licitación con adjudicaciones por lote, documentos y cronología. |
GET /api/public/v1/contracts/{id o slug}/documents | Pliegos, anuncios y actas. |
GET /api/public/v1/changes?since=… | Lo que cambió desde una fecha: para mantener tu propia copia al día. |
GET /api/public/v1/organizations/{NIF o id} | Un organismo contratante. |
/api/public/v1/alerts | Tus alertas: listar, crear, cambiar, borrar y ver sus coincidencias. |
/api/public/v1/follows | Tus seguimientos de licitaciones concretas. |
Autenticación
Cada petición lleva tu clave, que empieza por dl_live_, en una de estas dos cabeceras:
Authorization: Bearer dl_live_…
X-API-Key: dl_live_…
Trátala como una contraseña: no la pongas en código que se publica ni en el navegador. Si se filtra, revócala en el panel y crea otra. Una clave de solo lectura no puede crear ni cambiar alertas o seguimientos; al crearla eliges si le das escritura.
Límites
Por clave: 60 peticiones por minuto y 10.000 al día (el día cuenta en UTC). Hasta 5 claves activas por cuenta. Cada respuesta dice cuánto te queda:
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 57
X-Quota-Limit: 10000
X-Quota-Remaining: 9431
Si te pasas, recibes un 429 con Retry-After en segundos.
Errores
Siempre con la misma forma, y un code estable para que tu programa decida qué hacer:
{"error": {"code": "plan_required", "message": "…", "upgrade_url": "https://donlicitacion.es/pro?origen=api"}}
| HTTP | code | Qué pasa |
|---|---|---|
| 400 | invalid_parameter / invalid_cursor | Un filtro con un valor que no existe, o un cursor alterado. |
| 401 | missing_api_key | No viene clave. |
| 401 | invalid_api_key | La clave no existe o está mal copiada. |
| 401 | revoked_api_key | La clave se revocó. |
| 403 | plan_required | La cuenta no es Pro. La clave se conserva y vuelve a funcionar al contratar. |
| 403 | insufficient_scope | Escritura con una clave de solo lectura. |
| 404 | not_found | No existe esa licitación u organismo. |
| 429 | rate_limited | Demasiadas peticiones por minuto. Espera lo que diga `Retry-After`. |
| 429 | quota_exceeded | Cuota diaria agotada. Se renueva a las 00:00 UTC. |
| 503 | api_not_configured | La API no está disponible en este momento. |
| 503 | query_timeout | La búsqueda tardó demasiado: añade un texto o acota por fechas o provincia. |
Si dejas de ser Pro, tus claves no se borran: responden plan_required y vuelven a
funcionar en cuanto contratas de nuevo.
Paginación
Los listados devuelven {"data": […], "meta": {"siguiente_cursor": "…", "page_size": 25}}.
Para la página siguiente, repite la llamada con cursor= y el valor de
siguiente_cursor, tal cual. Cuando viene null, no hay más. No hay números
de página: el cursor no se salta ni repite resultados aunque entren licitaciones nuevas mientras
paginas. page_size va de 1 a 100.
Ejemplos
curl
curl -H "Authorization: Bearer $DL_API_KEY" \
"https://donlicitacion.es/api/public/v1/contracts?cpv=45&provincia=Madrid&solo_abiertas=true&page_size=50"
Python
import os, httpx
cliente = httpx.Client(
base_url="https://donlicitacion.es/api/public/v1",
headers={"Authorization": f"Bearer {os.environ['DL_API_KEY']}"},
)
cursor = None
while True:
r = cliente.get("/contracts", params={"q": "limpieza", "solo_abiertas": True, "cursor": cursor})
r.raise_for_status()
cuerpo = r.json()
for lic in cuerpo["data"]:
print(lic["fecha_limite"], lic["titulo"], lic["url"])
cursor = cuerpo["meta"]["siguiente_cursor"]
if not cursor:
break
JavaScript
const r = await fetch(
"https://donlicitacion.es/api/public/v1/changes?since=2026-09-24T00:00:00Z",
{ headers: { Authorization: `Bearer ${process.env.DL_API_KEY}` } },
);
const { data, meta } = await r.json();
Crear una alerta (clave con escritura)
curl -X POST -H "Authorization: Bearer $DL_API_KEY" -H "Content-Type: application/json" \
-d '{"name": "Limpieza en Madrid", "filter_text": "limpieza", "filter_provincia": ["Madrid"]}' \
https://donlicitacion.es/api/public/v1/alerts
Con un agente de IA
Dale al agente la URL del OpenAPI (/api/public/v1/openapi.json) y tu clave como
secreto: cada ruta y cada campo llevan su descripción en castellano. Los estados, tipos y
procedimientos vienen como {"codigo", "etiqueta"}: el código para filtrar, la
etiqueta para contar. abierta ya tiene en cuenta el plazo: no hace falta
compararlo con la fecha.
Conectar tu IA por MCP
Si usas Claude, Cursor, VS Code u otro asistente compatible con MCP, puedes conectarlo directamente a las licitaciones con tu misma clave, sin escribir código: servidor MCP de Don Licitación.
Fuentes y licencias
Los datos vienen de plataformas oficiales, y cada una exige que se la cite. Por eso cada
licitación lleva un objeto fuente con el titular, la licencia y el texto de
atribución: si reutilizas o publicas un registro, conserva ese texto. Los datos
de Galicia se publican con licencia CC BY-SA 4.0: puedes redistribuirlos, con la misma licencia.
| Titular | Licencia |
|---|---|
| Ministerio de Hacienda, Plataforma de Contratación del Sector Público | ES-RISP-AGE |
| Generalitat de Catalunya, Departament d'Economia i Finances | LOUI-CAT |
| Gobierno Vasco, Open Data Euskadi (KontratazioA) | CC-BY-4.0 |
| Xunta de Galicia, Contratos Públicos de Galicia | CC-BY-SA-4.0 |
| Junta de Andalucía | CC-BY-3.0 |
| Gobierno de Navarra, Gobierno Abierto de Navarra | CC-BY-4.0 |
Ninguno de estos organismos participa en este servicio, lo patrocina ni lo respalda.
Cambios en la API
- v1 (24 de septiembre de 2026): primera versión.