# EU Tenders Finder & Bid Matcher: TED Fit Score & Past Winners (`nerolabs/eu-tender-bid-matcher`) Actor

Finds open EU public tenders on TED that fit your CPV codes and keywords, scores fit 0 to 100, flags close deadlines, and adds past winners, median award value and typical bid count for similar contracts. Monitor mode returns only new tenders. $0.01 per matched tender. Agent-ready: x402, MCP.

- **URL**: https://apify.com/nerolabs/eu-tender-bid-matcher.md
- **Developed by:** [Adam Pearce](https://apify.com/nerolabs) (community)
- **Categories:** Lead generation, Automation, Business
- **Stats:** 2 total users, 1 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $7.00 / 1,000 matched tenders

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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 Finder & Bid Matcher: TED Fit Score & Past Winners

**Tired of scrolling TED every morning for tenders you could actually win?** Give this Actor your CPV codes and a few words about what you do. It returns the open EU public tenders that fit you, best first, each with a fit score out of 100, the deadline and days left, the estimated value in euro, and what similar contracts went for: who won them, the median award value, and how many bids they usually get.

It reads TED (Tenders Electronic Daily), the EU's official public procurement journal, through the official TED search API. No scraping, no login, no key.

### Who it is for

- **Companies that bid on public contracts** (IT, consulting, construction, facilities, medical supplies): a short daily list of tenders that fit, instead of hundreds of raw notices.
- **Bid writers and tender consultants**: one watch per client, each with its own CPV codes and keywords, from a Google Sheet.
- **Sales and market teams**: who keeps winning in your category and country, and at what price.
- **AI agents and automations**: one call returns scored, ready-to-act rows (agent-ready through MCP and x402 payments).

### What you get for each tender

| Field | What it means |
|---|---|
| `fitScore` | 0 to 100. CPV match up to 50 (more exact codes score higher), keywords up to 40, estimated value inside your range 10. |
| `matchedCpv`, `matchedKeywords`, `fitReasons` | Why it scored what it did, in plain words. |
| `title`, `originalTitle`, `buyer`, `buyerCountry` | English title from TED plus the buyer's own title and name. |
| `deadline`, `daysLeft`, `urgent` | Earliest open submission deadline; `urgent` is 14 days or less. |
| `estimatedValue`, `estimatedValueCurrency`, `estimatedValueEur` | The buyer's estimate, converted to euro at the ECB rate of the day. |
| `similarAwards`, `medianAwardEur`, `estimateVsMedianAward` | Recent award notices in the same CPV class and country, their median value, and this tender's estimate against it (2.0 means twice the usual size). |
| `medianBidsPerTender`, `smeWinShare` | How many bids similar contracts usually get, and the share won by small and medium firms. |
| `topPastWinners`, `topPastWinnersList` | The firms that won most of those contracts: your likely rivals, or partners. |
| `noticeUrl`, `pdfUrl` | The official TED notice and its PDF. |
| `olderNoticeNumbers` | When a buyer published the same tender twice, the older notice numbers. You get one row and pay once. |

A run summary (`SUMMARY` in the key-value store) holds the TED query used, counts, and the top 10 tenders.

### How to use it

1. Put your **CPV codes** in `cpvCodes`, e.g. `72000000` for all IT services, `72200000` for software consultancy, `45000000` for construction. Trailing zeros mean the whole branch.
2. Add **keywords** for what you do (`cloud`, `cybersecurity`, `GIS`). Notices are often in the buyer's language, so add local words too (`Software`, `logiciel`, `oprogramowanie`). With no CPV codes, keywords run a TED full-text search instead.
3. Optional: **countries** (`DE`, `FR`, `PL`...), a value range in euro, **exclude words** (`hardware`, `catering`), days left to bid.
4. Or keep the whole profile in a **Google Sheet or CSV** (`capabilityListUrl`): CPV codes in one column, services or keywords in another.
5. For a daily alert, turn on **monitor mode**, give the watch a name, and schedule the Actor. Each run returns only tenders it has not returned before, optionally posted to your **webhook** (Slack, Zapier, Make, n8n).

#### Example input

```json
{
  "cpvCodes": ["72200000", "72500000"],
  "keywords": ["cloud", "cybersecurity", "Software", "logiciel"],
  "countries": ["DE", "FR", "NL", "IE"],
  "minValueEur": 50000,
  "publishedWithinDays": 2,
  "minFitScore": 60,
  "monitorMode": true,
  "watchName": "acme-it"
}
```

### Pricing

Pay per event: **$0.01 per matched tender returned**, past winner benchmark included. Scanning TED, tenders below your minimum fit score, excluded tenders and tenders already returned in monitor mode are **never charged**.

Examples:

- A daily monitor returning about 15 new matching tenders a day: about **$4.50 a month**.
- A consultant running 5 client watches at 20 tenders a day each: about **$30 a month**.
- A one-off sweep of the 300 best IT tenders open across the EU: **$3**.

Paid tender alert services usually charge 50 to 300 euros a month per seat.

### FAQ

**Is this allowed?** Yes. TED is published by the EU Publications Office for reuse, commercial use included, under Commission Decision 2011/833/EU, with the source credited (each row carries a `source` field). The Actor uses TED's official search API, which needs no key.

**Which countries?** Every buyer that publishes on TED: all EU member states plus EEA countries, Switzerland and others that use it. Below-threshold national tenders that never reach TED are not included.

**Why do some tenders have no estimated value?** Buyers do not always publish one. Those tenders are kept (your value range only drops tenders whose value is known and outside it).

**How exact are the past winners?** They come straight from TED contract award notices in the same CPV class (first 5 digits) and buyer country, up to the latest 250 notices in your benchmark window. If fewer than 5 exist in that country, all countries are used, and `benchmarkScope` says which.

**Does it read the tender documents?** No. It reads the notice (titles, descriptions, CPV codes, values, deadlines). Follow `noticeUrl` for the documents.

If this saved you a morning on TED, a review on the Apify Store helps a lot.

### Data source

TED, Tenders Electronic Daily, © European Union, https://ted.europa.eu. Euro rates: European Central Bank reference rates.

# Actor input Schema

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

CPV codes (Common Procurement Vocabulary, the EU's category codes) for what you sell, e.g. 72000000 (all IT services), 72200000 (software programming and consultancy), 45000000 (construction work), 79400000 (business consulting). Trailing zeros mean the whole branch. Searched on TED's side, so they are the fastest, most exact filter.

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

Words or phrases describing what you do. Each one found in a tender's title or description adds to its fit score (whole words, case and accent blind, every language TED holds). Notices are often in the buyer's own language, so add local words too (e.g. 'logiciel', 'Software', 'oprogramowanie'). With no CPV codes, keywords run a TED full-text search instead.

## `capabilityListUrl` (type: `string`):

Link to a CSV or a Google Sheet shared as 'Anyone with the link can view'. Cells holding 8 digit CPV codes are added as CPV codes; cells in a column named keyword, capability, service, product or skill (or the first column if there is no header) are added as keywords. Handy for keeping one bid profile per client.

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

Any tender containing one of these words is dropped and not charged, e.g. 'hardware', 'cleaning', 'catering'.

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

Only tenders from buyers in these countries. 2 or 3 letter codes: DE, FR, PL, IE, NL, ES or DEU, FRA. Empty means every country that publishes on TED (EU, EEA and others).

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

Drop tenders whose estimated value is below this, converted to euro at the ECB rate. Tenders with no published value are kept.

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

Drop tenders whose estimated value is above this. Tenders with no published value are kept.

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

How far back to look for newly published tenders. Use 1 or 2 for a daily scheduled monitor.

## `minDaysToDeadline` (type: `integer`):

Only tenders whose submission deadline is at least this many days away, so you have time to prepare.

## `minFitScore` (type: `integer`):

Only tenders scoring this or more are returned and charged. CPV match is worth up to 50, keywords up to 40, value inside your range 10.

## `includeBenchmark` (type: `boolean`):

For each tender, look up up to 250 recent contract award notices in the same CPV class and buyer country (all countries if fewer than 5): top past winners, median award value in euro, the tender's estimate against that median, median bids per tender and the share won by SMEs. Included in the price.

## `benchmarkMonths` (type: `integer`):

How far back the past award benchmark looks.

## `maxTenders` (type: `integer`):

The best fitting tenders up to this number are returned (and charged), highest score first.

## `maxNoticesScanned` (type: `integer`):

How many open notices to read from TED before scoring (newest first). Scanning is free; only returned tenders are charged.

## `monitorMode` (type: `boolean`):

Remembers every tender already returned under this watch name and returns only new ones, so a daily schedule sends just fresh matches. Already-seen tenders are never charged again.

## `watchName` (type: `string`):

Keep one watch per bid profile or client, e.g. 'acme-it' and 'acme-construction'.

## `webhookUrl` (type: `string`):

POST a JSON summary with the top tenders here when the run ends (in monitor mode only when there are new matches). Works with Slack workflows, Zapier, Make and n8n. Free.

## Actor input object example

```json
{
  "cpvCodes": [
    "72000000"
  ],
  "keywords": [
    "software",
    "cloud",
    "cybersecurity"
  ],
  "publishedWithinDays": 7,
  "minDaysToDeadline": 3,
  "minFitScore": 50,
  "includeBenchmark": true,
  "benchmarkMonths": 24,
  "maxTenders": 20,
  "maxNoticesScanned": 1500,
  "monitorMode": false,
  "watchName": "default"
}
```

# 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 = {
    "cpvCodes": [
        "72000000"
    ],
    "keywords": [
        "software",
        "cloud",
        "cybersecurity"
    ],
    "publishedWithinDays": 7,
    "maxTenders": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("nerolabs/eu-tender-bid-matcher").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"],
    "keywords": [
        "software",
        "cloud",
        "cybersecurity",
    ],
    "publishedWithinDays": 7,
    "maxTenders": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("nerolabs/eu-tender-bid-matcher").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"
  ],
  "keywords": [
    "software",
    "cloud",
    "cybersecurity"
  ],
  "publishedWithinDays": 7,
  "maxTenders": 20
}' |
apify call nerolabs/eu-tender-bid-matcher --silent --output-dataset

```

## MCP server setup

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

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/3eUgIHk9yBhYxmHPx/builds/a5B7nr5lDUR5OmdMx/openapi.json
