# EU Tenders Monitor (TED official API) (`colbyham/ted-tenders-monitor`) Actor

Weekly EU tender alert for bid consultants: new TED calls for tender filtered by CPV code, country and title keywords, one clean row per notice with buyer, deadline, value and link. Official TED API, no scraping. You pay only for notices you have not seen before.

- **URL**: https://apify.com/colbyham/ted-tenders-monitor.md
- **Developed by:** [Colby Ham](https://apify.com/colbyham) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $4.00 / 1,000 new tender notices

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 official API)

A weekly EU tender alert. It pulls **new calls for tender** from TED (Tenders Electronic Daily, the EU's official procurement journal), filters them by **CPV code, country and title keywords**, and returns one clean row per notice: buyer, deadline, estimated value, CPV codes and a link to the notice. Schedule it weekly with **Only new notices** on and you only get, and only pay for, notices you have not seen before.

### Who it is for

- **Bid and tender consultants** who sweep TED every week for clients in a few CPV families and countries.
- **Sales teams at IT, engineering and services firms** that sell to the public sector in the EU.
- Anyone who wants TED results in a spreadsheet, CRM, Slack or email digest, not in a browser tab.

### What it does

1. Queries TED's official Search API with your CPV prefixes, countries (place of performance), keywords and publication window.
2. Normalises each notice into one flat row (English title where TED provides one).
3. With **Only new notices** on (off by default; turn it on for schedules), keeps a bookmark per **feed name**: the last TED publication number it delivered. The next run fetches only notices published after it, oldest first, so a weekly schedule becomes an alert that never double-bills, and a paused or capped run catches up with no gap. Each feed name has its own bookmark, so several tasks with different filters never mute each other.
4. Writes a `SUMMARY` record (query, matched, new, run time) to the run's key-value store.

### Input example

```json
{
  "cpv": ["72", "48"],
  "countries": ["DEU", "NLD"],
  "keywords": [],
  "days": 7,
  "noticeTypes": ["cn-standard", "cn-social"],
  "onlyNew": true,
  "feedName": "de-nl-software",
  "maxRows": 500
}
```

- `cpv`: CPV prefixes, e.g. `72` IT services, `48` software packages, `45` construction, `79` business services. Empty = all.
- `countries`: ISO-3 codes for place of performance (`DEU`, `FRA`, `NLD`, ...). Empty = all.
- `keywords`: optional title words, any language (titles are in the buyer's language, so add local terms).
- `days`: publication window, default 7.
- `noticeTypes`: default open calls for tender; add `pin-only` for prior information or `can-standard` for awards.
- `onlyNew`: default off, turn on for scheduled alerts; the bookmark lives in a named key-value store `ted-feed-<feedName>` in your account.
- `feedName`: one bookmark per name (default `default`). Give each task its own name; use a new name to start over or after changing filters.
- `maxRows`: hard cap per run, which also caps cost.

### Output example

Real rows from a local run on 2026-09-27 (input above, 200 notices matched):

```json
[
  {
    "noticeId": "648029-2026",
    "title": "Netherlands – Information technology services – Datafundament gemeente Den Helder",
    "buyer": "Gemeente Den Helder",
    "buyerCountry": "NLD",
    "placeOfPerformance": ["NLD"],
    "cpv": ["30236200", "72222300"],
    "noticeType": "cn-standard",
    "published": "2026-09-21",
    "deadline": "2026-11-20",
    "estimatedValue": 1845000.0,
    "currency": "EUR",
    "url": "https://ted.europa.eu/en/notice/-/detail/648029-2026",
    "pdf": "https://ted.europa.eu/en/notice/648029-2026/pdf"
  },
  {
    "noticeId": "648136-2026",
    "title": "Netherlands – Software-related services – Softwarebroker",
    "buyer": "Gemeente Nieuwegein",
    "buyerCountry": "NLD",
    "placeOfPerformance": ["NLD"],
    "cpv": ["72260000", "72266000", "72268000"],
    "noticeType": "cn-standard",
    "published": "2026-09-21",
    "deadline": "2026-09-29",
    "estimatedValue": 1040000.0,
    "currency": "EUR",
    "url": "https://ted.europa.eu/en/notice/-/detail/648136-2026",
    "pdf": "https://ted.europa.eu/en/notice/648136-2026/pdf"
  }
]
```

`deadline` is empty and `estimatedValue`/`currency` are `null` when the notice does not state them.

### Pricing

Pay per event: **`notice` = $0.004 per new notice delivered** ($4 per 1,000). Notices already delivered to you are skipped and not charged, so re-running the same window costs nothing but the start. Example: 2 CPV families in 2 countries is typically 100-300 new notices a week, about $0.40-$1.20.

### Suggested schedule

Create a schedule (Apify Console > Schedules) running weekly, e.g. Monday 06:00 UTC (cron `0 6 * * 1`), with `days: 7`, `onlyNew: true` and its own `feedName`. Connect the dataset to Google Sheets, Slack, email or a webhook via Integrations.

### Why this and not a scraper

It reads TED's official Search API (`https://api.ted.europa.eu/v3/notices/search`), not the website, so it does not break when the site changes and it stays inside TED's terms.

### Data source and licence

- TED API docs (docs.ted.europa.eu, fetched 2026-09-26): "The Search API does not require a key."
- TED legal notice (ted.europa.eu/en/legal-notice, fetched 2026-09-26): procurement notices are reusable under the Commission Decision of 12 December 2011 on the reuse of Commission documents, freely reusable for commercial or non-commercial purposes unless otherwise noted; editorial content CC BY 4.0; metadata CC0; the TED logo may not be used without consent.
- Attribution: "Source: TED, Publications Office of the European Union." No TED logo is used. No personal data is requested or stored.
- This Actor is not affiliated with or endorsed by the Publications Office of the European Union.

### Development

Local run: `PATH=.venv/bin:$PATH apify run -p -i '<json input>'` (no login needed). Check: `.venv/bin/python test_main.py`. Publish steps: see `PUBLISH.md`. Terms re-read quarterly (brainstorm terms-watch).

# Actor input Schema

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

CPV code prefixes; a notice matches if any of its CPV codes starts with one of these. Examples: 72 (IT services), 48 (software packages), 45 (construction), 79 (business services), 7226 (software consultancy). Empty = all sectors.

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

ISO 3166 alpha-3 codes for where the contract is performed, e.g. DEU, FRA, NLD, BEL, AUT, POL. Empty = all countries.

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

Optional. A notice matches if its title contains any of these words (TED titles are in the buyer's language, so add local terms too, e.g. software, Software, logiciel). Empty = no keyword filter.

## `days` (type: `integer`):

Publication window. Use 7 for a weekly schedule. With 'Only new notices' on, it only sets how far back a new feed starts; after that the bookmark decides.

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

TED notice types. Default: open calls for tender (cn-standard, cn-social). Add pin-only / pin-buyer for prior information notices, can-standard for contract awards.

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

Keep a bookmark per feed (the last TED publication number delivered, in a named key-value store in your account) and deliver and charge only notices published after it, oldest first. A paused schedule catches up with no gap. Turn on for scheduled alerts.

## `feedName` (type: `string`):

With 'Only new notices' on, each feed name keeps its own bookmark, so several tasks with different filters never mute each other. Use a new name to start over or after changing filters.

## `maxRows` (type: `integer`):

Hard cap on notices fetched per run, which also caps the cost (max rows x $0.004).

## Actor input object example

```json
{
  "cpv": [
    "72",
    "48"
  ],
  "countries": [
    "DEU",
    "NLD"
  ],
  "keywords": [
    "software"
  ],
  "days": 7,
  "noticeTypes": [
    "cn-standard",
    "cn-social"
  ],
  "onlyNew": false,
  "feedName": "default",
  "maxRows": 500
}
```

# Actor output Schema

## `tenders` (type: `string`):

No description

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

No description

# 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 = {
    "cpv": [
        "72",
        "48"
    ],
    "countries": [
        "DEU",
        "NLD"
    ],
    "keywords": [
        "software"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("colbyham/ted-tenders-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 = {
    "cpv": [
        "72",
        "48",
    ],
    "countries": [
        "DEU",
        "NLD",
    ],
    "keywords": ["software"],
}

# Run the Actor and wait for it to finish
run = client.actor("colbyham/ted-tenders-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 '{
  "cpv": [
    "72",
    "48"
  ],
  "countries": [
    "DEU",
    "NLD"
  ],
  "keywords": [
    "software"
  ]
}' |
apify call colbyham/ted-tenders-monitor --silent --output-dataset

```

## MCP server setup

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