# TED Tenders API – EU Public Procurement Search (`adamhaleworks/ted-tenders-api`) Actor

TED tenders API for EU public procurement: search tenders and contract awards from TED (Tenders Electronic Daily) by keyword, CPV code, country, value and deadline. Clean rows with English titles, buyer, deadline, EUR values, lots and winners. Only-new mode for daily tender alerts.

- **URL**: https://apify.com/adamhaleworks/ted-tenders-api.md
- **Developed by:** [Adam Hale](https://apify.com/adamhaleworks) (community)
- **Categories:** Business, Lead generation, Developer tools
- **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 Tenders API: EU public procurement search and tender alerts with English titles, deadlines, EUR values and winners

Search **every public tender published in the EU's official journal** (TED, Tenders Electronic Daily) by keyword, CPV sector code, country or region, value and deadline. Each notice becomes one clean row:

- **English title** (TED's translation) plus the original title and language
- **Buyer:** name, country, city, type and website
- **Deadline** for tenders or requests to participate, with days left and an open/closed flag
- **Estimated value and awarded value**, converted to **EUR** with ECB reference rates
- **Winners of contract awards** (company names, country, size, registration number)
- **Lots** with title, value, deadline and duration
- Description, CPV codes, NUTS regions, procedure type, and links to the notice, PDF, XML and the e-tendering platform

Turn on **Only new notices** and schedule a daily run to get your own **tender alert** for a fraction of the price of tender-alert subscriptions.

It uses the official TED Search API (v3), so there is no scraping, no browser, no blocking and no proxy cost. **Free while in launch; planned pay-per-event price: $2.50 per 1,000 notices.**

### What can I use it for?

- **Tender alerts for your sales team.** Get new calls for tenders in your sector and countries every morning, for example IT services (CPV 72) in Bulgaria and Romania, or medical equipment (CPV 33) above €500,000 anywhere in the EU.
- **Competitor and market analysis.** Pull contract award notices to see who wins which contracts, at what price, from which buyers.
- **Bid pipeline planning.** Prior information notices (planning) show what buyers intend to buy months in advance.
- **CRM and BI feeds.** Send clean JSON or CSV to your CRM, Google Sheets, Airtable or data warehouse through Apify integrations or the API.
- **Research and journalism.** Analyse public spending by sector, region, procedure type or buyer.

### What data does it return?

| Field | Example |
|---|---|
| `publicationNumber`, `noticeUrl`, `pdfUrl`, `xmlUrl` | `681004-2026`, links to ted.europa.eu |
| `noticeType`, `noticeTypeLabel`, `formType` | `can-standard`, `Contract award notice`, `result` |
| `title`, `mainCategory`, `titleOriginal`, `originalLanguage` | `Poland – Document management system – Zmiana stosu…`, `Document management system`, …, `pl` |
| `publicationDate`, `dispatchDate` | `2026-10-02` |
| `buyerName`, `buyerCountry`, `buyerCity`, `buyerType`, `buyerWebsite` | `Państwowy Fundusz Rehabilitacji Osób Niepełnosprawnych`, `POL`, `Warszawa` |
| `placeOfPerformanceCountries`, `placeOfPerformanceNuts` | `["POL"]`, `["PL911"]` |
| `cpvMain`, `cpvCodes` | `48311100` |
| `deadline`, `deadlineType`, `daysUntilDeadline`, `isOpen` | `2026-11-03T23:59:59+02:00`, `tenders`, `31`, `true` |
| `estimatedValue`, `estimatedValueCurrency`, `estimatedValueEur` | `18815284.59`, `PLN`, `4298180.37` |
| `awardedValue`, `awardedValueCurrency`, `awardedValueEur` | `13884357.4`, `PLN`, `3171754.97` |
| `winnerNames`, `winners[]` | `["SOFTIQ Sp. z o.o."]`, with country, size and registration number |
| `lots[]`, `lotCount` | lot ID, title, estimated value, deadline, duration |
| `procedureType`, `contractNature`, `frameworkAgreement` | `open`, `supplies`, `false` |
| `submissionUrl`, `documentsUrl` | Link to the e-tendering platform |
| `description` | Original-language description (contact details removed) |

#### Example output

A call for tenders from a real run on 2026-10-03 (shortened):

```json
{
  "publicationNumber": "681471-2026",
  "noticeUrl": "https://ted.europa.eu/en/notice/-/detail/681471-2026",
  "noticeTypeLabel": "Contract notice",
  "procedureType": "open",
  "contractNature": "supplies",
  "title": "Bulgaria – Motor vehicles – PPD26-110 „Доставка на нови неупотредявани автомобили“",
  "mainCategory": "Motor vehicles",
  "originalLanguage": "bg",
  "publicationDate": "2026-10-02",
  "buyerName": "Електроразпределителни мрежи Запад ЕАД",
  "buyerCountry": "BGR",
  "buyerWebsite": "https://ermzapad.bg",
  "placeOfPerformanceNuts": ["BG411"],
  "cpvMain": "34100000",
  "deadline": "2026-11-03T23:59:59+02:00",
  "daysUntilDeadline": 31,
  "isOpen": true,
  "estimatedValue": 2545000.0,
  "estimatedValueCurrency": "EUR",
  "estimatedValueEur": 2545000.0,
  "submissionUrl": "https://app.eop.bg/today/608285",
  "lotCount": 5,
  "lots": [
    {"lotId": "LOT-0001", "title": "„Доставка на нови неупотребявани високопроходими автомобили (пикап)“",
     "estimatedValue": 290000.0, "currency": "EUR", "deadline": "2026-11-03T23:59:59+02:00", "duration": "24 month"}
  ]
}
```

A contract award from the same day (shortened):

```json
{
  "publicationNumber": "681004-2026",
  "noticeTypeLabel": "Contract award notice",
  "title": "Poland – Document management system – Zmiana stosu technologicznego, świadczenie usługi Asysty Technicznej…",
  "buyerName": "Państwowy Fundusz Rehabilitacji Osób Niepełnosprawnych",
  "cpvMain": "48311100",
  "estimatedValue": 18815284.59, "estimatedValueCurrency": "PLN", "estimatedValueEur": 4298180.37,
  "awardedValue": 13884357.4, "awardedValueCurrency": "PLN", "awardedValueEur": 3171754.97,
  "winners": [{"name": "SOFTIQ Sp. z o.o.", "country": "POL", "size": "medium", "identifier": "NIP 9691613588"}]
}
```

The Output tab has two ready-made views, **Tenders** and **Contract awards**. Export as CSV, Excel or JSON, or fetch the results through the API.

### How much does it cost?

**Free while in launch.** The actor charges no fee of its own right now; you pay only the Apify platform usage of your runs (the free Apify plan includes $5 of usage a month). The pay-per-event price below is planned and applies only once it is switched on; Apify notifies existing users before a price change takes effect.

| Event | Planned price |
|---|---|
| Notice output | **$0.0025** (= $2.50 per 1,000 notices) |

- Notices removed by your filters, and notices already delivered in earlier runs ("Only new" mode), are **not charged**.
- **Alert example:** in our test, a daily alert for "software" or "cloud computing" calls for tenders across the whole EU matched about 160 notices per day, which at the planned price is about $0.40 a day. One country or a CPV filter usually brings that down to a few cents a day.
- **Cost cap:** once pricing is on, set **Maximum cost per run** and the actor stops cleanly when it reaches it.

For comparison (checked 2026-10-03): other TED actors on the Apify Store charge $4 per 1,000 notices, or $0.10 per record; tender-alert subscriptions such as TenderPulse, TenderMetric or Tendium cost €19–125 per month.

### How to use it

1. Set your filters: keywords, CPV codes, countries, notice types, value range or "Only open tenders". All filters are optional and combined with AND. Multiple values inside one filter are combined with OR.
2. Choose the period: **Published in the last N days** (default 7), or exact dates.
3. Click **Start**. Results are sorted newest first.

#### Daily tender alert

```json
{
  "keywords": ["software", "cloud computing"],
  "cpvCodes": ["72", "48"],
  "countries": ["BG", "RO"],
  "noticeTypes": ["competition"],
  "onlyOpen": true,
  "publishedWithinDays": 7,
  "onlyNew": true
}
```

Create a schedule (for example every weekday at 08:00) with this input and connect an integration (e-mail, Slack, Google Sheets, webhook) to the run's dataset. Each run returns only notices you have not received before. The 7-day window means a missed run never loses notices.

#### Competitor analysis: who won IT contracts above €100,000?

```json
{
  "cpvCodes": ["72", "48"],
  "countries": ["DE", "AT", "FR", "PL"],
  "noticeTypes": ["result"],
  "publishedWithinDays": 30,
  "minValueEur": 100000,
  "maxItems": 5000
}
```

#### API example

```bash
curl -X POST "https://api.apify.com/v2/acts/adamhaleworks~ted-tenders-api/run-sync-get-dataset-items?token=<TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{"cpvCodes": ["45"], "countries": ["BG"], "noticeTypes": ["competition"], "onlyOpen": true}'
```

#### Useful CPV codes

`72` IT services · `48` software packages · `45` construction work · `33` medical equipment · `79` business services · `71` architectural and engineering services · `90` sewage, refuse and environmental services · `34` transport equipment · `30` office and computing machinery · `09` fuels and energy. A short code includes every code below it.

### How it works

- **Data source.** The official [TED Search API](https://docs.ted.europa.eu/api/latest/search.html) of the EU Publications Office. It needs no key and is intended for commercial reuse. Requests are paced at 1 per second, each returning up to about 170 notices. HTTP 429 and 5xx responses get retries with backoff.
- **Search.** Your filters become a TED expert query, which is shown in the log and in the `SUMMARY` record. Advanced users can add their own conditions in **TED expert query**.
- **EUR values.** Values in other currencies are converted with the latest ECB euro reference rates. Old BGN and HRK values use the fixed euro conversion rates.
- **Only new.** The publication numbers already delivered for a search are stored in a named key-value store in your account. A different search keeps a separate memory.
- **Reliability.** A run that is migrated or restarted continues without delivering or charging notices twice. If TED is down, notices fetched so far are kept and the run fails with a clear message.

### Limitations

- TED publishes notices above the EU thresholds plus some voluntary ones. Many smaller national tenders exist only on national portals.
- TED translates titles as "Country – CPV category – original title". Descriptions and lot titles stay in the original language.
- Values are what the buyer published. Some notices have no value, or have values only per lot or per framework agreement.
- Contact persons, e-mail addresses and phone numbers are not included. Descriptions are scanned to remove e-mail addresses and phone numbers.
- **Winner names:** a winner can be a sole trader whose business name is a person's name. To avoid outputting personal data, a winner's name is shown only when it contains a company or organisation marker (GmbH, Sp. z o.o., ЕООД, S.A., Ltd, University and so on). Otherwise the row says `"nameWithheld": true` and keeps the country and size. In a test on 3,000 recent notices, 14% of winner entries were withheld; most of them were sole traders, plus some companies that publish their name without a legal form.

### Is it legal?

TED notices are official EU publications. The Commission's reuse policy (Decision 2011/833/EU) allows reuse "for commercial or non-commercial purposes", and the TED API is offered for exactly this. This actor is not affiliated with the EU Publications Office. It outputs organisations, not people, and leaves out contact persons. You are responsible for using the data in line with the laws that apply to you.

### FAQ

**Why do I get fewer results than on the TED website?** "Only latest notice versions" is on by default, so notices replaced by a change notice are skipped. The value filters also drop notices without a published value.

**How do I search a region instead of a whole country?** Use NUTS codes in **Place of performance**, for example `BG411` (Sofia), `DE21` (Upper Bavaria) or `FR10` (Île-de-France).

**Can I search in my own language?** Yes. Full-text search covers every language version of the notice, so you can use keywords in any EU language. Set **Preferred language** to get titles in your language.

**Something is wrong or missing?** Open an issue on the actor's Issues tab and include the publication number.

***

Author: Adam Hale

# Actor input Schema

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

Notices matching ANY of these words or phrases. Searches the full notice text in all languages (or only titles, see below). Supports \* wildcards, for example soft\*.

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

Common Procurement Vocabulary codes. A short code covers everything below it: 72 = all IT services, 45 = all construction work, 33 = medical equipment, 48 = software packages.

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

Where the contract is carried out. Country codes (BG, DE, FR or BGR, DEU) or NUTS region codes (BG411 = Sofia, DE21 = Upper Bavaria).

## `buyerCountries` (type: `array`):

Country of the contracting authority. Usually the same as the place of performance, but differs for EU institutions and cross-border projects.

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

competition = calls for tenders (contract notices), result = contract awards with winners, planning = prior information notices, dir-awa-pre = direct award announcements, cont-modif = contract modifications, consultation = pre-market consultations. Empty = all types.

## `contractTypes` (type: `array`):

Works, supplies and/or services. Empty = all.

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

Only notices published in the last N days. 0 = no date limit (use with other filters). Ignored when "Published from" is set.

## `onlyOpen` (type: `boolean`):

Keep only notices whose deadline for tenders or requests to participate is still in the future.

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

Keep only notices with an estimated (or awarded) value of at least this amount, converted to EUR with ECB rates. Notices without a published value are dropped when this is set.

## `maxValueEur` (type: `integer`):

Keep only notices with an estimated (or awarded) value of at most this amount in EUR. Notices without a published value are dropped when this is set.

## `excludeKeywords` (type: `array`):

Drop notices that contain any of these words or phrases.

## `searchIn` (type: `string`):

Full text searches the whole notice (titles, descriptions, lots) in every language. Title only is stricter.

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

Start date, for example 2026-01-01. Overrides "Published in the last N days".

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

End date (inclusive), for example 2026-06-30.

## `expertQuery` (type: `string`):

Optional extra condition in TED expert search syntax, combined with AND, for example: buyer-legal-type IN (cga) AND procedure-type = open. See https://ted.europa.eu/en/help/expert-search

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

Remember which notices were already output for this search and skip them next time. Schedule the actor daily to get tender alerts. The first run outputs all matches in the date window.

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

Named key-value store that remembers output notices for "Only new" mode. Each different search keeps its own memory inside it.

## `language` (type: `string`):

TED translates notice titles into all EU languages. Descriptions stay in the original language.

## `includeDescription` (type: `boolean`):

Add the procurement description (original language, up to 4,000 characters). E-mail addresses and phone numbers are removed.

## `includeLots` (type: `boolean`):

Add a list of lots with title, estimated value, deadline and duration.

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

Stop after this many notices (newest first). 0 = up to 200,000.

## `scope` (type: `string`):

All = everything published in the last 10 years. Active = planning notices of the last 364 days, competition notices with an open deadline and results of the last 99 days. Latest = only the latest daily edition.

## `onlyLatestVersions` (type: `boolean`):

Skip notices that were later replaced by a change notice.

## `requestIntervalSecs` (type: `integer`):

The TED API rate-limits bursts. 1 second (up to 250 notices per request) is safe.

## `requestTimeoutSecs` (type: `integer`):

Timeout for one API request.

## `maxRetries` (type: `integer`):

Retries for network errors, HTTP 429 and 5xx responses, with backoff.

## Actor input object example

```json
{
  "keywords": [
    "software",
    "cloud computing"
  ],
  "cpvCodes": [
    "72",
    "48000000"
  ],
  "countries": [
    "BG",
    "RO"
  ],
  "noticeTypes": [
    "competition"
  ],
  "publishedWithinDays": 7,
  "onlyOpen": false,
  "searchIn": "fulltext",
  "onlyNew": false,
  "stateStoreName": "ted-tenders-state",
  "language": "en",
  "includeDescription": true,
  "includeLots": true,
  "maxItems": 100,
  "scope": "ALL",
  "onlyLatestVersions": true,
  "requestIntervalSecs": 1,
  "requestTimeoutSecs": 60,
  "maxRetries": 5
}
```

# Actor output Schema

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

Dataset items, one per notice. Views: tenders, contract awards.

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

SUMMARY record in the default key-value store: TED expert query, matched and output counts, only-new state, stop reason and API requests.

# 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",
        "cloud computing"
    ],
    "noticeTypes": [
        "competition"
    ],
    "maxItems": 100
};

// Run the Actor and wait for it to finish
const run = await client.actor("adamhaleworks/ted-tenders-api").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",
        "cloud computing",
    ],
    "noticeTypes": ["competition"],
    "maxItems": 100,
}

# Run the Actor and wait for it to finish
run = client.actor("adamhaleworks/ted-tenders-api").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",
    "cloud computing"
  ],
  "noticeTypes": [
    "competition"
  ],
  "maxItems": 100
}' |
apify call adamhaleworks/ted-tenders-api --silent --output-dataset

```

## MCP server setup

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

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/sdsXKKrkPgfRbelKH/builds/16WOjwqsSnLJHSP8z/openapi.json
