# EU Tenders (TED): Search & New-Tender Alerts (`stego-bot/ted-tenders`) Actor

Search EU public tenders published on TED, the EU's official journal. Filter by keyword, CPV, country, value and open deadlines, or get only new tenders daily. Clean rows, official links.

- **URL**: https://apify.com/stego-bot/ted-tenders.md
- **Developed by:** [Stego](https://apify.com/stego-bot) (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.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 Tenders (TED): Search & New-Tender Alerts

Search EU public tenders published on TED, the EU's official journal. Filter by keyword, CPV, country, value and open deadlines, or get only new tenders daily. Clean rows, official links.

TED (Tenders Electronic Daily) carries the tenders that must be published EU-wide – mostly those above the EU value thresholds – plus notices buyers publish voluntarily, from the 27 EU countries, Norway, Iceland, Switzerland and candidate countries. Smaller national tenders below the thresholds are often only on national portals and are not covered. You get clean, English-first rows: title, buyer, countries, CPV codes, deadline, estimated value, award winners and links to the official notice, PDF and XML.

Run it once for research, or schedule it daily with **Only new since last run** to get just the tenders you haven't seen yet.

Data comes from the official, free and anonymous **TED Search API v3** of the EU Publications Office. No login, no proxy, no scraping of web pages.

### What you can filter on

| Input | Example | Notes |
|---|---|---|
| Keywords | `software`, `cloud hosting` | Full-text search over the whole notice (all languages TED holds). `any` or `all` matching. |
| Exclude keywords | `hardware` | Notices containing these are dropped. |
| Notice stages | `competition` (open tenders, default), `planning` (prior info), `result` (awards), `cont-modif`, `dir-awa-pre`, `consultation` | |
| CPV codes | `72` (all IT services), `45233000` | Hierarchical: `72` matches every 72xxxxxx code. Trailing zeros are treated as a prefix (`72200000` = `722*`). |
| Buyer countries | `DE`, `FR`, `PL` (ISO2 or ISO3) | |
| Place of performance (NUTS) | `DE1`, `FR10` | Hierarchical. |
| Contract type | `services`, `supplies`, `works` | |
| Date window | last N days (default 7) or from/to dates | Max 90 calendar days per run, today included. Dates are Brussels time. |
| Value | min/max + currency (default EUR) | Applied to the awarded value if present, else the estimated value. No currency conversion: notices in other currencies or without a value count as "unknown" and are kept unless you untick *Keep notices with unknown value*. |
| Only open | | Drops notices whose submission deadline has passed (notices with no deadline are kept). |
| Max results | default 100, up to 10,000 | Newest first. |

### Output (one row per notice)

`noticeId`, `title` (English where TED provides one), `titleOriginal`, `originalLanguage`, `stage`, `noticeType`, `procedureType`, `contractNature`, `buyerName`, `buyerCity`, `buyerCountry` (first buyer), `buyerCountries` (all buyers – joint procurements can list many; the country filter matches any of them), `placeOfPerformanceCountries`, `placeOfPerformanceNuts`, `mainCpv`, `cpvCodes`, `publicationDate`, `dispatchDate`, `deadline` (with time zone), `deadlineDate`, `estimatedValue` + `estimatedValueCurrency`, `awardedValue` + `awardedValueCurrency` and `winners` (award notices), `frameworkAgreement`, `description` (trimmed to *Description max length*), `documentsUrls`, `noticeUrl`, `pdfUrl`, `xmlUrl`, `procedureId`, `noticeVersion`.

Example row:

```json
{
  "noticeId": "755341-2026",
  "publicationDate": "2026-10-30",
  "stage": "competition",
  "title": "Czechia – IT services: consulting, software development, Internet and support – Dodávka funkčního celku evidence vodohospodářské infrastruktury…",
  "buyerName": "Ministerstvo zemědělství",
  "buyerCountry": "CZE",
  "mainCpv": "72000000",
  "deadline": "2026-11-12T13:00:00+01:00",
  "estimatedValue": 81618000.0,
  "estimatedValueCurrency": "CZK",
  "noticeUrl": "https://ted.europa.eu/en/notice/-/detail/755341-2026"
}
```

A run summary (query used, notices read, whether more matched) is saved as `OUTPUT` in the run's key-value store.

### Alerts: only new tenders

Tick **Only new since last run** and schedule the Actor (e.g. daily). The Actor remembers the notice IDs it has returned in a named key-value store (`ted-tenders-state`; set **State key** to keep several alert profiles apart).

- First run saves a baseline and returns nothing (untick *First run only saves a baseline* to get current notices immediately).
- If more new notices match than *Max results*, the rest are returned on the next run.
- Changing the filters under the same state key starts a new baseline; notices already returned stay skipped.

### Pricing

Pay per event: a small fee per run start plus a fee per notice returned. You only pay for rows you get. If TED is unavailable the run fails and no notices are charged (the small start fee still applies). Set a *maximum charge per run* in Apify and the Actor stops at that limit and says so in the status. Delivery is crash-safe: if a run is restarted or migrated by the platform, or dies mid-delivery, notices already delivered are not delivered or charged again. (One rare exception: if an alert run dies mid-delivery and its dataset is deleted or expires before the next run, the next run cannot check what was delivered and re-delivers that one batch, at most 100 notices.)

### Good to know

- **Keyword search is broad.** TED's full-text search covers every field and translation, so `software` can match "installation services (except software)". Combine keywords with CPV codes for precision, or use *Exclude keywords*.
- TED publishes about 4,000 notices per working day.
- Corrections are published by TED as new notices (new `noticeId`, same `procedureId`).
- Buyer contact emails are off by default because they can identify individuals. Winner names can also be sole traders. If you use personal data from the results, you are responsible for handling it under the GDPR.

### Source and licence

Source: TED – Tenders Electronic Daily, © European Union, https://ted.europa.eu. Procurement notices are reused under the Commission's reuse policy (Commission Decision 2011/833/EU), which allows commercial and non-commercial reuse. Records are reformatted and abridged by this Actor; the official text is at each `noticeUrl`. This Actor is not affiliated with or endorsed by the Publications Office of the EU or the European Commission.

# Actor input Schema

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

Words or phrases to search for in the full notice text (TED full-text search, which also covers the official English titles of notices in other languages). Leave empty to match everything.

## `keywordMode` (type: `string`):

Match notices containing ANY of the keywords, or only notices containing ALL of them.

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

Drop notices whose text contains any of these words or phrases.

## `noticeStages` (type: `array`):

Which kinds of notices to return. Default: competition (open tenders). Add "result" to see who won.

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

CPV codes or prefixes. Trailing zeros mean the whole category: 72000000 (or 72) = all IT services, 45 = construction work, 33 = medical equipment. The check digit (72000000-5) is accepted. Matches main and additional CPV codes.

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

Country of the buying organisation, as ISO codes: DE, FR, PL… (3-letter DEU, FRA, POL also work). Leave empty for all countries.

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

NUTS region codes or prefixes for where the work is performed, e.g. DE1 (Baden-Württemberg), FR10 (Île-de-France), PL9.

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

Services, supplies and/or works. Leave empty for all.

## `postedWithinDays` (type: `integer`):

Notices published in the last N days (1 = today only, in Brussels time). Ignored when "Published from" is set. TED publishes on working days only.

## `postedFrom` (type: `string`):

Exact start date (YYYY-MM-DD), at most 90 days ago.

## `postedTo` (type: `string`):

Exact end date (YYYY-MM-DD), inclusive.

## `minValue` (type: `integer`):

Minimum estimated value (or awarded value for award notices), in the currency below. Values are as published, usually net of VAT.

## `maxValue` (type: `integer`):

Maximum estimated or awarded value, in the currency below.

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

Currency of the value filter (3-letter code). Values are not converted: a notice in another currency (e.g. PLN, SEK) counts as "unknown value".

## `keepUnknownValue` (type: `boolean`):

When a value filter is set, keep notices with no published value or a value in another currency. Many notices publish no value.

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

Drop notices whose earliest tender deadline is before today. Notices without a deadline are kept.

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

Remember what was already returned and return only new notices. Use with a daily schedule. The first run saves a baseline and returns nothing (see below).

## `baselineOnFirstRun` (type: `boolean`):

With alerts on, the first run (or the first run after you change filters) remembers the current notices from today and yesterday and returns nothing, so you are not charged for the backlog. Turn off to receive the backlog on the first run.

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

Name for this alert (letters, digits and "-"), e.g. "it-services-germany". Use a different key per saved search. Leave empty to derive one from the filters.

## `stateStoreName` (type: `string`):

Named key-value store where alert state is kept (lowercase letters, digits, "-").

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

Maximum number of notices to return (1-10,000), newest first. With alerts on, matches over this limit are kept for the next run.

## `descriptionMaxLength` (type: `integer`):

Truncate descriptions to this many characters (0 = omit descriptions).

## `includeContacts` (type: `boolean`):

Add the buyer contact email addresses published in the notice. Some identify individuals (personal data under the GDPR): only enable if you need them to respond to the procurement, and handle them lawfully. Off by default.

## Actor input object example

```json
{
  "keywords": [
    "software"
  ],
  "keywordMode": "any",
  "noticeStages": [
    "competition"
  ],
  "postedWithinDays": 7,
  "valueCurrency": "EUR",
  "keepUnknownValue": true,
  "onlyOpen": false,
  "onlyNew": false,
  "baselineOnFirstRun": true,
  "stateStoreName": "ted-tenders-state",
  "maxResults": 100,
  "descriptionMaxLength": 1000,
  "includeContacts": false
}
```

# Actor output Schema

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

Dataset with one item per matching TED notice.

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

OUTPUT record with result counts, the TED query used and alert/monitoring status for this run.

# 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("stego-bot/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 = { "keywords": ["software"] }

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

```

## MCP server setup

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