# EU Tender Opportunities (`dataio/eu-tender-opportunities`) Actor

Open EU public procurement notices with the days remaining to bid, buyer, CPV codes and place of performance. Titles resolved to a readable language.

- **URL**: https://apify.com/dataio/eu-tender-opportunities.md
- **Developed by:** [Tom Awake](https://apify.com/dataio) (community)
- **Categories:** Business, Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$3.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?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## EU Tender Opportunities

Open EU public procurement notices with **the days remaining to bid** —
buyer, country, CPV codes, place of performance and value.

**No login. No API key. No proxies.**

### The countdown, and a readable title

TED publishes a submission deadline on **100 %** of tender notices and never
publishes how long is left. That is the only number that matters to a
company deciding whether to respond.

It also returns the title in whichever language happens to be indexed
first — measured 13 September 2026, a German buyer with a Hungarian title.
This Actor resolves the title to **English** where available, falls back to
the buyer country's language, and records which language it used in
`titleLanguage`.

A real run, IT services closing soon:

| Tender | Country | Days left |
|---|---|---|
| Sweden – IT services: consulting, software development | SWE | **1** |
| France – Technical computer support services | FRA | **1** |
| Belgium – IT services: consulting, software development | BEL | **1** |

52 of 80 results closing within a fortnight.

### Why the deadline window matters

**TED cannot sort.** Every sort parameter returns an error, and its natural
order mixes deadlines in 2027 with framework agreements running to 2038.

So "give me the 500 most urgent tenders in Europe" is not a query TED can
answer — and an Actor that sorted an arbitrary sample would be quietly
lying. Instead, **Closing within (days)** bounds the window at the source.
Inside that window the result is **complete**, and ordering it by urgency
means something.

It defaults to 60 days. Widen it to look further out, narrow it to 14 for a
weekly bid review.

This also matters for cost: filtering deadlines server-side cut the notices
fetched and discarded from **1,954 to 1** on the same query.

### Output

| Field | Example |
|---|---|
| `title`, `titleLanguage` | France – Sewerage management services, `eng` |
| `buyerName`, `buyerCountry` | Stadt Essen, DEU |
| `submissionDeadline` | 2026-09-22T14:00:00+02:00 |
| **`daysUntilDeadline`** | **1** |
| `deadlinePassed` | false |
| `cpvMain`, `cpvCodes` | 72000000 |
| `contractNature` | services / supplies / works |
| `procedureType` | open, restricted, negotiated |
| `placeOfPerformance` | NUTS codes |
| `totalValueEur` | present on about 42 % of notices |
| `winnerName`, `winnerCountry` | on award notices |
| `publicationNumber`, `publicationDate` | 599726-2026 |
| `noticeUrl`, `xmlUrl` | the notice and its machine-readable form |

### Input

```json
{
  "noticeType": "open-tenders",
  "cpvCodes": ["72000000"],
  "maxDaysUntilDeadline": 60,
  "maxItems": 500
}
```

| Field | Default | Notes |
|---|---|---|
| `noticeType` | `open-tenders` | Tenders, awards, prior information, social |
| `openOnly` | `true` | Drops closed deadlines, at the source |
| `maxDaysUntilDeadline` | `60` | The window that makes results complete |
| `cpvCodes` | `["72000000"]` | 45000000 construction, 33100000 medical |
| `countries` | — | Three-letter codes: `FRA`, `DEU`, `ESP` |
| `searchText` | — | See the caveat below |
| `maxItems` | `500` | One row per notice |
| `publishedAfter` | — | Only used when the deadline filter is off |

### Use cases

- **Bid pipeline** — every open tender in your CPV codes and countries,
  ordered by how soon it closes.
- **Market entry** — which public buyers purchase what you sell, and where.
- **Competitor tracking** — switch to award notices to see who wins.
- **Partner search** — foreign buyers and suppliers active in your sector.
- **Market sizing** — declared contract values by CPV and country.

### Limits, honestly

- **Free-text search is language-bound.** Notices are published in the
  buyer's own language, so a French keyword finds French notices and misses
  the German ones. Prefer CPV codes, which are language-neutral.
- **`totalValueEur` is present on about 42 % of tender notices.** Many
  buyers do not publish an estimate before bids.
- Award notices carry no submission deadline, so `daysUntilDeadline` is
  empty there by design.
- `winnerName` appears on roughly 90 % of award notices. Where several
  suppliers won different lots, all are listed together — TED does not say
  which lot each won, and this Actor does not guess.
- Deadlines reaching 2035 and beyond are real: long framework agreements.
  They are not errors, but they will dominate an unbounded window.
- Requests are paced out of courtesy to a free public service.
- Not affiliated with TED or the Publications Office of the European Union.

# Actor input Schema

## `noticeType` (type: `string`):

Open tenders are the ones you can still bid on. Awards show who won a past contract.

## `openOnly` (type: `boolean`):

Drops notices whose submission deadline has gone. This is the actionable set.

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

EU procurement classification, for example 72000000 for IT services, 45000000 for construction, 33100000 for medical equipment. Prefixes match broadly.

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

Three-letter codes, for example \["FRA", "DEU", "ESP"].

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

One row per notice, sorted by the nearest deadline first.

## `maxDaysUntilDeadline` (type: `integer`):

The most important setting. TED cannot sort by deadline, so this window is what makes a result complete rather than an arbitrary sample: inside it you get every matching notice, ordered by urgency. Defaults to 60 days.

## `searchText` (type: `string`):

Searched across the notice. Note that notices are published in the buyer's own language, so a French keyword finds French notices.

## `publishedAfter` (type: `string`):

YYYY-MM-DD. Defaults to 90 days ago — older notices have almost all closed.

## Actor input object example

```json
{
  "noticeType": "open-tenders",
  "openOnly": true,
  "cpvCodes": [
    "72000000"
  ],
  "maxItems": 500,
  "maxDaysUntilDeadline": 60
}
```

# Actor output Schema

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

Every row produced by the run, in JSON.

# 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 = {
    "cpvCodes": [
        "72000000"
    ],
    "maxItems": 500,
    "maxDaysUntilDeadline": 60
};

// Run the Actor and wait for it to finish
const run = await client.actor("dataio/eu-tender-opportunities").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 = {
    "cpvCodes": ["72000000"],
    "maxItems": 500,
    "maxDaysUntilDeadline": 60,
}

# Run the Actor and wait for it to finish
run = client.actor("dataio/eu-tender-opportunities").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 '{
  "cpvCodes": [
    "72000000"
  ],
  "maxItems": 500,
  "maxDaysUntilDeadline": 60
}' |
apify call dataio/eu-tender-opportunities --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,dataio/eu-tender-opportunities"
        }
    }
}
```

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/zs1IdGFYizAeygpzP/builds/dLGxzc1S8kseFSDsT/openapi.json
