# UK Public Tenders Search (`thesjostrandproject/uk-tenders-search`) Actor

Search UK public tender notices by last-updated date, stage, CPV code and buyer through the UK's official procurement API. Clean, typed records with no contact persons and no suppliers. No login, no scraping. Pay per record.

- **URL**: https://apify.com/thesjostrandproject/uk-tenders-search.md
- **Developed by:** [The Sjöstrand Project](https://apify.com/thesjostrandproject) (community)
- **Categories:** Business, Lead generation
- **Stats:** 2 total users, 1 monthly users, 92.3% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

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

## UK Public Tenders Search

### What this Actor returns

Search the public procurement notices that UK buyers publish, by publication date, stage, CPV code and buyer name, and get one clean, typed record per notice. Every record has the same 12 fields, and a value the notice does not have is `null`, never a missing key.

- `ocid`, `notice_id`, `release_tag`: which procurement process and which notice it is, and its stage (planning, tender or award)
- `published_date`, `tender_deadline_date`: when the notice was published, and when tenders close, if it says
- `buyer_org`, `buyer_org_id`, `buyer_country`: who is buying
- `cpv_codes`, `procurement_method`, `estimated_value`, `currency`: what is being bought, by which procedure, and its estimated value

The Actor reads the UK Government's official procurement-notice API and nothing else. It does not scrape any website, and there is no login.

### Who it helps

- **Businesses that bid for public contracts**, who want a daily or weekly list of new tenders in their sector, ready for a spreadsheet or a CRM.
- **Analysts and developers** who want tidy UK tender data for market research or their own alerts, through the Apify API, without writing their own client for the source.

### Quick start

1. Open the Input tab and leave the defaults as they are. They search the notices published on one past day, 1 October 2026, at the tender stage. That day has 7 such notices, so a first run returns 7 records (the default Maximum records is 10, an upper bound).
2. Press Start. The default run costs about $0.021: 7 records at $0.003 each, plus Apify's tiny start event of $0.00005 (see What it costs). To try it on even less, set Maximum records to 1.
3. Open the Output tab, check the records, then set your own dates, stage, CPV codes and buyer.

### Input

| Field | What it does | Default |
|---|---|---|
| Published from | Only notices published or last changed on or after this date. | `2026-10-01` |
| Published to | Only notices published or last changed on or before this date. | `2026-10-01` |
| Notice stage | Planning, tender (open for bids), award, or any stage. | `tender` |
| CPV codes | 8-digit CPV codes like `45000000`, separated by commas. A broad code includes the codes under it. | empty |
| Buyer name contains | Only buyers whose name contains this text, in any letter case, like `Council`. | empty |
| Maximum records | How many records to return at most, from 1 to 1000. | 10 |

Give at least one of the two dates. Results come in the order the source gives them.

### Output

One record per notice. This is one record of what the default input returned on 2026-10-12, unchanged:

```json
{
  "ocid": "ocds-h6vhtk-02acfb",
  "notice_id": "092650-2026",
  "release_tag": "tender",
  "published_date": "2026-10-01",
  "tender_deadline_date": "2026-11-02",
  "buyer_org": "Orkney Islands Council",
  "buyer_org_id": "GB-FTS-4848",
  "buyer_country": "United Kingdom",
  "cpv_codes": ["90511200", "90500000", "90511000"],
  "procurement_method": "open",
  "estimated_value": 1068006,
  "currency": "GBP"
}
```

### What it costs

You pay for one event, **Tender notice**, at $0.003 per record returned. Apify also adds its standard run-start event, $0.00005 per start for an Actor run with up to 1 GB of memory; it is the platform's own event, not ours. The default run of 7 records costs about $0.021. Records the Actor leaves out (see below) are never charged.

For example, a search that returns 200 notices costs $0.60. If your Apify plan includes monthly credit, a small run draws on that credit.

If the source cannot be reached or keeps answering with errors, the run stops with a clear status message, and only the records already returned are charged.

### Limits and honest notes

- **No contact persons, emails or phone numbers, and no suppliers or award winners.** The Actor never copies those from a notice. It also leaves out a notice whose buyer name happens to contain an email address or a phone number.
- **No titles or descriptions.** Those are free text written by the buyer, so they are not part of a record. The notice number, CPV codes and buyer let you find the full notice at the source.
- **Dates mean published or last changed.** The source filters by the time a notice was last updated, so a notice that was changed later appears at the date of its change, and `published_date` shows that date.
- **The buyer and CPV filters are applied here, not by the source.** The source offers no such filters, so the Actor reads the notices your dates and stage return and keeps the matching ones. A narrow filter on a long date range reads many pages and takes longer; one run reads at most 10,000 notices. The left-out count in the run's status message includes the notices that did not match.
- **One estimate per notice.** `estimated_value` is the value of the whole procurement. When a notice gives separate values for several lots, it is `null`.
- **Up to 1000 records per run.** For more, split the search by date range.
- **Pace.** The source states no request limit; it asks clients to wait when it answers "too many requests" or "unavailable". The Actor sends at most one request per second and waits as long as the source asks.
- **Freshness** follows the source. The Actor reads each notice as the source gives it at the time of your run.

### Questions

**Why did my run return fewer records than I asked for?**
Either fewer notices matched, or some were left out because they lacked a buyer name or a publication date, or held contact details in the buyer name. You were not charged for those.

**What does the run say when something is wrong?**
It says what it found and what to try. "Give at least one publication date" means both dates were empty: fill in one. A message about CPV codes or dates names the field to fix and shows the right shape. "Could not be reached" or "kept answering" means the source is busy; wait a few minutes and run again.

**How do I find only tenders I can still bid for?**
Keep the stage on Tender, and look at `tender_deadline_date`.

**Why does a notice from last year show a recent date?**
Dates follow the last change to a notice, not its first publication. See the note above.

**Which CPV codes do I use?**
CPV codes are the 8-digit codes for what is bought; a broad code such as `45000000` (construction work) includes the codes under it.

**Can I run it on a schedule?**
Yes, with the Apify scheduler or the API. Set the dates to the period you want; each run is independent and charged per record returned.

### Data source and AI note

Data source: the Find a Tender service, the UK Government's procurement notice service, through its Open Contracting Data Standard API. Contains public sector information licensed under the Open Government Licence v3.0. `published_date` is the date of the notice's latest release in the source's data; the records have no source_updated_at field.

This tool is not affiliated with, endorsed by or sponsored by the Find a Tender service or the Cabinet Office.

This tool was built with the help of AI coding assistants.

### Help

Questions, a record that looks wrong, or an idea for a field: please open an issue on the Issues tab. Thank you for the report; every one is read.

# Actor input Schema

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

Only notices published or last changed on or after this date (YYYY-MM-DD). Leave empty for no lower bound, but give at least one of the two dates.

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

Only notices published or last changed on or before this date (YYYY-MM-DD). Leave empty for no upper bound, but give at least one of the two dates.

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

Which stage of the buying process to return: planning (a buyer announcing plans), tender (open for bids), award (a contract awarded), or any.

## `cpvCodes` (type: `string`):

Only notices with these 8-digit CPV codes (what is being bought), like 45000000 for construction work. A broad code includes the codes under it. Separate several with commas. Leave empty for any. This filter is applied after the notices are read, so a narrow one reads more pages.

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

Only notices whose buyer name contains this text, in any letter case, like Council or NHS. Leave empty for any. This filter is applied after the notices are read, so a narrow one reads more pages.

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

How many notices to return at most. You pay only for records returned.

## Actor input object example

```json
{
  "publishedFrom": "2026-10-01",
  "publishedTo": "2026-10-01",
  "stage": "tender",
  "cpvCodes": "",
  "buyer": "",
  "maxItems": 10
}
```

# Actor output Schema

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

The tender notices of this run, one per notice, with the 12 fields described in the dataset schema (process and notice ids, stage, dates, buyer, CPV codes, procedure, estimated value).

# 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 = {
    "publishedFrom": "2026-10-01",
    "publishedTo": "2026-10-01",
    "stage": "tender",
    "cpvCodes": "",
    "buyer": "",
    "maxItems": 10
};

// Run the Actor and wait for it to finish
const run = await client.actor("thesjostrandproject/uk-tenders-search").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 = {
    "publishedFrom": "2026-10-01",
    "publishedTo": "2026-10-01",
    "stage": "tender",
    "cpvCodes": "",
    "buyer": "",
    "maxItems": 10,
}

# Run the Actor and wait for it to finish
run = client.actor("thesjostrandproject/uk-tenders-search").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 '{
  "publishedFrom": "2026-10-01",
  "publishedTo": "2026-10-01",
  "stage": "tender",
  "cpvCodes": "",
  "buyer": "",
  "maxItems": 10
}' |
apify call thesjostrandproject/uk-tenders-search --silent --output-dataset

```

## MCP server setup

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

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/pfL8lf4g4o7Mxynv4/builds/x2bhudkbxhT1IOVNl/openapi.json
