# UK Public Procurement - Find a Tender & Contracts Finder (`j0401/uk-public-procurement`) Actor

UK public procurement notices from both official OCDS feeds (OGL v3): Find a Tender (above threshold, since 2021) and Contracts Finder (below threshold, since 2011). Buyer, suppliers, CPV codes, values, dates and links. Filter by keyword, CPV, buyer, supplier, stage, value or date; aggregate.

- **URL**: https://apify.com/j0401/uk-public-procurement.md
- **Developed by:** [Wenhao Yang](https://apify.com/j0401) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.03 / 1,000 uk procurement notices

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

## UK Public Procurement - Find a Tender & Contracts Finder

UK public-sector procurement notices from **both official OCDS feeds**:

- **Find a Tender** - above-threshold notices since January 2021, across the
  UK. Roughly **500-600 notices on a typical weekday**.
- **Contracts Finder** - below-threshold notices since 2016. (The service's
  OCDS API also serves an archived 2011-2015 collection; the daily harvester
  files used here begin in 2016, and the actor says so rather than returning a
  silent gap.)

Both are free, need no key and are published under the Open Government
Licence v3. Every record carries the title, description, buyer name (plus town,
postcode, region and email on Find a Tender), awarded suppliers and their company numbers, CPV
codes, tender / award / contract values, award and contract dates, the OCDS
stage and the official notice link.

At the 2026-10-19 check, the last three days (**16-18 October 2026**) held
**639 notices** - 545 from Find a Tender and 94 from Contracts Finder. Buyer
names are present on 630 of them, CPV codes on 629, awarded suppliers on 373,
and a value (tender, award or contract) on 568 - the tender value alone on 288.

### Low cost

**From $0.00005 per record, down to $0.00003 at Gold.** Pay only for the
notices you receive - the date window stays fully searchable, you are never
billed for the scan behind it.

### Search it

- **Keyword** - `keyword="CCTV"` (2 notices in the last three days) or
  `"software"` (22). Matches the title and description.
- **CPV** - `cpv="45"` (construction, 125 notices) or a full code such as
  `"45210000"`. Matches every CPV on the notice.
- **Buyer** - `buyer="NHS"` (67), `"Belfast"`, `"Council"`.
- **Supplier** - `supplier="Ltd"` (131), `"Balfour"` - matches any awarded
  supplier on award notices.
- **Stage** - `stage="award"` (376) for contract awards, `"tender"` (114) for
  open opportunities, `"planning"` (49) for prior information / pipelines.
- **Value** - `valueMin=1000000` (133 notices of 1m+) or `valueMax`.
- **Dates** - `dateFrom` / `dateTo` (YYYY-MM-DD). A window may span up to 180
  days; blank means the last three days. Find a Tender files start on
  2021-01-04 and Contracts Finder files on 2016-01-01; earlier windows must
  pick the feed that covers them.

### Example inputs

**Open opportunities about CCTV** - the bid-finding case.

```json
{ "keyword": "CCTV", "stage": "tender", "dateFrom": "2026-09-18", "dateTo": "2026-10-18" }
```

**Construction notices by CPV**

```json
{ "cpv": "45", "maxResults": 50 }
```

**Everything an NHS body published**

```json
{ "buyer": "NHS", "maxResults": 50 }
```

**Large awards in the last three months**

```json
{ "stage": "award", "valueMin": 1000000, "dateFrom": "2026-07-18", "dateTo": "2026-10-18", "maxResults": 100 }
```

**Below-threshold only** - Contracts Finder alone.

```json
{ "corpus": "cf", "maxResults": 50 }
```

**Counts by stage** - the default aggregate.

```json
{ "mode": "aggregate", "groupBy": "stage" }
```

**Spend by contracting authority**

```json
{ "mode": "aggregate", "groupBy": "buyer", "dateFrom": "2026-07-18", "dateTo": "2026-10-18" }
```

### Or roll it up

`mode=aggregate` returns one count row per group - **stage**, **corpus**,
**month**, **category**, **buyer** or **valueBand**. The default (empty) run
aggregates the last three days.

Stage distribution for 16-18 October 2026: award **376** / tender **114** /
planning **49** / tenderUpdate **34** / update **28** / awardUpdate **13** /
planningUpdate **11** / tenderCancellation **8** / contractAmendment **4** /
contractTermination **1** / other **1**.

### Example output

A Find a Tender contract award:

```json
{
 "corpus": "fts",
 "ocid": "ocds-h6vhtk-0788fe",
 "releaseId": "097691-2026",
 "noticeId": "097691-2026",
 "noticeUrl": "https://www.find-tender.service.gov.uk/Notice/097691-2026",
 "publishedDate": "2026-10-16",
 "stage": "award",
 "tags": "award;contract",
 "title": "Removal & Storage Services",
 "description": "Removal and Storage Services",
 "tenderStatus": "complete",
 "procurementMethodDetails": "Below threshold - unknown",
 "mainCategory": "services",
 "buyerName": "THE GUINNESS PARTNERSHIP LIMITED",
 "buyerId": "GB-COH-IP031693",
 "buyerTown": "London",
 "buyerPostcode": "NW1 3AX",
 "buyerRegion": "UKI31",
 "buyerEmail": "procurement@guinness.org.uk",
 "supplierNames": "INLINE REMOVALS & STORAGE LIMITED",
 "supplierCount": "1",
 "supplierIds": "GB-COH-05407873",
 "cpvCodes": "60000000;63120000;98392000",
 "cpvCount": "3",
 "valueCurrency": "GBP",
 "contractValue": "100000",
 "awardDate": "2026-05-25",
 "contractStartDate": "2026-06-01",
 "contractEndDate": "2027-05-31",
 "sourceFormat": "ocds",
 "refreshedDate": "2026-10-16"
}
```

### Notes on the data, from the sources

- **One row = one notice, not one tender.** A tender can produce a contract
  notice, then award and contract notices; each is a separate record with its
  own date, and the OCDS `tags` show which stage it is.
- **Field coverage varies by stage and feed.** Award notices often carry
  supplier names but no tender value; Contracts Finder notices almost always
  carry CPV codes and a buyer, while Find a Tender award notices frequently
  publish the value only on the contract. In the three-day sample, a value was
  present on 568 of 639 notices (tender value alone on 288) and an awarded
  supplier on 373. Buyer town/postcode/region/email come from Find a Tender;
  the Contracts Finder daily file carries no buyer address, so those fields
  are blank on its records.
- **A minority of Find a Tender notices use the legacy TED XML format**
  (about 15% in the sample). Those carry `sourceFormat="ted"`, a notice-derived
  `ocid` and no OCDS lot structure; everything the form carries is mapped.
  Payment-compliance notices (form UK17) contain no procurement record and are
  not included.
- **Scope.** Find a Tender covers UK-wide above-threshold procurement,
  including Scotland and Northern Ireland buyers. Contracts Finder covers
  below-threshold notices published on that service. Scotland's PCS and
  Northern Ireland's eTendersNI run separate below-threshold portals and are
  not part of these two feeds.
- **Daily files, not the rate-limited API.** Both services throttle their OCDS
  APIs to a handful of requests per two minutes. This actor reads the official
  daily harvester files instead - one request per day, no throttling, the same
  notices.
- **Licence.** Open Government Licence v3 - commercial reuse is expressly
  permitted, with attribution to the Crown Commercial Service.

Data sources: Find a Tender daily notice archive (Crown Commercial Service,
published via data.gov.uk) and Contracts Finder
(`contractsfinder.service.gov.uk`).

# Actor input Schema

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

search = notices matching your filters. aggregate = one row per group with count. Leave blank to auto-route: filters -> search, no filters -> aggregate.

## `corpus` (type: `string`):

both = Find a Tender + Contracts Finder (default); fts = above-threshold only; cf = below-threshold only.

## `keyword` (type: `string`):

Case-insensitive substring of the notice title or description, e.g. "CCTV" or "software".

## `cpv` (type: `string`):

CPV code prefix (2 to 8 digits), matched against every CPV on the notice, e.g. "45" (construction) or "45210000".

## `buyer` (type: `string`):

Case-insensitive substring of the contracting authority name, e.g. "NHS" or "Belfast".

## `supplier` (type: `string`):

Case-insensitive substring of any awarded supplier name, e.g. "Ltd" or "Balfour".

## `stage` (type: `string`):

Exact OCDS tag. award = contract award notice; tender = open opportunity; planning = prior information / pipeline. Blank = all stages.

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

Exact OCDS tender status where published, e.g. "active", "complete", "cancelled".

## `valueMin` (type: `number`):

Minimum value in pounds - matches if any of the tender, award or contract value on the notice is at least this.

## `valueMax` (type: `number`):

Maximum value in pounds.

## `dateFrom` (type: `string`):

Earliest publication date (YYYY-MM-DD), inclusive. Blank with dateTo blank = the last three days.

## `dateTo` (type: `string`):

Latest publication date (YYYY-MM-DD), inclusive. The window may span at most 180 days.

## `aggregate` (type: `boolean`):

When on, returns one summary record per group with count, instead of individual notices.

## `groupBy` (type: `string`):

stage -> award vs tender vs planning; corpus -> Find a Tender vs Contracts Finder; month -> publication month; category -> services/goods/works; buyer -> contracting authority; valueBand -> value range. Blank defaults to stage.

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

Cap the number of search records pushed (0 = the default ceiling of 50, maximum 5000). Aggregate returns every group.

## Actor input object example

```json
{
  "aggregate": false,
  "maxResults": 50
}
```

# Actor output Schema

## `recordsUrl` (type: `string`):

UK public procurement notices or aggregate rows - as JSON

## `datasetUrl` (type: `string`):

No description

## `runUrl` (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 = {};

// Run the Actor and wait for it to finish
const run = await client.actor("j0401/uk-public-procurement").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 = {}

# Run the Actor and wait for it to finish
run = client.actor("j0401/uk-public-procurement").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 '{}' |
apify call j0401/uk-public-procurement --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,j0401/uk-public-procurement"
        }
    }
}
```

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/7cMTAOHKOpPQUYvP5/builds/ORvzqXk95PgW4foDd/openapi.json
