# TED EU Tenders API: Notices, CPV, Buyers, Deadlines (`actose/ted-eu-tenders`) Actor

EU public tenders from TED (official API): title in your language, buyer, country, CPV, deadline, estimated and awarded value in EUR, winners, PDF link. Filter by country, CPV, keyword, notice type, dates, value. onlyNew alerts. No API key, no login. MCP-ready. Pay per result. $1 per 1,000 notices

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

## Pricing

from $0.85 / 1,000 ted notices

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

## TED EU Tenders API: European Public Procurement Notices

**$1 per 1,000 notices. You pay only for notices delivered. Errors and empty searches cost nothing.**

This actor searches **TED (Tenders Electronic Daily)**, the official EU database of public procurement notices (the "S" series of the Official Journal of the EU). It returns each notice as clean JSON: title **in the language you choose**, buyer, country, CPV codes, tender deadline, estimated and awarded value (also converted to EUR), lots, winners and direct links (HTML, PDF, XML).

It reads the **official TED Search API v3** (`api.ted.europa.eu`). It does not scrape HTML, so it keeps working when the website changes. No API key, no login, no proxy.

- Filter by **country** (buyer or place of performance), **CPV codes** (hierarchical), **keywords** (full text), **notice type** (calls for tenders, awards, prior information, corrigenda…), **publication dates**, **tender deadline**, **value in EUR**
- **Choose the language** of the titles: all 24 EU languages
- **onlyNew** mode for daily or hourly alerts: each run returns only the notices you have not received yet
- **LLM-ready**: every notice includes a `markdown` field you can drop into a prompt or a RAG index
- **MCP-ready** for Claude, Cursor, ChatGPT and other AI agents

### How much does it cost?

You pay one **`notice`** event per notice written to the dataset: **$0.001 per notice**.

| Run | Notices | Price |
|---|---|---|
| Daily alert, one country + one CPV | ~20 | $0.02 |
| Weekly market watch, 5 countries | 500 | $0.50 |
| Bulk export for analysis | 1,000 | **$1.00** |
| Annual dataset of one sector | 50,000 | $50 |

There is no monthly rental. Nothing is charged for errors, duplicates, notices dropped by the value filter, or searches with no result. If you set a maximum charge for a run, the actor stops cleanly when the budget is reached.

### Input example

```json
{
  "countries": ["FR"],
  "cpvCodes": ["72000000"],
  "noticeTypes": ["competition"],
  "language": "fr",
  "publishedWithinDays": 7,
  "onlyOpen": true,
  "maxResults": 50
}
```

| Field | Description |
|---|---|
| `countries` | ISO codes (`FR`, `DEU`) or English names. OR between countries |
| `countryField` | `buyer` (default) or `placeOfPerformance` |
| `cpvCodes` | 8-digit CPV codes. A parent code (`72000000`) includes all its sub-codes |
| `keywords`, `keywordsMatch`, `excludeKeywords` | Full-text search, any/all |
| `noticeTypes` | `competition` (calls for tenders), `result` (awards), `planning` (prior information), `change` (corrigenda), `dir-awa-pre`, `cont-modif`, or exact eForms subtypes (`cn-standard`, `can-standard`, `pin-only`…) |
| `language` | `en`, `fr`, `de`, `es`, `it`, `pl`… or `original` |
| `publishedWithinDays`, `publishedFrom`, `publishedTo` | Publication date (YYYY-MM-DD or `7 days`) |
| `deadlineFrom`, `deadlineTo`, `onlyOpen` | Tender submission deadline |
| `minValueEur`, `maxValueEur`, `includeNoValue` | Value range in EUR (estimated value, or awarded value for awards) |
| `maxResults` | Maximum notices, newest first (default 100) |
| `onlyNew` | Return only notices not delivered by a previous run with the same filters |
| `scope` | `ALL`, `ACTIVE` or `LATEST` (latest OJ S issue) |
| `expertQuery` | Optional raw TED expert-search clause, added with AND |

### Output example

```json
{
  "publicationNumber": "612345-2026",
  "url": "https://ted.europa.eu/fr/notice/-/detail/612345-2026",
  "pdfUrl": "https://ted.europa.eu/fr/notice/612345-2026/pdf",
  "xmlUrl": "https://ted.europa.eu/en/notice/612345-2026/xml",
  "title": "France – Services de programmation de logiciels – Maintenance et évolution du système d'information RH",
  "originalTitle": "Maintenance et évolution du système d'information RH",
  "description": "Le présent accord-cadre a pour objet la tierce maintenance applicative…",
  "language": "fra",
  "officialLanguages": ["fra"],
  "noticeType": "cn-standard",
  "formType": "competition",
  "procedureType": "open",
  "contractNature": "services",
  "publicationDate": "2026-10-16",
  "deadline": "2026-11-20",
  "deadlineTime": "12:00:00+01:00",
  "deadlineType": "tender",
  "isOpen": true,
  "buyerName": "Région Occitanie",
  "buyerCountry": "FRA",
  "buyerCity": "Toulouse",
  "buyerEmail": "marches@example.fr",
  "mainCpvCode": "72262000",
  "cpvCodes": ["72262000", "72267000"],
  "placeOfPerformance": ["FRJ23"],
  "estimatedValue": 1800000,
  "estimatedValueCurrency": "EUR",
  "estimatedValueEur": 1800000,
  "awardedValue": null,
  "lotsCount": 2,
  "lotTitles": ["Lot 1 – TMA", "Lot 2 – Évolutions"],
  "winners": [],
  "documentsUrl": "https://marches.example.fr/dce/12345",
  "submissionUrl": "https://marches.example.fr/depot/12345",
  "procedureId": "3f1c…",
  "markdown": "## TED 612345-2026: France – Services de programmation…\n- **Buyer:** Région Occitanie, Toulouse, FRA\n…",
  "scrapedAt": "2026-10-18T07:00:04+00:00"
}
```

Fields that a notice does not publish are `null` or an empty list. The **Overview** tab of the dataset shows a table: notice, title, buyer, country, type, dates, CPV, values, winners, link.

### Use cases

#### 1. Daily IT tender alert for a bid manager (France)

A bid manager at an IT services firm wants every new French call for tenders in IT services, in French, in Google Sheets each morning.

Input (scheduled every day at 7:00):

```json
{"countries": ["FR"], "cpvCodes": ["72000000", "48000000"], "noticeTypes": ["competition"], "language": "fr", "onlyOpen": true, "onlyNew": true, "maxResults": 200}
```

Output extract:

```json
[{"publicationNumber": "612345-2026", "title": "France – Services de programmation de logiciels – …", "buyerName": "Région Occitanie", "deadline": "2026-11-20", "estimatedValueEur": 1800000, "url": "https://ted.europa.eu/fr/notice/-/detail/612345-2026"}]
```

Next: about 15 to 40 new notices a day (≈ $0.03/day, under $1/month) go into a Google Sheet through the Apify integration. The team marks go / no-go, and the `deadline` column feeds the bid calendar.

#### 2. Competitive intelligence on contract awards (DACH region)

A market analyst follows who wins medical equipment contracts above €1M in Germany, Austria and Switzerland.

Input (weekly):

```json
{"countries": ["DE", "AT", "CH"], "cpvCodes": ["33100000"], "noticeTypes": ["result"], "minValueEur": 1000000, "publishedWithinDays": 7, "language": "en", "maxResults": 500}
```

Output extract:

```json
[{"title": "Germany – Medical equipments – CT scanner for University Hospital", "buyerName": "Universitätsklinikum …", "awardedValue": 2350000, "awardedValueCurrency": "EUR", "winners": ["Siemens Healthcare GmbH"], "publicationDate": "2026-10-14"}]
```

Next: the weekly dataset (≈ 60 awards, $0.06) is loaded into a BI tool to compute market share per supplier and average contract value per buyer.

#### 3. AI agent that answers "which tenders fit my company?"

A consulting firm's AI assistant (Claude via MCP) receives a client profile and searches open EU tenders in several languages.

Input sent by the agent:

```json
{"keywords": ["cybersecurity", "cybersécurité", "Cybersicherheit"], "countries": ["FR", "BE", "LU", "DE"], "onlyOpen": true, "language": "en", "maxResults": 30}
```

Output used by the agent: the `markdown` field of each notice (title, buyer, deadline, CPV, value, link). The model ranks the 30 notices against the profile and writes a shortlist with deadlines, for $0.03 per question.

#### 4. Lead generation for subcontractors (Poland, construction)

A construction subcontractor wants the winners of large Polish works contracts, to offer them its services.

```json
{"countries": ["PL"], "noticeTypes": ["result"], "expertQuery": "contract-nature IN (works)", "minValueEur": 5000000, "publishedWithinDays": 30, "maxResults": 300}
```

Values in PLN are converted with an approximate rate in `awardedValueEur`, and the original amount stays in `awardedValue`. The `winners` list becomes the call list for the month.

### Call it from the API

**Python**

```python
from apify_client import ApifyClient

client = ApifyClient("<APIFY_TOKEN>")
run = client.actor("<username>/ted-eu-tenders").call(run_input={
    "countries": ["FR"], "cpvCodes": ["72000000"], "noticeTypes": ["competition"],
    "language": "fr", "publishedWithinDays": 7, "maxResults": 100,
})
for notice in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(notice["publicationNumber"], notice["deadline"], notice["title"])
```

**JavaScript**

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

const client = new ApifyClient({ token: '<APIFY_TOKEN>' });
const run = await client.actor('<username>/ted-eu-tenders').call({
    countries: ['DE'], cpvCodes: ['45000000'], noticeTypes: ['competition'], onlyOpen: true, maxResults: 100,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items.map((n) => `${n.publicationNumber} ${n.deadline} ${n.title}`));
```

**HTTP (one call, returns the items)**

```
POST https://api.apify.com/v2/acts/<username>~ted-eu-tenders/run-sync-get-dataset-items?token=<APIFY_TOKEN>
{"countries": ["ES"], "cpvCodes": ["72000000"], "maxResults": 20}
```

### Automation (Make, n8n, Zapier, Google Sheets)

- **Make / Zapier**: use the Apify app, action "Run an Actor" with the input JSON above, then "Get dataset items". Map `title`, `buyerName`, `deadline`, `estimatedValueEur` and `url` to a Google Sheets row, a Slack message or a CRM deal.
- **n8n**: a *Schedule Trigger* (every morning) → *Apify* node "Run actor and get dataset" with `"onlyNew": true` → *IF* `estimatedValueEur > 100000` → *Gmail* or *Microsoft Teams* message. Because of `onlyNew`, each notice is sent only once.
- **Google Sheets**: Apify's Google Sheets integration appends each run's dataset to a sheet. Schedule the actor in Apify Console (Schedules → daily).
- **Webhooks**: trigger your own endpoint when a run succeeds and fetch `.../datasets/<id>/items?format=csv`.

### Use with AI agents (MCP)

The actor works with the Apify MCP server (`https://mcp.apify.com`), so Claude, Cursor, ChatGPT and other agents can call it as a tool. Typical prompts:

- "Find open IT tenders in France and Belgium published this week, in French."
- "Who won hospital equipment contracts above €1M in Germany last month?"

Each notice comes with a compact `markdown` summary, which keeps the agent's context small.

### FAQ

**Is this the official data?** Yes. It reads the public TED Search API of the Publications Office of the EU, the same data as ted.europa.eu. TED data is free to reuse with attribution.

**Which notices are on TED?** Procurement above the EU thresholds in the 27 EU member states, plus EEA countries, Switzerland and EU institutions, and some below-threshold notices that buyers publish voluntarily. Purely national, small tenders (for example French MAPA notices that appear only on BOAMP) are not on TED. Use a national source for those.

**Which language do I get?** Notice titles exist in all 24 EU languages. Descriptions, buyer names and lot titles are published only in the notice's own language(s): when your language is missing, the actor returns the original text and shows its language in `descriptionLanguage`.

**How does onlyNew work?** The actor remembers the notices it delivered, per set of filters, in a named key-value store (`ted-eu-tenders-state`). The next run returns only notices it has not delivered yet, and looks back 7 days to catch notices that were indexed late. When there is nothing new, nothing is charged.

**Does the CPV filter include sub-codes?** Yes. TED's CPV search is hierarchical: `72000000` also returns `72262000`, and so on. You can also type a shorter prefix like `72`.

**Why is the value often empty?** Many notices do not publish an estimated value. With a value filter, those notices are skipped unless you turn on `includeNoValue`.

**How fast is it?** About 250 notices per request: 1,000 notices take under a minute.

### Limits

- The data is exactly what TED publishes. Missing fields stay `null`, and the actor does not guess them.
- EUR conversion uses fixed approximate rates. It is good for filtering and ranking, not for accounting. The original amount and currency are always included.
- Lot-level fields (lot titles, lot deadlines, document URLs) come as lists. When a notice has several lots, `deadline` is the earliest deadline still in the future, and `deadlines` holds all of them.
- Full-text keywords follow TED's own search engine (word stems, all languages of the notice).
- Notices published before eForms (2023 and earlier) have fewer structured fields.
- Fair use: the actor spaces its requests and retries on rate limits. If TED ever refuses the server IP, it switches automatically to a proxy (still at no extra cost for you). Very large exports (100,000+ notices) take longer.

# Actor input Schema

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

Buyer countries, as ISO codes ("FR", "DE", "ESP") or English names ("Poland"). Empty = all countries. Several countries are combined with OR.

## `countryField` (type: `string`):

Match the country of the buyer (default) or the place where the contract is performed.

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

Common Procurement Vocabulary codes (8 digits, e.g. "72000000" IT services). A parent code also returns its sub-codes. Several codes are combined with OR.

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

Full-text search in the notice (all languages of the notice). Several keywords are combined with OR unless 'Keywords match' is set to all.

## `keywordsMatch` (type: `string`):

Return notices containing any of the keywords, or all of them.

## `excludeKeywords` (type: `array`):

Drop notices containing any of these words.

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

competition (calls for tenders), result (contract awards), planning (prior information), change (corrigenda), dir-awa-pre (direct award pre-notification), cont-modif (contract modification), or an exact eForms subtype such as cn-standard, can-standard, pin-only. Empty = all types.

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

Language of the title, buyer name and description (2-letter EU code). Titles exist in every EU language; other texts fall back to the notice's own language when no translation exists. 'original' = the language of the notice.

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

Shortcut for 'Published from'. Ignored when 'Published from' is set.

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

Earliest publication date: YYYY-MM-DD or relative ("7 days", "2 weeks").

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

Latest publication date: YYYY-MM-DD or relative.

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

Only notices whose tender submission deadline is on or after this date (YYYY-MM-DD or "+7 days").

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

Only notices whose tender submission deadline is on or before this date (YYYY-MM-DD or "+1 month").

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

Keep only notices whose tender deadline is today or later.

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

Minimum estimated (or awarded) value in euros. Non-euro amounts are converted with an approximate rate. Notices without any value are dropped unless 'Keep notices without value' is on.

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

Maximum estimated (or awarded) value in euros.

## `includeNoValue` (type: `boolean`):

With a value filter, also keep notices that publish no value (more than half of TED notices).

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

Maximum number of notices to return (newest first). Each notice is one paid event.

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

For scheduled runs: remembers the notices already delivered for these filters (in a named key-value store) and returns only new ones. Nothing is charged when there is nothing new.

## `scope` (type: `string`):

ALL = full archive, ACTIVE = notices still active on TED, LATEST = only the latest Official Journal issue.

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

Optional extra TED expert-search clause added with AND, e.g. procedure-type IN (open) or buyer-city=Lyon. See the TED expert search help.

## Actor input object example

```json
{
  "countries": [
    "FR"
  ],
  "countryField": "buyer",
  "cpvCodes": [
    "72000000"
  ],
  "keywordsMatch": "any",
  "noticeTypes": [
    "competition"
  ],
  "language": "en",
  "publishedWithinDays": 30,
  "onlyOpen": false,
  "includeNoValue": false,
  "maxResults": 50,
  "onlyNew": false,
  "scope": "ALL"
}
```

# Actor output Schema

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

One item per TED notice (overview table).

## `noticesJson` (type: `string`):

Every field of every notice, including lots, winners, links and the Markdown summary.

# 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": [
        "FR"
    ],
    "cpvCodes": [
        "72000000"
    ],
    "noticeTypes": [
        "competition"
    ],
    "publishedWithinDays": 30,
    "maxResults": 50
};

// Run the Actor and wait for it to finish
const run = await client.actor("actose/ted-eu-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": ["FR"],
    "cpvCodes": ["72000000"],
    "noticeTypes": ["competition"],
    "publishedWithinDays": 30,
    "maxResults": 50,
}

# Run the Actor and wait for it to finish
run = client.actor("actose/ted-eu-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": [
    "FR"
  ],
  "cpvCodes": [
    "72000000"
  ],
  "noticeTypes": [
    "competition"
  ],
  "publishedWithinDays": 30,
  "maxResults": 50
}' |
apify call actose/ted-eu-tenders --silent --output-dataset

```

## MCP server setup

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