# EU Tenders (TED): Open Public Procurement with EUR Values (`yzy001/eu-tenders-ted`) Actor

EU public tenders open for bidding, from TED's official API: buyer, CPV category in English, deadline and days left, estimated value converted to EUR, lots, submission links. Filter by country, CPV, value, keyword or procedure, and track only new or changed tenders.

- **URL**: https://apify.com/yzy001/eu-tenders-ted.md
- **Developed by:** [宗諭 楊](https://apify.com/yzy001) (community)
- **Categories:** Lead generation, Business, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.50 / 1,000 tenders

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 (TED): Open Public Procurement with EUR Values

Public tenders from all over Europe, read from TED (Tenders Electronic Daily), the official journal of EU public procurement, through the EU Publications Office's own Search API. Each tender comes back as one clean row: buyer, what is being bought (CPV category in English), deadline and days left, estimated value converted to euros, lots, and the links to the notice and the submission portal. Filter by country, CPV code, value, keyword, contract nature or procedure, and schedule it with change tracking to receive only tenders you have not seen yet, or that were changed since.

TED publishes about 9,500 notices a week. A sector search is much smaller: IT services and software (CPV 72 and 48) are about 870 notices a week across all countries, and about 155 for Germany and Austria together.

### What you get for each tender

| Field | Meaning |
|---|---|
| `publicationNumber`, `noticeUrl`, `publicationDate` | TED notice number, the notice on TED, and the publication day |
| `title`, `titleLanguage`, `titleEnglishSummary` | The buyer's title in its own language, and TED's English line "country – CPV category – title" |
| `description` | The buyer's description of the purchase |
| `buyerName`, `buyerCountry`, `buyerCity`, `buyerWebsite` | The contracting authority |
| `mainCpv`, `mainCpvLabel`, `cpvCodes` | CPV codes; the main one with its official English label |
| `contractNature`, `procedureType` | `WORKS`, `SUPPLIES` or `SERVICES`; `OPEN`, `RESTRICTED`, `NEGOTIATED_WITH_CALL` and so on |
| `estimatedValue`, `currency`, `valueBasis` | The buyer's estimated value, and whether it is the procedure's value or the sum of its lots |
| `estimatedValueEur`, `eurRate` | The value in euros at the European Central Bank's reference rate of the publication day |
| `tenderDeadline`, `requestToParticipateDeadline`, `daysUntilDeadline`, `isOpen` | The next deadline still ahead, days left, and whether any lot can still be bid for |
| `lots` | Each lot: title, estimated value, deadline, framework agreement, submission link |
| `placeOfPerformanceNuts`, `placeOfPerformanceCountries` | Where the work is done (NUTS regions) |
| `submissionUrl`, `documentsUrl` | Where to get the documents and submit a tender |
| `noticeVersion`, `changesEarlierNotice`, `changeDescription`, `procedureId` | Notice versions: a later version changes an earlier notice |
| `dataFlags` | Problems in the notice itself (see below) |
| `changeStatus`, `firstSeen` | With tracking: `FIRST_RUN`, `NEW`, `CHANGED` or `SEEN` |

### Values in euros

Notices state values in their own currency (euro, Czech koruna, Swedish krona, Romanian leu, Polish złoty and others). `estimatedValueEur` divides the value by the ECB euro reference rate of the publication day, or the last working day before it, and `eurRate` shows the rate used. Currencies the ECB does not publish (Moldovan leu, Macedonian denar, Ukrainian hryvnia and a few others) keep their own value without a euro amount. Buyers enter 0 or 1 when they give no value; those are returned as empty. Fewer than half of all notices state a value at all, so `minValueEur` and `maxValueEur` leave the others out.

### Open for bidding

A tender is open while any of its lots can still be bid for: lots can close on different days, and `tenderDeadline` is the next one still ahead. Restricted and negotiated procedures first take requests to participate, with their own deadline. `onlyOpen` (on by default) leaves out tenders whose deadlines have all passed; notices without any deadline are kept with `isOpen` empty.

### One row per tender

When a buyer changes a notice (for example to extend the deadline), TED publishes a new version with a new notice number. Within a run, only the newest version of each procedure is returned. With `trackChanges`, a procedure returned before comes back as `CHANGED` when a newer version appears.

### Data quality flags

`dataFlags` marks what the notice gets wrong or leaves open, measured on real notices: `PROCEDURE_AND_LOT_VALUES_DIFFER_10X` (the procedure value and the sum of the lot values disagree by more than ten times), `LOT_VALUES_NOT_ALIGNED` (fewer lot values than lots, so no value is matched to a lot), `DEADLINE_BEFORE_DISPATCH` (a deadline earlier than the day the notice was sent), `NO_ECB_RATE_FOR_CURRENCY`, `VALUE_WITHOUT_CURRENCY`, `UNKNOWN_CPV_CODE`.

### Personal data

No contact persons, e-mail addresses or phone numbers are collected; those fields are not even requested. E-mail addresses that buyers type into a title or description are replaced with `[e-mail removed]`. Contract award notices (who won) are not part of this Actor.

### Filters

`cpvCodes`, `keywords`, `contractNature`, `countries`, `daysBack` or `fromDate`/`toDate`, `onlyOpen`, `minDaysToDeadline`, `minValueEur`, `maxValueEur`, `procedureTypes`, `includePriorInformation`, `trackChanges`, `onlyNew`, `maxItems`.

### Things to know

- Titles and descriptions are in the buyer's language, as TED publishes them. Keywords match the text as written, so add the words in the languages you care about; CPV codes work across all languages.
- If TED has not published anything for more than six days, the run fails instead of returning an old picture as current.
- The run summary lists the exact query sent to TED, counts by country, CPV division and procedure, and every data flag.

### Data

TED (Tenders Electronic Daily), the Supplement to the Official Journal of the European Union, read through the EU Publications Office's public Search API, which is open to reusers without registration. Euro reference rates from the European Central Bank. CPV labels from the EU Vocabularies (CPV 2008). One request per second; no login and no scraping of web pages.

# Actor input Schema

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

Keep tenders with any of these CPV codes or their sub-codes, for example 72 (IT services), 48 (software), 45 (construction), 33 (medical) or a full code like 45233120. A check digit like 72000000-8 is accepted. Empty = all.

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

Optional. Keep tenders whose title, description, buyer or lot titles contain any of these words (case-insensitive). Notices are in the buyer's language, so add translations where it matters.

## `contractNature` (type: `array`):

Works, supplies or services. Empty = all.

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

Optional. Two- or three-letter country codes of the buyer, for example DE, FR, PL or DEU. Empty = all countries publishing on TED (the EU, EEA, Switzerland and candidate countries).

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

Notices published in the last N days, today included (1-31). TED publishes every working day; a week is about 9,500 notices for all of Europe. Ignored when a from date is set.

## `fromDate` (type: `string`):

Optional. First publication date to include (YYYY-MM-DD). The range can cover at most 31 days.

## `toDate` (type: `string`):

Optional. Last publication date to include. Defaults to today.

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

Leave out tenders whose deadlines have all passed. A tender with several lots stays in while any lot is open. Notices without any deadline are kept.

## `minDaysToDeadline` (type: `integer`):

Optional. Keep tenders with at least this many days left to bid.

## `minValueEur` (type: `integer`):

Optional. Fewer than half of all notices state a value; the others are left out when this is set.

## `maxValueEur` (type: `integer`):

Optional. Notices without a value are left out when this is set.

## `procedureTypes` (type: `array`):

Optional. Open, restricted, negotiated and so on. Empty = all.

## `includePriorInformation` (type: `boolean`):

Also return planned procurements announced in advance (no deadline yet).

## `trackChanges` (type: `boolean`):

Remember which tenders were returned before (in your own key-value store) and mark each row NEW, CHANGED (a newer version of the notice), SEEN or FIRST_RUN.

## `onlyNew` (type: `boolean`):

With tracking on, return only tenders not returned before, or changed since.

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

Upper limit on rows, newest first.

## Actor input object example

```json
{
  "cpvCodes": [
    "72",
    "48"
  ],
  "keywords": [],
  "contractNature": [],
  "countries": [],
  "daysBack": 7,
  "onlyOpen": true,
  "procedureTypes": [],
  "includePriorInformation": false,
  "trackChanges": false,
  "onlyNew": false,
  "maxItems": 200
}
```

# Actor output Schema

## `items` (type: `string`):

Normalised TED notices.

## `summary` (type: `string`):

Query, counts by country, CPV division and procedure, data flags, caveats.

# 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 = {
    "cpvCodes": [
        "72",
        "48"
    ],
    "daysBack": 7,
    "maxItems": 200
};

// Run the Actor and wait for it to finish
const run = await client.actor("yzy001/eu-tenders-ted").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 = {
    "cpvCodes": [
        "72",
        "48",
    ],
    "daysBack": 7,
    "maxItems": 200,
}

# Run the Actor and wait for it to finish
run = client.actor("yzy001/eu-tenders-ted").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 '{
  "cpvCodes": [
    "72",
    "48"
  ],
  "daysBack": 7,
  "maxItems": 200
}' |
apify call yzy001/eu-tenders-ted --silent --output-dataset

```

## MCP server setup

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

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/eLTlJNcLZQlcT51hO/builds/fdrEmfL2CeoQkUS1C/openapi.json
