# EU Tenders (TED): Public Procurement Notices (`agentready/eu-tenders-ted`) Actor

Search every EU public tender on TED, the EU's official procurement journal: calls for tenders, contract awards and upcoming tenders from 30+ countries. Filter by keyword, CPV code, country, deadline and value, or get only new notices since your last run. Official TED API.

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

## Pricing

from $3.50 / 1,000 notices

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): Public Procurement Notices

Search **every EU public tender** published on **TED (Tenders Electronic Daily)**, the European Union's official procurement journal. That covers calls for tenders you can still bid on, contract awards showing who won and for how much, and prior notices of upcoming tenders, from 30+ countries, in one clean, flat format.

Filter by keyword, CPV category, country, deadline and value, or turn on **"only new notices"** to get just what was published since your last run. Data comes from the **official TED Search API**: no scraping, no logins, no blocked pages.

### What you can do with it

- **Find tenders to bid on.** Get every open call for IT services in Germany and France, updated daily.
- **Track competitors and markets.** Contract awards show the buyer, the value and the category.
- **Plan ahead.** Prior information notices reveal tenders months before they open.
- **Feed an AI agent or CRM.** English headlines, stable IDs and ISO dates make the records easy to use.

### Quick start

Open IT tenders from German and French buyers, published in the last 7 days:

```json
{
  "cpvCodes": ["72000000"],
  "countries": ["DE", "FR"],
  "noticeTypes": ["contract"],
  "onlyOpenForBids": true
}
```

#### Daily feed of new tenders

Schedule this every morning. The first run returns everything that matches; after that, only new notices appear, and **you only pay for those**.

```json
{
  "keywords": ["cybersecurity", "penetration testing"],
  "countries": ["NL", "BE", "LU"],
  "publishedWithinDays": 3,
  "onlyNewNotices": true,
  "stateKey": "benelux-security"
}
```

Use a different `stateKey` for each scheduled search.

### Input

| Field | What it does |
| --- | --- |
| `keywords` | Full-text search in any language. Any keyword matches. |
| `cpvCodes` | EU procurement categories. `72000000` also matches every IT sub-category. [Find codes](https://simap.ted.europa.eu/cpv). |
| `countries` | Buyer countries: `DE`, `DEU` or `Germany`. |
| `noticeTypes` | `contract` (open calls), `award` (winners) and/or `prior` (upcoming). Default: `contract`. |
| `publishedWithinDays` | Published in the last N days (default 7). |
| `onlyOpenForBids` | Calls for tenders whose bid deadline hasn't passed. |
| `minEstimatedValue` | Minimum estimated value (notice currency, usually EUR). |
| `language` | Preferred language for titles, headlines and links (default English). |
| `customQuery` | Advanced: any extra [TED expert-search](https://ted.europa.eu/en/search/expert-search) condition, ANDed with the rest. |
| `maxResults` | Default 500; `0` means up to 20,000. |
| `onlyNewNotices` / `stateKey` | Output only notices not returned in earlier runs under the same key. |

### Output

One record per notice, always with the same fields. Missing values are `null`.

```json
{
  "id": "ted:667762-2026",
  "publicationNumber": "667762-2026",
  "noticeKind": "contract",
  "noticeType": "cn-standard",
  "procedureType": "open",
  "contractNature": "services",
  "title": "Restructuration et de Construction neuve du lycée Jean Rostand à Mantes-la-Jolie (78)",
  "headline": "France – Technical control services – Restructuration et de Construction neuve du lycée Jean Rostand à Mantes-la-Jolie (78)",
  "originalLanguage": "fra",
  "description": "Mission de contrôle technique pour la restructuration et de construction neuve du lycée Jean Rostand...",
  "buyerName": "Région Ile de France",
  "buyerCity": "SAINT-OUEN-SUR-SEINE",
  "buyerCountry": "FRA",
  "buyerCountryName": "France",
  "placesOfPerformance": ["FR103", "FRA"],
  "cpvMain": "71356100",
  "cpvCodes": ["71356100"],
  "estimatedValue": null,
  "awardedValue": null,
  "lotTitles": ["Restructuration et de Construction neuve du lycée Jean Rostand à Mantes-la-Jolie (78)"],
  "tenderDeadline": "2026-10-30T12:00:00+02:00",
  "publishedAt": "2026-09-29",
  "dispatchedAt": "2026-09-25",
  "noticeVersion": 1,
  "url": "https://ted.europa.eu/en/notice/-/detail/667762-2026",
  "pdfUrl": "https://ted.europa.eu/en/notice/667762-2026/pdf",
  "xmlUrl": "https://ted.europa.eu/en/notice/667762-2026/xml",
  "scrapedAt": "2026-09-29T12:00:00Z"
}
```

- `headline` is TED's own translated summary ("Country – Category – Title"). It's the quickest way to read foreign-language notices.
- `title` and `description` are in your chosen language when the buyer provided one; otherwise they're in the original language, shown in `originalLanguage`.
- `estimatedValue` and `awardedValue` are `{amount, currency}` objects.
- `tenderDeadline` is the earliest bid deadline across lots.

Each run also saves a **`RUN_SUMMARY`** record with the exact TED query used, how many notices matched, and how many were output. You can paste that query into TED's website to check the results.

### Using it from an AI agent (MCP)

This Actor works as a tool in Claude, Cursor and other MCP clients through [Apify's MCP server](https://mcp.apify.com). For example: *"Use EU Tenders to list open cloud-hosting tenders from Nordic countries with a deadline after next week."* Keep `maxResults` small for chat use.

### Pricing

You pay **per notice returned**, with no monthly fee. Searches with no matches cost almost nothing. Set a **maximum charge** on any run and the Actor stops cleanly when it's reached.

### Good to know

- Results are newest first. Only the latest version of each notice is returned.
- Keyword search matches text in any language. Adding CPV codes catches notices written in other languages that your keywords would miss.
- TED publishes new notices every weekday morning (Luxembourg time).

### Data source and reuse

Data comes from TED's official public Search API, provided by the Publications Office of the European Union. Under the [TED legal notice](https://ted.europa.eu/en/legal-notice), notices may be reused, including commercially, with credit given and changes indicated (CC BY 4.0).

**Source:** TED – Tenders Electronic Daily, © European Union. **Changes made:** this Actor selects a subset of each notice's fields, picks one language per field, removes duplicate values, and reformats dates and amounts. The full original notice is always linked in `url`, `pdfUrl` and `xmlUrl`. This Actor is not affiliated with or endorsed by the EU.

### Support

Found a problem or want a field added? Open an issue on the Actor's **Issues** tab.

# Actor input Schema

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

Find notices containing any of these words or phrases anywhere in the notice text, in any language (TED full-text search). For best results also add CPV codes, since many notices are not in English.

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

EU procurement categories (CPV). A code also matches everything under it: 72000000 covers all IT services, 45000000 all construction work. Find codes at https://simap.ted.europa.eu/cpv

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

Countries of the buying organisation: 2- or 3-letter codes or English names, e.g. DE, FRA, Netherlands. Leave empty for all countries.

## `noticeTypes` (type: `array`):

Which kinds of notice to return. Default: calls for tenders only.

## `publishedWithinDays` (type: `integer`):

Only notices published in the last N days. 0 means any date (can be very many results).

## `onlyOpenForBids` (type: `boolean`):

For calls for tenders, keep only those whose bid deadline is today or later. Other notice types are unaffected.

## `minEstimatedValue` (type: `integer`):

Keep notices whose estimated value is at least this amount (in the notice's own currency, usually EUR). Notices without a published estimate are excluded when this is set. 0 means no minimum.

## `customQuery` (type: `string`):

Optional extra condition in TED expert-search syntax, combined with the filters above using AND. Example: procedure-type IN (open). Test queries at https://ted.europa.eu/en/search/expert-search

## `language` (type: `string`):

Language for titles, headlines and notice links when TED has them (TED translates headlines into all EU languages; titles are usually in the buyer's language).

## `maxResults` (type: `integer`):

Stop after this many notices. 0 means up to 20,000. You can also cap cost with the run's maximum charge.

## `onlyNewNotices` (type: `boolean`):

Remember which notices this account already received and output only new ones. Ideal for scheduled daily runs; you pay only for new notices.

## `stateKey` (type: `string`):

Keeps separate 'already seen' lists for different searches. Use a different name for each scheduled search.

## Actor input object example

```json
{
  "keywords": [
    "software"
  ],
  "noticeTypes": [
    "contract"
  ],
  "publishedWithinDays": 7,
  "onlyOpenForBids": false,
  "minEstimatedValue": 0,
  "language": "eng",
  "maxResults": 500,
  "onlyNewNotices": false,
  "stateKey": "default"
}
```

# Actor output Schema

## `notices` (type: `string`):

Every TED notice returned by this run, one record per notice.

## `runSummary` (type: `string`):

The TED query used, how many notices matched and how many were output.

# 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": [
        "software"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("agentready/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 = { "keywords": ["software"] }

# Run the Actor and wait for it to finish
run = client.actor("agentready/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 '{
  "keywords": [
    "software"
  ]
}' |
apify call agentready/eu-tenders-ted --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,agentready/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/1qharsjkdoXBRnJBR/builds/ScvKgf03DRzbPeY4H/openapi.json
