# EU TED Tenders: Public Procurement by CPV, Country (`itayozer9/eu-ted-tenders`) Actor

EU public tenders from the official TED search API: calls for competition, prior information and award notices from 30+ countries. Filter by keyword, buyer country, CPV code, deadline and estimated value. Clean JSON with deadline, buyer, value, CPV and links. Only-new mode, contacts removed.

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

## Pricing

from $1.00 / 1,000 notice returneds

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 TED Tenders: Public Procurement by CPV, Country

Get European public tenders as clean JSON: every call for competition published on TED (Tenders Electronic Daily, the EU's official procurement journal) with its deadline, buyer, estimated value, CPV codes and links. Filter by buyer country, CPV code, keyword, deadline and value, and schedule it with only-new mode to receive each tender once.

The data comes from TED's official Search API, which the EU Publications Office runs for data reusers. No scraping, no logins, no blocked pages and no proxy costs. TED notices may be reused for commercial purposes.

Built for bid managers, sales teams selling to the public sector, tender alert services, consultants and anyone feeding EU procurement data into a CRM, a spreadsheet or an AI agent.

### What you get

For every notice:

- **Title** in the buyer's language, plus TED's **English heading** (country, subject and title)
- **Tender deadline** (and the deadline for requests to participate in restricted procedures)
- **Buyer**: contracting authority name, city, country and website
- **Estimated value** and currency, when the buyer published one (about half of all notices)
- **CPV codes**: the main code and all codes in the notice
- **Procedure**: notice type, procedure type (open, restricted, negotiated...), works, supplies or services
- **Place of performance** as NUTS region codes
- **Links**: the notice on TED, the official PDF, the procurement documents and the submission page
- **Description** of the procedure (length you choose)

Contact persons, emails and phone numbers are never returned.

### Input

Every field is optional. With no input you get the newest calls for competition from all countries.

| Field | Example | Notes |
|---|---|---|
| `keywords` | `software, logiciel` | Words to find anywhere in the full notice (all lots, as TED indexes it). Words in one part must all appear; commas separate alternatives. Notices are in the buyer's language, so add local words |
| `countries` | `["DE", "FR", "PL"]` | Buyer country, 2 or 3-letter codes. EU, EEA, Switzerland, UK (older notices) and candidate countries |
| `cpvCodes` | `["72", "48000000"]` | A short code matches everything under it: `72` is IT services, `45` construction, `33` medical equipment |
| `noticeTypes` | `["competition"]` | `competition` (default: open calls for tenders), `planning`, `consultation`, `result` (awards), `direct-award`, `modification` |
| `publishedWithinDays` | `7` | Only notices published in the last N days |
| `openOnly` | `true` | Only notices whose deadline is today or later |
| `deadlineWithinDays` | `14` | Only notices that close in the next N days |
| `minEstimatedValue` / `maxEstimatedValue` | `1000000` | Estimated total value range, in `valueCurrency` |
| `valueCurrency` | `EUR` | Currency the value range applies to (no conversion), or `ANY` |
| `onlyNew` | `true` | Skip notices this search already returned in earlier runs |
| `descriptionMaxChars` | `1000` | 0 leaves the description out |
| `maxItems` | `100` | 1 to 10,000, newest first. You pay only for notices returned |

#### Examples

IT tenders from Germany and Austria that close in the next 30 days:

```json
{
    "countries": ["DE", "AT"],
    "cpvCodes": ["72", "48"],
    "deadlineWithinDays": 30,
    "maxItems": 200
}
```

Construction contracts worth 5 million euros or more, anywhere in Europe, still open:

```json
{
    "cpvCodes": ["45"],
    "minEstimatedValue": 5000000,
    "openOnly": true
}
```

Daily alert for software tenders in France, Belgium and Poland (schedule it once a day):

```json
{
    "keywords": "software, logiciel, oprogramowanie",
    "countries": ["FR", "BE", "PL"],
    "publishedWithinDays": 3,
    "onlyNew": true
}
```

### Output example

One dataset item per notice:

```json
{
    "noticeId": "753103-2026",
    "url": "https://ted.europa.eu/en/notice/-/detail/753103-2026",
    "pdfUrl": "https://ted.europa.eu/en/notice/753103-2026/pdf",
    "title": "UEM OSS/MPC",
    "titleEnglish": "Germany - Software package and information systems - UEM OSS/MPC",
    "language": "deu",
    "noticeType": "cn-standard",
    "formType": "competition",
    "procedureType": "open",
    "contractNature": "supplies",
    "publishedDate": "2026-10-30",
    "tenderDeadline": "2026-11-17",
    "requestDeadline": null,
    "buyerName": "Dataport AöR",
    "buyerCity": "Altenholz",
    "buyerCountry": "DEU",
    "buyerWebsite": "https://www.dataport.de",
    "cpvMain": "48000000",
    "cpvCodes": ["48000000", "72267000"],
    "estimatedValue": null,
    "currency": null,
    "placeOfPerformance": ["DEF0B", "DEU"],
    "documentsUrl": "https://fbhh-evergabe.web.hamburg.de/evergabe.bieter/api/supplier/external/deeplink/subproject/45f3564b-d660-45cb-8b84-4e3fb40d1337",
    "submissionUrl": "https://fbhh-evergabe.web.hamburg.de/evergabe.bieter/api/supplier/external/deeplink/subproject/45f3564b-d660-45cb-8b84-4e3fb40d1337",
    "description": "Beschaffung von Workspace One OSS Lizenzen",
    "readAt": "2026-10-31T18:50:10.438Z"
}
```

Fields TED does not have for a notice are `null`, never guessed. Dates are `YYYY-MM-DD` in the buyer's time zone; open the notice for the exact hour.

### Pricing

You pay per notice returned, nothing per run beyond Apify's standard start fee:

| Event | Price | When |
|---|---|---|
| Notice returned | $0.001 | Every notice in your dataset |

1,000 notices cost $1. A daily alert that finds 30 new tenders costs about $0.90 a month.

The actor reads your run's maximum charge before it calls TED and stops at the number of notices that covers, so a run never goes over the limit you set. Runs that find nothing, and runs that fail, return no notices and cost nothing beyond the start fee.

### Limits

- Up to 10,000 notices per run, newest first. A run reads at most 10,000 notices from TED (only-new and deadline filters may skip some of them), so narrow the filters to reach further back.
- TED publishes on working days (about 1,500 calls for competition a day). Notices appear here as soon as TED publishes them.
- Titles and descriptions are in the buyer's language; machine translation is not included. The English heading always names the country and the CPV subject.
- The value filter compares numbers in one currency; there is no currency conversion.
- Award winners and contract amounts of result notices are not included.
- Speed: about 6 notices a second (1,000 notices take about 3 minutes).

### FAQ

**Where does the data come from?**
From TED's official Search API (api.ted.europa.eu), run by the Publications Office of the European Union. Its legal notice says the procurement notices "can be freely reused, for commercial or non-commercial purposes".

**How do I get only open tenders?**
Leave `noticeTypes` empty (calls for competition) and set `openOnly` or `deadlineWithinDays`.

**Which CPV code should I use?**
Use the first 2 to 4 digits for a broad sector: `72` IT services, `48` software packages, `45` construction work, `33` medical equipment, `79` business services, `90` environmental services. The full list is on the EU's SIMAP site.

**Why did I get fewer notices than `maxItems`?**
Either TED had fewer notices for your filters, or your run's maximum charge covered fewer notices.

**Can I schedule it or call it from an AI agent?**
Yes. It runs with limited permissions, so it needs no access to your other Apify data, and it works from schedules, the API and MCP clients. With `onlyNew` each scheduled run returns only notices it has not returned before.

**Is there personal data in the results?**
No contact fields are requested from TED. Email addresses, phone numbers and names next to them are removed from titles and descriptions by pattern matching, which covers the common formats.

**Something broke or a field is missing. What do I do?**
Open an issue on the Issues tab with your run link. Issues are answered within a few days.

# Actor input Schema

## `keywords` (type: `string`):

Words to find anywhere in the notice. Titles and descriptions are in the buyer's own language, so add local words for best recall: "software, logiciel, oprogramowanie". Words in one part must all appear; commas separate alternatives: "cloud, cybersecurity" finds either. Leave empty for every notice.

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

Country of the contracting authority, as 2 or 3-letter codes: DE or DEU, FR, PL, IT, ES, NL, SE, NO, CH... Empty means every country that publishes on TED.

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

Common Procurement Vocabulary codes. A short code matches everything under it: "72" (IT services) matches 72000000 and all its children, "45" is construction work, "33" medical equipment.

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

Which kinds of notices to return. Empty means calls for competition only (open tenders).

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

Only notices published in the last N days. TED publishes every working day, about 1,500 calls for competition a day.

## `openOnly` (type: `boolean`):

Only notices whose tender (or request to participate) deadline is today or later.

## `deadlineWithinDays` (type: `integer`):

Only notices that close in the next N days (implies still open).

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

Only notices whose estimated total value is at least this, in the currency below. Notices without an estimated value (about half) are left out when this is set.

## `maxEstimatedValue` (type: `integer`):

Only notices whose estimated total value is at most this, in the currency below.

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

Currency the value filters apply to (no conversion): EUR, SEK, PLN, CZK, RON, NOK, DKK... or ANY to compare raw numbers across currencies.

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

Skip notices this search already returned in earlier runs (remembered per filter set in your own account). Use it with a schedule to get each tender once.

## `descriptionMaxChars` (type: `integer`):

Cut the description to this many characters (0 leaves it out). TED descriptions run up to about 6,000 characters.

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

Most notices to return (1 to 10,000), newest first. You pay only for notices returned.

## Actor input object example

```json
{
  "countries": [
    "DE"
  ],
  "cpvCodes": [
    "72"
  ],
  "publishedWithinDays": 7,
  "openOnly": false,
  "valueCurrency": "EUR",
  "onlyNew": false,
  "descriptionMaxChars": 1000,
  "maxItems": 20
}
```

# Actor output Schema

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

One item per TED notice, newest published first.

# 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 = {
    "countries": [
        "DE"
    ],
    "cpvCodes": [
        "72"
    ],
    "publishedWithinDays": 7,
    "maxItems": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("itayozer9/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 = {
    "countries": ["DE"],
    "cpvCodes": ["72"],
    "publishedWithinDays": 7,
    "maxItems": 20,
}

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

```

## MCP server setup

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