If you need EU public procurement data — who's buying what, from which government body, for how much, closing when — you do not need a scraper, and you do not need to pay one of the half-dozen "TED scraper" tools on the market. The EU's own TED (Tenders Electronic Daily) journal exposes all of it as clean JSON through an official, keyless v3 search API.
No sign-up. No API key. No token. Just a POST request.
The endpoint
POST https://api.ted.europa.eu/v3/notices/search
Anonymous access — search and retrieval require no authentication at all (only submitting notices does).
Pull the newest notices
curl -X POST 'https://api.ted.europa.eu/v3/notices/search' \
-H 'Content-Type: application/json' \
-d '{
"query": "FT~\"cloud computing\" SORT BY publication-date DESC",
"fields": ["publication-number", "notice-title", "buyer-name", "buyer-country", "deadline"],
"limit": 10,
"scope": "ACTIVE",
"paginationMode": "ITERATION"
}'
query uses TED's expert-search syntax: FT~"..." for full-text, field filters like buyer-country=DEU or PD>=20260101 (publication date), combined with AND/OR, and SORT BY publication-date DESC to get live opportunities instead of the 2016 backlog. fields is an explicit allowlist — ask for exactly the eForms fields you want back (notice-title is always included even if you forget it).
What comes back
Each notice in the notices array is keyed by the same eForms field names you requested — notice-title, buyer-name, classification-cpv (procurement category codes), total-value / total-value-cur, deadline, links. Multilingual fields like the title arrive as an object keyed by language ({"eng": [...], "fra": [...]}) rather than a plain string — grab eng when present, fall back to whatever language is there.
Filter by country, value, category
# German buyers, AI-related, published this year
curl -X POST 'https://api.ted.europa.eu/v3/notices/search' \
-H 'Content-Type: application/json' \
-d '{"query": "FT~\"artificial intelligence\" AND buyer-country=DEU AND PD>=20260101 SORT BY publication-date DESC", "fields": ["publication-number","notice-title","buyer-name","total-value","deadline"], "limit": 50, "scope": "ACTIVE"}'
Page through results
Set paginationMode: "ITERATION" and bump page (or follow the pagination token TED returns) while limit stays at or under 100 per call. scope: "ACTIVE" returns currently-open notices; use "ALL" to search the full historical archive (480,000+ notices back to the mid-2010s).
The one gotcha
Field names are the eForms names (notice-title, classification-cpv, buyer-country) — not the old two-letter TED codes from the legacy API. If you copy a query from a pre-2023 blog post, expect it to 404 or return nothing; the schema changed with the eForms rollout.
That's the whole thing: one POST endpoint, an expert-search query string, and a field allowlist — no key, no proxy, no anti-bot to fight.
If you'd rather skip the pagination and the multilingual-field unwrapping, the EU Tenders Scraper on Apify wraps exactly this endpoint — keyword or expert query in, flat rows out (buyer, country, CPV, value, deadline, direct link).
📌 Full field reference + copy-paste query cheatsheet: github.com/noble-ronin/ted-tenders-api


Top comments (0)