# UK Tenders & Awards – Find a Tender, Contracts Finder, TED (`notational_bush/uk-eu-contract-awards`) Actor

UK government tenders and contract awards from Find a Tender, Contracts Finder and EU TED in one feed. See which public contracts expire in the next 12 months, who holds them, and each UK winner's Companies House number. First 25 rows free per run. Official APIs, no personal data.

- **URL**: https://apify.com/notational_bush/uk-eu-contract-awards.md
- **Developed by:** [Dave Harding](https://apify.com/notational_bush) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.00 / 1,000 contract award rows

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

## UK Tenders & Contract Awards – Find a Tender, Contracts Finder and TED, with expiry dates

> Find UK public contracts that are up for renewal, who holds them, and the winner's Companies House number. **First 25 rows of every run free**, then $3 per 1,000 rows.

### What does this UK tenders scraper do?

It pulls contract awards and open tenders from three official, free public APIs into one clean table, with one schema:

- **Find a Tender** (UK, above threshold)
- **Contracts Finder** (England, below threshold)
- **TED** (EU, optional)

Every award gets a **contract end date and expiry flag** (`<=6m`, `<=12m`, …), and UK winners get their **Companies House number**. It uses official APIs only: no HTML scraping, no login, no API key needed.

### Who uses it

- **B2G sales and bid teams:** a pipeline of public contracts ending in the next 6–12 months, with the incumbent supplier.
- **Competitor tracking:** which buyers your competitors win, and for how much, keyed by company number rather than fuzzy names.
- **Market research and analysts:** UK and EU award data in one schema for CPV, buyer and value analysis.
- **AI agents and automations:** call it through the Apify API or MCP server and get structured JSON back.

### Quick start (3 steps)

1. Click **Start** with the prefilled input. It returns up to 25 UK contract awards whose contract ends in the next 12 months, from Find a Tender and Contracts Finder. This first run is free (25 free rows) and usually takes 1–3 minutes.
2. Narrow it down with `cpvCodes` (e.g. `72` IT services, `45` construction, `85` health) or `keywords`, and raise `maxItems`.
3. Export the dataset as CSV, Excel or JSON, or send it to Google Sheets, Slack or your CRM with an integration.

### Example row

A real award row from October 2026 (trimmed; full sample in the Output tab):

| Field | Value |
|---|---|
| `title` | Drawing Document Management Licences and Professional Services |
| `buyerName` | Sunderland City Council |
| `source` | findATender |
| `awardDate` | 2026-10-27 |
| `value` / `currency` | 69,621.50 GBP |
| `supplierName` | Symetri Ltd |
| `supplierCompanyNumber` | 03239798 (`supplierMatch`: identifier, status Active) |
| `contractStart` → `contractEnd` | 2026-10-27 → 2029-10-27 (`contractEndSource`: notice_text_duration) |
| `monthsToExpiry` / `expiryFlag` | 36 / later |
| `noticeUrl` | https://www.find-tender.service.gov.uk/Notice/101787-2026 |

### Find contracts expiring in the next 12 months

```json
{"noticeType": "awards", "sources": ["findATender", "contractsFinder"], "expiringWithinMonths": 12,
 "cpvCodes": ["72"], "publishedFrom": "2025-11-01", "maxItems": 500, "linkedNoticeLookups": 50}
```

A longer date window finds more contracts ending soon (awards from a year or more ago are the ones coming up for renewal). Awards with an unknown end date are left out when `expiringWithinMonths` is set; clear it to get every award.

### Track competitor contract wins by Companies House number

Run awards with your sector's CPV codes or keywords over the last year, then group the dataset by `supplierCompanyNumber`. Join it to your CRM or to Companies House data on the company number instead of the supplier's name, which varies between notices.

### Daily UK tender alerts (Find a Tender + Contracts Finder)

Schedule this input daily (Console › Schedules) and connect Slack, email or Google Sheets:

```json
{"noticeType": "open", "sources": ["findATender", "contractsFinder"], "keywords": ["cyber security", "penetration testing"],
 "publishedFrom": "2026-10-27", "openOnly": true, "maxItems": 100}
```

### How much does it cost?

You pay per row returned, and **the first 25 rows of every run are free**. Rows that fail validation are never written or charged, and the run stops at your maximum cost per run.

| Rows in one run | Charged rows | Cost |
|---|---|---|
| 25 | 0 | $0.00 |
| 100 | 75 | ≈ $0.23 |
| 1,000 | 975 | ≈ $2.93 |
| 10,000 | 9,975 | ≈ $29.93 |

Prices: `award-record` and `tender-record` $0.003 per row ($3 per 1,000), plus Apify's tiny Actor-start event. Apify's free plan credit covers trial runs. Commercial tender-alert services typically charge a monthly subscription; here you pay only for the rows you pull.

### Integrations

- **Google Sheets, Slack, email, Zapier, Make, n8n:** through Apify integrations on the Actor or a schedule.
- **API:** `POST https://api.apify.com/v2/acts/notational_bush~uk-eu-contract-awards/run-sync-get-dataset-items?token=…` with the JSON input.
- **AI agents:** available through the Apify MCP server, so agents can find and run it.

### Input

| Field | Default | Notes |
|---|---|---|
| `noticeType` | `awards` | `open` (one row per tender lot), `awards` (one row per award × supplier), or `both` |
| `sources` | Find a Tender, Contracts Finder | `findATender`, `contractsFinder`, `ted` |
| `publishedFrom` / `publishedTo` | today − 90 days / today | Award date for awards, publication date for open notices. Range ≤ 366 days |
| `openOnly` | true | Open mode: drop notices past their deadline |
| `cpvCodes`, `keywords` | none | CPV prefix match; keywords are case-insensitive matches in the title or description. Up to 50 each |
| `tedCountries` | all | ISO-2 buyer countries for TED |
| `minValue` | none | In the notice's own currency |
| `expiringWithinMonths` | none (form prefill: 12) | Awards only. 1–60. Unknown end dates are dropped when this is set |
| `maxItems` | 25 | Total across all sources. Maximum 10,000. The first 25 rows of every run are free |
| `linkedNoticeLookups` | 10 | Find a Tender awards only. For awards still missing an end date, look up at most this many earlier notices in the same procurement (about 10 seconds each, because Find a Tender is rate-limited). 0–500; 0 turns it off |
| `companiesHouseApiKey` | none | Optional, secret. Your own key, used only as a fallback for dissolved or renamed suppliers |

### Output

There is one row per **award × supplier** or per **open tender × lot**. The fields are: `recordId`, `noticeType`, `source`, `noticeUrl`, `noticeId`, `publishedAt`, `buyerName`, `buyerId`, `buyerCountry`, `title`, `description`, `cpvCodes`, `category`, `procedure`, `lotId`, `awardDate`, `tenderDeadline`, `estimatedValue`, `tenderStatus`, `contractStart`, `contractEnd`, `contractEndSource` (`notice`, `notice_text`, `notice_text_duration`, `model`, `linked_notice`), `monthsToExpiry`, `expiryFlag` (`expired`, `<=6m`, `<=12m`, `later`, `unknown`), `hasRenewalOptions`, `value`, `currency`, `supplierName`, `supplierScale`, `supplierCompanyNumber`, `supplierMatch` (`identifier`, `name_exact`, `name_normalised`, `name_variant`, `api`, `none`), `supplierCompanyStatus`, `supplierNationalId`, `licence`, `fetchedAt`.

#### Where `contractEnd` comes from

`contractEndSource` says how each end date was found, in this order:

1. `notice`: the structured contract period on the notice itself.
2. `notice_text` / `notice_text_duration`: the notice's own text. Either explicit dates ("from 1 April 2026 to 31 March 2029") or an initial term ("initial term of 36 months") added to the stated start, or to the award/signature date when no start is given. A term is used only when exactly one distinct term is found. Extension and option periods are never added.
3. `model`: off on the public build unless the operator sets a model key. A small language model reads the same text, capped per run, and only when the text mentions a period.
4. `linked_notice`: Find a Tender only. The contract period published on an earlier notice in the same procurement (usually the tender notice), capped by `linkedNoticeLookups`.

End dates are the **initial term**, not the maximum term with extensions. Where a start is estimated from the award date, the end can be some weeks out.

Notices that appear in both Find a Tender and Contracts Finder are deduplicated, and the Find a Tender copy is kept. After the first 25 free rows of each run, you are charged per row: `award-record` for award rows and `tender-record` for open-tender rows. Rows that fail validation are never written and never charged.

### Companies House matching

Matching uses the free **Companies House Free Company Data Product** (the monthly bulk CSV). The index is built into the image at build time from the latest monthly file, so rebuild the Actor once a month **without the Docker cache** to refresh it (Console build option "Use cache" off, or API `POST /v2/acts/{id}/builds?version=0.1&useCache=false`). A cached build reuses the old snapshot. Each UK supplier goes through these tiers in order:

1. A `GB-COH` identifier on the notice, if it is a well-formed number found in the live register.
2. An exact name match that is unique.
3. A unique match on a tidied name, after case and punctuation are folded and `Limited`/`Ltd`, `PLC`, `&`/`and` and a leading `The` are normalised.
4. `name_variant`: the legal-entity part of a longer supplier string, such as "Acme Ltd T/A Acme Services", "Acme Ltd (trading as Acme)" or "Acme Ltd (ACM)". The part must end in a company suffix (Ltd, Limited, PLC, LLP or CIC) and must match uniquely in tier 2 or 3. A sole trader's own name is never looked up.

Names that are ambiguous are left unmatched. A well-formed identifier that isn't in the live register is kept, with the status `not-in-live-register`. An optional API key adds a lookup fallback for those cases. The 2026 match test on 1,000 real award suppliers found about 70% matched. On the fixed October 2026 sample of 1,141 UK award-supplier rows, the rate is 69.8% (68.1% before the `name_variant` tier). Most of the rest are NHS trusts, universities and councils (not Companies House companies), sole traders, and brand names without a company suffix.

### Personal data

No personal data is collected. The Actor drops contact names, emails and phone numbers, and supplier street addresses. It also removes emails and phone numbers from free text. Suppliers that look like individuals or sole traders are shown as `[individual]`, or `[individual] t/a <trading name>`.

### Licences and attribution

- 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/). Both API responses name OGL v3.0 as their licence, and both services' terms say most content is Crown copyright published under the OGL.
- TED: © European Union, https://ted.europa.eu. Procurement notices may be freely reused for commercial or non-commercial purposes under Commission Decision 2011/833/EU (TED legal notice).
- Companies House: company numbers and statuses come from the Companies House Free Company Data Product. Companies House places no restriction on how public-register information is used (Companies House, "Our public task, copyright and Crown copyright"). It does not release this product under the OGL. Source: Companies House.

This Actor is not endorsed by Cabinet Office, Companies House or the European Union. Data is provided as is.

Each row includes a `licence` field naming its source licence.

### FAQ

**Is this data legal to reuse?** Yes. Find a Tender and Contracts Finder data is published under the Open Government Licence v3.0, TED notices may be reused under Commission Decision 2011/833/EU, and company numbers come from Companies House's free bulk product. Each row names its licence in `licence`.

**How fresh is it?** Every run queries the live APIs, so new notices appear as soon as the portals publish them. Companies House matching uses the monthly snapshot built into the Actor.

**Why are some contract end dates `unknown`?** Many Find a Tender award notices don't publish a contract period. The Actor reads the term from the notice text and from the earlier tender notice; about half of those stay unknown. TED end dates are known for about 80% of awards.

**What's the difference between Find a Tender and Contracts Finder?** Find a Tender carries higher-value UK notices (above the procurement thresholds); Contracts Finder carries lower-value contracts in England. Notices published on both are deduplicated (the Find a Tender copy is kept).

**Can I get only new notices?** Schedule the Actor with `publishedFrom` set to the last run's date (or a short window such as the last 1–2 days) and send new rows to your integration.

**Does it collect personal data?** No. Contact names, emails, phones and street addresses are dropped, and sole traders are shown as `[individual]`.

### Known limits (v1)

- Most Find a Tender award notices don't publish a structured contract period. The text parser and linked-notice lookup fill about 40–50% of them (50% on the fixed sample, 42% in the October 2026 live run); the rest stay `unknown`. TED end dates come from the notice only (about 80% known). Contracts Finder end dates can include extensions, because that is how buyers enter them.
- TED values and lots are aligned per winner on a best-effort basis. Winners on multi-lot notices may list several lots.
- Win history and buyer-side Companies House matching are not included in v1. Neither source API can search by supplier, so win history would need a separate bulk archive.

### More from this developer

- [UK Company Number Lookup](https://apify.com/notational_bush/uk-company-number-lookup): have supplier names from elsewhere? It matches any list of names to Companies House numbers with the same rules.

### Changelog

- **0.1 (Oct 2026):** first public release. First 25 rows free per run; small default run (awards ending within 12 months, 25 rows); Find a Tender, Contracts Finder and TED; Companies House matching; contract end dates from notice text and linked notices.

# Actor input Schema

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

Open tenders (one row per lot), contract awards (one row per award and supplier), or both.

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

Official free APIs to query. Add TED (EU) for European notices; it makes runs a little slower.

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

Award date (awards) or publication date (open). Defaults to 90 days before the end date. The range can be up to 366 days.

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

Defaults to today.

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

Open mode: drop notices whose tender deadline has passed.

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

CPV prefixes, prefix match. Examples: 72 = IT services, 45 = construction, 85 = health and social care, 79410000 = business consultancy.

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

Keep notices whose title or description contains any keyword (case-insensitive).

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

ISO-2 buyer country codes for TED, e.g. DE, FR, IE. Empty means all.

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

Minimum award value or estimated value, in the notice's own currency.

## `expiringWithinMonths` (type: `integer`):

Awards only: keep contracts whose initial term ends within this many months (e.g. 12 = up for renewal in the next year). Awards with an unknown end date are dropped when this is set. Clear it to get all awards.

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

Total rows across all sources. The first 25 rows of every run are free; after that you are charged per row.

## `linkedNoticeLookups` (type: `integer`):

Many Find a Tender award notices publish no contract period. When the notice text doesn't state one either, the Actor can read it from an earlier notice of the same procurement (official record API). Each lookup adds about 10 seconds because Find a Tender is rate-limited. 0 turns this off.

## `companiesHouseApiKey` (type: `string`):

Your own free Companies House API key. Used only as a fallback for dissolved or renamed suppliers. Matching works without it.

## `canary` (type: `boolean`):

Internal monitoring only; leave off.

## `failOnPurpose` (type: `boolean`):

Internal alert testing only; leave off.

## Actor input object example

```json
{
  "noticeType": "awards",
  "sources": [
    "findATender",
    "contractsFinder"
  ],
  "openOnly": true,
  "expiringWithinMonths": 12,
  "maxItems": 25,
  "linkedNoticeLookups": 10,
  "canary": false,
  "failOnPurpose": false
}
```

# Actor output Schema

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

No description

## `table` (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 = {
    "noticeType": "awards",
    "sources": [
        "findATender",
        "contractsFinder"
    ],
    "expiringWithinMonths": 12,
    "maxItems": 25,
    "linkedNoticeLookups": 10
};

// Run the Actor and wait for it to finish
const run = await client.actor("notational_bush/uk-eu-contract-awards").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 = {
    "noticeType": "awards",
    "sources": [
        "findATender",
        "contractsFinder",
    ],
    "expiringWithinMonths": 12,
    "maxItems": 25,
    "linkedNoticeLookups": 10,
}

# Run the Actor and wait for it to finish
run = client.actor("notational_bush/uk-eu-contract-awards").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 '{
  "noticeType": "awards",
  "sources": [
    "findATender",
    "contractsFinder"
  ],
  "expiringWithinMonths": 12,
  "maxItems": 25,
  "linkedNoticeLookups": 10
}' |
apify call notational_bush/uk-eu-contract-awards --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,notational_bush/uk-eu-contract-awards"
        }
    }
}
```

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/3dWLRSXNaZuq6Ptd4/builds/U95yMD6bI7bCsZrqC/openapi.json
