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

EU public tenders from TED (Tenders Electronic Daily) as clean JSON. Filter by keywords, CPV codes, countries, NUTS regions, notice type, dates and open deadlines. Buyer, values, deadlines, CPV labels and document links per notice. Official TED API, no browser.

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

## Pricing

from $2.10 / 1,000 notice founds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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 Scraper (TED): Public Procurement by CPV, Country and Region

Find open public tenders from all EU and EEA countries in TED (Tenders Electronic Daily), the official journal for EU public procurement. Filter by industry (CPV codes or keywords), country, NUTS region, notice type, publication date and open deadline. Every notice comes back as one flat JSON row with the buyer, the estimated value, the deadline and direct links to the notice and the tender documents.

The actor uses the official TED Search API (no browser, no login), so runs are fast and cheap.

### What you get per notice

| field | meaning |
|---|---|
| `publicationNumber` | TED notice ID, e.g. 739394-2026 |
| `noticeType`, `noticeTypeLabel`, `formType` | e.g. cn-standard, "Contract or concession notice, standard regime", competition |
| `title` | procedure title (preferred language if the buyer provided it, else original) |
| `noticeTitle` | TED headline in your language: country, main CPV, title |
| `description` | short description of the procedure or first lot |
| `buyerName`, `buyerCity`, `buyerPostCode`, `buyerCountry`, `buyerNuts` | contracting authority |
| `placeOfPerformance`, `placeOfPerformanceCountries` | NUTS codes and countries where the work is done |
| `mainCpv`, `cpvCodes` | CPV codes with official English labels; `mainCpvLabelLocalized` in your language |
| `estimatedValue`, `currency` | estimated contract value, when published |
| `awardedValue`, `awardedCurrency` | total value of award notices |
| `submissionDeadline`, `deadlines` | earliest open deadline for tenders or requests to participate (ISO 8601 with offset) and all deadlines |
| `procedureType`, `procedureTypeLabel`, `contractNature`, `lotCount` | open, restricted, negotiated...; services, works, supplies |
| `publicationDate`, `dispatchDate`, `officialLanguages` | |
| `tedUrl`, `pdfUrl`, `xmlUrl` | notice on ted.europa.eu in your language |
| `documentsUrl`, `submissionUrl`, `buyerProfileUrl`, `buyerWebsite` | where to download the tender documents and submit |

### Inputs

- **Keywords**: words or phrases in any EU language, with stemming. By default only titles and descriptions are searched, which avoids hits in boilerplate text.
- **CPV codes**: industry codes. TED includes the whole branch below a code, e.g. 90910000 finds all cleaning services. Turn off sub-codes to keep exact codes only.
- **Countries** (DE or DEU) and **NUTS regions** (DE2 = Bavaria), matched against the place of performance, the buyer address or both.
- **Notice types**: contract notices (default), prior information, award notices, direct award pre-announcements, modifications.
- **Dates**: last N days (default 30) or a from/to range, plus **Only open deadlines** (default on).
- **Output language**: titles, descriptions and links in one of the 24 EU languages with fallback to the original language.
- **Expert query**: any TED expert search query for power users, combined with the filters above.

### Example: cleaning tenders in Germany

```json
{ "cpvCodes": ["90910000"], "countries": ["DE"], "lastDays": 30, "language": "de" }
```

### Example: locksmith tenders across Europe

```json
{ "cpvCodes": ["98395000", "44521000"], "openDeadlineOnly": true, "lastDays": 90 }
```

### Pricing

You pay per notice delivered. Errors and filtered-out notices are not charged.

### Limits and notes

- Results are paged with the TED API iteration mode, so there is no 15,000 notice cap; `maxResults` is your safety limit.
- Requests are paced well below the TED fair usage limit (700 requests per minute) and retried with backoff on rate limits or server errors.
- Values, deadlines and links are only as complete as the buyer filled them in. Older notices (before the eForms switch in 2023) have fewer fields.
- TED data is published by the Publications Office of the European Union and may be reused for commercial and non-commercial purposes (Commission Decision 2011/833/EU). Source: TED, ted.europa.eu.

Not affiliated with the Publications Office of the European Union or TED.

### FAQ

**Do I need a TED account, an API key or a proxy?** No. The Actor calls the public TED Search API without login. The proxy is off by default and only needed if your network is blocked.

**What am I charged for?** One event per notice delivered. Error items and notices removed by the post-filters (exact CPV codes, deadline already passed) are not charged.

**Why do I get fewer notices than TED reports?** By default only notices with a deadline still in the future are kept (`openDeadlineOnly`), and `maxResults` (default 200, maximum 50,000) stops the run. Turn off sub-codes and only exact CPV codes are kept. TED's total count is written to the `STATS` record in the key-value store.

**What happens when the TED API fails?** Rate limits (429), timeouts (408) and server errors are retried up to 6 times with backoff. If the API still fails, or answers with a non-retryable error such as an invalid query, the run pushes one item with `error` and the `query` that was sent. Notices delivered before that stay in the dataset. Invalid input produces one item with `error` and the `input`.

**Does it include award notices and prior information notices?** Only if you select them in `noticeTypes` and turn off `openDeadlineOnly`, because most of these notices have no deadline. The default is contract notices (`competition`). Award values are in `awardedValue`, estimated values in `estimatedValue`.

### Use with AI agents (MCP)

This Actor works as a tool for Claude, ChatGPT, Cursor and other MCP clients through the [Apify MCP server](https://docs.apify.com/platform/integrations/mcp). Add only this Actor:

```
https://mcp.apify.com?tools=webify-lab/eu-tenders-ted
```

On first use the server signs you in with OAuth. Alternatively send the header `Authorization: Bearer <APIFY_TOKEN>`. Agents on the default Apify MCP setup can also find this Actor with `search-actors` and run it with `call-actor`. Pricing is the same as in Apify Console: you pay per result.

# Actor input Schema

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

Words or phrases, matched with TED stemming in any EU language. A notice matches if it contains at least one entry. Multi-word entries are searched as exact phrases.

## `keywordScope` (type: `string`):

Full text also matches boilerplate such as buyer addresses and legal text, which brings many false positives.

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

8-digit Common Procurement Vocabulary codes, e.g. 90910000 (cleaning services), 98395000 (locksmith services), 72413000 (website design), 60100000 (road transport). A check digit like -5 is ignored.

## `includeCpvSubCodes` (type: `boolean`):

TED matches the whole CPV branch (90910000 also finds 90911200 building cleaning). Turn off to keep only notices that list exactly the given codes.

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

ISO country codes, 2 or 3 letters (DE or DEU, AT, FR, EL for Greece).

## `nutsCodes` (type: `array`):

NUTS codes of any level, sub-regions are included: DE2 (Bavaria), DE21 (Upper Bavaria), DE212 (Munich city), DE7 (Hesse).

## `locationMatch` (type: `string`):

Which location the country and NUTS filters are matched against.

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

TED form types. Empty means all types.

## `lastDays` (type: `integer`):

0 turns it off and uses the date range below.

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

YYYY-MM-DD. Used when Last N days is 0.

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

YYYY-MM-DD, inclusive. Used when Last N days is 0.

## `openDeadlineOnly` (type: `boolean`):

Keep only notices whose deadline for tenders or requests to participate is still in the future. Notices without a deadline (awards, most prior information notices) are dropped when this is on.

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

Preferred language for titles, descriptions, buyer names and links. Falls back to the notice's original language, then English.

## `expertQuery` (type: `string`):

Raw TED expert query, e.g. classification-cpv IN (98395000) AND buyer-country = AUT. Combined with AND with the filters above (leave them empty to use only this). A SORT BY clause is removed because results are always paged by publication number for completeness.

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

Safety limit per run.

## `maxDescriptionLength` (type: `integer`):

Characters of the short description to keep, 0 for no description.

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

Not needed: the TED API is public. Only set it if your network is blocked.

## Actor input object example

```json
{
  "keywords": [
    "Gebäudereinigung",
    "Unterhaltsreinigung"
  ],
  "keywordScope": "title-description",
  "cpvCodes": [
    "90910000"
  ],
  "includeCpvSubCodes": true,
  "countries": [
    "DE"
  ],
  "locationMatch": "either",
  "noticeTypes": [
    "competition"
  ],
  "lastDays": 30,
  "openDeadlineOnly": true,
  "language": "en",
  "maxResults": 200,
  "maxDescriptionLength": 1000,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `results` (type: `string`):

One item per notice: publicationNumber, noticeType, formType, title, noticeTitle, description, buyerName, buyerCountry, buyerCity, buyerPostCode, buyerNuts, placeOfPerformance, mainCpv, cpvCodes (code and label), estimatedValue, currency, awardedValue, submissionDeadline, procedureType, contractNature, lotCount, publicationDate, tedUrl, pdfUrl, xmlUrl, documentsUrl, submissionUrl, buyerProfileUrl, buyerWebsite; or error.

# 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": [
        "Gebäudereinigung",
        "Unterhaltsreinigung"
    ],
    "cpvCodes": [
        "90910000"
    ],
    "countries": [
        "DE"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("webify-lab/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": [
        "Gebäudereinigung",
        "Unterhaltsreinigung",
    ],
    "cpvCodes": ["90910000"],
    "countries": ["DE"],
}

# Run the Actor and wait for it to finish
run = client.actor("webify-lab/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": [
    "Gebäudereinigung",
    "Unterhaltsreinigung"
  ],
  "cpvCodes": [
    "90910000"
  ],
  "countries": [
    "DE"
  ]
}' |
apify call webify-lab/eu-tenders-ted --silent --output-dataset

```

## MCP server setup

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