# SiteVerdict — Public Tenders & Contracts Finder (UK, EU) (`siteverdict/siteverdict-public-tenders`) Actor

Search UK and EU public-sector tenders and contract awards in one feed: Find a Tender, Contracts Finder, Public Contracts Scotland, Sell2Wales and TED. Filter by keyword, CPV, buyer, region, value and deadline; get daily new-notice alerts and closing-soon digests.

- **URL**: https://apify.com/siteverdict/siteverdict-public-tenders.md
- **Developed by:** [Aman Thakran](https://apify.com/siteverdict) (community)
- **Categories:** Lead generation, Business
- **Stats:** 3 total users, 2 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

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

## SiteVerdict — Public Tenders & Contracts Finder (UK, EU)

**Every UK and EU public-sector opportunity in one clean feed — with daily "new tender" alerts and a closing-soon digest.**

One search covers **Find a Tender** (all UK notices under the Procurement Act 2023), **Contracts Finder** (England, below-threshold and legacy procurements), **Public Contracts Scotland**, **Sell2Wales** and the EU's **TED** (Tenders Electronic Daily). Results come back in one normalised, OCDS-based format: title, buyer, value, CPV codes with labels, location, procedure, deadline, documents, notice link, lots and award winners. Cross-posted duplicates are merged.

Uses only the official, open government APIs. No logins, no scraping of web pages, no proxies.

### Who it is for

- **SMEs and bid teams** who want every relevant tender without checking five portals.
- **Bid writers and consultancies** monitoring several sectors or clients.
- **Sales and market-intelligence teams** tracking who wins what (awards, incumbents, contract values).
- **Developers and AI agents** who need a clean procurement feed (also available as an MCP tool).

### What you can do

| Need | How |
|---|---|
| Find open tenders for your services | `keywords`, `cpvCodes` or `cpvKeywords` + `openOnly` |
| Don't know CPV codes? | `cpvKeywords: ["cleaning", "website"]` looks them up in the official CPV 2008 vocabulary (9,454 codes) |
| Only your area | `regions` (`"London"`, `"Scotland"`, `"UKI3"`, `"TLM"`, `"DE1"`) or `postcodes` (`"M"`, `"LS1"`) |
| Right-sized contracts | `minValue` / `maxValue` |
| Specific buyers | `buyers: ["NHS", "Ministry of Defence"]` |
| Daily alerts | `mode: "monitor"` on a daily schedule — only notices you have not seen before |
| Weekly "closing soon" email | `mode: "closingSoon"` + `closingWithinDays: 7` → markdown digest in the `DIGEST.md` record |
| Rank by fit | `profileKeywords` + `profileExcludeKeywords` → 0–100 relevance score, `sortBy: "relevance"` |
| Who won what | `noticeTypes: ["award"]` → supplier organisations and awarded values |

### Sources and coverage

| Source | What it adds | Notes |
|---|---|---|
| **Find a Tender** (Cabinet Office, Central Digital Platform) | All UK notices under the **Procurement Act 2023** (UK1–UK17 notices, from 24 Feb 2025), plus above-threshold notices under the old regulations and Scottish above-threshold notices | Queried by update date; we deliberately do not use its `stages` filter (see FAQ) |
| **Contracts Finder** | England: below-threshold opportunities and awards, and procurements started under the old regulations (before 24 Feb 2025) | Strict rate limit — the Actor paces itself |
| **Public Contracts Scotland** | Scottish below-threshold "website" notices and Scottish-regime notices | Month-level API; above-threshold Scottish notices are also on Find a Tender and are merged |
| **Sell2Wales** | Welsh below-threshold notices | Same platform as PCS. **On 11 Oct 2026 its list API returned HTTP 500 for every query**; the Actor detects this, skips it and reports it in the run summary |
| **TED** (Publications Office of the EU) | EU/EEA above-threshold notices in eForms: contract notices, awards, prior information, modifications | Keyword search uses TED's own full-text search across all languages |

UK notices stopped going to TED after Brexit (2021), so UK and EU results do not overlap.

### Input examples

**Open digital/IT tenders in London and the South East, £25k–£500k**

```json
{
  "sources": ["fts", "contractsFinder"],
  "keywords": ["website", "software", "digital"],
  "regions": ["London", "South East"],
  "minValue": 25000,
  "maxValue": 500000,
  "openOnly": true,
  "lookbackDays": 14
}
```

**Daily alert (schedule it every morning)**

```json
{
  "mode": "monitor",
  "monitorKey": "cleaning-scotland",
  "sources": ["fts", "scotland"],
  "cpvKeywords": ["cleaning"],
  "regions": ["Scotland"],
  "noticeTypes": ["tender", "planning"]
}
```

**Closing-soon digest across the UK and Ireland**

```json
{
  "mode": "closingSoon",
  "closingWithinDays": 7,
  "sources": ["fts", "contractsFinder", "scotland", "ted"],
  "cpvCodes": ["72000000"],
  "tedCountries": ["IE"]
}
```

**Who won NHS cleaning contracts this quarter**

```json
{
  "noticeTypes": ["award"],
  "buyers": ["NHS"],
  "cpvKeywords": ["cleaning"],
  "publishedFrom": "2026-07-01",
  "sources": ["fts", "contractsFinder", "scotland"]
}
```

Try it offline first with `"useSampleData": true` (bundled recorded responses, no network, no charges).

### Output

One dataset item per notice (trimmed example from a live run on 11 Oct 2026):

```json
{
  "uid": "fts:095671-2026",
  "source": "fts",
  "sourceName": "Find a Tender (UK)",
  "id": "095671-2026",
  "ocid": "ocds-h6vhtk-077751",
  "noticeType": "tender",
  "noticeTypeCode": "UK4",
  "noticeTypeLabel": "Tender notice",
  "status": "active",
  "title": "Chelmsford College Website tender",
  "description": "The College is looking for a company to build a new website in ASP.net …",
  "buyer": { "name": "Chelmsford College", "id": "GB-PPON-PPHT-3744-XBMQ", "identifiers": [{ "scheme": "GB-PPON", "id": "PPHT-3744-XBMQ" }], "address": { "locality": "Chelmsford", "region": "UKH36", "postcode": "CM2 0JQ", "country": "United Kingdom" }, "type": "Public authority - sub-central government" },
  "value": { "amount": null, "amountMin": null, "currency": null },
  "cpv": [{ "code": "72413000", "label": "World wide web (www) site design services" }],
  "location": { "countries": ["United Kingdom"], "nutsCodes": ["UKH3", "UKH36"], "postcodes": ["CM2 0JQ"] },
  "procedure": { "method": "open", "details": "Below threshold - open competition", "legalBasis": "2023/54", "regime": "Procurement Act 2023", "aboveThreshold": false, "smeSuitable": true },
  "publishedDate": "2026-10-09T12:16:49.000Z",
  "deadline": "2026-11-06T23:59:59.000Z",
  "deadlineType": "tender",
  "daysUntilDeadline": 26.7,
  "isOpen": true,
  "documents": [{ "type": "biddingDocuments", "url": "https://www.find-tender.service.gov.uk/Notice/Attachment/A-23859" }],
  "noticeUrl": "https://www.find-tender.service.gov.uk/Notice/095671-2026",
  "awards": [],
  "lots": [],
  "relevance": { "score": 41, "matchedKeywords": ["website"], "matchedCpv": [], "excludedBy": [] },
  "alsoPublishedOn": [],
  "licence": "Open Government Licence v3.0 — https://www.nationalarchives.gov.uk/doc/open-government-licence/version/3/",
  "attribution": "Contains public sector information from Find a Tender, licensed under the Open Government Licence v3.0."
}
```

Also written to the run's key-value store:

- `OUTPUT` — run summary: per-source status, records fetched, why notices were filtered out, CPV codes used, duplicates merged, warnings, attribution.
- `DIGEST.md` — a ready-to-send markdown digest (paste into email, Slack or Teams, or send it with an Apify integration/webhook).
- `DIGEST` — the same digest as JSON, including a closing-soon list.

Dataset views: **Overview**, **Closing soon**, **Awards**, **Relevance**.

### Monitoring (daily alerts)

1. Set `mode: "monitor"` and give the alert a `monitorKey` (e.g. `"it-london"`).
2. Schedule the Actor daily (Apify Console → Schedules).
3. Each run continues from the previous run (with one day of overlap) and outputs **only notices it has not sent before**, so you are charged only for new ones. State is kept in the named key-value store `siteverdict-public-tenders-state`; each `monitorKey` is independent.
4. By default you get one alert per procurement and stage (tender, then award). Set `alertOnUpdates: true` to be alerted on every change notice too.

### Relevance ranking

Score 0–100 per notice, fully transparent: keyword in title +30, in description/lots +12, in CPV labels +6 (per keyword); a CPV code match +25; still open +5. Any `profileExcludeKeywords` hit sets the score to 0. Use `minRelevance` to drop weak matches.

### FAQ

**Why not use Find a Tender's own `stages` filter?** We tested it on 11 Oct 2026: with `stages=tender` it returned only notices under the old regulations and silently dropped every Procurement Act 2023 notice (15 results vs 198 tender-stage notices actually published that week). So we fetch by date and filter stages ourselves. It is slower but complete.

**Do values get converted between currencies?** No. Value filters compare in each notice's own currency (GBP for UK sources, mostly EUR for TED, sometimes SEK, PLN etc.).

**Are TED titles in English?** `title` is the buyer's original title. `headline` is TED's translated headline ("Country – CPV – title") in your `tedLanguage`. Descriptions are in the original language.

**How far back can I search?** Any date range. UK APIs only filter by date, so long windows mean more pages: about 300–450 Find a Tender records per weekday (100 per page). Raise `maxPagesPerSource` for long ranges; the summary tells you if a source was truncated.

**What counts as a duplicate?** The same procurement on two platforms (e.g. a Scottish tender on both PCS and Find a Tender, linked by its PCS reference), or the same title + buyer + stage. The best source is kept and the others are listed in `alsoPublishedOn`.

**Is a notice "open" if it has no deadline?** `isOpen` is `null` when no deadline is published; `openOnly` and `closingWithinDays` exclude those.

### Limits

- Speed is set by the sources' rate limits. Contracts Finder locks clients out for 2 minutes after about 12 rapid requests, and Find a Tender asks clients to back off (HTTP 429, Retry-After 120 s) after bursts. The Actor waits as asked, so a 45-day closing-soon scan can take several minutes.
- Sell2Wales was down (HTTP 500) when this version was built. It is skipped automatically while that lasts.
- Public Contracts Scotland and Sell2Wales only filter by month and notice type, so the Actor trims to your dates.
- TED keyword matching happens on TED's side (all languages, full text), so it can be broader than the UK keyword matching (title, description, lots, CPV labels).
- Keyword → CPV lookup matches words in official CPV labels, plus a small curated synonym list (e.g. website, cyber security, cloud, AI). Check `OUTPUT.cpvLookup` to see which codes were used.
- Documents are links only. Many buyers host tender packs on their own e-tendering portals, which may need a free supplier registration.

### Compliance, sources and licences

- **Find a Tender, Contracts Finder, Public Contracts Scotland, Sell2Wales:** Open Government Licence v3.0. *Contains public sector information licensed under the Open Government Licence v3.0.* Each item carries its own `licence` and `attribution`.
- **TED:** © European Union, reused under Commission Decision 2011/833/EU (reuse of Commission documents). CPV 2008 labels come from the EU eForms SDK code list (OP-TED), under the same reuse policy.
- Only official open APIs are used, with an honest User-Agent and polite pacing. No logins, CAPTCHAs, paywalls or proxy rotation.
- **Personal data is off by default.** Buyer contact names, emails and phone numbers are excluded unless you set `includeContactDetails: true`. If you do, they are output exactly as the buyer published them, and you are responsible under UK GDPR and PECR: assess legitimate interest, and do not use them for unsolicited marketing to individuals. Award winners are organisations as published by the buyer (a sole trader's trading name can be a person's name, so treat it with care).
- **Not legal, financial or procurement advice.** Always read the official notice and documents before bidding. Data is as published by the sources, with dates shown on each notice.

### Pricing

Pay per event: you pay for each notice saved to the dataset (event `notice`). Nothing is charged for errors, empty runs, sample-data runs or notices skipped as already seen in monitor mode. The run stops cleanly when your maximum charge per run is reached. See PRICING.md.

# Changelog

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

# Actor input Schema

## `mode` (type: `string`):

<b>search</b>: one-off search. <b>monitor</b>: only notices that are NEW since the previous run with the same monitor name (schedule it daily for alerts). <b>closingSoon</b>: open tenders whose deadline falls within the next N days, sorted by deadline.

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

Official open APIs to search. Find a Tender = all UK notices under the Procurement Act 2023 (from 24 Feb 2025) plus older above-threshold notices. Contracts Finder = England below-threshold and legacy (pre-24 Feb 2025) procurements. Public Contracts Scotland and Sell2Wales add below-threshold Scottish/Welsh notices. TED = EU/EEA above-threshold notices (eForms).

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

Words or phrases to look for in the title, description, lots and CPV labels (whole-word, case-insensitive, simple plurals match; end a word with \* for prefix match, e.g. "cyber\*"). TED uses its own full-text search in all languages.

## `keywordMatch` (type: `string`):

Match ANY keyword or ALL keywords.

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

Drop notices whose title or description contains any of these words or phrases.

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

Common Procurement Vocabulary codes. Hierarchical: "72" or "72000000" matches every IT service code below it; "79340000" matches advertising and marketing. Check digits ("-5") are optional.

## `cpvKeywords` (type: `array`):

Plain-English terms (e.g. "cleaning", "software development", "catering") looked up in the official CPV 2008 vocabulary; matching codes are added to the CPV filter. The run summary (OUTPUT) shows which codes were used.

## `buyers` (type: `array`):

Keep notices whose buyer name contains any of these (e.g. "NHS", "Leeds City Council", "Ministry of Defence").

## `regions` (type: `array`):

Delivery or buyer location. UK: region names ("London", "Scotland", "North West") or NUTS/ITL codes ("UKI", "TLI3", "UKM7"). EU: NUTS codes ("DE1", "FR10", "IE06"). Codes are prefix-matched.

## `postcodes` (type: `array`):

UK postcode areas or districts (e.g. "M", "LS1", "EH"). Matches buyer or delivery postcodes.

## `includeNationwide` (type: `boolean`):

When filtering by a UK region, also keep notices whose delivery location is the whole UK.

## `tedCountries` (type: `array`):

Limit TED results to buyers or places of performance in these countries (ISO codes: IE or IRL, DE or DEU, FR, NL …).

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

Minimum estimated (or awarded) value, in the notice's own currency (GBP for UK sources, mostly EUR for TED). No currency conversion is done.

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

Maximum estimated (or awarded) value, in the notice's own currency.

## `includeNoValue` (type: `boolean`):

Many notices do not publish a value. Keep them when a value range is set?

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

planning = pipeline / prior information / market engagement; tender = open opportunities (contract notices, tender notices); award = contract awards (who won); contract = contract details, changes and terminations.

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

Only notices with a submission deadline in the future (excludes cancelled tenders).

## `closingWithinDays` (type: `integer`):

Only notices whose deadline falls within the next N days. In closingSoon mode the default is 7.

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

Search notices published or updated in the last N days (ignored when 'Published from' is set). closingSoon mode looks back at least 45 days so long-running tenders are included. Monitor mode continues from the previous run automatically.

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

Start date (YYYY-MM-DD) or relative ("14 days", "2 weeks").

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

End date (YYYY-MM-DD). Defaults to now.

## `profileKeywords` (type: `array`):

What you sell. Title hits score highest, then description, lots and CPV labels.

## `profileExcludeKeywords` (type: `array`):

Notices mentioning these get relevance 0 (e.g. "construction", "framework call-off only").

## `minRelevance` (type: `integer`):

Drop notices scoring below this (0 = keep all).

## `sortBy` (type: `string`):

Order of the results.

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

Name of the saved search for monitor mode. Each name remembers which notices it has already sent you. Use a different name per alert.

## `alertOnUpdates` (type: `boolean`):

Off: one alert per procurement and stage (tender, then award). On: every updated notice (corrections, changed deadlines) alerts again.

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

Maximum notices to save (each saved notice is one billable 'notice' event).

## `maxPagesPerSource` (type: `integer`):

Safety cap on API pages (100 records each) per source. UK APIs filter only by date, so long windows need more pages.

## `maxDescriptionChars` (type: `integer`):

Truncate long descriptions (0 = no limit).

## `includeLots` (type: `boolean`):

Include lot titles, values and contract periods.

## `includeContactDetails` (type: `boolean`):

Off by default. When on, the buyer's published contact point (name, email, phone) is included exactly as published. You are responsible for UK GDPR / PECR compliance — do not use it for unsolicited marketing to individuals.

## `tedLanguage` (type: `string`):

Preferred language for TED titles and descriptions (3-letter code: eng, deu, fra …). Falls back to English, then the original language.

## `useSampleData` (type: `boolean`):

Run on bundled recorded responses from each API (October 2026) — no network calls, no charges. Handy for testing integrations.

## Actor input object example

```json
{
  "mode": "search",
  "sources": [
    "fts",
    "contractsFinder",
    "scotland"
  ],
  "keywords": [
    "website",
    "digital"
  ],
  "keywordMatch": "any",
  "includeNationwide": true,
  "includeNoValue": true,
  "noticeTypes": [
    "tender"
  ],
  "openOnly": false,
  "lookbackDays": 7,
  "minRelevance": 0,
  "sortBy": "publishedDate",
  "monitorKey": "default",
  "alertOnUpdates": false,
  "maxResults": 50,
  "maxPagesPerSource": 40,
  "maxDescriptionChars": 1500,
  "includeLots": true,
  "includeContactDetails": false,
  "tedLanguage": "eng",
  "useSampleData": false
}
```

# Actor output Schema

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

No description

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

No description

## `files` (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 = {
    "mode": "search",
    "sources": [
        "fts",
        "contractsFinder",
        "scotland"
    ],
    "keywords": [
        "website",
        "digital"
    ],
    "noticeTypes": [
        "tender"
    ],
    "lookbackDays": 7,
    "maxResults": 50
};

// Run the Actor and wait for it to finish
const run = await client.actor("siteverdict/siteverdict-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 = {
    "mode": "search",
    "sources": [
        "fts",
        "contractsFinder",
        "scotland",
    ],
    "keywords": [
        "website",
        "digital",
    ],
    "noticeTypes": ["tender"],
    "lookbackDays": 7,
    "maxResults": 50,
}

# Run the Actor and wait for it to finish
run = client.actor("siteverdict/siteverdict-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 '{
  "mode": "search",
  "sources": [
    "fts",
    "contractsFinder",
    "scotland"
  ],
  "keywords": [
    "website",
    "digital"
  ],
  "noticeTypes": [
    "tender"
  ],
  "lookbackDays": 7,
  "maxResults": 50
}' |
apify call siteverdict/siteverdict-public-tenders --silent --output-dataset

```

## MCP server setup

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