# UK Tender Notices from Find a Tender (`pontio/uk-tender-notices`) Actor

UK public procurement notices from the official Find a Tender API, one row per notice. Pick a last-update window and stage. You pay only for notice rows.

- **URL**: https://apify.com/pontio/uk-tender-notices.md
- **Developed by:** [Gabor Molnar](https://apify.com/pontio) (community)
- **Categories:** Developer tools, Lead generation, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.40 / 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.
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 Tender Notices from Find a Tender

Get UK public procurement notices from Find a Tender, the UK government's official notice service, with one dataset row per notice. You choose a date window and a stage, and the Actor pages through the official API for you. You don't need an API key.

### Input

```json
{
  "updatedFrom": "2026-09-28T00:00:00",
  "updatedTo": "2026-09-28T23:59:59",
  "stage": "tender",
  "maxNotices": 100
}
```

- `updatedFrom` and `updatedTo` take times as `YYYY-MM-DDTHH:MM:SS`, with no timezone. Find a Tender matches them against when a notice was last updated, not when it was first published. The window can be at most 31 days long.
- `stage` is `planning`, `tender` (the default) or `award`. One notice can belong to more than one stage.
- `maxNotices` is between 1 and 1000, and defaults to 100.
- `cursor` continues an earlier run. See "Continuing a run" below.

### Output

Each notice is one row with these fields:

- `ocid` and `id`. The `ocid` names the procurement process and the `id` names this notice within it. Several notices can share an `ocid`, so use the pair as the key.
- `date`, `tags`, `title`, `status`, `buyer` (the buying organisation's name), `cpv` (the main CPV code), `value` (amount and currency) and `deadline`. If a notice gives its deadline as a bare date, you get the bare date. A field the notice leaves out is `null`.
- `sourceUrl`, the API request that returned the notice, plus `licence` and `attribution`.

The Actor returns only these fields. It leaves out contact details, addresses, suppliers, descriptions, documents and the raw OCDS record. It doesn't filter by sector or region.

The live API can move a notice from one page to the next while the Actor reads them. You still get that notice once.

A run adds one status row, with every notice field set to `null`, in three cases:

- `no_notices` means nothing matched the window and stage.
- `more_available` means the run reached `maxNotices` and Find a Tender has more.
- A failure code from the table below means a request failed. Notices read before the failure stay in the dataset.

### Continuing a run

A `more_available` or failure row carries a `nextCursor`. To pick up where the run stopped, run again with the same `updatedFrom`, `updatedTo` and `stage`, and put that value in `cursor`. After `rate_limited`, wait for the time in the row's `retryAfter` first. In our tests Find a Tender accepted about ten requests in quick succession and then asked for a two-minute wait. A run of 1000 notices makes ten requests, so a second large run, or a continuation, started straight after it is likely to be `rate_limited`. Notices updated between the two runs can move, because the API serves live data.

### Pricing

You pay for each notice row. Status rows are free.

| reasonCode | Meaning | Charged |
| --- | --- | --- |
| `notice` | One notice | yes |
| `no_notices` | Nothing matched the window and stage | no |
| `more_available` | The run reached `maxNotices` and more notices exist | no |
| `invalid_window` | A time in the wrong format, a date that doesn't exist, a window that ends before it starts, or one longer than 31 days | no |
| `rate_limited` | Find a Tender answered HTTP 429 | no |
| `upstream_error` | Another HTTP error, a refused redirect, a network failure or a timeout | no |
| `invalid_response` | Invalid JSON, an unexpected shape or licence, or a next-page link for a different query | no |
| `too_large` | A response larger than 4 MiB | no |

Each request has a 15-second deadline. If the connection drops, the Actor tries once more. An HTTP error, including 429 or 503, ends the run, because Find a Tender asks clients to send nothing until its `Retry-After` time has passed. Running the same window twice fetches and bills its notices twice.

Notices read before a failed request are charged, because they are in your dataset. If a run reaches your spending limit, it stops with the notices already saved and adds no status row, so there is no `nextCursor` to continue from. Use `maxNotices` to bound what a run costs.

### Coverage

The Actor reads Find a Tender only. Other UK services, such as Contracts Finder, publish notices that may not appear here. An empty result means Find a Tender returned nothing for that query. It doesn't mean no UK contract opportunity exists.

### Source and licence

The data comes from the [Find a Tender OCDS release API](https://www.find-tender.service.gov.uk/apidocumentation/1.0/GET-ocdsReleasePackages). Find a Tender's [data documentation](https://www.find-tender.service.gov.uk/Developer/Documentation) licenses notice data under the [Open Government Licence v3.0](https://www.nationalarchives.gov.uk/doc/open-government-licence/version/3/).

Every row carries the attribution "Contains public sector information licensed under the Open Government Licence v3.0." and a link to the licence. Keep both when you share the data. The licence doesn't cover personal data or third-party rights. Neither the Cabinet Office nor any contracting authority endorses this Actor. Check the original notice before you act on it.

# Changelog

This Actor's version history is a separate document: https://apify.com/pontio/uk-tender-notices/changelog.md

# Actor input Schema

## `updatedFrom` (type: `string`):

Earliest last-update time, as YYYY-MM-DDTHH:MM:SS with no timezone. Find a Tender filters on when a notice was last updated, not when it was first published.

## `updatedTo` (type: `string`):

Latest last-update time, same format. The window can be at most 31 days long.

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

Procurement stage to fetch. One notice can belong to several stages.

## `maxNotices` (type: `integer`):

Stop after this many notices. If the window holds more, the last row has reasonCode more_available and a nextCursor to continue from.

## `cursor` (type: `string`):

Continue a previous run: paste its nextCursor here and keep updatedFrom, updatedTo and stage the same.

## Actor input object example

```json
{
  "updatedFrom": "2026-09-28T00:00:00",
  "updatedTo": "2026-09-28T23:59:59",
  "stage": "tender",
  "maxNotices": 2
}
```

# Actor output Schema

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

Results produced by this run, in its default dataset.

# 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 = {
    "updatedFrom": "2026-09-28T00:00:00",
    "updatedTo": "2026-09-28T23:59:59",
    "maxNotices": 2
};

// Run the Actor and wait for it to finish
const run = await client.actor("pontio/uk-tender-notices").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 = {
    "updatedFrom": "2026-09-28T00:00:00",
    "updatedTo": "2026-09-28T23:59:59",
    "maxNotices": 2,
}

# Run the Actor and wait for it to finish
run = client.actor("pontio/uk-tender-notices").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 '{
  "updatedFrom": "2026-09-28T00:00:00",
  "updatedTo": "2026-09-28T23:59:59",
  "maxNotices": 2
}' |
apify call pontio/uk-tender-notices --silent --output-dataset

```

## MCP server setup

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

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/JDzjoJ6uIfScXyWBP/builds/Sn5yg8lSkW5I33N8O/openapi.json
