# EU & UK Public Tenders Scraper (TED + Find a Tender) (`atesen-software/eu-uk-public-tenders-monitor`) Actor

Search and monitor EU (TED) and UK (Find a Tender, Contracts Finder) public tenders through official open APIs. Filter by keyword, CPV code, country, notice type and value. Monitor mode returns only new or changed tenders. No contact fields; e-mails and phones in texts are masked.

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

## Pricing

$4.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

## EU & UK Public Tenders Scraper: TED, Find a Tender, Contracts Finder

An **EU tenders API** and **public procurement monitor** in one Actor. It collects **TED notices** (the EU Official Journal S), **UK Find a Tender** notices and, optionally, **UK Contracts Finder** notices from their official open APIs. Every notice comes back in the same schema.

Filter by **keyword**, **CPV code**, buyer country, notice type and minimum contract value. Each notice has the buyer, deadline, estimated value, CPV codes, lots, a link to the procurement documents and a status.

Turn on **monitor mode** and a scheduled run returns only **new tenders** and tenders whose **deadline or status changed**. Notices you already received are skipped and are not charged.

**What it does**

- Reads three official, keyless government APIs: no HTML scraping, no login, no API key, no proxy.
- Normalizes TED (eForms) and UK OCDS releases into one flat row with the same field names.
- Does not output contact fields (contact person, e-mail, phone, fax) and masks e-mail addresses and phone numbers that appear in free text. Names of people written inside free text are not detected.
- Adds an `attribution` field to every row with the licence statement that applies.

**What it does not do**

- It does not translate TED notices. Most titles and descriptions stay in the buyer's language.
- It does not convert currencies. Values are in the currency of the notice.
- It does not download tender documents or submit bids. It gives you the link to the documents.
- It does not cover national portals that are not published on TED, Find a Tender or Contracts Finder (for example most below-threshold tenders in the EU).

> This Actor is not affiliated with, or endorsed by, the EU Publications Office (TED), the UK Cabinet Office or the Crown Commercial Service (Find a Tender, Contracts Finder).

### What you can use it for

- **Bid/no-bid pipeline.** Get a daily feed of new government tenders that match your CPV codes and keywords. Send it to Google Sheets, a CRM, Slack or a webhook with Apify integrations.
- **Deadline and status tracking.** Find out when a procedure's submission deadline moves, or when its status changes (open → closed / awarded / cancelled).
- **Market research.** See how many software, construction or consulting tenders were published per country, and how large they were.
- **Lead lists for suppliers.** Each notice gives the buyer organisation, city, country, estimated value and a link to the procurement documents.

### Sources and licences

| Source | `sources` value | Coverage | API used |
|---|---|---|---|
| TED: Tenders Electronic Daily | `ted` | EU/EEA notices published in the Official Journal S (mostly above the EU thresholds) | TED Search API v3 |
| Find a Tender (FTS) | `fts` | UK notices: above-threshold notices and Procurement Act 2023 notices | FTS OCDS release packages |
| Contracts Finder (CF) | `cf` | UK lower-value opportunities (England) | Contracts Finder OCDS search |

Licences:

- **TED** data is © European Union. Reuse is authorised under Commission Decision 2011/833/EU. The TED name and logo are not licensed and are not used to suggest endorsement.
- **Find a Tender** and **Contracts Finder** contain public sector information licensed under the **Open Government Licence v3.0**.

Every output row has an `attribution` field with the statement that applies to it. Keep that statement when you republish the data.

### Input

| Field | Default | Notes |
|---|---|---|
| `keywords` | – | Any of these words (OR). TED uses its full-text search. FTS/CF match a keyword at the start of a word in the title, description, lots, items and buyer name. Keywords of 3 characters or fewer must match a whole word. Acronyms typed in capitals (`IT`, `AI`, `CCTV`) are case-sensitive. |
| `cpvCodes` | – | CPV prefixes, e.g. `48` (software packages), `72` (IT services) or `45` (construction). A full code such as `72000000` or `72000000-5` also works. If none of the codes you give is valid, the run stops with an error, so it never returns unfiltered notices. If only some codes are invalid, those are ignored and a warning is logged. |
| `countries` | – | ISO-2 buyer countries such as `DE`, `FR` or `PL`. FTS and CF are always `GB`. A list without `GB` skips the UK sources, and `["GB"]` alone skips TED. Invalid codes follow the same rule as CPV codes: if all are invalid the run errors, and if only some are, those are ignored with a warning. |
| `noticeTypes` | `competition` | `competition` (open tenders), `planning` (prior information / market engagement), `result` (awards), `change` (corrigenda). |
| `sources` | `ted`, `fts` | Add `cf` to include Contracts Finder. |
| `lookbackDays` / `publishedSince` | 3 days | The publication window. `publishedSince` (YYYY-MM-DD) overrides `lookbackDays`. The maximum is 366 days. |
| `minValue` + `minValueCurrency` | – | Minimum estimated value. No currency conversion is done. `otherCurrencies` decides whether notices in other currencies are kept or dropped. |
| `includeWithoutValue` | false | Many notices publish no value. Set this to true to keep them when `minValue` is set. |
| `maxResultsPerSource` | 100 (the console form pre-fills 5 for a quick try) | The most notices output per source per run. In monitor mode only new or changed notices count; unchanged notices are skipped and do not use up the limit. |
| `maxRuntimeSeconds` | 0 = no limit (the console form pre-fills 180 for a quick try) | Soft time limit for the whole run. When it is reached, or when a source API (Find a Tender in particular) rate-limits and asks you to wait past it, the run stops reading, keeps the notices it already found and ends with a `time_limit` status row for that source. The run still succeeds when at least one source delivered data. |
| `changesOnly` + `monitorKey` | false | Monitor mode, described below. |
| `preferredLanguage` | `en` | The language picked for TED's multilingual fields. TED `title` and `description` are usually published only in the buyer's original language and are **not translated**. `headline` ("Country – CPV – title") is available in every EU language, but its title part stays in the original language. FTS and Contracts Finder are in English. |
| `descriptionMaxLength` | 600 | Longer descriptions are truncated to this length. |
| `includeRaw` | false | Adds the trimmed source record. Contact points, persons and suppliers' contact details are removed. |

Invalid input stops the run before any API call is made, and the reason is written to a status row. Examples are an unknown source or notice type, a bad date or a date in the future, and a currency that is not an ISO code. If every CPV code or every country code you give is invalid, the run also stops, rather than silently dropping the filter. Smaller problems produce a warning and the run continues: if some CPV or country codes are invalid, those are ignored; a value that is too large is capped.

#### Example: EU software tenders by CPV

```json
{
  "keywords": ["software"],
  "cpvCodes": ["72000000", "48000000"],
  "sources": ["ted"],
  "lookbackDays": 3,
  "maxResultsPerSource": 50
}
```

#### Example: acronyms and short keywords

```json
{
  "keywords": ["IT", "AI", "CCTV", "cyber security"],
  "sources": ["fts", "cf"],
  "lookbackDays": 2
}
```

Type acronyms in **capitals**. `IT` matches "IT services" and "IT/AV support". It does not match "it is", "items" or "its premises". Lower-case `it` would match the pronoun "it" in almost every notice.

Keywords of **3 characters or fewer** must match a **whole word**. `bim` matches "BIM services" but not "bimonthly". Longer keywords match the start of a word, so `software` also matches "softwares". This applies to the UK sources (FTS, CF). TED uses its own full-text search.

An acronym only finds notices that actually contain it. An IT tender that never writes "IT" is missed, so combine keywords with CPV codes (e.g. `72`, `48`) when you need full coverage.

#### Example: UK only, Find a Tender + Contracts Finder

```json
{
  "keywords": ["software", "IT"],
  "countries": ["GB"],
  "sources": ["fts", "cf"],
  "lookbackDays": 1,
  "minValue": 100000,
  "minValueCurrency": "GBP"
}
```

#### Example: daily monitor (schedule it)

```json
{
  "keywords": ["software"],
  "cpvCodes": ["48", "72"],
  "sources": ["ted", "fts"],
  "lookbackDays": 2,
  "maxResultsPerSource": 500,
  "changesOnly": true,
  "monitorKey": "software-eu-uk"
}
```

### Monitor mode (changes only)

With `changesOnly: true`, the actor stores a small, compressed state for each `monitorKey` in the named key-value store `tenders-monitor-state`. A notice is output only when its `changeType` is one of these:

- `new`: the procedure has not been seen before. On the first run, everything is new.
- `deadline_changed`: the submission deadline moved. `previousDeadlineDate` holds the old value.
- `status_changed`: the status moved, e.g. open → awarded or cancelled. `previousStatus` holds the old value.
- `new_notice`: a new notice was published for a known procedure, such as a corrigendum or a result.

Every other notice is counted as `unchanged`. It is **not output and not charged**. A notice is recorded as seen only after it has been written to the dataset, so notices skipped because your spending limit was reached are returned on the next run.

The state belongs to your Apify account and is keyed by `monitorKey`. If you leave `monitorKey` empty, the key is derived from the filters (keywords, CPV codes, countries, notice types, sources, value filter), so changing one of those filters starts a fresh state. **If you delete the store or use a new key, the next run treats every notice in the window as new and charges for it.** The state keeps at most 150,000 procedures per key; the least recently seen ones are dropped first.

To set it up:

1. Create an Apify **Schedule** (e.g. daily).
2. Use the same input and the same `monitorKey` on every run.
3. Use a different `monitorKey` for each watch list.

Tips:

- Set `lookbackDays` a little longer than the schedule interval, e.g. 2 days for a daily schedule, so nothing falls into a gap.
- `maxResultsPerSource` counts only notices that are output (new or changed). Unchanged notices are skipped and don't use it up, so a small limit such as 10 can't hide new notices behind unchanged ones. As a safety limit, TED stops after scanning 1,000 notices or 20 × `maxResultsPerSource`, whichever is larger. The source's status row then says `scan_limit` instead of `ok`, because the results may be incomplete. If you see it, shorten `lookbackDays` or narrow the filters.
- **The first runs may not return everything at once.** If the window holds more new notices than `maxResultsPerSource`, the first run stops at the limit. The next run skips what was already returned and outputs (and charges for) the older notices still waiting in the window, up to the limit again. This continues until the backlog is cleared; only after that do runs return just the new and changed notices. To clear it in one run, set `maxResultsPerSource` above the number of notices in the window for the first run.

Example from a cloud test run on 7 Nov 2026 (TED, buyer country `LU`, CPV `72`, last 7 days, `changesOnly` on): the first run returned **4 new notices**. A second run with the same input and `monitorKey` returned **0 notices**, reported 4 as unchanged, and was not charged for any notice. If the first run had stopped at `maxResultsPerSource`, the second run would have returned the remaining older notices instead of 0.

### Output

Each notice is one dataset item with `type: "notice"`. Each source also adds one `type: "status"` row that says what was scanned or why the source was skipped. Status rows are free. Their `status` is one of:

- `ok`: the source finished normally, either because every matching notice was scanned or because `maxResultsPerSource` was reached.
- `scan_limit`: monitor mode stopped at the TED scan safety limit before reaching `maxResultsPerSource`. Results may be incomplete.
- `page_limit`: the source's page limit was reached. Results may be incomplete.
- `charge_limit_reached`: the maximum cost per run was reached.
- `time_limit`: the run reached `maxRuntimeSeconds` or was about to time out, or the source API asked to wait longer than the time left. Notices found so far are kept; results may be incomplete.
- `error`: the source failed; the other sources still ran. If every source fails, or is stopped before delivering anything because its API was rate-limited or too slow, the run itself is marked as failed.
- `input_warning` / `invalid_input`: problems with the input (see above). A run summary is saved as `RUN_SUMMARY` in the default key-value store.

This Find a Tender row comes from a real run on 26 Oct 2026, with the description shortened:

```json
{
  "type": "notice",
  "source": "fts",
  "sourceName": "Find a Tender (UK)",
  "noticeId": "101176-2026",
  "procedureId": "ocds-h6vhtk-06bcf9",
  "url": "https://www.find-tender.service.gov.uk/Notice/101176-2026",
  "title": "The Provision of OBSIDIAN Support",
  "buyerName": "Ministry of Defence",
  "buyerCity": "Andover",
  "buyerCountry": "GB",
  "cpvCodes": ["75221000"],
  "mainCpv": "75221000",
  "procedureType": "open",
  "procedureDetails": "Open procedure",
  "contractNature": "services",
  "noticeType": "competition",
  "sourceNoticeType": "UK4",
  "sourceStatus": "tender|active",
  "publishedDate": "2026-10-26T15:58:08.000Z",
  "deadlineDate": "2027-01-06T23:59:00.000Z",
  "estimatedValue": 2375000,
  "currency": "GBP",
  "lotsCount": 1,
  "lots": [{ "lotId": "1", "title": null, "estimatedValue": 2375000, "currency": "GBP", "status": "active" }],
  "description": "This procurement seeks a 24-month support, maintenance, and training contract for the OBSIDIAN Electronic Surveillance (ES) system…",
  "documentsUrl": "https://contracts.mod.uk",
  "submissionUrl": "https://contracts.mod.uk",
  "placeOfPerformance": ["UK"],
  "performanceCountries": ["GB"],
  "performanceNutsCodes": ["UK"],
  "performanceRegions": [],
  "performanceScope": null,
  "language": "en",
  "status": "open",
  "attribution": "Contains public sector information licensed under the Open Government Licence v3.0.",
  "scrapedAt": "2026-10-26T18:05:47.572Z"
}
```

This TED row comes from a monitor run, with the fields shortened:

```json
{
  "type": "notice",
  "source": "ted",
  "noticeId": "741024-2026",
  "url": "https://ted.europa.eu/en/notice/-/detail/741024-2026",
  "title": "Rammeaftale for Standardsoftware - 26/21024",
  "buyerName": "Energinet",
  "buyerCity": "Fredericia",
  "buyerCountry": "DK",
  "mainCpv": "48000000",
  "procedureType": "open",
  "contractNature": "supplies",
  "noticeType": "competition",
  "publishedDate": "2026-10-26",
  "deadlineDate": "2026-11-03T11:00:00.000Z",
  "estimatedValue": 320000000,
  "currency": "DKK",
  "documentsUrl": "https://www.comdia.com/energinet/tenderinformationshow.aspx?Id=805690",
  "noticePdfUrl": "https://ted.europa.eu/en/notice/741024-2026/pdf",
  "status": "open",
  "attribution": "© European Union, https://ted.europa.eu",
  "changeType": "new",
  "previousDeadlineDate": null,
  "previousStatus": null
}
```

**Place of performance.** These fields use one consistent format for every source:

- `performanceCountries`: ISO-2 codes such as `ES` or `GB`. They come from TED's ISO-3 codes, from NUTS prefixes (`EL` → `GR`, `UK` → `GB`) and from country names.
- `performanceNutsCodes`: NUTS codes such as `DE111` or `UKM82`.
- `performanceRegions`: free-text region names from Contracts Finder, such as "London" or "Rest of the World".
- `performanceScope`: set to `anywhere`, `anywhere_eea` or `anywhere_in_country` when TED gives no fixed place. For `anywhere_in_country` TED usually gives no country code, so `performanceCountries` is filled with the buyer's country (`buyerCountry`). If TED does name a country, that country is used instead.

The older `placeOfPerformance` field is kept unchanged for compatibility. It holds the codes exactly as each source publishes them (TED mixes NUTS and ISO-3 codes) and is cut at 20 entries.

**Personal data.** Contact points are left out of the output: names, emails, phone and fax numbers. Email addresses and phone numbers that appear in free text are replaced with `[email removed]` / `[phone removed]`. Names of people written inside descriptions cannot be detected reliably, so check the data before you use it for outreach. You are responsible for complying with GDPR / UK GDPR.

### Pricing

**Pay per event.** You pay for each notice written to the dataset (the `notice` event). The current price and every billed event are on the Actor's **Pricing** tab.

These are free:

- status rows (`type: "status"`);
- the run summary;
- notices skipped as `unchanged` in monitor mode;
- runs that find nothing: you get a status row with the reason and no notice charge.

Platform usage is included in the event price, so there are no separate compute costs for you. Set a maximum cost per run and the Actor stops cleanly when it reaches that limit. Notices that were not delivered because of the limit are returned by the next monitor run.

Cost = number of notices in your dataset x the price per notice. A search that returns 250 matching tenders is charged for 250 notices. A monitor run where nothing changed is charged for 0 notices.

### Limits and known behaviour

- **Find a Tender stage filter is slow.** The FTS API does not filter reliably by stage, so the actor reads every release in the date window and filters locally. FTS publishes roughly 400–500 releases a day, about 5 API pages, and the actor reads about 1 page per second. A 1-day UK run takes under 10 seconds when the API does not push back. A 30-day lookback reads roughly 150 pages and takes several minutes. **Find a Tender rate-limits by IP address** (HTTP 429, "Retry-After: 120"). On the shared platform IPs this can happen on the very first request, and a long window can run into it more than once, so a UK run can take 2 minutes or more longer than the page count suggests. The actor waits for the `Retry-After` time (at most 2 minutes) and then continues. If you set `maxRuntimeSeconds`, it does not wait past that limit: it keeps the notices it already found and reports `time_limit` for the source instead. For scheduled runs, keep the lookback short (1 to 3 days) or set `maxRuntimeSeconds`.
- **TED is in the original language.** Titles and descriptions come in the language the buyer published, e.g. Danish, Polish or German. The actor does not translate them.
- **TED full-text matching is loose.** The TED keyword search also matches text inside lots and other notice fields. Some hits are therefore only loosely related; for example, a teaching-equipment tender can match "software" because one lot mentions it. Combine keywords with CPV codes for precise results.
- **Values.** Many notices publish no estimated value, and some publish `0`. Values are given in the notice currency with no currency conversion. If you set `minValue`, a notice with a value of `0` is treated as below the minimum.
- **Dates.** TED `publishedDate` is a date only. FTS and Contracts Finder give a full timestamp.
- **CPV lists.** Some TED notices carry dozens of CPV codes across their lots, and `cpvCodes` contains all of them.
- **Matching in capitals.** For UK sources, an acronym such as `IT` is matched case-sensitively. Text written entirely in capitals can still match it.
- **Find a Tender and Contracts Finder overlap.** Some UK opportunities are published on both. They have different IDs, so if you select `fts` and `cf` together, such a notice can come back twice and is charged twice (3 of 24 Contracts Finder competition notices in a 3-day sample on 7 Nov 2026 also appeared on Find a Tender with the same title and buyer). TED (EU) and Find a Tender (UK) are separate publication systems and are not expected to overlap.
- **Availability.** The source APIs are run by third parties and may change, slow down or become unavailable. If one source fails, the others still run, and that source's status row shows the error.

### FAQ

**Do I need an API key for TED or Find a Tender?** No. The Actor uses the public endpoints that do not need a key.

**Can I get only new tenders every day?** Yes. Turn on `changesOnly`, set a `monitorKey`, and schedule the Actor daily. The saved state is kept per `monitorKey`.

**Why are some titles not in English?** TED publishes most notices only in the buyer's language, and the Actor does not translate them. `headline` follows `preferredLanguage` when TED provides it. Find a Tender and Contracts Finder are in English.

**Why does a keyword return loosely related notices on TED?** TED's full-text search also looks at lots and other notice fields. Combine keywords with CPV codes for precise results.

**Does it include contact persons or e-mail addresses?** No. They are never requested from TED and are removed from UK records. E-mail addresses and phone numbers found inside free text are replaced with `[email removed]` / `[phone removed]`. Names of people written inside descriptions cannot be detected reliably, so check the data before you use it for outreach. You are responsible for complying with GDPR / UK GDPR.

**Is it allowed to reuse this data commercially?** TED notices can be reused for commercial and non-commercial purposes under the Commission's reuse policy. Find a Tender and Contracts Finder content is published under the Open Government Licence v3.0, which also allows commercial use if you acknowledge the source. This is not legal advice; read the terms linked below.

**How polite is it to the source APIs?** It sends about one request per second per host, retries with back-off, and honours `Retry-After` on HTTP 429 and 503.

### Data sources and attribution

- TED notices: © European Union, https://ted.europa.eu. Reused under the Commission's reuse policy (Decision 2011/833/EU). The TED name and logo are not used. Terms: https://ted.europa.eu/en/legal-notice
- Find a Tender and Contracts Finder: Contains public sector information licensed under the Open Government Licence v3.0. Terms: https://www.contractsfinder.service.gov.uk/Home/TermsAndConditions and https://www.nationalarchives.gov.uk/doc/open-government-licence/version/3/
- Source data is provided by third parties without guarantee of accuracy or completeness. Always check the original notice before you bid.

# Changelog

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

# Actor input Schema

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

Full-text keywords or phrases (any of them must match). TED searches all notice languages server-side; UK sources are matched on title, description, lots, items and buyer name (case- and accent-insensitive, word start; keywords of 3 characters or fewer must match a whole word, and acronyms typed in capitals such as IT or AI are matched case-sensitively). Leave empty to get every notice that matches the other filters. Tip: type acronyms in capitals (IT, not it).

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

Common Procurement Vocabulary codes. Trailing zeros act as a prefix: 72000000 matches every 72xxxxxx (IT services), 48783000 matches 48783xxx. The check digit (-5) is optional. If none of the given codes is valid, the run stops with an input error instead of running unfiltered.

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

ISO country codes of the contracting authority (DE, FR, PL, GB/UK...). Empty = all. A filter without GB skips the UK sources; GB alone skips TED. If none of the given codes is valid, the run stops with an input error instead of returning all countries.

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

competition = calls for tenders (open opportunities); planning = prior information / pipeline; result = contract awards; change = corrigenda and modifications.

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

ted = TED, EU + EEA (Official Journal S); fts = UK Find a Tender (above-threshold UK notices); cf = UK Contracts Finder (lower-value English notices).

## `lookbackDays` (type: `integer`):

Notices published (TED) or released/updated (UK) in the last N days, counted from 00:00 UTC. Ignored when 'Published since' is set.

## `publishedSince` (type: `string`):

Absolute start date (YYYY-MM-DD). Overrides the lookback.

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

Only notices whose estimated / awarded value is at least this amount in the currency below. 0 or empty = no value filter.

## `minValueCurrency` (type: `string`):

ISO 4217 code for the minimum value. No currency conversion is done.

## `otherCurrencies` (type: `string`):

When a minimum value is set: keep (include) or drop (exclude) notices whose value is in a different currency.

## `includeWithoutValue` (type: `boolean`):

When a minimum value is set, also keep notices that publish no value (many do not).

## `maxResultsPerSource` (type: `integer`):

Upper limit of notices returned per source (newest first). Each returned notice is one billable 'notice' event. In monitor mode only new/changed notices count; unchanged ones are skipped (TED scans at most max(1000, 20x this value) notices; the status row then says scan_limit). If the window holds more new notices than this, later runs return the rest.

## `maxRuntimeSeconds` (type: `integer`):

Soft time limit for the whole run. When it is reached, or when a source API (Find a Tender in particular) rate-limits and asks to wait past it, the run stops reading, keeps the notices already found and ends with a 'time_limit' status row for that source. 0 = no limit (only the run timeout applies). The console pre-fill uses 180 so a quick try always finishes in a few minutes.

## `changesOnly` (type: `boolean`):

Remember what was returned before (per monitor key) and only output new notices or procedures whose deadline, status or latest notice changed. Unchanged notices are not output and not charged. Schedule the actor daily for alerts.

## `monitorKey` (type: `string`):

Name of the saved state (letters, digits, - \_ .). Use one key per saved search. Empty = derived from the filters.

## `preferredLanguage` (type: `string`):

Language picked for TED multilingual fields when the notice provides it (falls back to English, then the original language). Most TED titles and descriptions exist only in the buyer's original language and are not translated.

## `descriptionMaxLength` (type: `integer`):

Truncate descriptions to this many characters (0 = no description).

## `includeRaw` (type: `boolean`):

Add the source record (TED search fields or OCDS release) as 'raw'. Contact points, persons, bids and supplier details are removed and e-mails/phone numbers in texts are masked.

## Actor input object example

```json
{
  "keywords": [
    "software",
    "cloud hosting"
  ],
  "cpvCodes": [
    "72000000",
    "48000000"
  ],
  "countries": [
    "DE",
    "FR",
    "GB"
  ],
  "noticeTypes": [
    "competition"
  ],
  "sources": [
    "ted",
    "fts"
  ],
  "lookbackDays": 3,
  "minValueCurrency": "EUR",
  "otherCurrencies": "include",
  "includeWithoutValue": false,
  "maxResultsPerSource": 5,
  "maxRuntimeSeconds": 180,
  "changesOnly": false,
  "preferredLanguage": "en",
  "descriptionMaxLength": 600,
  "includeRaw": false
}
```

# Actor output Schema

## `notices` (type: `string`):

No description

## `status` (type: `string`):

No description

## `runSummary` (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 = {
    "keywords": [
        "software"
    ],
    "cpvCodes": [
        "72000000"
    ],
    "lookbackDays": 3,
    "maxResultsPerSource": 5,
    "maxRuntimeSeconds": 180
};

// Run the Actor and wait for it to finish
const run = await client.actor("atesen-software/eu-uk-public-tenders-monitor").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"],
    "cpvCodes": ["72000000"],
    "lookbackDays": 3,
    "maxResultsPerSource": 5,
    "maxRuntimeSeconds": 180,
}

# Run the Actor and wait for it to finish
run = client.actor("atesen-software/eu-uk-public-tenders-monitor").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"
  ],
  "cpvCodes": [
    "72000000"
  ],
  "lookbackDays": 3,
  "maxResultsPerSource": 5,
  "maxRuntimeSeconds": 180
}' |
apify call atesen-software/eu-uk-public-tenders-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,atesen-software/eu-uk-public-tenders-monitor"
        }
    }
}
```

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/63qS5y6mnLdk6ot0G/builds/GnFQJxExjJdBGxbSb/openapi.json
