# TED EU Tenders - Netherlands & Benelux Public Procurement (`ryuuk/ted-tenders`) Actor

Get EU public procurement notices from TED (Tenders Electronic Daily) for the Netherlands, Belgium, Luxembourg or any EU country. Filter by date, CPV code and keywords. Clean, flat JSON with English field names; contact details removed (GDPR). Pay per notice.

- **URL**: https://apify.com/ryuuk/ted-tenders.md
- **Developed by:** [Jishnu Harinandansingh](https://apify.com/ryuuk) (community)
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 notices

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

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 – Netherlands & Benelux Public Procurement

Get EU public procurement notices from **TED (Tenders Electronic Daily)**, the official EU
journal for public tenders. Defaults to buyers in the **Netherlands**. Switch to Belgium, Luxembourg
or any other European country, and filter by publication date, CPV code and keywords.

Each notice becomes one flat JSON item with stable English field names, ready for spreadsheets,
CRMs or a daily tender-alert workflow. Contact persons, e-mail addresses and phone numbers are removed (GDPR).

### What it does

- Queries the official [TED Search API](https://docs.ted.europa.eu/api/latest/index.html), not
  HTML scraping, so results stay stable when the website changes.
- Returns notices newest first. This includes contract notices (open tenders), award notices and
  prior information notices.
- Each item has the notice ID and link, title (original and English), buyer, buyer country, CPV codes,
  estimated value and currency, publication date, tender deadline, procedure type, notice type, place of
  performance (NUTS), description, and links to the tender documents and submission page.

### Input

| Field | Type | Default | Description |
|---|---|---|---|
| `countries` | list of ISO codes | `["NL"]` | Buyer countries, e.g. `NL`, `BE`, `LU`, `DE`. A notice matches if **any** of its buyers is in one of these countries. |
| `lastDays` | integer | `7` | Notices published in the last N days. Ignored when `publishedFrom` is set. |
| `publishedFrom` | date `YYYY-MM-DD` | – | Start of the publication date range. |
| `publishedTo` | date `YYYY-MM-DD` | – | End of the range (inclusive). Empty means up to today. |
| `cpvCodes` | list | `[]` | CPV codes; sub-codes match too. For example `72000000` (IT services) also matches `72260000`. The check digit (`-5`) is optional. |
| `keywords` | list | `[]` | Full-text search. A notice matches if it contains **any** of the keywords (in any language). |
| `maxItems` | integer | `100` | Maximum number of notices returned (1–100,000). |

Example: IT and cleaning tenders in the Benelux from the last 3 days:

```json
{
  "countries": ["NL", "BE", "LU"],
  "lastDays": 3,
  "cpvCodes": ["72000000", "90910000"],
  "keywords": [],
  "maxItems": 200
}
```

### Output

One item per notice (real example, description shortened):

```json
{
  "noticeId": "756055-2026",
  "noticeUrl": "https://ted.europa.eu/en/notice/-/detail/756055-2026",
  "pdfUrl": "https://ted.europa.eu/en/notice/756055-2026/pdf",
  "title": "TA- verbindingen",
  "titleEnglish": "Netherlands – Telephone and data transmission services – TA- verbindingen",
  "buyerName": "Hoogheemraadschap van Delfland",
  "buyerCity": "Delft",
  "buyerCountry": "NL",
  "buyerCountries": ["NL"],
  "cpvCodes": ["64210000", "72315000"],
  "estimatedValue": 3000000.0,
  "currency": "EUR",
  "publicationDate": "2026-10-30",
  "deadline": null,
  "procedureType": "open",
  "noticeType": "can-standard",
  "contractType": "services",
  "placeOfPerformance": ["NLD"],
  "description": "Het doel van deze aanbesteding is het afsluiten van een nieuwe overeenkomst voor TA-WAN dienstverlening ...",
  "documentsUrl": null,
  "submissionUrl": null,
  "source": "TED - Tenders Electronic Daily (https://ted.europa.eu)",
  "attribution": "Source: TED - Tenders Electronic Daily (https://ted.europa.eu), (c) European Union. Reused under Commission Decision 2011/833/EU. Changes: fields selected and reformatted, contact details removed."
}
```

| Field | Notes |
|---|---|
| `noticeId` | TED publication number, which is unique and stable. Use it for de-duplication. |
| `title` | Title in the notice's original language. `titleEnglish` is TED's English heading (country – CPV description – original title). |
| `buyerName`, `buyerCity`, `buyerCountry` | Lead buyer (normally an organisation; free text is e-mail/phone-redacted). `buyerCountries` lists the countries of all buyers in a joint procurement. |
| `estimatedValue`, `currency` | Estimated value of the whole procedure, or the sum of the lot values when there is only one currency. `null` when not published. Placeholder values of 0 or 1 count as not published. |
| `deadline` | Earliest tender submission deadline across all lots (ISO 8601 with offset). `null` for award and information notices. |
| `procedureType` | For example `open`, `restricted`, `neg-w-call`, `comp-dial`, `innovation`. |
| `noticeType` | eForms notice type. `cn-*` = contract notice (open tender), `can-*` = contract award notice, `pin-*` = prior information notice, `pmc` = pre-market consultation. |
| `contractType` | `works`, `supplies` or `services`. |
| `placeOfPerformance` | NUTS and country codes. |
| `source`, `attribution` | Credit required by TED's reuse terms. Keep them when you republish the data. |

### Pricing

Pay per result: **$0.002 per notice** (launch price). 1,000 notices cost $2. You only pay for
notices written to the dataset. Set `maxItems` or a maximum cost per run to cap spend.

### Limits and notes

- **Personal data:** contact persons, e-mail addresses and phone numbers are never requested from TED.
  E-mail and phone patterns in free text (title, description) are replaced with `[email redacted]` and
  `[phone redacted]`. Personal names typed into free text cannot be detected reliably, so they may remain.
  If you spot personal data in the output, report it in the **Issues** tab of this Actor and the redaction
  will be extended.
- **Rate limits:** TED does not publish limits. The Actor sends at most one request every 1.5 s, at most
  250 notices per request, and retries with backoff on errors and HTTP 429.
- Most text is in the notice's original language (Dutch, French, ...). Only `titleEnglish` is in English.
- Keyword search uses TED's full-text index, so results depend on TED's own matching.
- Award notices for older tenders can appear in a recent date range, because the date filter applies to the
  **publication** date.
- This is not an official TED or European Union product.

### Data source and license

Data from [TED – Tenders Electronic Daily](https://ted.europa.eu), © European Union. Notices can be
reused freely, including commercially, under Commission Decision 2011/833/EU (CC BY 4.0,
[TED legal notice](https://ted.europa.eu/en/legal-notice)). The output credits the source and states
the changes made in the `attribution` field.

### Development

```bash
## from the repo root
pip install -r requirements-dev.txt
pytest -m "not live"          # unit tests on recorded fixtures
pytest -m live                # live smoke test against the real TED API
cd actors/ted-tenders && PYTHONPATH=../.. apify run   # local run, input in storage/key_value_stores/default/INPUT.json
```

The Docker build context is the repo root (`dockerContextDir`), so the shared helpers in `shared/` are
included in the image. To re-record the fixture, run `python actors/ted-tenders/tests/record_fixture.py`.

# Actor input Schema

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

ISO country codes of the contracting authority, e.g. NL, BE, LU, DE. A notice matches if any of its buyers is in one of these countries.

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

Used when 'Published from' is empty.

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

Start date (YYYY-MM-DD). Overrides 'last N days'.

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

End date (YYYY-MM-DD), inclusive. Empty = up to today.

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

Only notices with a CPV code under these codes, e.g. 72000000 (IT services) also matches 72260000. Check digit (-5) is optional. Leave empty for all.

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

Full-text search; a notice matches if it contains any keyword (any language, e.g. 'schoonmaak' or 'cleaning').

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

Maximum number of notices to return (newest first). You pay per notice.

## Actor input object example

```json
{
  "countries": [
    "NL"
  ],
  "lastDays": 7,
  "maxItems": 100
}
```

# Actor output Schema

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

One flat JSON item per notice in the default dataset.

# 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": [
        "NL"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("ryuuk/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": ["NL"] }

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

```

## MCP server setup

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