# TED EU Tender Monitor (`flamelit_constellation/ted-monitor`) Actor

Unofficial tool, not affiliated with the EU, Publications Office or TED. Get only new and amended EU public tenders since your last run, filtered by CPV, NUTS or country. Source: TED, © European Union.

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

## Pricing

from $3.00 / 1,000 new or amended records

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

## TED EU Tender Monitor

**Not affiliated with or endorsed by the European Union, the Publications Office of the European Union, or TED (Tenders Electronic Daily).** This is an independent tool from Two Five Labs that reads publicly available data. No government seals or logos are used.

### What it does

Searches the TED Search API v3 for EU procurement notices published in your look-back window. You can filter by CPV code, NUTS region, country and title keyword, and it returns only what is new or changed since your last run.

### Who it's for

Companies that bid on EU public tenders, and bid consultants who track them.

### Input

| Field | Description |
|---|---|
| `lookbackDays` | integer, default 3. Days of TED publications to check. On a daily schedule this overlaps earlier runs; already-seen notices are not output again. |
| `cpv` | list. CPV codes; trailing zeros act as a prefix (e.g. `45000000` = all construction). |
| `nuts` | list. NUTS regions, e.g. `CZ052` or prefix `CZ0`. Must be a valid NUTS code; use `countries` for whole countries. |
| `countries` | list. ISO 3166 alpha-3 codes, e.g. `FRA`, `DEU`. |
| `keywords` | list. Matches the English title (case-insensitive). |
| `limit` | integer, default 100 (TED maximum 250). Notices per page. |
| `maxPages` | integer, default 5. |
| `maxSpendUsd`, `emitUnchanged`, `stateStoreName` | see "How runs work". |

No API key is needed for this source.

### Run it via API

```bash
curl -X POST "https://api.apify.com/v2/acts/flamelit_constellation~ted-monitor/runs?token=$APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"maxSpendUsd": 1.0}'
```

Use your own Apify token.

### How runs work

- **First run:** returns every matching record in the look-back window, all marked `changeType: "new"`.
- **Later runs:** return only records that are new, or whose content changed since they were last seen (`amended`). The actor keeps a content hash per record in a key-value store. A second run over the same data outputs nothing.
- `stateStoreName`: give each saved search its own name so each one tracks its own history.
- `emitUnchanged: true` also outputs unchanged records (`changeType: "same"`), which are never charged.
- **Spend cap:** `maxSpendUsd` (default 1.0) is a hard cap. When it is reached, the actor stops charging and stops output. Records not yet output are kept for the next run.
- **Errors and rate limits:** network errors, HTTP 429 and 5xx responses are retried up to 3 times with backoff. `Retry-After` is honoured in both its seconds and date forms; if the source asks for a wait longer than 2 minutes, the run stops instead of waiting.

### Output

Tender record : `id, source ("ted"), title, buyer, cpv[], naics (null), region, value, currency, posted, deadline, url, changeType, extra{noticeType, attribution, modified}`.

Excerpt from a live run (NUTS FR101):

```json
{
 "id": "689304-2026",
 "source": "ted",
 "title": "France – Road transport services – Prestations de transport de fonds",
 "buyer": "Monnaie de Paris",
 "cpv": [
  "60100000"
 ],
 "region": "FR101, FRA, anyw",
 "value": 0,
 "currency": "EUR",
 "posted": "2026-10-07T00:00:00.000Z",
 "deadline": "2026-11-05T22:00:00.000Z",
 "url": "https://ted.europa.eu/en/notice/-/detail/689304-2026",
 "changeType": "new",
 "extra": {
  "noticeType": "cn-standard",
  "attribution": "Source: TED, © European Union, https://ted.europa.eu/en/notice/-/detail/689304-2026",
  "modified": "Data transformed: fields normalized, selected and filtered by this actor."
 }
}
```

`value`, `currency` and `deadline` are sometimes empty in live data.

**Personal data:** contact persons, and tenderers or winners who are named individuals, are removed. Emails and phone numbers in free text are masked. URLs and reference numbers are not masked.

### Pricing

Pay per event: one `run-start` charge per run and one `new-item` charge per new or amended record output. Current prices are shown on this actor's Apify Store page.

### Limits

- Throttle: at least 1 second between requests, at most 20 requests per run. This is well below TED's fair-usage guidance.
- Up to `limit` × `maxPages` notices per run (default 500). The default run used 5 requests for 500 notices.

### Data source and terms

- Source: TED, © European Union (`https://ted.europa.eu`).
- **Data has been modified:** notices are reformatted, normalized, filtered and compared between runs. Each record carries `extra.attribution` ("Source: TED, © European Union" plus the notice address) and `extra.modified` as TED's reuse terms require credit and an indication of changes.
- No TED logo is used.
- **Not affiliated with or endorsed by the European Union, the Publications Office of the European Union, or TED (Tenders Electronic Daily).**

### FAQ

**Does it return every record?** The first run returns everything matching. After that it returns only new or changed records.
**How often should I run it?** Daily is enough.
**Can I cap spend?** Yes. `maxSpendUsd` is a hard cap, and records it stops are output on the next run.
**Does it need a key?** No.

### Support

Questions or problems: please use the Issues tab on this actor's Apify page first.
Publisher: Two Five Labs, contact `twofivelabs@gmail.com`.

Requests to the source identify themselves with a contact address: `flamelit-constellation-actors/0.1 (+mailto:twofivelabs@gmail.com)`.

# Actor input Schema

## `lookbackDays` (type: `integer`):

How many days of TED publications to check, counting back from today. 1 suits a daily schedule.

## `cpv` (type: `array`):

Only include notices with at least one of these CPV codes. Trailing zeros act as a prefix, e.g. 45000000 matches all construction (45...).

## `nuts` (type: `array`):

Only include notices performed in these NUTS regions, e.g. CZ052 or a prefix such as CZ0. Must be a valid NUTS code; a bare country prefix like "FR" is rejected by TED, use countries for that.

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

Only include notices performed in these countries, as ISO 3166 alpha-3 codes, e.g. FRA, DEU, CZE.

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

Only include notices whose English title contains at least one of these words (case-insensitive). Leave empty for all.

## `limit` (type: `integer`):

Notices requested per TED API page (max 250 per TED docs; 100 recommended).

## `maxPages` (type: `integer`):

Upper limit on TED API pages fetched per run. Requests are spaced at least 1 second apart.

## `maxSpendUsd` (type: `number`):

Hard spending cap for this run, in US dollars. The actor stops charging and stops adding results once this amount is reached. Unsent items are kept for the next run.

## `emitUnchanged` (type: `boolean`):

If on, items already seen in earlier runs (changeType "same") are also output. Off by default, so you only get new and amended items. Unchanged items are never charged.

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

Optional name of the key-value store that remembers what earlier runs saw. Use a different name per saved search so each search tracks its own new/amended items. Leave empty to use the run's default store.

## `fixturePath` (type: `string`):

Testing only. Path to a local file to replay instead of calling the live source. Leave empty for normal use.

## Actor input object example

```json
{
  "lookbackDays": 3,
  "cpv": [],
  "nuts": [],
  "countries": [],
  "keywords": [],
  "limit": 100,
  "maxPages": 5,
  "maxSpendUsd": 1,
  "emitUnchanged": false
}
```

# Actor output Schema

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

Tender records (new and amended only)

# 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 = {
    "lookbackDays": 3
};

// Run the Actor and wait for it to finish
const run = await client.actor("flamelit_constellation/ted-monitor").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 = { "lookbackDays": 3 }

# Run the Actor and wait for it to finish
run = client.actor("flamelit_constellation/ted-monitor").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 '{
  "lookbackDays": 3
}' |
apify call flamelit_constellation/ted-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,flamelit_constellation/ted-monitor"
        }
    }
}
```

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/3iIix2y9lz85hRRM4/builds/uuoxyIozFo9uZlmiP/openapi.json
