# EU Tenders Monitor (TED): European Public Procurement (`fedsignals/eu-tenders-monitor-ted`) Actor

Get new EU tenders and contract awards from TED (Tenders Electronic Daily) via the official API, no key. Filter by country, CPV code, keywords and EUR value. Scheduled runs return only new notices, with deadline, buyer, lots and link.

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

## Pricing

from $3.00 / 1,000 tender notice rows

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 Monitor (TED): European Public Procurement

Get **new EU public procurement notices** (calls for tenders, contract awards and prior information notices) from **TED (Tenders Electronic Daily)**, the EU's official procurement journal, as clean JSON rows. Filter by **buyer country, CPV code, keywords and value in EUR**. Schedule it daily and it returns **only the notices you haven't seen yet**. It uses the official TED Search API, so you don't need an API key, a login or any scraping.

Built and maintained by **FedSignals Data**.

### What it does

- **Searches every notice on TED** (EU 27, EEA and other countries that publish there): thousands of new notices every working day.
- **Filters** by buyer country, CPV code (parent codes include all sub-codes), keywords in any language, notice type and minimum value.
- **Normalizes the eForms data**: English title where available, buyer, earliest and latest lot deadline in UTC, value converted to EUR (ECB reference rate), unique CPV codes, lots, and links to the TED page and the buyer's tender documents.
- **Open calls only by default**: `openOnly` drops calls once every lot's deadline has passed, so you only see tenders you can still bid on (a notice stays in while any lot is open).
- **Incremental by default**: `onlyNew` remembers which notices it already delivered for your filter set, so a daily schedule returns, and charges for, new notices only.
- **Privacy by design**: contact persons, emails and phone numbers are never requested, emails and phone numbers that buyers write into titles or descriptions are replaced with `[redacted]`, and winner names are not collected. Titles and descriptions are passed on as the buyer published them; in rare cases (about 0.15% of notices in our 2,000-notice check) they name an official or a designer in their professional role. Emails and phone numbers in that text are still redacted.

### Use cases

- Daily "new tenders in my sector" alerts for bid teams, by email, Slack or CRM
- Lead lists of public buyers for IT, construction, consulting, medical and facility services
- Market research on contract awards by country and sector
- Feeding a bid/no-bid scoring model or an LLM agent with fresh tenders

### Input

| Field | Type | Default | What it does |
|---|---|---|---|
| `countries` | list | all | Buyer countries: `DE`, `DEU` or `Germany`. Misspellings fail before any notice is charged, with a suggestion. |
| `cpvCodes` | list | all | CPV codes, e.g. `72000000` (IT services) or `45000000` (construction). Sub-codes are included. Check digit optional. |
| `keywords` | text | – | Comma-separated words or phrases; a notice matches if it contains any of them. |
| `noticeTypes` | list | `competition` | `competition` (calls for tenders), `result` (contract awards), `planning` (prior information). An empty list returns all three. |
| `minValueEur` | integer | 0 | Only notices worth at least this much in EUR. On award notices for framework agreements, TED's total can be the framework maximum, so such notices may pass a high minimum. |
| `includeWithoutValue` | boolean | true | With a minimum value set, keep notices whose buyer published no value. |
| `publishedWithinDays` | integer | 3 | Look back this many days (1–90). |
| `openOnly` | boolean | true | Drop calls for tenders and prior information notices once every lot deadline has passed (checked against the current UTC time; a notice with any lot still open is kept). Notices with no deadline, and contract awards, are always kept. |
| `onlyNew` | boolean | true | Return only notices not delivered by an earlier run with the same filters. |
| `maxItems` | integer | 100 | Stop after this many notices (caps the cost). |
| `stateKey` | text | – | Advanced: name the "already seen" memory to share it between tasks. |

### Example input

```json
{
  "countries": [
    "DE",
    "FR"
  ],
  "cpvCodes": [
    "72000000"
  ],
  "noticeTypes": [
    "competition"
  ],
  "publishedWithinDays": 3,
  "openOnly": true,
  "onlyNew": false,
  "maxItems": 10
}
```

Up to 10 IT-services calls for tenders from German and French buyers, published in the last 3 days and still open for bids.

More examples (tested Oct 30, 2026):

**French construction works** (CPV 45000000 includes all sub-codes):

```json
{"countries": ["FR"], "cpvCodes": ["45000000"], "noticeTypes": ["competition"], "publishedWithinDays": 3, "onlyNew": false, "maxItems": 5}
```

**Nordic IT tenders with keywords in local languages** (Norway publishes on TED as an EEA country):

```json
{"countries": ["SE", "DK", "FI", "NO"], "keywords": "IT-tjänster, it-konsulent, tietojärjestelmä, programvare, software", "noticeTypes": ["competition"], "publishedWithinDays": 5, "onlyNew": false, "maxItems": 5}
```

### Output

One row per notice. Sample (real output, description shortened):

```json
{
  "noticeId": "87c6d6e6-878d-4613-9b0c-eb7dc9c0d5a2",
  "publicationNumber": "741403-2026",
  "title": "France – Systems and technical consultancy services – Prestation d'externalisation de la fonction de responsable de la sécurité des systèmes d'information (RSSI)",
  "description": "Les prestations comprennent notamment : la gouvernance de la sécurité des systèmes d'information, la conformité réglementaire, la sécurité opérationnelle et la …",
  "buyerName": "OPH Rives de Seine Habitat",
  "buyerCity": "Puteaux",
  "buyerCountry": "FRA",
  "buyerCountryIso2": "FR",
  "noticeType": "competition",
  "noticeSubtype": "cn-standard",
  "procedureType": "open",
  "contractNature": "services",
  "cpvCodes": [
    "72220000",
    "72810000",
    "79417000",
    "80533100"
  ],
  "placeOfPerformance": [
    "FR105"
  ],
  "estimatedValue": 260000.0,
  "currency": "EUR",
  "estimatedValueEur": 260000.0,
  "awardedValue": null,
  "awardedCurrency": null,
  "awardedValueEur": null,
  "valueBasis": "estimated",
  "publicationDate": "2026-10-27",
  "deadline": "2026-11-23T11:00:00Z",
  "latestDeadline": "2026-11-23T11:00:00Z",
  "deadlineType": "tenders",
  "lotCount": 1,
  "lots": [
    {
      "lotId": "LOT-0000",
      "title": "Prestation d'externalisation de la fonction de responsable de la sécurité des systèmes d'information (RSSI)",
      "estimatedValue": 260000.0
    }
  ],
  "documentsUrl": "https://www.marches-publics.info/mpiaws/index.cfm?fuseaction=dematEnt.login&type=DCE&IDM=1894369",
  "url": "https://ted.europa.eu/en/notice/-/detail/741403-2026",
  "source": "TED (Tenders Electronic Daily), © European Union",
  "scrapedAt": "2026-10-30T16:26:17Z"
}
```

`estimatedValue` / `estimatedValueEur` hold the buyer's estimate only. On contract award (result) notices the total awarded is in `awardedValue` / `awardedCurrency` / `awardedValueEur` (null on other notices). `valueBasis` tells you which figure `minValueEur` was compared against: `awarded` (`awardedValueEur`, result notices), `estimated` (procedure estimate), `estimatedLots` (sum of lot estimates) or `none` (the buyer published no value). **Framework agreements:** on award notices TED's total is often the framework maximum, which can far exceed what was actually awarded (e.g. notice 745274-2026 shows €4.01 billion against €407,237.86 payable), so `awardedValue`, `awardedValueEur` and any `minValueEur` filter on award notices can be inflated by such rows. `deadline` is the earliest lot deadline and `latestDeadline` the latest one (they are the same for single-lot notices). `deadlineType` is `tenders`, or `requestsToParticipate` for restricted and negotiated procedures.

A **SUMMARY** record in the run's key-value store shows the TED query, total matches, notices delivered per type and country, skipped notices (already seen, deadline passed, below the minimum value) and why the run stopped (`completed`, `maxItems`, `spendingLimit`, `scanLimit`, `upstreamError`). If TED fails partway through, the run keeps the notices it already delivered and lists the error under `partialFailures` instead of crashing.

### Pricing

Pay per result: **$0.003 per notice** ($3 per 1,000), plus Apify's start fee of $0.00005 per run. Already-seen notices are skipped for free. Example: a daily run returning 20 new notices costs about $0.06 per day, or about $1.80 a month. Set `maxItems` or a maximum charge per run to cap the cost; the run stops cleanly before going over it (start fee included). Runs that find nothing new cost only the start fee. If the input is invalid, the run stops before any notice is charged: no results were charged; only Apify's small start fee ($0.00005) applied.

### FAQ

**Do I need a TED account or API key?** No. The TED Search API is open and needs no authentication.

**Why is the title in English but the description in French?** TED translates notice titles into all EU languages; descriptions stay in the buyer's language.

**Why do some notices have no value?** Many buyers don't publish one. Use `includeWithoutValue` to keep or drop them when filtering by value.

**Why did my run return no notices?** The status message says why: nothing new since the last run (with `onlyNew`), every match already past its deadline (with `openOnly`), nothing above your `minValueEur`, or no matches at all. Try more `publishedWithinDays`, fewer filters or a broader parent CPV code (e.g. 72000000 instead of 72212000). The `SUMMARY` record shows the exact TED query that was run.

**How do I get only tenders I can still bid on?** Keep the defaults: `noticeTypes: ["competition"]` and `openOnly: true`. Calls whose lots have all passed their deadline (UTC, judged by `latestDeadline`) are skipped for free; a multi-lot call with one lot still open is kept, so check `deadline` and `latestDeadline`. A date-only deadline counts as open through that day. Notices with no deadline are kept, so check `deadline` on those. Set `openOnly: false` to get closed calls too.

**Where is the contract value on award notices?** In `awardedValue` and `awardedValueEur`. `estimatedValue` is only the buyer's estimate, which award notices usually leave empty. For framework agreements the awarded total is often the framework maximum, not the amount actually spent.

**Can I search in several languages?** Yes. Add translations to `keywords`, e.g. `cybersecurity, cybersécurité, Cybersicherheit`.

### Dates, time zones and currency

- `deadline` is ISO 8601 in UTC (`Z`). Buyers set deadlines in local time, so a Swedish deadline of 23:59 CET shows as `22:59:00Z`.
- `publicationDate` is the TED publication date (calendar date, no time zone). `scrapedAt` is UTC.
- `currency` is the ISO 4217 code of `estimatedValue` as the buyer published it (e.g. `EUR`, `SEK`, `PLN`). `estimatedValueEur` is the same value converted to euros. `awardedCurrency` and `awardedValueEur` work the same way for `awardedValue`.
- `openOnly` compares `latestDeadline` (the last lot deadline) with the current UTC time when the run starts.

### Other languages and regions

Covers buyers in the EU 27, the EEA and other countries that publish on TED. Keywords work in any language; titles are in English where TED provides them.

Also searched as: Ausschreibungen, öffentliche Vergabe (DE) · appels d'offres, marchés publics (FR) · licitaciones, contratación pública (ES) · gare d'appalto (IT) · przetargi (PL) · aanbestedingen (NL) · licitações, contratos públicos (PT) · upphandlingar (SV) · udbud (DA) · kilpailutukset (FI).

### Limits

- At most 50,000 notices are scanned per run (narrow the filters for bigger backfills); `publishedWithinDays` goes back 90 days.
- Values in non-EUR currencies are converted with the ECB reference rate of the run day; if the ECB rate is unavailable, `estimatedValueEur` and `awardedValueEur` are null.
- Notice data is as published by the buyers on TED; corrections appear as new notices.

### Source and terms

Source: TED (Tenders Electronic Daily), © European Union, https://ted.europa.eu. Reused under the TED legal notice (https://ted.europa.eu/en/legal-notice) and Commission Decision 2011/833/EU, which allow commercial reuse with acknowledgement of the source. Data comes from the TED Search API (https://docs.ted.europa.eu/api/latest/search.html). Exchange rates: European Central Bank euro foreign exchange reference rates. This Actor is not affiliated with or endorsed by the European Union, the Publications Office of the EU or TED.

### Support

Questions or feature requests: open an issue on the Actor's Issues tab or email fedsignals.alerts@gmail.com.

# Actor input Schema

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

Returns notices from buyers in these countries. Use 2-letter codes (DE), 3-letter codes (DEU) or English names (Germany). Empty = all countries on TED (EU, EEA and others). A misspelled country fails the run before any notice is charged, with a suggestion.

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

Returns notices classified under these CPV codes, including all sub-codes (72000000 = all IT services; 45000000 = all construction work). The check digit (72000000-5) is optional. Empty = all sectors.

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

Returns notices whose text contains any of these words or phrases, separated by commas, e.g. cybersecurity, cloud computing. A phrase matches as a whole. Titles and descriptions are often in the buyer's language, so add translations if you need them (e.g. cybersecurity, cybersécurité, Cybersicherheit).

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

Which notices to return: calls for tenders (competition), contract awards (result) and/or prior information notices (planning). Leave empty to get all three. To keep only calls you can still bid on, leave 'Only open notices' on.

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

Returns only notices whose value is at least this amount in EUR. Other currencies are converted with the ECB reference rate of the day. 0 = no value filter.

## `includeWithoutValue` (type: `boolean`):

Many buyers don't publish a value. When a minimum value is set, keep those notices (on) or drop them (off).

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

Returns notices published in the last N days (1-90). TED publishes every working day.

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

On: drops calls for tenders and prior information notices once every lot deadline has passed (compared with the current UTC time; a notice with any lot still open is kept; a date-only deadline stays open through that day). Notices with no deadline, and contract awards, are always kept. Off: returns closed calls too.

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

On: each run returns only notices this filter set hasn't returned before, so a daily schedule gives you just the new tenders. Off: returns every match each run.

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

Stops after this many notices, to cap the cost of a run.

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

Optional name for the 'already seen' memory. Runs with the same key share it. Leave empty to use one memory per filter set.

## Actor input object example

```json
{
  "countries": [
    "DE",
    "FR"
  ],
  "cpvCodes": [
    "72000000"
  ],
  "noticeTypes": [
    "competition"
  ],
  "minValueEur": 0,
  "includeWithoutValue": true,
  "publishedWithinDays": 3,
  "openOnly": true,
  "onlyNew": true,
  "maxItems": 10
}
```

# Actor output Schema

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

New EU public procurement notices from TED. One item per row; field definitions are in the dataset schema.

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

JSON summary of the run: the TED query, total matches, rows delivered per type and country, skipped rows and why the run stopped.

# 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",
        "FR"
    ],
    "cpvCodes": [
        "72000000"
    ],
    "noticeTypes": [
        "competition"
    ],
    "publishedWithinDays": 3,
    "openOnly": true,
    "onlyNew": false,
    "maxItems": 10
};

// Run the Actor and wait for it to finish
const run = await client.actor("fedsignals/eu-tenders-monitor-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 = {
    "countries": [
        "DE",
        "FR",
    ],
    "cpvCodes": ["72000000"],
    "noticeTypes": ["competition"],
    "publishedWithinDays": 3,
    "openOnly": True,
    "onlyNew": False,
    "maxItems": 10,
}

# Run the Actor and wait for it to finish
run = client.actor("fedsignals/eu-tenders-monitor-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 '{
  "countries": [
    "DE",
    "FR"
  ],
  "cpvCodes": [
    "72000000"
  ],
  "noticeTypes": [
    "competition"
  ],
  "publishedWithinDays": 3,
  "openOnly": true,
  "onlyNew": false,
  "maxItems": 10
}' |
apify call fedsignals/eu-tenders-monitor-ted --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,fedsignals/eu-tenders-monitor-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/qmzg8lfxmVA4bvkbg/builds/d04cEK9OALsdbPdC0/openapi.json
