Znajdź przetargi dzięki TED Search API

Czym jest TED Search API?

TED (Tenders Electronic Daily) to oficjalny dziennik UE dotyczący zamówień publicznych, w którym publikowane jest każde ogłoszenie o przetargu powyżej progów ze wszystkich 27 państw członkowskich. TED Search API udostępnia te ogłoszenia jako JSON przez jeden punkt końcowy:

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

Możesz wywołać je bez żadnego uwierzytelniania, więc jest otwarte dla każdego ponownego użytkownika. Pełną dokumentację żądań i odpowiedzi znajdziesz w dokumentacji Swagger.

Czy potrzebujesz klucza API?

Nie do wyszukiwania. Search API jest w pełni publiczne, a klucz jedynie zwiększa limity zapytań i odblokowuje inne punkty końcowe, takie jak zarządzanie własnymi ogłoszeniami. Jeśli mimo to chcesz klucz, wystarczą trzy kroki:

  1. Wejdź na TED Developer Portal.
  2. Zaloguj się danymi EU Login.
  3. Wygeneruj klucz w sekcji Manage API Keys.

Wyszukiwanie przetargów w Pythonie

Każde żądanie zawiera trzy rzeczy: query, fields, które chcesz otrzymać, oraz limit. Sama query korzysta ze składni wyszukiwania eksperckiego TED, zapisanej jako field operator value i łączonej za pomocą AND, OR i NOT. Oto pola, których będziesz używać najczęściej:

PolePrzykładZnaczenie
classification-cpvclassification-cpv=38000000Kod CPV (branża)
buyer-countrybuyer-country=POLKraj zamawiającego, ISO 3-literowe
publication-datepublication-date>=20260420Opublikowane w danym dniu lub później
estimated-value-procestimated-value-proc>=50000Szacowana wartość zamówienia

Zamiast uczyć się składni na pamięć, zbuduj zapytanie wizualnie w wyszukiwaniu eksperckim TED i skopiuj powstały ciąg zapytania do swojego kodu. Jeśli nie masz pewności, który kod CPV pasuje do twojej branży, sprawdź go w naszej wyszukiwarce kodów CPV.

Poniższy przykład znajduje przetargi na sprzęt laboratoryjny (CPV 38000000) opublikowane od początku roku, o szacowanej wartości od 50 000 do 500 000 EUR, od zamawiających w Polsce. Ponieważ pojedyncza strona zawiera najwyżej 250 ogłoszeń, przewija wyniki w trybie iteracji, pobierając pięć stron po 100, czyli do 500 ogłoszeń w jednym uruchomieniu:

import requests
import time

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

query = " AND ".join([
    "classification-cpv=38000000",     # Sprzęt laboratoryjny
    "buyer-country=POL",               # Polska
    "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):  # Pobierz pięć stron.
    data = requests.post(URL, json=payload).json()
    notices.extend(data["notices"])

    # Użyj tokenu iteracji do wydajnej paginacji.
    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"]["pol"]
    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}")

Warto znać kilka szczegółów dotyczących odpowiedzi. notice-title jest indeksowane według kodu języka, więc notice-title["pol"] zwraca tytuł po polsku, a classification-cpv przychodzi jako lista kodów. W trybie iteracji każda strona przekazuje token iterationNextToken, który odsyłasz w kolejnym żądaniu, a pętla zatrzymuje się, gdy tylko strona wróci mniejsza niż twój limit. Stąd możesz zamienić POL na dowolny kod kraju lub 38000000 na branżę, w której startujesz.

Ograniczenia i dobre praktyki

Search API jest hojne, ale kilka ograniczeń wpływa na sposób korzystania:

  • Rozmiar strony. Żądanie zwraca najwyżej 250 ogłoszeń, więc cokolwiek większego wymaga paginationMode: "ITERATION" i pokazanej powyżej pętli z tokenem.
  • Rozmiar zapytania. Pojedyncze zapytanie może zawierać do 2000 klauzul. Gdy celujesz w wiele kodów CPV, grupuj je za pomocą IN (...) zamiast łączyć długi ciąg warunków OR.
  • Limity zapytań. Wywołania anonimowe są ograniczane, więc zarejestruj klucz API, zanim uruchomisz ciężkie lub zaplanowane zadania.
  • Kształt pól. Wiele pól jest wielojęzycznych lub wraca jako listy, dlatego przykład odczytuje je ostrożnie za pomocą .get() i klucza języka.
  • Bądź w porządku. Buforuj pobrane dane i unikaj dwukrotnego pobierania tych samych ogłoszeń. TED aktualizuje się w ciągu dnia, więc zwykle wystarcza synchronizacja godzinna lub dzienna.

To cała pętla: zbuduj zapytanie, wyślij je metodą POST, odczytaj JSON i paginuj. Stąd możesz zapisywać ogłoszenia w bazie danych, wysyłać powiadomienia do zespołu lub przekazywać je bezpośrednio do własnego produktu.