# TED, European public procurement

TED (Tenders Electronic Daily) is the EU's procurement journal. Every public body buying above the European thresholds must report here: prior information, contract notice, award and modification, with CPV code, contracting authority and often the winner and value. The search API works without a key. In 2025 Dutch contracting authorities published 22,755 notices, over 183,000 since October 2016.

- Publisher: Publicatiebureau van de Europese Unie
- Area: Europe · Finest detail: notice (per tender and lot)
- Period: zoekbaar sinds oktober 2016 · Refreshed: daily
- Access: Open · Licence: Aankondigingen vrij herbruikbaar, ook commercieel (Besluit 2011/833/EU); redactionele inhoud CC BY 4.0
- Join keys: publicatienummer (bv. 599786-2026), CPV-code, landcode (NLD), naam aanbestedende dienst
- Status: ok (2026-10-16) · 183.548 Nederlandse aankondigingen, nieuwste 715510-2026
- URL: https://ted.europa.eu/

## What can you do with it?
- **What does your municipality buy?.** Search by the contracting authority's name. On 16 October 2026, for example, there was an award by the municipality of Hengelo for office furniture.
- **More tenders per year.** Count per year with buyer-country=NLD and a date range. From 13,531 in 2017 to 22,755 in 2025. Mind the switch to eForms in 2023.
- **Who wins most often?.** Fetch one year's awards (form-type=result) and count per winner. Link the names to GLEIF or KvK to group companies into their parent groups.
- **Services, supplies or works.** In 2025, 14,214 Dutch notices concerned services, 6,836 supplies and 2,510 works. A notice with several lots can fall into more than one group.

## How to process it
1. **Search with an expert query.** POST to /v3/notices/search with query, fields and limit. No key. At most 250 per page and 15,000 per query (page × limit).
   `curl -X POST -H "Content-Type: application/json" -d '{"query":"buyer-country=NLD SORT BY publication-date DESC","fields":["publication-number","publication-date","notice-title","buyer-name","notice-type"],"limit":10,"paginationMode":"PAGE_NUMBER"}' https://api.ted.europa.eu/v3/notices/search`
2. **Count without fetching everything.** With limit 1 the count is in totalNoticeCount. This way you count per year, per notice form (form-type) or per contract type (contract-nature).
   `curl -X POST -H "Content-Type: application/json" -d '{"query":"buyer-country=NLD AND publication-date>=20250101 AND publication-date<=20251231 AND form-type=result","fields":["publication-number"],"limit":1,"paginationMode":"PAGE_NUMBER"}' https://api.ted.europa.eu/v3/notices/search`
3. **More than 15,000 results.** Use paginationMode ITERATION. Each response returns an iterationNextToken for the next batch.
   `curl -X POST -H "Content-Type: application/json" -d '{"query":"buyer-country=NLD AND publication-date>=20261001","fields":["publication-number"],"limit":250,"paginationMode":"ITERATION"}' https://api.ted.europa.eu/v3/notices/search`
4. **The full notice.** Each result links to the notice as XML (eForms) and as PDF in all EU languages.
   `https://ted.europa.eu/en/notice/599786-2026/xml`

## Interesting combinations
- Which groups do the winners belong to? → [gleif-lei](https://www.opendataindex.nl/en/bron/gleif-lei.md) via naam van de winnaar. Look up the winning companies in GLEIF and count awards per ultimate parent company.
- How much of the budget goes through European tenders? → [iv3-gemeentefinancien](https://www.opendataindex.nl/en/bron/iv3-gemeentefinancien.md) via gemeentenaam. Sum the awarded values per municipality in TED and put them next to expenditure from the Iv3 figures. Not every award states a value.

## Similar sources
- [tenderned](https://www.opendataindex.nl/en/bron/tenderned.md): TenderNed is the Dutch procurement platform, also for contracts below the European thresholds. TED only has the European tenders, but from all EU countries.
- [data-europa](https://www.opendataindex.nl/en/bron/data-europa.md): The European data portal lists TED as a dataset (ted-1) and a CSV subset (ted-csv), handy for bulk, but no search on individual notices.

## What to watch out for
- **Only above the European thresholds.** Smaller contracts are not in TED. For a full picture of Dutch procurement also look at TenderNed.
- **A notice is not a tender.** One tender often produces several notices (prior information, contract notice, award, modification). Count per notice form if you want to count tenders.
- **Search index starts in October 2016.** Queries on earlier publication dates returned zero results on 16 October 2026. Look for older notices in the TED datasets on data.europa.eu.
- **Switch to eForms.** Since late 2023 contracting authorities use eForms, with different forms and fields. Compare years before and after the switch with care.
- **Fields are sometimes lists or multilingual.** contract-nature and buyer-name come back as a list or as an object per language (e.g. buyer-name.nld). A notice with lots can therefore count twice.

## API (REST (POST, JSON), OpenAPI 3)

- Base: https://api.ted.europa.eu/v3
- Access: No key for searching. The other v3 endpoints (submit, validate, render) are for contracting authorities and eSenders and need an API key. (tested)
- Formats: json, xml, pdf, html
- Size: 183548 notices with a Dutch buyer (buyer-country=NLD, scope ALL, 16 Oct 2026); 17,776 active (tested)
- Filtering: TED expert query: field operator value, combined with AND/OR/NOT and brackets, lists with IN (A B), text contains with ~ "word", FT~ for full text, sort with SORT BY field ASC|DESC at the end.; =, !=, >, >=, <, <=, IN ( ), ~, FT~, AND, OR, NOT, SORT BY

### Endpoints
- `POST /notices/search`: Search with an expert query; JSON body with query (required), fields (required), limit, page, scope, paginationMode. Response: notices, totalNoticeCount, iterationNextToken.
- `GET https://ted.europa.eu/{taal}/notice/{publicatienummer}/xml`: The full notice as XML (eForms or the old TED schema). Every search result includes these links.
- `GET https://ted.europa.eu/{taal}/notice/{publicatienummer}/pdf`: The notice as PDF in every EU language (also /html).

### Parameters
- `query`: Expert query, e.g. buyer-country=NLD AND publication-date>=20250101 SORT BY publication-date DESC. Dates as YYYYMMDD. (tested)
- `fields`: Which fields to return (required), e.g. publication-number, publication-date, notice-title, buyer-name, notice-type, form-type, classification-cpv, winner-name. (from the description)
- `limit`: Number per page, default 10, at most 250 (251 returns SEARCH_EXCEEDS_MAX_LIMIT). Also at most 10,000 fields per page (limit × number of fields). (tested)
- `page`: Page number, starts at 1 (PAGE_NUMBER only). (from the description)
- `paginationMode`: PAGE_NUMBER (default, at most 15,000 results) or ITERATION (unlimited, with iterationNextToken; valid until 24 hours after the next OJ S issue). (from the description)
- `iterationNextToken`: Token from the previous response, for the next page in ITERATION. (from the description)
- `scope`: ALL (default), ACTIVE (only active notices) or LATEST (only the latest OJ S issue). (tested)
- `onlyLatestVersions`: Only the latest version of a notice. (from the description)
- `checkQuerySyntax`: Only check the syntax, don't search. (from the description)

### Fields you can request in fields (selection of 1,830) (14)
`publication-number` string, `publication-date` date, `notice-title` object, `buyer-name` object, `buyer-country` string, `notice-type` string, `form-type` string, `contract-nature` lijst, `classification-cpv` lijst, `procedure-type` string, `place-of-performance` lijst, `winner-name` object, `deadline-receipt-tender-date-lot` lijst, `links` object

### Limits and pitfalls
- PAGE_NUMBER: at most 250 per page and 15,000 per query (page × limit; beyond that SEARCH_WINDOW_TOO_WIDE). ITERATION: no maximum number of results. (from the description)
- No rate limit headers seen. A query with SORT BY took about 7 s; a count with limit 1 is faster. (tested)
- Errors come as JSON with error.type: QUERY_UNKNOWN_FIELD (with fieldName and position), QUERY_SYNTAX_ERROR, SEARCH_EXCEEDS_MAX_LIMIT … (tested)
- Counting: limit 1 and read totalNoticeCount. NL 2025: 22,755 notices; with buyer-country IN (NLD BEL) 349,226 since 2016. (tested)
- The search index starts in October 2016; earlier publication dates return 0. buyer-country=NLD is incomplete for the first years (2016: 2,912, 2018: 15,491). (experience)
- Fields that are missing are simply not returned (total-value was absent for awards). buyer-name and notice-title are objects per language; contract-nature and classification-cpv are lists per lot, so count notices, not list values. (tested)
- api.ted.europa.eu has no robots.txt (404). On ted.europa.eu only portal and search pages are disallowed; /…/notice/<nr>/xml is allowed. (experience)

### Example
```
https://api.ted.europa.eu/v3/notices/search
```

## How to fetch it

### curl
```bash
curl -X POST -H "Content-Type: application/json" -d '{"query":"buyer-country=NLD SORT BY publication-date DESC","fields":["publication-number","publication-date","buyer-name","notice-type"],"limit":5,"paginationMode":"PAGE_NUMBER"}' https://api.ted.europa.eu/v3/notices/search
```

### python
```python
import requests

url = "https://api.ted.europa.eu/v3/notices/search"
for jaar in range(2017, 2026):
    q = f"buyer-country=NLD AND publication-date>={jaar}0101 AND publication-date<={jaar}1231"
    r = requests.post(url, json={"query": q, "fields": ["publication-number"], "limit": 1,
                                 "paginationMode": "PAGE_NUMBER"})
    print(jaar, r.json()["totalNoticeCount"])
```

## What you can build with it
- [Procurement radar: who wins public contracts?](https://www.opendataindex.nl/en/bouwen/aanbestedingsradar.md): See per quarter which companies win Dutch public contracts, in which sector and for what amount, with their company number, LEI and parent company.


## Examples with real figures (1)

For each example the finding, the reference date and the call that fetches exactly these figures.

- **TED notices from Dutch contracting authorities: 22,755 notices in 2025, 68% more than in 2017** (2025). Table notices/search. [Example](https://www.opendataindex.nl/en/voorbeeld/ted-aankondigingen-nl)
  - `curl -X POST -H "Content-Type: application/json" -d '{"query":"buyer-country=NLD AND publication-date>=20250101 AND publication-date<=20251231","fields":["publication-number"],"limit":1,"paginationMode":"PAGE_NUMBER"}' https://api.ted.europa.eu/v3/notices/search`
