# TED Tenders Scraper – EU Tenders, Awards & Winners (`s-r/ted-tenders`) Actor

Search EU tenders published on TED (Tenders Electronic Daily) by keyword, buyer country, CPV code, date and value. Get buyers, deadlines, contract values, award winners with registration numbers, and XML/PDF links for bid teams and market analysts.

- **URL**: https://apify.com/s-r/ted-tenders.md
- **Developed by:** [SR](https://apify.com/s-r) (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

$2.00 / 1,000 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

## TED Tenders Scraper – EU Tenders, Awards & Winners

Search TED tenders and European public procurement awards by keyword, buyer country, CPV,
publication date and value. Export notices with deadlines, buyer details and award winners,
including national registration numbers when TED supplies a reliable match.

### What you can collect from TED tenders

TED (Tenders Electronic Daily) is the European Union’s public procurement publication
service. Suppliers can follow new EU tenders in their sector, consultants can prepare a
shortlist for clients, and analysts can compare published awards across buyers and
countries. This actor returns one row for each published notice, so a contract notice and
its later award remain separate records with separate notice numbers. A notice may describe
several lots without creating an extra charge for each lot.

The results include the notice identifier, publication date, title, procedure type, buyer
name and national identifier, buyer country, unique CPV classifications, available value
information and the earliest submission or participation deadline. Links point to the
published notice and its XML and PDF versions. Award notices can also include the winning
suppliers, their countries and their national registration numbers.

### Use cases for TED tenders data

- **Bid and sales teams** monitor new European tenders for their CPV codes and countries,
  and route each notice with its deadline into a CRM, spreadsheet or alert channel.
- **Bid consultants** build a weekly shortlist of open procurement opportunities for each
  client, filtered by value and buyer country.
- **Market analysts** study who wins public contracts in a sector, at what value, and for
  which buyers, using award notices with winner names and registration numbers.
- **Sales intelligence** joins winning suppliers to company registers through the
  normalized registration number, to find companies that already sell to governments.
- **Researchers and journalists** collect award notices for a buyer or region over a
  historical date range and keep the original XML and PDF links as evidence.

### Input

Start with `keywords`, `countries` and `max_items` when looking for opportunities. Buyer
countries accept either two-letter or three-letter ISO codes. The country filter describes
the buying organisation, so it does not require a winning supplier to be based in the same
country. `cpv_codes` use eight digits, with an optional check digit. TED treats
classifications hierarchically, which means a broad classification can include more
specific activities.

Use `notice_types` to select individual TED notice types. `cn-standard` selects standard
contract notices and `can-standard` selects standard contract award notices. The convenience
group `competition` expands to related contract notice types. `award` selects `can-standard`,
`can-social`, `can-desg`, `can-tran` and `veat`. Select `can-modif` explicitly to include
contract modifications. Use the individual
codes if your workflow requires an exact publication category.

`published_from` and `published_to` accept calendar dates in YYYY-MM-DD format. If neither
boundary is provided, the actor searches from seven days ago. This date floor also applies
to expert queries. For an older notice, provide an explicit historical date boundary.
Supplying only `published_to` searches through that date without applying the recent floor.
The default ordering uses the unique publication number descending, so notices from the same
publication date remain reachable across result pages.

`query` accepts TED expert search syntax and combines it with the other filters. If the
query contains an explicit sorting clause, that clause is preserved. Sorting explicitly on
a non-unique field can skip notices on subsequent result pages. For ordinary text, commas
outside double quotes in `keywords` separate alternatives. Quoted phrases stay together,
including when preceded by other words. Input containing only commas is rejected. The aliases
`keyword`, `expertQuery`, `maxItems` and `maxResults` are available; the corresponding primary
field takes precedence when both are supplied.

`min_value` filters TED’s total value in the notice’s original currency. This number may
represent an estimated procurement value or a contract award, depending on the notice.
Values in euros, Czech crowns and other currencies are not converted into a common unit.
Compare values together with `currency`. `only_open` uses TED’s ACTIVE search scope.

`language` defaults to ENG and accepts TED’s 24 publication language codes. The chosen
language controls the notice heading and the detail and PDF links. The country and CPV
wording is localized by TED; the original procurement title, buyer name and description
are not automatically translated.

This expert query searches standard contract notices from German buyers, with German
headings and the unique publication number as the sort field:

```json
{
  "query": "FT~software AND buyer-country=DEU AND notice-type=cn-standard AND publication-date>=20261001 SORT BY publication-number DESC",
  "published_from": "2026-10-01",
  "language": "DEU",
  "max_items": 3
}
```

### Output

Each dataset row uses stable field names, including `source`, `fetched_at`, `notice_id`,
`publication_date`, `published_at`, `title`, `notice_type`, `notice_type_code`, `buyer_name`, `buyer_country`, `buyer_national_id`, `cpv_codes`,
`deadline`, `estimated_value`, `awarded_value`, `value`, `currency`, `estimated_currency`, `winners`, `url`, `xml_url` and
`pdf_url`. `notice_type` is the readable English label from the official eForms notice-type
code list; `notice_type_code` keeps the raw code (`can-standard`, `veat`, …) that
`notice_types` accepts. Buyer and winner countries are two-letter codes; `buyer_country_iso3` retains the
original three-letter buyer code. The `stage` field uses the stages shared with other
public tender sources: `planning`, `tender` (call for competition) or `award` (including
VEAT and modifications of a running contract); it is null for corrections and other forms.
`stage_detail` keeps the finer TED stage: planning, competition, award, modification,
correction or other.

Estimated and awarded values are separate fields. VEAT notices have stage `award` and
their total value is returned as `awarded_value`. During planning or competition, total
value can fill a missing estimate. A contract modification’s total value fills neither
field; an explicit source estimate is retained. `value` is the single amount for the
stage: the estimate for planning and tender, the awarded value for an award. `currency`
is null whenever `value` is null, including contract modifications without an award amount.
Missing information remains null, and missing supplier lists
remain empty. Older notices often lack original procurement titles, descriptions and
winner information. The actor preserves that absence instead of inferring those fields.

Winners are taken from TED’s actual winning supplier names. A supplier’s registration
number is included only when the supplier name matches the tenderer organisation data.
Non-winning tenderers are not returned as winners. Repeated winner names across contracts
and lots are deduplicated. Each supplier can include `national_id`, its original identifier,
and `registry_id`, a normalized identifier for a company register lookup, with
`jurisdiction` naming that register's country. A French SIRET
is reduced to its SIREN where its format is valid. Recognized formats also include British
Companies House numbers, eight-digit Dutch and Czech numbers and nine-digit Portuguese
numbers. Other countries and unrecognized identifiers have a null `registry_id`; their raw
`national_id` is retained. Format recognition does not verify a company’s registration.
Register data is not automatically
fetched, so customers can choose which register or verification service to join.

#### Output example: an award notice with its winner

Notice 674647-2026 is Stedin’s award for Pre- en In-Employment Screening. Its winning
supplier is International Security Partners B.V., with Dutch registration number 39050726.
Other organisations that submitted a tender are not included in its winners list. The
example files contain actual TED responses captured on 5 October 2026 and projected into
the documented row format. This is that row, with the long description shortened:

```json
{
  "source": "ted-tenders",
  "fetched_at": "2026-10-05T09:05:14Z",
  "notice_id": "674647-2026",
  "publication_date": "2026-10-01",
  "published_at": "2026-10-01T00:00:00+02:00",
  "url": "https://ted.europa.eu/en/notice/-/detail/674647-2026",
  "title": "Netherlands – Business services: law, marketing, consulting, recruitment, printing and security – Pre- en In-Employment Screening",
  "description": "Het voorwerp van deze aanbesteding betreft het op rechtmatige wijze contracteren van één (1) leverancier …",
  "notice_type": "Contract or concession award notice – standard regime",
  "notice_type_code": "can-standard",
  "stage": "award",
  "stage_detail": "award",
  "procedure_type": "open",
  "buyer_name": "Stedin",
  "buyer_country": "NL",
  "buyer_national_id": "24289101",
  "cpv_codes": ["79000000", "79611000", "79700000"],
  "deadline": null,
  "estimated_value": 3900000,
  "awarded_value": 3900000,
  "value": 3900000,
  "currency": "EUR",
  "estimated_currency": "EUR",
  "winners": [
    {
      "name": "International Security Partners B.V.",
      "country": "NL",
      "national_id": "39050726",
      "registry_id": "39050726",
      "jurisdiction": "NL",
      "size": null
    }
  ],
  "form_type": "result",
  "notice_subtype": "30",
  "notice_version": 1,
  "title_original": "Pre- en In-Employment Screening",
  "original_language": "NLD",
  "buyer_names": ["Stedin"],
  "buyer_country_iso3": "NLD",
  "buyer_city": "Rotterdam",
  "buyer_legal_type": null,
  "main_cpv": "79000000",
  "contract_nature": "services",
  "place_of_performance_country": "NL",
  "dispatch_date": "2026-09-29",
  "contract_conclusion_date": "2026-08-25",
  "lot_count": 1,
  "submission_url": null,
  "documents_url": null,
  "xml_url": "https://ted.europa.eu/en/notice/674647-2026/xml",
  "pdf_url": "https://ted.europa.eu/en/notice/674647-2026/pdf"
}
```

### Result limits and continuation

`max_items` defaults to 100 and can request up to 100,000 notices. Large actor runs collect
successive result pages automatically until they reach the requested number or the
available results. The run summary reports incomplete work when a source timeout or a
request limit prevents completion. Keep the summary alongside your dataset when auditing
coverage. An empty search returns no dataset rows.

When using the API directly, `next_cursor` lets you continue a larger search. Return the
complete token unchanged with the same filters, language and scope and resume promptly,
because source tokens can expire. The default date window stays anchored to the initial
search when continuing across UTC midnight. The continuation keeps unread notices so a result limit
does not discard them. `total_count` is the source’s total number of matched notices and can
exceed the number you requested. A notice deadline is published information; confirm current
tender documents before making a submission decision.

### How this compares to other ways of getting TED tenders

| | TED website search | TED bulk XML packages | This actor |
|---|---|---|---|
| Filter by keyword, country, CPV, date and value | yes, by hand | no, you filter yourself | yes, in one input |
| One flat row per notice | no | no, nested eForms XML | yes |
| Winning suppliers with registration numbers | read each notice | parse each XML file | in the `winners` field |
| Estimated and awarded value kept apart | read each notice | parse each XML file | separate fields |
| Schedule, API, webhooks and exports | no | no | yes, through Apify |

Other TED tender scrapers in the Apify Store mostly return the search fields of a notice.
This actor also reads the award data, keeps non-winning tenderers out of the winners list,
and normalizes the winner’s national identifier so you can match it to a company register.

### Pricing

This TED tenders actor uses Apify’s pay-per-event pricing. The billable event is `tender`,
charged once for each notice delivered to the dataset, at a list price of $0.002 per notice
($2 per 1,000 notices). No additional event is charged for each winning supplier or lot.
Empty searches deliver zero notices and incur zero tender events. The actor’s pricing panel
in the Apify Store is the applicable price; an example or an export does not replace it.

Users on a free Apify plan can receive up to ten notices per run. The same limit applies
when using a volume alias. Paid-plan users can request the larger documented limit.
Choose a small maximum when testing a filter, then increase it after checking the results.

### FAQ

#### Can I search historical procurement notices?

Yes. Set an explicit publication date boundary and use a keyword, filter or expert query.
Without a date boundary, the actor applies its rolling seven-day publication floor.
Historical notices may contain fewer structured fields than newer notices.

#### Are buyer and winner identifiers verified company records?

They are identifiers published by TED, matched to the correct supplier name when possible.
The actor does not confirm a company’s current legal status. Use the normalized identifier
and country to join a company register if your workflow needs that information.

#### Does the language option translate the full procurement description?

TED’s heading and links follow the selected language. Original procurement titles and
free-text descriptions remain in their published language, so the actor does not promise
a translated specification or translated contract documents.

#### Why can an award have an empty winners list?

The source may not expose structured winner names, especially for older notices. The
actor returns an empty list and keeps other available award fields. It does not substitute
all tenderers for the winning supplier.

#### Can I get only open tenders with a deadline still ahead?

Set `only_open` to true and choose competition notice types. The actor then uses TED’s
active search scope. Always check the deadline in the tender documents before you bid.

#### How do I get daily alerts for new EU tenders?

Save your input as an Apify task and schedule it once a day with the default seven-day
window or a `published_from` date. Connect a webhook or an integration to send new notices
to your inbox, spreadsheet or CRM.

# Actor input Schema

## `keywords` (type: `string`):

Free-text terms; commas mean OR and double quotes preserve a phrase. Use query for TED expert syntax.

## `keyword` (type: `string`):

Alias of keywords; keywords takes precedence.

## `query` (type: `string`):

TED expert query, combined with the filters below. An explicit SORT BY is preserved.

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

Alias of query; query takes precedence.

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

Buyer countries as ISO alpha-3 or alpha-2 codes, for example DEU or DE. These filter the buyer, not the supplier.

## `cpv_codes` (type: `array`):

Eight-digit CPV codes with an optional check digit. TED also matches descendants in the CPV hierarchy.

## `notice_types` (type: `array`):

TED notice types, for example cn-standard or can-standard. competition expands to cn-\* and pin-cfc-\*; award selects can-standard, can-social, can-desg, can-tran and veat. Contract modifications require can-modif explicitly.

## `published_from` (type: `string`):

Publication date floor, YYYY-MM-DD. Defaults to seven days ago when neither date boundary is supplied, including expert queries.

## `published_to` (type: `string`):

Inclusive publication date ceiling, YYYY-MM-DD. Supplying only this boundary disables the rolling seven-day floor.

## `min_value` (type: `number`):

Minimum TED total-value, in each notice’s original currency. This may be an estimate or an award amount. No currency conversion.

## `only_open` (type: `boolean`):

Use TED ACTIVE scope when true; otherwise search all notices. This is TED’s scope, not a recalculated deadline filter.

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

TED language for the notice title, detail URL and PDF. The country and CPV wording is localized; the original procurement title is not translated.

## `max_items` (type: `integer`):

Maximum notices in the actor run; default 100. Each API call returns at most 2,000 and exposes next_cursor for continuation.

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

Alias of max_items; max_items takes precedence.

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

Alias of max_items; max_items and maxItems take precedence.

## `cursor` (type: `string`):

Opaque next_cursor from the previous response. Keep filters, language and scope unchanged. The cursor preserves unread notices and TED’s original page size; resume promptly.

## Actor input object example

```json
{
  "query": "FT~software AND buyer-country=DEU AND notice-type=cn-standard AND publication-date>=20261001 SORT BY publication-number DESC",
  "published_from": "2026-10-01",
  "only_open": false,
  "language": "ENG",
  "max_items": 3
}
```

# Actor output Schema

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

One dataset row per TED notice.

## `output` (type: `string`):

Counts, errors and incomplete work in OUTPUT.

# 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 = {
    "query": "FT~software AND buyer-country=DEU AND notice-type=cn-standard AND publication-date>=20261001 SORT BY publication-number DESC",
    "published_from": "2026-10-01",
    "max_items": 3
};

// Run the Actor and wait for it to finish
const run = await client.actor("s-r/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 = {
    "query": "FT~software AND buyer-country=DEU AND notice-type=cn-standard AND publication-date>=20261001 SORT BY publication-number DESC",
    "published_from": "2026-10-01",
    "max_items": 3,
}

# Run the Actor and wait for it to finish
run = client.actor("s-r/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 '{
  "query": "FT~software AND buyer-country=DEU AND notice-type=cn-standard AND publication-date>=20261001 SORT BY publication-number DESC",
  "published_from": "2026-10-01",
  "max_items": 3
}' |
apify call s-r/ted-tenders --silent --output-dataset

```

## MCP server setup

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