# UK Tender Pipeline Monitor (`maydit/uk-tender-pipeline-monitor`) Actor

Track official Find a Tender procedures, deadlines, values and award changes. Export one compiled record per OCID with source links and optional saved comparisons.

- **URL**: https://apify.com/maydit/uk-tender-pipeline-monitor.md
- **Developed by:** [Brandt May](https://apify.com/maydit) (community)
- **Categories:** Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.00 / 1,000 procurement observations

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 Pipeline Monitor - procurement change intelligence](https://api.apify.com/v2/key-value-stores/cCyrofyNNh9lwffXB/records/uk-tender-pipeline-monitor-933c5e9297b9.png?signature=1GZJupKsPDFrhhCYl9pcl)

## Keep a UK bid pipeline current

Turn official Find a Tender notices into **one current procurement observation per OCID**. Watch deadlines, published values, buyer details, lots, awards and document links, then compare the fields with your last saved observation.

Built for bid teams, procurement analysts and suppliers maintaining a shortlist. The Actor discovers a bounded window of recent notices and resolves each procedure through the official **compiled OCDS record**, so repeated notices do not become duplicate pipeline entries.

[Run in Apify Console](https://console.apify.com/actors?search=uk-tender-pipeline-monitor) · [Output](#what-you-receive) · [Watchlist](#watch-a-named-procedure) · [Coverage](#coverage-and-boundaries)

### Start with three procedures

```json
{
  "maxResults": 3,
  "maxSourcePages": 1
}
```

Run the Actor, open **Dataset** for observations, and open **Run report** for checked procedures, failures and limits. The default inspects up to 20 recent official releases and saves at most three matching procedures. It requires no account or API key for the source.

### What you receive

| Fields | Use in your workflow |
| --- | --- |
| `ocid`, `title`, `buyerId`, `buyerName` | Stable procedure identity and CRM label |
| `tenderStatus`, `tenderDeadline`, `enquiryDeadline` | Review published status and submission dates |
| `value`, `cpvCodes`, `deliveryRegions` | Published amount/currency and sector/geographic screening |
| `lots`, `awards`, `documents` | Structured lot/award summaries and links to procurement documents |
| `noticeIds`, `latestReleaseDate`, `sourceUrl` | Trace the compiled record back to the official source |
| `contentHash`, `comparisonStatus`, `changedFields` | Route new or changed observations |
| `previous`, `previousObservedAt`, `observedAt` | Explain a change using the previous saved snapshot |

For example, retained official source evidence from **15 October 2026** contains procedure `ocds-h6vhtk-0784ad`, Sevenoaks District Council's sports-hall roof replacement, with GBP 120,000 excluding tax and a published tender deadline of 6 November 2026. This dated example is not a promise that the opportunity is still open.

### Watch a named procedure

```json
{
  "ocids": ["ocds-h6vhtk-0784ad"],
  "maxResults": 3,
  "comparePrevious": true,
  "snapshotName": "roof-procurement-demo"
}
```

1. Save your exact OCIDs in a private Apify task.
2. Use a dedicated `snapshotName`; the first comparison emits `new` and establishes history after each row is saved.
3. On later runs, route `changed` rows to review. `changedFields` identifies top-level fields; `previous` lets your integration inspect the old deadline or amount.
4. Set `onlyChanges: true` when you want unchanged observations counted in `SUMMARY` without additional dataset rows. Empty output can therefore be a successful no-change check.
5. Upsert into your own spreadsheet or CRM by `ocid`. Check the run's own summary before treating missing output as meaningful.

Use **one writer per snapshot namespace and filter scope**. A concurrent history change prevents overwrite and makes the run partial; it is not a distributed lock. Only confirmed saved rows advance history. No missing procedure becomes a deletion signal.

### Inspect recent award procedures

```json
{
  "stages": ["award"],
  "maxResults": 3,
  "maxSourcePages": 1
}
```

`stages` selects notices during discovery. The compiled record represents the current procedure and can include later changes. Optional `keywords` match title, description or buyer; `cpvPrefixes` match published item codes. OR applies within each filter list, AND between keyword and CPV lists. Filtering a small window can correctly return no matches.

### Pricing and controls

The base result price is **$0.005 per saved procurement observation**, plus the Actor's published start event. Your Apify plan may apply its displayed discount. A no-change row skipped by `onlyChanges`, a failed source request, or a filtered record is not a paid result.

- `maxResults`: 1-100 confirmed rows, default 3.
- `maxSourcePages`: 1-5 discovery pages of up to 20 releases each, default 1.
- `ocids`: up to 50 exact procedures; bypasses discovery.
- `maxRunSeconds`: default 240, also constrained by the platform timeout with a 25-second reserve.
- Set a platform spending limit appropriate for your task. A spending stop is explicit in `SUMMARY`; check saved counts before downstream actions.

### Coverage and boundaries

**Source:** Find a Tender only. This does not aggregate Contracts Finder, devolved portals or all UK purchasing. The source exports OCDS records under the Open Government Licence.

The Actor reads current compiled records, not an as-of reconstruction. `updatedFrom` and `updatedTo` filter the source's release last-update window in its documented timezone-less `YYYY-MM-DDTHH:MM:SS` format. They do not filter deadlines or freeze the compiled record at that date. Date and stage discovery filters cannot be combined with an explicit watchlist.

Published dates, amounts and labels are preserved. Missing optional fields remain `null` or empty arrays; they are not estimated. This is a selected metadata projection, not every OCDS field: it does not download attachments, collect contact details, submit bids or assess eligibility. Supplier organization names in awards remain public procurement evidence.

`status: "ok"` means the configured bounded work succeeded. Read `coverageComplete`, `discoveryComplete`, `stoppedOnSourcePageLimit`, `sourcesNotReached` and `stoppedOnMaxResults` to understand its extent. Reaching a configured sample cap is distinct from a failed source. Partial source failures and time/spending stops are explicit; an all-failed run fails instead of emitting error rows.

### Source references and support

- [Official Find a Tender developer documentation](https://www.find-tender.service.gov.uk/Developer/Documentation)
- [Release package API and discovery parameters](https://www.find-tender.service.gov.uk/apidocumentation/1.0/GET-ocdsReleasePackages)
- [Record package API and compiled records](https://www.find-tender.service.gov.uk/apidocumentation/1.0/GET-ocdsRecordPackages)

For source changes, support or data correction requests, use this Actor's **Issues** tab or **bmay@mayd-it.com**. Include a run URL and OCID; do not send credentials or private bid documents.

# Actor input Schema

## `ocids` (type: `array`):

Optional exact official OCIDs, at most 50. Leave empty to discover recent releases. Date and stage filters apply only to discovery.

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

Optional literal case-insensitive OR terms, applied after fetching current records. May return no matches within the bounded window.

## `cpvPrefixes` (type: `array`):

Optional OR list of 2-8 digit prefixes, checked against published item CPV codes.

## `stages` (type: `array`):

Optional planning, tender or award stages. A stage selects release discovery; current compiled records can have a later status.

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

Optional source last-update bound, YYYY-MM-DDTHH:MM:SS with no timezone, exactly as the official API requires. This is not a tender deadline.

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

Optional source last-update upper bound in YYYY-MM-DDTHH:MM:SS. Use a fixed pair for a repeatable discovery window.

## `maxSourcePages` (type: `integer`):

Discovery only. Each official page contains up to 20 notices; duplicate OCIDs are checked once. This is a bounded window, not full coverage.

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

Stops after this many confirmed dataset rows. Unchanged rows skipped by onlyChanges do not count.

## `comparePrevious` (type: `boolean`):

Enable a private named history. First observations are new; history advances only after output is saved. Use one writer per snapshot namespace.

## `onlyChanges` (type: `boolean`):

Implies comparison. Unchanged observations are counted in SUMMARY and produce no paid dataset row.

## `snapshotName` (type: `string`):

1-80 letters, numbers, hyphens or underscores. Changing filters creates a separate scope. Use a new namespace to reset history.

## `maxRunSeconds` (type: `integer`):

Own time budget, also bounded by the platform timeout with a 25-second reserve.

## Actor input object example

```json
{
  "ocids": [],
  "maxSourcePages": 1,
  "maxResults": 3,
  "comparePrevious": false,
  "onlyChanges": false,
  "snapshotName": "default",
  "maxRunSeconds": 240
}
```

# Actor output Schema

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

Successful public metadata observations only. Failures are never synthetic paid rows.

## `runReport` (type: `string`):

Readable coverage, limits and history outcome from this run.

## `summary` (type: `string`):

Saved/observed counts, failed sources, unreached procedures and time/spending stops.

## `csvExport` (type: `string`):

Download the current run observations for spreadsheets.

# 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 = {
    "ocids": [],
    "maxResults": 3
};

// Run the Actor and wait for it to finish
const run = await client.actor("maydit/uk-tender-pipeline-monitor").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 = {
    "ocids": [],
    "maxResults": 3,
}

# Run the Actor and wait for it to finish
run = client.actor("maydit/uk-tender-pipeline-monitor").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 '{
  "ocids": [],
  "maxResults": 3
}' |
apify call maydit/uk-tender-pipeline-monitor --silent --output-dataset

```

## MCP server setup

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

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/o7PVSXGFpiYOgwMRB/builds/ACmNjOQuez2liVwuq/openapi.json
