# EU Tenders & Contract Awards (TED) - One Row per Procedure (`jpopendata/eu-ted-tenders`) Actor

EU tenders and contract awards from the official TED API, one row per procedure: each call for tender joined with its award notices and corrigenda. Buyer, CPV, estimate, deadline, award value, winning companies. Keyword, country, CPV, value and date filters. Unofficial; not affiliated with the EU.

- **URL**: https://apify.com/jpopendata/eu-ted-tenders.md
- **Developed by:** [JP Open Data](https://apify.com/jpopendata) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.00 / 1,000 results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## EU Tenders & Contract Awards (TED) — One Row per Procedure

Get EU public procurement from **TED (Tenders Electronic Daily)**, the official EU journal for public contracts, as clean rows — **one row per procurement procedure**, not one row per notice. Each row joins the call for tender with the notices that followed it: corrigenda, contract award notices and contract modifications. So an award row still carries the original estimate and submission deadline, and a tender row shows whether it was corrected or already awarded.

Data comes live from the **official TED Search API v3** (Publications Office of the European Union). No login, no API key, no browser.

### What you get

- **One row per procedure**, linked by TED's own procedure identifier: original contract notice, change notices (corrigenda), award notice(s), modifications, with every notice listed and linked.
- **Tender facts**: English title, buyer and buyer country, CPV codes, contract nature, procedure type, estimated value and currency, submission deadline, open/closed status.
- **Award facts**: awarded value and currency (summed over the award notices), award decision date, **winning companies**, winner countries and declared sizes (SME, large, ...).
- **Filters**: full-text keywords, buyer countries, CPV codes (whole branch), notice stages, buyer name, value range, publication window, deadline window, "only open for bids".
- **Companies only**: winner names are shown only when they are clearly a company, cooperative, foundation or public body. Sole traders, partnerships and anything that may be a private person are withheld and counted (`winnersWithheld`). No contact names, e-mails, phone numbers or notice descriptions are collected at all.

### Quick start — verified input

Open calls and awards for software in Germany from the last 14 days:

```json
{
  "keywords": ["software"],
  "countries": ["Germany"],
  "daysBack": 14,
  "maxItems": 20
}
```

An empty input `{}` also works: the newest 20 procedures with a notice published in the last 7 days, all countries.

### Input

| Field | Example | What it does |
|---|---|---|
| `keywords` | `["software", "cloud services"]` | Full-text search in the notices (original language plus TED's English title). Any keyword matches. Add the local word too (`"Reinigung"` next to `"cleaning"`). |
| `countries` | `["DE", "France", "POL"]` | Buyer countries: names, ISO-2 or ISO-3 codes, native names (`"Deutschland"`). EU, EEA, Switzerland, candidate countries. |
| `cpvCodes` | `["72000000", "45"]` | CPV codes or prefixes. TED matches the whole branch: `72000000` covers every IT-services code. |
| `stages` | `["tender", "award"]` | Which notices are searched: `planning`, `tender`, `award`, `modification`. Empty = all. |
| `buyers` | `["Stadt München"]` | Part of the buyer's name as written on TED (usually in the local language). |
| `valueMin` / `valueMax` | `100000` / `5000000` | Notice value range (estimate for calls, awarded total for awards) in `valueCurrency`. |
| `valueCurrency` | `"EUR"` | Currency of the value range. Values are never converted. |
| `daysBack` | `7` | Publication window: from N days ago up to today (Brussels time). |
| `publishedFrom` / `publishedTo` | `"2026-09-01"` | Explicit publication window (at most 366 days). |
| `deadlineFrom` / `deadlineTo` | `"2026-11-01"` | Submission-deadline window. |
| `onlyOpen` | `true` | Only calls for tender whose deadline is still ahead and that have no award yet. |
| `linkProcedures` | `true` | Read every other notice of each procedure (about 1 extra request per 50 procedures). |
| `maxItems` | `20` | Maximum rows (procedures), newest first. |
| `maxApiRequests` | `40` | Hard request budget for the run. |

#### Common input mistakes

| You wrote | Write instead | Why |
|---|---|---|
| `"countries": ["Bavaria"]` | `"countries": ["Germany"]`, `"keywords": ["Bayern"]` | Countries only; regions and cities go in keywords. |
| `"cpvCodes": ["IT services"]` | `"cpvCodes": ["72000000"]` | CPV codes are digits; put words in `keywords`. |
| `"valueMin": 1000000` for Polish tenders | add `"valueCurrency": "PLN"` | Values are compared in one currency, never converted. |
| `"stages": ["award"], "onlyOpen": true` | `"onlyOpen": true` | Open calls are tenders, not awards. |
| `"keywords": ["cleaning"]` only | `["cleaning", "Reinigung", "nettoyage"]` | Notices are written in the buyer's language. |

### Output example

```json
{
  "id": "13f71dbe-a3b4-413c-8c31-fb3acfa95ba1",
  "procedureId": "13f71dbe-a3b4-413c-8c31-fb3acfa95ba1",
  "stage": "award",
  "status": "awarded",
  "isOpenForBids": false,
  "title": "Spain – Facilities management services for computer systems maintenance – Servicio de asistencia técnica informática, para la administración de Sistemas del Centro Proceso de Datos (CPD) del ISFAS OA",
  "originalTitle": "Servicio de asistencia técnica informática, para la administración de Sistemas del Centro Proceso de Datos (CPD) del ISFAS OA",
  "mainCpvLabel": "Facilities management services for computer systems maintenance",
  "buyerName": "Instituto Social de las Fuerzas Armadas (ISFAS)",
  "buyerCountry": "ESP",
  "buyerCountryName": "Spain",
  "buyerCity": "Madrid",
  "buyerType": "Central government authority",
  "mainCpvCode": "72514300",
  "cpvCodes": ["72514000", "72514300", "72590000"],
  "contractNature": "services",
  "procedureType": "open",
  "procedureTypeLabel": "Open procedure",
  "estimatedValue": 1289160,
  "estimatedValueCurrency": "EUR",
  "tenderDeadline": "2026-08-11T23:59:00+02:00",
  "awardedValue": 511200,
  "awardedValueCurrency": "EUR",
  "awardDecisionDate": "2026-09-09",
  "winners": ["Seguel Solutions SRL"],
  "winnerCountries": ["ESP"],
  "winnerSizes": ["sme"],
  "winnersWithheld": 0,
  "contractNoticeNumber": "521890-2026",
  "awardNoticeNumber": "704141-2026",
  "firstPublished": "2026-07-28",
  "lastPublished": "2026-10-12",
  "noticeCount": 2,
  "changeNotices": 0,
  "lifecycleLinked": true,
  "notices": [
    { "publicationNumber": "704141-2026", "noticeType": "can-standard", "noticeTypeLabel": "Contract award notice", "publicationDate": "2026-10-12", "isChange": false, "valueAmount": 511200, "valueCurrency": "EUR", "url": "https://ted.europa.eu/en/notice/-/detail/704141-2026" },
    { "publicationNumber": "521890-2026", "noticeType": "cn-standard", "noticeTypeLabel": "Contract notice", "publicationDate": "2026-07-28", "isChange": false, "valueAmount": 1289160, "valueCurrency": "EUR", "url": "https://ted.europa.eu/en/notice/-/detail/521890-2026" }
  ],
  "tedUrl": "https://ted.europa.eu/en/notice/-/detail/704141-2026",
  "source": "TED - Tenders Electronic Daily (Publications Office of the European Union)",
  "sourceUrl": "https://ted.europa.eu/en/",
  "license": "© European Union, https://ted.europa.eu. Procurement notices reused under the European Commission reuse policy (Commission Decision 2011/833/EU: commercial and non-commercial reuse, source acknowledged). Changed by this tool: selected fields only, values normalised, notices grouped per procedure; only the notices published in the Supplement to the Official Journal of the EU are authentic. Unofficial tool, not affiliated with or endorsed by the European Union or the Publications Office.",
  "retrievedAt": "2026-10-12T18:30:00.000Z"
}
```

#### Main fields

| Field | Meaning |
|---|---|
| `stage` | Most advanced stage reached: `planning`, `tender`, `award`. |
| `status` | `planned`, `open` (deadline ahead), `closed` (deadline passed, no award notice yet), `awarded`, `not-awarded` (all lots closed without a winner), `unknown`. |
| `title` | TED's English title: country – main CPV label – the title as written by the buyer. |
| `estimatedValue` | Newest published estimate (procedure value, or the lot values when they share a currency). |
| `awardedValue` | Sum of the values published in the award notices, when they share a currency. |
| `winners` | Company / public-body names that passed the legal-entity gate. |
| `winnersWithheld` | Number of winner names withheld (possible private persons, sole traders, partnerships). |
| `matchedNotices` | Publication numbers that matched your search window and filters. |
| `notices` | Every notice of the procedure read by the run, newest first, with links. |
| `lifecycleLinked` | `true` when all other notices of the procedure were looked up. |
| `id` | Stable row key: the procedure id, or `notice:<publication number>` for prior information notices (TED gives those no procedure id). |

### How it works

1. Searches TED for notices published in your window that match your filters, newest first.
2. Collects the procedures behind them until it has `maxItems` procedures.
3. Looks up every other notice of those procedures (50 procedures per request) and compiles one row per procedure: the newest notice wins for descriptive fields, award notices are combined.

Requests are sent one at a time, at least 2 seconds apart, within a hard request budget. TED's own limits are respected: at most 250 notices per request, at most 15,000 notices per search.

### Empty results?

- **Weekends and holidays**: TED publishes on working days (around 09:00 Brussels time). A one-day window on a Sunday is empty.
- **Too many filters together**: a keyword plus a CPV code plus a country plus a value range often matches nothing in a short window. Widen `daysBack` first.
- **Language**: notices are in the buyer's language; an English-only keyword misses many of them.
- **Value range**: notices in other currencies, or without a published value, are skipped when a value range is set.
- A run that matches nothing ends successfully with 0 rows and a warning in the log; you are not charged for rows.

### Personal data (GDPR)

TED notices can contain personal data (contact persons, and occasionally private persons who won a contract). This Actor is built to leave it out:

- It **never requests** contact points, e-mail addresses, phone numbers, street addresses or notice descriptions from the API.
- **Winner names** are shown only when the name carries a company, cooperative or foundation form (GmbH, s.r.o., Sp. z o.o., S.A., SRL, Kft., Oy, AB, B.V., ...) or names a public body. Sole traders (e.K., OSVČ, PFA, EI, s.p., ...), partnerships (GbR, KG, Sp. j., s.c., v.o.s., ...) and plain names are withheld. Some real companies are withheld too; that is intended.
- Buyer names are public bodies and are shown, except names that read like a person or a sole trader.
- Names are shown as published: some buyers type a department or the company's address into the name field.

You remain responsible for how you process the data under the GDPR and local law.

### Source, licence and attribution

- Source: TED – Tenders Electronic Daily, Publications Office of the European Union, https://ted.europa.eu.
- TED's legal notice: "Unless otherwise noted, the procurement notices published in the Supplement to the Official Journal of the European Union can be freely reused, for commercial or non-commercial purposes" (Commission Decision 2011/833/EU on the reuse of Commission documents). Every row carries the attribution in `license`. Only the notices published in the Supplement to the Official Journal of the EU are authentic; this dataset is a restructured, partial copy.
- Do not use TED's logo: the legal notice reserves it.

### Disclaimer

This is an **unofficial** tool. It is **not affiliated with or endorsed by** the European Union, the European Commission or the Publications Office of the European Union. It reads **public data only** through TED's public search API. You are responsible for complying with TED's terms and the laws that apply to your use of the data.

# Actor input Schema

## `keywords` (type: `array`):

Optional. Words or phrases searched in the full text of the notices (TED's full-text index: the notice in its original language plus the English title), any case, e.g. "software", "cloud services", "Rahmenvertrag". A procedure matches if a notice contains ANY of them. Notices are written in the buyer's language, so add the local word for best recall (e.g. "Reinigung" next to "cleaning"). Leave empty for all notices.

## `countries` (type: `array`):

Optional. Countries of the buyer (contracting authority), as names or ISO codes: "Germany", "DE" or "DEU"; native names such as "Deutschland" or "Polska" work too. Covers the EU, EEA, Switzerland and candidate countries. Empty = all countries.

## `cpvCodes` (type: `array`):

Optional. CPV codes or prefixes, e.g. "72000000" (IT services: matches every code under 72), "45" (construction work), "33600000-6". TED matches the whole branch below each code, in the main and the additional CPV codes.

## `stages` (type: `array`):

Optional. Which notices are searched in the window: planning (prior information notices), tender (contract notices = open calls), award (contract award notices, voluntary ex-ante transparency notices) and/or modification (contract modifications). Each row still shows the whole procedure and its most advanced stage. Empty = all.

## `buyers` (type: `array`):

Optional. Part of the buyer's name as written on TED (usually in the local language), e.g. "Stadt München", "Deutsche Bahn", "Gmina". Any match counts.

## `valueMin` (type: `integer`):

Optional. Minimum notice value in Value currency (the estimated value of a call for tender, the total awarded value of an award notice), e.g. 100000. Notices without a value in that currency are dropped when a value range is set.

## `valueMax` (type: `integer`):

Optional. Maximum notice value in Value currency, e.g. 5000000.

## `valueCurrency` (type: `string`):

The currency the value range refers to, as a 3-letter code: EUR (default), PLN, CZK, SEK, DKK, HUF, RON, NOK, CHF ... Values are not converted between currencies.

## `daysBack` (type: `integer`):

Search notices published from N days ago up to today (1..366, Brussels calendar days). Ignored when Published from is set. TED publishes about 3,000-4,000 notices per working day; with Max rows the run stops early once it has the newest matching procedures.

## `publishedFrom` (type: `string`):

Optional. First publication day of the window, YYYY-MM-DD, e.g. "2026-09-01". YYYYMMDD, DD.MM.YYYY, "today" and "yesterday" also work. The window can be at most 366 days.

## `publishedTo` (type: `string`):

Optional. Last publication day of the window, YYYY-MM-DD. Empty = today.

## `deadlineFrom` (type: `string`):

Optional. Keep only notices whose tender submission deadline is on or after this day, YYYY-MM-DD. Notices without a deadline (for example award notices) are dropped when this is set.

## `deadlineTo` (type: `string`):

Optional. Keep only notices whose tender submission deadline is on or before this day, YYYY-MM-DD.

## `onlyOpen` (type: `boolean`):

Keep only calls for tender whose submission deadline is still ahead (searches contract notices with a deadline from today on, then drops procedures that already have an award or whose newest deadline has passed).

## `linkProcedures` (type: `boolean`):

Also read every other notice of each procedure found (the original contract notice, award notices, corrigenda, modifications), so an award row carries the original estimate and deadline and a tender row shows later corrigenda. About 1 extra request per 50 procedures. Turn off for a faster notice-only view.

## `maxItems` (type: `integer`):

Maximum procedure rows (1..5000), newest first. You are charged per row.

## `maxApiRequests` (type: `integer`):

Hard budget of requests to the TED API for the whole run (1..500). Requests are sent one at a time at least 2 seconds apart; one request returns up to 250 notices. If the budget runs out the run still succeeds with what it read (complete=false in RUN_SUMMARY).

## `proxyConfiguration` (type: `object`):

Optional and normally not needed: the TED API answers Apify datacenter IPs. If set, one sticky session is used for the whole run (never rotation).

## Actor input object example

```json
{
  "keywords": [],
  "countries": [],
  "cpvCodes": [],
  "stages": [],
  "buyers": [],
  "valueCurrency": "EUR",
  "daysBack": 7,
  "publishedFrom": "",
  "publishedTo": "",
  "deadlineFrom": "",
  "deadlineTo": "",
  "onlyOpen": false,
  "linkProcedures": true,
  "maxItems": 20,
  "maxApiRequests": 40,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `records` (type: `string`):

One row per EU procurement procedure with the TED attribution (source, sourceUrl, license, retrievedAt) on every item.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "keywords": [],
    "countries": [],
    "cpvCodes": [],
    "stages": [],
    "buyers": [],
    "valueCurrency": "EUR",
    "daysBack": 7,
    "publishedFrom": "",
    "publishedTo": "",
    "deadlineFrom": "",
    "deadlineTo": "",
    "onlyOpen": false,
    "linkProcedures": true,
    "maxItems": 20,
    "maxApiRequests": 40,
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("jpopendata/eu-ted-tenders").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "keywords": [],
    "countries": [],
    "cpvCodes": [],
    "stages": [],
    "buyers": [],
    "valueCurrency": "EUR",
    "daysBack": 7,
    "publishedFrom": "",
    "publishedTo": "",
    "deadlineFrom": "",
    "deadlineTo": "",
    "onlyOpen": False,
    "linkProcedures": True,
    "maxItems": 20,
    "maxApiRequests": 40,
    "proxyConfiguration": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("jpopendata/eu-ted-tenders").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "keywords": [],
  "countries": [],
  "cpvCodes": [],
  "stages": [],
  "buyers": [],
  "valueCurrency": "EUR",
  "daysBack": 7,
  "publishedFrom": "",
  "publishedTo": "",
  "deadlineFrom": "",
  "deadlineTo": "",
  "onlyOpen": false,
  "linkProcedures": true,
  "maxItems": 20,
  "maxApiRequests": 40,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}' |
apify call jpopendata/eu-ted-tenders --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,jpopendata/eu-ted-tenders"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/9xVeHM4gbZjdFeASU/builds/pc1U7g6rG7MwwUKa8/openapi.json
