# TED Tender Notices Search (unofficial) – open calls & awards (`licensedpipe/tender-notices-ted-unofficial`) Actor

- **URL**: https://apify.com/licensedpipe/tender-notices-ted-unofficial.md
- **Developed by:** [licensed pipe](https://apify.com/licensedpipe) (community)
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per usage

This Actor is paid per platform usage. The Actor is free to use, and you only pay for the Apify platform usage, which gets cheaper the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-usage

## 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 Tender Notices Search (unofficial) – v0.3

Publisher: **Licensed Pipe** · Contact: licensedpipe@gmail.com

Search the EU's official public procurement journal (TED – Tenders Electronic Daily) and get clean, flat rows for **open calls** and **contract awards**:
publication number, notice URL, title (original language + English where present), buyer name/country, CPV codes, contract nature, procedure type, estimated value, submission deadline – and for awards: awarded value + currency, winner country and size class (micro/small/SME/large), number of tenders received, contract conclusion date, winner-selection status.

> **Unofficial.** This actor is an independent third-party tool. It is not provided, operated, endorsed or supported by the European Union, the European Commission or the Publications Office of the European Union. No EU emblem or TED/SIMAP logo is used. Data is shown as published by the buyers; it can be wrong, incomplete or outdated and is not legal, financial or procurement advice. Only the notice on ted.europa.eu is authoritative (see `noticeUrl`).

**Permitted use / no profiling.** Do not use this data (or data derived from it) to profile, score, track or target natural persons. The actor is meant for organisation-level procurement monitoring only. Output fields `title`, `titleEnglish` and `buyerName` may in rare cases contain a person's name; do not use them for profiling or direct marketing to individuals.

Built for procurement monitoring, bid-alert pipelines and AI agents (small, stable JSON schema; usable via the Apify MCP server).

### Data source, licence and required attribution

| item | value |
|---|---|
| Source | TED Search API v3, `POST https://api.ted.europa.eu/v3/notices/search` (official, anonymous, no key) |
| Publisher | Publications Office of the European Union (OP) |
| Licence | OP/Commission reuse policy, **Commission Decision 2011/833/EU** (dataset licence entry "COM_REUSE" on data.europa.eu, ted-1) |
| Commercial reuse | Yes – Art. 4: documents "shall be available for reuse for commercial or non-commercial purposes ... without charge ... without the need to make an individual application" |
| Conditions | Art. 6(2): may include acknowledging the source, not distorting the original meaning, non-liability of the Commission |
| **Attribution (required)** | "Source: TED (Tenders Electronic Daily), Publications Office of the European Union, https://ted.europa.eu. Reused under Commission Decision 2011/833/EU. Data restructured by this actor; not an official EU product." – shipped in each row's `source` field and in the `RUN_SUMMARY` record. |
| TED legal notice | https://ted.europa.eu/en/legal-notice – "procurement notices published in the Supplement to the Official Journal ... can be freely reused, for commercial or non-commercial purposes"; editorial content of the SIMAP sites is CC BY 4.0; additional rights may have to be cleared where content depicts identifiable private individuals or contains third-party works; TED/SIMAP logos may not be used without consent (read 2026-11-02) |

### Personal data / compliance design

- **No free-text descriptions.** Buyer-authored description texts may carry third-party rights (Decision 2011/833/EU Art. 2(2)(b)); they are neither requested from the API nor output (removed in v0.3). Only structured fields and the notice title are returned; full text is one click away via `noticeUrl`.
- Buyer = contracting authority (organisation). Contact persons, e-mails, phone numbers: **not requested** (TED notices contain them; the Publications Office's privacy statement for "TED notices" lists contact persons and, for awards, tenderers that may be natural persons).
- **Residual risk (read before use):** the `title`, `titleEnglish` and `buyerName` fields are free text written by the buyer. In rare cases they can contain the name of a natural person (e.g. a private buyer, or a person named in a title). The actor cannot reliably detect this. Under Apify's Standard Actor Contract you, the user, are the data controller of any personal data in the output and the actor author acts only as your processor on your instructions; you need your own lawful basis, must honour data-subject requests and should not store notices longer than needed (TED itself removes notices from the public site after 10 years). If you are not sure, drop those fields in your pipeline.
- The actor writes no raw API responses to logs or storage; the dataset contains only the fields listed above and `RUN_SUMMARY` contains the query you entered.
- Winner **names are deliberately not collected** (sole traders would make them personal data under GDPR); only country, size class and aggregate values are returned. Winner details remain one click away through the `noticeUrl`.
- No scraping of HTML pages; official API only. Not a legal/tender-advice service; values are as published and may be wrong or missing.

### Politeness and hard limits

TED publishes no rate limit for the anonymous Search API, so the actor is deliberately conservative: one request at a time, **at least 1 s between request starts** (max ~1 request/s per run), random 0–3 s start jitter, **hard cap 1000 notices (max 10 requests) per run**, max 3 retries with exponential backoff + jitter, `Retry-After` honoured (numeric and HTTP-date; if the server asks for more than 60 s the run aborts instead of waiting/hammering), immediate stop on HTTP 202/403 (CDN/WAF challenge) and when your spending limit is reached. Identifying User-Agent with run id. api.ted.europa.eu/robots.txt returns 404 (no restrictions). Please do not start many parallel runs; for bigger exports use TED's own bulk download.

### Input (see .actor/input_schema.json)

| field | meaning |
|---|---|
| keywords | full-text keywords (OR) |
| cpvPrefixes | CPV code prefixes (OR), e.g. `72` IT services |
| countries | buyer country, ISO3 (DEU, FRA, FIN ...) |
| publishedFrom / publishedTo | publication date window (default: last 7 days) |
| noticeKind | contract (open calls) / award / all |
| deadlineAfter | only tenders with submission deadline on/after |
| minEstimatedValueEur | minimum estimated value |
| maxResults | cap, default 100, **max 1000** (each result billed) |

### Example output item (award)

```json
{"publicationNumber":"718666-2026","noticeUrl":"https://ted.europa.eu/en/notice/-/detail/718666-2026","publicationDate":"2026-10-19","noticeType":"can-standard","title":"...","buyerName":"Miejskie Przedsiębiorstwo Komunikacyjne – Łódź ...","buyerCountry":"POL","cpvCodes":["50316000"],"contractNature":"services","procedureType":"open","awardedValue":3012300,"awardedCurrency":"PLN","winnerSelectionStatus":["selec-w"],"winnerCountries":["POL"],"winnerSizes":["large"],"contractConclusionDates":["2026-09-29"],"tendersReceived":2,"source":"TED / Publications Office of the EU (Decision 2011/833/EU)"}
```

### Local run (no account needed)

```bash
npm install
mkdir -p storage/key_value_stores/default
echo '{"countries":["FIN"],"maxResults":50}' > storage/key_value_stores/default/INPUT.json
APIFY_LOCAL_STORAGE_DIR=./storage node main.js
```

### Measured on 2026-11-02 (2 vCPU / 8 GB Debian server, Node 24)

| run | rows | wall | CPU (user+sys) | peak RSS |
|---|---|---|---|---|
| open calls, published since 2026-10-19 (v0.3, no descriptions; re-test 2.11. iltapäivä) | 1000 | 18.5 s (API latency varies 14–50 s) | 2.5 s | 139 MB |
| **award notices published since 2026-10-19** (v0.3 re-test) | 1000 | 14.6 s | 2.7 s | 143 MB |
Open calls (1000, unique, no description field): title/buyer/CPV 100 %; submissionDeadline 89 %; estimatedValue 48 %. Award data quality (re-test, 1000 unique rows): title 100 %; buyerName 100 %; buyerCountry 100 %; source 100 %; awardedValue 89 %; awardedCurrency 93 %; winnerCountries 90 %; winnerSizes 88 %; contractConclusionDates 89 %; tendersReceived 85 %. 17 313 award notices matched that date window.

### Known limitations

- Multi-lot notices: values come from the notice-level total (fallback lot-level sum); winner fields are de-duplicated lists, not per-lot rows.
- `tendersReceived` sums the TED "tenders" statistic across lots. Sentinel value -1 is dropped.
- Per-query cap in TED API: 15 000 notices; this actor returns at most 1000 per run: split by date window and run the windows one after another.
- Not legal advice; the names "TED" and "Tenders Electronic Daily" are used only to describe the data source (nominative use).

# Actor input Schema

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

Full-text keywords (OR). Quoted phrases supported. Leave empty to match everything.

## `cpvPrefixes` (type: `array`):

CPV code prefixes, e.g. 72 (IT services), 4521 (building work). Matches any (OR).

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

ISO 3166-1 alpha-3 codes of the contracting authority country, e.g. DEU, FRA, FIN.

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

Earliest publication date, YYYY-MM-DD. Default: 7 days ago.

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

Latest publication date, YYYY-MM-DD.

## `noticeKind` (type: `string`):

Open calls for tender, awarded contracts, or both.

## `deadlineAfter` (type: `string`):

Only tenders whose submission deadline is on/after this date (YYYY-MM-DD).

## `minEstimatedValueEur` (type: `integer`):

Minimum estimated procedure value (in the notice currency, usually EUR).

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

Maximum number of notices to return (each result is billed). Hard cap 1000 per run to protect the TED API; split larger exports into date windows run one after another.

## Actor input object example

```json
{
  "keywords": [
    "software"
  ],
  "cpvPrefixes": [],
  "countries": [],
  "noticeKind": "contract",
  "maxResults": 100
}
```

# Actor output Schema

## `results` (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 = {
    "keywords": [
        "software"
    ],
    "cpvPrefixes": [],
    "countries": []
};

// Run the Actor and wait for it to finish
const run = await client.actor("licensedpipe/tender-notices-ted-unofficial").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"],
    "cpvPrefixes": [],
    "countries": [],
}

# Run the Actor and wait for it to finish
run = client.actor("licensedpipe/tender-notices-ted-unofficial").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"
  ],
  "cpvPrefixes": [],
  "countries": []
}' |
apify call licensedpipe/tender-notices-ted-unofficial --silent --output-dataset

```

## MCP server setup

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

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/QecD1tWR9yelpRAMR/builds/N4MRcuLZa01hdvikG/openapi.json
