# Public Tenders API: EU TED, Find a Tender, Contracts Finder (`yourevenings/eu-uk-public-tenders`) Actor

Public tenders API: EU tenders (TED) and UK tenders (Find a Tender, Contracts Finder). Open tenders and contract awards in one schema, no source API key. Filter by CPV, country, NUTS, value, deadline, keywords. Daily tender alerts. Not affiliated with the EU, TED, Find a Tender or Contracts Finder.

- **URL**: https://apify.com/yourevenings/eu-uk-public-tenders.md
- **Developed by:** [Your Evenings](https://apify.com/yourevenings) (community)
- **Categories:** Lead generation, Business, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.20 / 1,000 notice returneds

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

## Public Tenders API: EU TED, Find a Tender, Contracts Finder

![Public Tenders API: sample dataset rows from TED, Find a Tender and Contracts Finder](https://api.apify.com/v2/key-value-stores/tGvBBcfxZCUrrcvjh/records/eu-uk-public-tenders-dataset.png)

**Public Tenders API** gives you **EU tenders** from TED and **UK tenders** from Find a Tender and Contracts Finder in one filterable dataset: open tenders, contract awards and contract changes. **No TED or UK government API key is needed** (you only need your Apify account). You can filter by CPV code, buyer country, NUTS/ITL region, value in EUR, deadline, buyer and keywords. Turn on **monitor mode** and schedule a daily run to get **tender alerts** for new and changed notices only.

> **Not affiliated with the EU, TED, Find a Tender or Contracts Finder.** This is an independent Actor by Your Evenings Ltd, not an official EU or UK government product. It isn't affiliated with or endorsed by the European Union, the Publications Office of the European Union, TED (Tenders Electronic Daily), Find a Tender, Contracts Finder, the Cabinet Office or Crown Commercial Service. It uses the data these services publish for reuse under their open licences (see "Attribution and licences").

### What is the Public Tenders API?

It's an Apify Actor that reads three official public procurement APIs live and returns every notice in the same normalised row: buyer, CPV, NUTS/ITL region, value (with a EUR conversion), deadline, lots and awards.

- **EU and UK in one schema.** TED (Tenders Electronic Daily, the EU Official Journal supplement), Find a Tender and Contracts Finder.
- **Filters run before you're charged, and you can see how much matched.** The run summary shows, for each source, the notices read, matched and returned, and why the rest were filtered out.
- **Official open APIs only.** No login, no browser and no HTML scraping. Requests are paced at one per second per service.
- **Daily alerts for new and changed notices** in monitor mode, when you schedule a daily run. Results land in your dataset; the Actor doesn't send emails itself.
- **You're told when a source fails, is empty or was cut short.** Each case gets a free status row.
- **Award rows carry Companies House numbers** when the UK notice publishes one (`supplierCompanyNumber`).

### Who it's for

- **Bid and sales teams at public-sector suppliers**, in the UK and across the EU.
- **Bid writers and public-procurement consultants** who watch several sectors or countries for clients.
- **Market researchers** looking at who buys what, from whom and for how much.

### How do I get started?

Paste this into the **JSON** view of the Input tab and press **Start**. It's also the form's prefilled input, so you can just press **Start**. It returns open IT-services tenders (CPV 72) published in the last 3 days, up to 30 per source, newest first.

```json
{
  "sources": ["ted", "find-a-tender", "contracts-finder"],
  "noticeStages": ["tender"],
  "cpvCodes": ["72"],
  "publishedWithinDays": 3,
  "maxResults": 30
}
```

We ran exactly this input on 31 October 2026 and it returned 47 notices: TED 30 (of 360 matching), Find a Tender 16, Contracts Finder 1. At the Free and Starter plan price, that's about $0.19 (see Pricing). Counts change daily with what's published.

### What can I use it for?

1. **A daily tender alert for your bid team.** For example, UK IT tenders (CPV 72), EU construction tenders (CPV 45) in chosen countries, or anything matching your keywords. Turn on `monitorMode` and schedule a daily run.
2. **Market research on public buyers.** Pull a period of notices for a CPV code or region, then compare buyers, values, procedures and regions in a spreadsheet.
3. **Contract award tracking.** Set `noticeStages` to `award` to see who won and for how much. UK awards include Companies House numbers when the notice publishes one.

### Where does the data come from?

| Source | What | How |
|---|---|---|
| **TED** | Notices in the Supplement to the Official Journal of the EU: EU, EEA and other buyers | TED Search API v3, anonymous, with iteration pagination. Reads up to `maxScanPerSource` notices (default 20,000) |
| **Find a Tender** | UK above-threshold notices and Procurement Act 2023 notices | Find a Tender OCDS release packages API |
| **Contracts Finder** | UK lower-value opportunities and awards (England and some UK-wide buyers) | Contracts Finder OCDS search API |

**Currency.** Values in other currencies are converted to EUR at the European Central Bank's latest euro reference rates (`valueEur`, rounded to whole euros). The original amount and currency stay on the row.

**Pace and limits.**

- **Request rate:** one request per second per service.
- **TED:** at most 60 requests a minute, well inside the 700 a minute that TED's fair usage policy allows.
- **Find a Tender:** its `Retry-After` header is honoured. It can be slow, so each UK source has a time budget (`maxSecondsPerSource`, default 210).
- **Contracts Finder:** a "wait 5 minutes" response stops that source with a free `source_error` row.
- **If the time budget runs out:** notices are read newest first, so only the oldest part of the window is skipped, and a free `scan_truncated` row tells you from when.

### Input

All fields are optional. With no input, you get open tenders (stage `tender`, deadline today or later) published in the last 7 days from all three sources, up to 50 per source.

#### Sources (`sources`)

`ted`, `find-a-tender`, `contracts-finder`. Default: all three.

#### Notice stages (`noticeStages`)

- `planning`
- `tender`: open opportunities (default)
- `award`
- `contract`: modifications and terminations

#### Keywords (`keywords`, `keywordMode`)

Whole words or phrases, matched in the title, description and lot titles, accent-insensitive. Use `any` (default) or `all`. The matches are listed in `matchedKeywords`.

#### CPV codes (`cpvCodes`)

CPV prefixes, 2 to 8 digits. For example, `72` = IT services and `45` = construction.

#### Buyer countries (`countries`)

ISO-2 codes (`DE`, `IE`, `GB`). The UK sources are skipped when `GB` isn't listed.

#### Regions (`nutsCodes`)

Place-of-performance region prefixes (`DE21`, `UKI`). When this is set, notices without a region code are filtered out. Contracts Finder often publishes region names rather than codes, so many of its notices drop out of a region filter.

#### Value in EUR (`minValue`, `maxValue`)

When either is set, notices without a value are filtered out. Many TED notices don't publish one.

#### Publication date (`publishedWithinDays`, `publishedFrom`, `publishedTo`)

A rolling window (default 7 days) or fixed dates. The rolling window counts from each run's date, so a scheduled task always covers the latest days.

#### Deadline (`deadlineAfter`, `includePastDeadlines`)

Tender-stage notices with a deadline before this date (default: today) are filtered out. Notices without a deadline are kept.

#### Buyer names (`buyerNames`)

Whole words or phrases in the buyer's name.

#### SME-suitable only (`smeSuitableOnly`)

Keeps only notices flagged as suitable for SMEs. The flag comes from Contracts Finder and some Find a Tender notices. TED search doesn't publish it.

#### Monitor mode (`monitorMode`, `emitBaselineOnFirstRun`, `stateStoreName`)

New and changed notice alerts. See "How do tender alerts work?" below.

#### Description (`includeDescription`)

Adds the notice description, up to 4,000 characters.

#### Contact details (`excludeContactDetails`)

On by default. See "What about personal data?" below.

#### Max results (`maxResults`)

The maximum number of notice rows per source, newest first. Default 50; 0 means up to 50,000.

#### Safety caps (`maxScanPerSource`, `maxSecondsPerSource`)

Limits on how much of each source a run reads.

Example: UK and Irish IT tenders worth at least €100,000:

```json
{ "cpvCodes": ["72"], "countries": ["GB", "IE"], "minValue": 100000, "publishedWithinDays": 3 }
```

### What does the output look like?

You get one row per notice (`recordType: "notice"`), with these fields:

- **Source and IDs:**
  - `source`, `sourceUrl`, `licence`
  - `noticeId`, `ocid` (UK), `procedureId`
- **Notice:** `stage`, `noticeType`, `formType` (TED), `title`, `description` (optional)
- **Buyer:** `buyerName`, `buyerId`, `buyerCountry`, `buyerWebsite`
- **Classification:** `nutsCodes`, `cpvCodes`, `cpvMain`
- **Value:** `valueAmount`, `valueCurrency`, `valueEur`
- **Dates and procedure:** `publishedAt`, `deadlineAt`, `procedureType`
- **Lots and awards:**
  - `lots[]`
  - `smeSuitable`, `documentsUrl`
  - `awards[]`: supplierName, supplierId, supplierCompanyNumber, supplierCountry, valueAmount, valueCurrency, date (UK awards also have supplierScale and status)
- **Matching and monitor mode:**
  - `matchedKeywords`
  - `changeType`, `firstSeenAt`, `lastSeenAt`
- **Duplicates:** `alsoPublishedOn`, `duplicateOf`
- **Retrieval:** `retrievedAt`

Sample rows from a test run of the Quick start input on 22 October 2026 (deadlines shown are from that day's notices):

| Source | Title | Buyer | Country | Main CPV | Value (EUR) | Deadline |
|---|---|---|---|---|---|---|
| ted | Zakup usługi serwisowej SAP Standard Support dla PKP S.A. na okres 24 m-cy | Polskie Koleje Państwowe S.A. | PL | 72000000 | – | 2026-11-05 |
| find-a-tender | Equals Trust - Provision of ICT Managed Services Stage 1 | Equals Trust | GB | 72000000 | 3,578,885 | 2027-02-26 |
| contracts-finder | GDPR Data Audit | Ryde Town Council | GB | 66170000 | – | 2026-10-26 |

**Duplicates.**

- **Repeat releases:** only the latest release per notice and stage is returned.
- **Cross-posting:** a notice on both Find a Tender and Contracts Finder is returned once, as the Find a Tender row, with `alsoPublishedOn`. The Contracts Finder copy comes back as a free `duplicate` status row (up to 200 of these rows per run; all duplicates are counted in the summary).

**Free status rows** (`recordType: "status"`): `no_matches`, `source_error`, `source_empty_or_stale`, `scan_truncated`, `duplicate`, `baseline_saved`. The `SUMMARY` record in the key-value store has the per-source counts.

### How do tender alerts work?

Set `monitorMode: true` and schedule the task to run daily. The first run saves the matching notices as a baseline and returns no notices, so no notice charges (only the tiny Actor start fee), unless you set `emitBaselineOnFirstRun`. After that, each run returns only:

- `new`: a notice you haven't seen before that matches your filters
- `amended`: a later version of a notice you've already had
- `awarded`: an award for a procedure you had at the planning or tender stage
- `cancelled`: a UK cancellation or termination

Use a different `stateStoreName` for each saved search.

### Can I call it from code?

Yes. Like any Apify Actor, it runs from the Apify API, the API clients, Make, Zapier or n8n. Here's a run that waits and returns the dataset items:

```bash
curl -X POST "https://api.apify.com/v2/acts/yourevenings~eu-uk-public-tenders/run-sync-get-dataset-items?token=YOUR_APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"cpvCodes":["72"],"countries":["GB","IE"],"publishedWithinDays":3}'
```

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("yourevenings/eu-uk-public-tenders").call(
    run_input={"cpvCodes": ["45"], "countries": ["DE", "FR"], "publishedWithinDays": 7}
)
for row in client.dataset(run["defaultDatasetId"]).iterate_items():
    if row.get("recordType") == "notice":
        print(row["title"], row["buyerName"], row.get("valueEur"))
```

### How much does it cost?

It's priced per event. Prices below are for the Free and Starter plans:

| Event | Price |
|---|---|
| Notice row (each notice, or each new or changed notice in monitor mode) | $0.004 |
| Alert run with matches (monitor mode, once per run that returns at least one notice) | $0.01 |
| Actor start (per GB of run memory, so one charge at the default 256 MB) | $0.00005 |

On the Scale plan a notice row is $0.0036 and an alert run $0.009. On Business and above they are $0.0032 and $0.008.

Status rows, filtered-out notices and duplicates are free.

- **Example:** a daily monitor with 15 new matches costs 15 × $0.004 + $0.01 = $0.07 a day, plus the Actor start fee.
- **Spending cap:** set a maximum charge per run, and the Actor stops before going over it.

### What about personal data?

- **Contact names:** this Actor never outputs contact people's names.
- **With `excludeContactDetails` on (the default):**
  - contact emails and phone numbers are removed from descriptions
  - identifiers that are really a phone number or email are dropped
- **With it off:**
  - the buyer's published business contact email is added (`buyerContactEmail`), plus the telephone (`buyerContactTelephone`) on UK notices
  - descriptions, URL fields and identifiers are returned as published, without the email and phone removal above

Please don't use this Actor to build lists of people.

### Attribution and licences

Every row has `source`, `sourceUrl` and `licence`.

- **TED:**
  - © European Union, https://ted.europa.eu.
  - Unless otherwise noted, procurement notices in the Supplement to the Official Journal of the EU can be freely reused, for commercial or non-commercial purposes, under the Commission's reuse policy (Commission Decision 2011/833/EU).
  - TED's own editorial content is licensed CC BY 4.0.
  - The TED logo isn't used.
- **Find a Tender and Contracts Finder:**
  - Contains public sector information licensed under the [Open Government Licence v3.0](https://www.nationalarchives.gov.uk/doc/open-government-licence/version/3/).
  - Departmental logos and crests aren't used.
- **Exchange rates:** European Central Bank euro foreign exchange reference rates.
- **Changes:** rows are normalised by this Actor (fields renamed and restructured, values converted to EUR, contact details removed by default); they are not the official published notices.

If you republish the data, keep these attribution lines and link to `sourceUrl` for the official notice.

### FAQ

**Why do I get fewer TED rows with a value filter?** Many TED notices don't publish an estimated value. When `minValue` or `maxValue` is set, those notices are filtered out and counted as `noValue` in the summary.

**Does it cover the Scotland, Wales and Northern Ireland portals?** Only the notices those buyers publish to Find a Tender or Contracts Finder. Public Contracts Scotland, Sell2Wales and eTendersNI aren't read.

**How fresh is it?** All three APIs are read live during the run.

**Do I need a TED or Find a Tender API key?** No. All three APIs are read anonymously.

### Feedback

Found a notice that looks wrong or missing? Open an issue on the Actor's Issues tab with a link to the notice.

<sub>Not affiliated with or endorsed by the European Union, the Publications Office of the EU, TED, Find a Tender, Contracts Finder or the UK government. Product names belong to their owners.</sub>

# Changelog

This Actor's version history is a separate document: https://apify.com/yourevenings/eu-uk-public-tenders/changelog.md

# Actor input Schema

## `sources` (type: `array`):

Which official APIs to search. Leave empty for all three.

## `noticeStages` (type: `array`):

Which stages to return. Default: tender (open opportunities).

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

Whole words or phrases, matched case- and accent-insensitively in the title, description and lot titles. "cloud" matches "Cloud hosting" but not "Cloudsley". Each row lists matchedKeywords.

## `keywordMode` (type: `string`):

Return notices matching any keyword (default) or all of them.

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

CPV code prefixes, 2 to 8 digits. 72 = all IT services, 45 = construction work, 7221 = software programming and consultancy.

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

2-letter ISO codes of the buyer's country, e.g. DE, FR, IE, GB. UK sources are skipped when GB isn't in the list.

## `nutsCodes` (type: `array`):

Place-of-performance region prefixes, e.g. DE21, IE06, UKI (London). Notices without a region code are filtered out when this is set. Contracts Finder often publishes region names rather than codes.

## `minValue` (type: `integer`):

Estimated or awarded value in euros. Non-euro values are converted with the latest ECB reference rate. Notices without a value are filtered out when a value filter is set.

## `maxValue` (type: `integer`):

See minimum value.

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

Rolling window counted back from the run date, so a saved task always looks at the latest days. Ignored when publishedFrom is set.

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

Fixed start date (YYYY-MM-DD). Overrides publishedWithinDays.

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

Fixed end date (YYYY-MM-DD). Leave empty for up to now.

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

Tender-stage notices whose submission deadline is before this date are filtered out. Default: today. Notices without a deadline are kept.

## `includePastDeadlines` (type: `boolean`):

Turn off the deadline filter.

## `buyerNames` (type: `array`):

Whole words or phrases matched in the buyer's name, e.g. "NHS" or "Stadt München".

## `smeSuitableOnly` (type: `boolean`):

Only notices the buyer flagged as suitable for SMEs. Only Contracts Finder (and some Find a Tender notices) publish this flag, so TED notices are filtered out.

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

Return only notices that are new or changed since the last monitor run (changeType new, amended, awarded or cancelled). The first run saves a free baseline. Schedule it daily for alerts.

## `emitBaselineOnFirstRun` (type: `boolean`):

By default the first monitor run returns nothing and only saves the baseline. Turn on to return (and pay for) the current matches too.

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

Named key-value store for monitor state. Use a different name for each saved search you monitor.

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

Add the notice description (up to 4,000 characters).

## `excludeContactDetails` (type: `boolean`):

On (default): no contact emails or phone numbers are output, and they are removed from descriptions. Off: adds the buyer's published contact email and telephone. Names of contact people are never output.

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

Maximum notice rows per source (newest first). 0 = no limit (up to 50,000).

## `maxScanPerSource` (type: `integer`):

Safety cap on notices read per source before filters. A free scan_truncated row says when it was reached.

## `maxSecondsPerSource` (type: `integer`):

Time budget for reading each UK source. Find a Tender can be slow (15 to 90 seconds per page of 100). When the budget runs out, a free scan_truncated row says which older notices weren't checked.

## Actor input object example

```json
{
  "sources": [
    "ted",
    "find-a-tender",
    "contracts-finder"
  ],
  "noticeStages": [
    "tender"
  ],
  "keywords": [],
  "keywordMode": "any",
  "cpvCodes": [
    "72"
  ],
  "publishedWithinDays": 3,
  "includePastDeadlines": false,
  "smeSuitableOnly": false,
  "monitorMode": false,
  "emitBaselineOnFirstRun": false,
  "stateStoreName": "eu-uk-public-tenders-state",
  "includeDescription": false,
  "excludeContactDetails": true,
  "maxResults": 30,
  "maxScanPerSource": 20000,
  "maxSecondsPerSource": 210
}
```

# Actor output Schema

## `notices` (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 = {
    "sources": [
        "ted",
        "find-a-tender",
        "contracts-finder"
    ],
    "noticeStages": [
        "tender"
    ],
    "keywords": [],
    "cpvCodes": [
        "72"
    ],
    "publishedWithinDays": 3,
    "maxResults": 30
};

// Run the Actor and wait for it to finish
const run = await client.actor("yourevenings/eu-uk-public-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 = {
    "sources": [
        "ted",
        "find-a-tender",
        "contracts-finder",
    ],
    "noticeStages": ["tender"],
    "keywords": [],
    "cpvCodes": ["72"],
    "publishedWithinDays": 3,
    "maxResults": 30,
}

# Run the Actor and wait for it to finish
run = client.actor("yourevenings/eu-uk-public-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 '{
  "sources": [
    "ted",
    "find-a-tender",
    "contracts-finder"
  ],
  "noticeStages": [
    "tender"
  ],
  "keywords": [],
  "cpvCodes": [
    "72"
  ],
  "publishedWithinDays": 3,
  "maxResults": 30
}' |
apify call yourevenings/eu-uk-public-tenders --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,yourevenings/eu-uk-public-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/eXCIY7NqT10dJYOhm/builds/pp96VF5ry12d5Cloc/openapi.json
