Encontrar licitaciones con la TED Search API

¿Qué es la TED Search API?

TED (Tenders Electronic Daily) es el diario oficial de la UE para la contratación pública, donde se publica cada anuncio de licitación por encima del umbral de los 27 Estados miembros. La TED Search API expone esos anuncios como JSON a través de un único endpoint:

POST https://api.ted.europa.eu/v3/notices/search

Puedes llamarla sin ninguna autenticación, así que está abierta a cualquier reutilizador. La referencia completa de petición y respuesta está en la documentación de Swagger.

¿Necesitas una clave API?

No para buscar. La Search API es totalmente pública, y una clave solo aumenta tus límites de frecuencia y desbloquea otros endpoints, como gestionar tus propios anuncios. Si aun así quieres una, son tres pasos:

  1. Visita el TED Developer Portal.
  2. Inicia sesión con tus credenciales de EU Login.
  3. Genera tu clave en Manage API Keys.

Buscar licitaciones con Python

Cada petición incluye tres cosas: una query, los fields que quieres recibir y un limit. La query usa la sintaxis de búsqueda experta de TED, escrita como field operator value y combinada con AND, OR y NOT. Estos son los campos que usarás más a menudo:

CampoEjemploSignificado
classification-cpvclassification-cpv=38000000Código CPV (sector)
buyer-countrybuyer-country=ESPPaís del comprador, ISO de 3 letras
publication-datepublication-date>=20260420Publicado en una fecha o después
estimated-value-procestimated-value-proc>=50000Valor estimado de la contratación

En lugar de memorizar la sintaxis, construye tu consulta visualmente en la búsqueda experta de TED y copia la cadena resultante en tu código. Si no estás seguro de qué código CPV encaja con tu sector, búscalo con nuestra búsqueda de códigos CPV.

El siguiente ejemplo encuentra licitaciones de equipos de laboratorio (CPV 38000000) publicadas desde principios de año, con un valor estimado entre 50.000 y 500.000 EUR, de compradores en España. Como una sola página contiene como máximo 250 anuncios, recorre los resultados en modo iteración, obteniendo cinco páginas de 100, es decir, hasta 500 anuncios en una ejecución:

import requests
import time

URL = "https://api.ted.europa.eu/v3/notices/search"

query = " AND ".join([
    "classification-cpv=38000000",     # Equipos de laboratorio
    "buyer-country=ESP",               # España
    "publication-date>=20260101",
    "estimated-value-proc>=50000",
    "estimated-value-proc<=500000",
])

payload = {
    "query": query,
    "fields": [
        "publication-number",
        "notice-title",
        "classification-cpv",
        "estimated-value-proc",
        "estimated-value-cur-proc",
    ],
    "limit": 100,
    "scope": "ACTIVE",
    "paginationMode": "ITERATION",
}

notices = []
for _ in range(5):  # Obtener cinco páginas.
    data = requests.post(URL, json=payload).json()
    notices.extend(data["notices"])

    # Usar el token de iteración para paginar de forma eficiente.
    token = data.get("iterationNextToken")
    if not token or len(data["notices"]) < payload["limit"]:
        break
    payload["iterationNextToken"] = token

    time.sleep(1)

for notice in notices:
    number = notice["publication-number"]
    title = notice["notice-title"]["spa"]
    cpv = ", ".join(notice["classification-cpv"])
    value = notice.get("estimated-value-proc", "n/a")
    currency = notice.get("estimated-value-cur-proc", "")

    print(f"{number} | {title} | {value} {currency} | {cpv}")

Conviene conocer un par de detalles de la respuesta. notice-title está indexado por código de idioma, así que notice-title["spa"] devuelve el título en español, mientras que classification-cpv llega como una lista de códigos. En modo iteración cada página te entrega un iterationNextToken que devuelves en la siguiente petición, y el bucle se detiene en cuanto una página vuelve más pequeña que tu límite. A partir de aquí puedes cambiar ESP por cualquier código de país, o 38000000 por el sector al que te presentas.

Límites y buenas prácticas

La Search API es generosa, pero algunos límites condicionan su uso:

  • Tamaño de página. Una petición devuelve como máximo 250 anuncios, así que cualquier cosa mayor necesita paginationMode: "ITERATION" y el bucle con token mostrado arriba.
  • Tamaño de consulta. Una sola consulta puede contener hasta 2.000 cláusulas. Cuando apuntes a muchos códigos CPV, agrúpalos con IN (...) en lugar de encadenar una larga serie de condiciones OR.
  • Límites de frecuencia. Las llamadas anónimas están limitadas, así que registra una clave API antes de ejecutar trabajos pesados o programados.
  • Forma de los campos. Muchos campos son multilingües o vuelven como listas, por eso el ejemplo los lee de forma defensiva con .get() y una clave de idioma.
  • Sé responsable. Almacena en caché lo que obtienes y evita descargar dos veces los mismos anuncios. TED se actualiza a lo largo del día, así que una sincronización horaria o diaria suele bastar.

Ese es el ciclo completo: construye una consulta, envíala con POST, lee el JSON y pagina. A partir de ahí puedes guardar los anuncios en una base de datos, enviar alertas a tu equipo o integrarlos directamente en tu propio producto.