# UK Public Tenders incl. Scotland — FTS + CF + PCS (`resourcefully_dialect/uk-tenders`) Actor

Deduplicated UK procurement notices from three official public feeds, including Scottish site notices, local filters and incremental monitoring. No API key.

- **URL**: https://apify.com/resourcefully_dialect/uk-tenders.md
- **Developed by:** [Biosick Johnny](https://apify.com/resourcefully_dialect) (community)
- **Categories:** Lead generation, Business
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 90.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $5.00 / 1,000 notice delivereds

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 including Scotland

One OCDS-normalised feed from **Find a Tender (FTS), Contracts Finder (CF), and Public Contracts Scotland (PCS)**. Combine official public notices, retain their provenance, apply procurement filters, and monitor changes without repeatedly delivering previously seen content versions.

The Scotland difference is practical: PCS site notices and Quick Quote awards provide Scottish below-threshold coverage that an FTS/CF-only feed misses. Exact Scottish reference matching joins notices published on both FTS and PCS, preferring PCS and retaining the FTS identity.

No source account, API key or login is needed. Price: **$5 per 1,000 delivered notices plus $0.005 per run start**. Source data itself is free.

### Quick start

```json
{
  "sources": ["fts", "cf", "pcs"],
  "mode": "snapshot",
  "keywords": ["software", "digital"],
  "cpvPrefixes": ["72"],
  "nations": ["Scotland"],
  "maxItems": 100
}
```

Omitting dates selects yesterday and today in UTC. Dates are inclusive calendar days. FTS is queried by update time, CF by publication time; PCS requests months covering the window and filters release dates locally. Filters are combined with AND; each `keywords`/CPV/nation list offers alternatives within that filter. Inspect `RUN_SUMMARY` before treating any export as complete.

### Sources and coverage

| Source | What it adds | Window and pagination | Licence |
| --- | --- | --- | --- |
| [Find a Tender](https://www.find-tender.service.gov.uk/apidocumentation/1.0/GET-ocdsReleasePackages) | Above-threshold UK procurement, plus Procurement Act 2023 above/below-threshold notices for England, Wales and Northern Ireland since 24 February 2025; Scottish above-threshold notices | `updatedFrom`/`updatedTo`, 100 releases per page, opaque `links.next` cursor | OGL v3.0 |
| [Contracts Finder](https://www.contractsfinder.service.gov.uk/) | Legacy PCR 2015 notices, now predominantly awards; complements the transition to FTS | `publishedFrom`/`publishedTo`, 100 releases per page, `links.next` cursor | OGL v3.0 |
| [Public Contracts Scotland](https://api.publiccontractsscotland.gov.uk/v1) | Scottish OJEU/FTS forms, site notices and Quick Quote awards; data from November 2016 | One calendar month × notice type per request; local date filter | OGL v3.0 |

These feeds are not all UK procurement. **Northern Ireland below-threshold notices published only on eTendersNI, Sell2Wales legacy-only notices, private tenders and unpublished Quick Quote invitations are not covered.** A Welsh reference is preserved when present, but Sell2Wales is not queried. Organisation identifiers are retained when supplied; absence of an identifier is not evidence of an invalid organisation.

### Deduplication and notice versions

With `dedup: "exact"` (default), the latest release for each source, OCID and stage is retained within the run. Sparse updates inherit missing values from the prior release. Planning, tender, award, contract, change and termination remain separate rows. Multiple releases do not necessarily mean multiple opportunities, and several award releases for one OCID/stage become one latest notice.

Scottish matches use `(SC Ref:846105)` or an ESPD download link ID to associate an FTS release with PCS OCID `ocds-r6ebe6-0000846105`. The stage must also match. PCS is preferred; `alsoPublishedIn` retains merged UIDs and `crossRefs.ftsIds` retains FTS release IDs. Without PCS in `sources`, the FTS row and Scottish reference remain available. `dedupMethod` describes the match; exact matches have `dedupConfidence: 1`. Unmerged rows have confidence `null`.

`fuzzyCrossSource: true` optionally merges FTS/CF rows with equal normalised buyer/title, equal non-null value and currency, the same stage, and dates within three days. Confidence is **0.85**, an indicative label rather than a calibrated probability. It can make false matches. The default is false. `dedup: "off"` retains individual releases and disables both match strategies.

CPV codes come from tender classifications, additional classifications and item classifications. Releases with no CPV inherit the latest CPV context for that source/OCID from the run or retained monitor state. No extra per-OCID requests are made. Awards without observed earlier context can still have an empty CPV list.

### Inputs

The complete UI schema is [.actor/input_schema.json](.actor/input_schema.json); unknown fields and malformed values are rejected.

| Input | Default | Behaviour |
| --- | --- | --- |
| `sources` | `["fts","cf","pcs"]` | Nonempty subset of the three official sources |
| `mode` | `snapshot` | `snapshot` or `monitor` |
| `dateFrom`, `dateTo` | Yesterday, today | ISO `YYYY-MM-DD`, inclusive UTC days; FTS/CF filter updated/published time respectively |
| `pcsNoticeTypes` | `[2,3,102,103,104]` | Allowed: 1–7, 12–15, 20–25, 101–104. Site types 101 PIN, 102 tender, 103 award, 104 Quick Quote award |
| `keywords` | `[]` | Any whole word/phrase in title + full sanitised description; case insensitive |
| `keywordsAll` | `[]` | All specified words/phrases must match |
| `excludeKeywords` | `[]` | Reject any matching word/phrase; punctuation is treated literally |
| `cpvPrefixes` | `[]` | Any string prefix, e.g. `"72"` or `"4521"`; codes are not converted to numbers |
| `nations` | `[]` | England, Scotland, Wales, Northern Ireland, derived from buyer ITL/NUTS region |
| `itlPrefixes` | `[]` | Any buyer region prefix, e.g. `UKM`, `UKI32` |
| `buyerContains` | Unset | Case-insensitive buyer organisation substring |
| `minValue`, `maxValue` | Unset | GBP bounds; non-GBP valued rows fail a numeric bound, with no currency conversion |
| `includeNoValue` | `true` | Unknown-value rows pass value bounds only when true |
| `stages` | `[]` | planning, tender, award, contract, change, termination, other |
| `belowThresholdOnly` | `false` | Best-effort: explicit `aboveThreshold: false`, PCS site types 102/103/104, or a below-threshold statement in method/status metadata |
| `deadlineAfter` | Unset | Require a deadline strictly after an ISO date or timezone-qualified timestamp |
| `dedup` | `exact` | `exact` or `off` |
| `fuzzyCrossSource` | `false` | Optional FTS/CF buyer/title/value/date match |
| `maxItems` | `100` | 0–100,000; zero delivers nothing and makes no source requests |
| `includeDescription` | `true` | False outputs `null`; filters and change detection still use full sanitised text |
| `descriptionMaxChars` | `2000` | 0–100,000 output characters |
| `monitorStateKey` | `UK_TENDERS_STATE` | Key inside the named `uk-tenders-monitor` key-value store |
| `requestPacingMs` | `1000` | 1,000–60,000 ms minimum between request starts per host |
| `maxRetries` | `5` | 0–10 retries after the original attempt |
| `proxyConfiguration` | None/direct | Optional Apify or custom HTTP(S) proxy configuration; provider charges may apply |

ITL `UKC`–`UKK` maps to England, `UKL` to Wales, `UKM` to Scotland and `UKN` to Northern Ireland. Unknown regions remain null. Buyer location can differ from the place of delivery. The below-threshold flag is a discovery heuristic: site forms, sector exceptions, contract dates and statutory thresholds prevent a reliable universal monetary threshold test. It is not a legal classification.

### Output

Each dataset row contains the fields below. The `overview` dataset view displays the main procurement fields. See [SAMPLE_OUTPUT.json](SAMPLE_OUTPUT.json) for a sanitised real API sample; it is historical, not a current opportunity list.

| Fields | Meaning |
| --- | --- |
| `uid`, `source`, `ocid`, `releaseId`, `noticeUrl` | Source release identity (`FTS:releaseId`, etc.) and official notice link |
| `crossRefs`, `alsoPublishedIn`, `dedupMethod`, `dedupConfidence` | PCS/Welsh references, FTS IDs, merged source/version UIDs and match evidence |
| `stage`, `tags`, `noticeType`, `noticeTypeLabel` | Normalised lifecycle and raw source type where supplied; unknown type is null |
| `legalBasis`, `regime` | Raw legal basis ID and readable regime label |
| `title`, `description` | Sanitised text; optional description truncation |
| `cpvCodes`, `mainProcurementCategory`, `procurementMethod` | Published classifications, with observed CPV backfill where available |
| `buyerName`, `buyerId`, `buyerItl`, `nation` | Organisation and buyer-region fields |
| `valueAmount`, `valueCurrency`, `awardedValue`, `suppliers` | Tender value, falling back to award value; sum of comparable award amounts; organisation suppliers `{name,id}` |
| `publishedAt`, `tenderDeadline`, `contractStart`, `contractEnd`, `fetchedAt` | UTC timestamps or null for unavailable dates |
| `belowThreshold`, `possiblyTruncatedSource` | Discovery heuristic and PCS completeness warning |
| `license`, `attribution` | OGL v3.0 attribution retained in every row |

Missing optional values are null; missing collections are empty arrays. Zero values are preserved. Mixed-currency awards are not summed. A row can carry both `award` and `contract` tags; award takes stage precedence. Cancellation tags map to termination, amendments to change. No raw parties, contact blocks or source response are passed through.

Illustrative output fragment (synthetic):

```json
{
  "uid": "PCS:846105",
  "source": "PCS",
  "ocid": "ocds-r6ebe6-0000846105",
  "crossRefs": { "pcsRef": "846105", "walesRef": null, "ftsIds": ["099191-2026"] },
  "alsoPublishedIn": ["FTS:099191-2026"],
  "dedupMethod": "scRef",
  "stage": "tender",
  "title": "Software services procurement",
  "buyerName": "Example Council",
  "nation": "Scotland",
  "valueAmount": 120000,
  "valueCurrency": "GBP",
  "possiblyTruncatedSource": false,
  "license": "Open Government Licence v3.0",
  "attribution": "Contains public sector information licensed under the Open Government Licence v3.0."
}
```

### Incremental monitor mode

```json
{
  "mode": "monitor",
  "sources": ["fts", "cf", "pcs"],
  "monitorStateKey": "UK_TENDERS_STATE",
  "keywords": ["laboratory", "sequencing"],
  "maxItems": 500
}
```

Run serially with the same state key and a **fresh default dataset for each run**. Named state retains source cursors/high-water marks, sanitised pending notices, CPV context and hashed delivered content versions for 120 days. After each page or PCS shard the cursor and pending data are saved together. The complete source window is prepared before delivery, allowing cross-source deduplication; a throttled scan can therefore finish with no rows yet delivered.

Only new or materially changed matching notices are pushed. Retrieval time, release-ID-only changes, publication timestamp and dedup bookkeeping do not alone create another delivery. Changes to the full sanitised title/description, values, classifications, buyer, suppliers, deadlines or other substantive fields do. Same-stage version identity is source/OCID/stage, or Scottish reference/stage for a verified Scottish match; `dedup: "off"` instead tracks release UIDs. Previously delivered content versions are retained, so an unchanged version reappearing after another update is suppressed.

After a completed scan, implicit start dates use the source high-water mark with two days of overlap to pick up delayed publications, including gaps between scheduled runs. Explicit dates repeat that requested window and rely on the seen-set. A pending scan always finishes its original window first. Changing sources or filters while work is pending requires resuming the original configuration or choosing a new state key.

Hitting `maxItems` or the SDK spending limit retains undelivered matching rows for the next run. Exhausted throttling/network retries or the overall time budget save the current cursor and finish successfully with a **resume next run** message. `RUN_SUMMARY` records the stop reason, delivery/request/retry/page counts, pending count and all capped PCS shards. `ACTOR_TIMEOUT_AT` reserves ten seconds for clean storage/shutdown. Off-platform, set that variable explicitly if a time budget is needed.

Use **one writer per state key**: concurrent runs can race. Dataset push and key-value checkpoint are separate platform operations; a hard kill between them can leave an ambiguous last row. Absolute exactly-once delivery across that failure window cannot be guaranteed by Apify dataset/KV storage. Inspect partial results before recovery. A nonempty default dataset is refused. Deleting state or replaying data older than retention can redeliver rows. A newly available PCS counterpart can constitute a material update to an earlier FTS-only row.

Snapshot runs are independent exports and can bill for the same notice on later runs. A paused snapshot writes `CHECKPOINT` for inspection; rerun the desired window in fresh storage. Automatic cross-run cursor continuation is provided by monitor mode.

### Reliability and known limitations

- **PCS 300-release cap:** month × notice-type shards returning at least 300 releases are marked `possiblyTruncatedSource`, logged, and listed under `RUN_SUMMARY.truncatedShards`. They are **not complete exports**. The documented API cannot reliably subdivide a month: day-formatted `dateFrom` is misparsed, and `dateTo`/`page` were ignored in the supplied probe. No invented day/page sharding is attempted. The strategy is isolated in `pcsShards()` for future changes.
- The cloud Actor's default run timeout is **900 seconds** (PCS shards can take 6–60 s each). Raise it for long historical windows.
- For Contracts Finder rows, `valueAmount` is only the advertised tender value; when CF omits it the field is `null` (award totals, often a placeholder `0`, stay in `awardedValue`).
- PCS is slow and uses `text/json`. Requests have a 60-second timeout. Its missing TLS intermediate is bundled from Sectigo and trusted **only for the PCS API host**, alongside Node's normal roots. Certificate and hostname verification remain enabled. The certificate is never fetched at runtime.
- FTS can throttle despite successful short probes. Request starts are paced by at least one second per host. HTTP 429/503 honour `Retry-After` seconds or HTTP dates. CF HTTP 403 is treated as throttling with at least five minutes of backoff. Other 5xx/network failures use exponential backoff with jitter. The cursor never advances on a failed attempt.
- Invalid JSON/envelopes, unsafe pagination URLs, cursor cycles, other rejected responses and bodies exceeding 20 MiB fail clearly. No login or access-control workaround is attempted. Normal retries stop cleanly if the requested wait cannot fit the remaining time.
- Source windows are not transactional, publisher updates may arrive late, and CF contains legacy notices. Full UK procurement coverage is not promised. `maxItems` limits delivery, not the number scanned: deduplication requires preparing the whole window. Large historical windows consume memory/checkpoint space; use small windows and the 256 MB default (maximum 1024 MB), and measure before increasing coverage.
- Missing CPV, buyer geography or declared value can make a filter exclude a real opportunity. Award values and tender estimates are not equivalent. No exchange rates, statutory threshold calculations or tender suitability scoring are performed.

### Personal-data policy

There is **no opt-in for personal contact data in v1**. The output is an organisation-level discovery feed. ContactPoint names, emails, telephone/fax numbers and personal contact URLs are omitted. Contact names found in those blocks and identifiable individual-party names are removed from text; emails and telephone-like strings are redacted. Parties marked as natural persons, individuals or sole traders are excluded from supplier names. Organisation names and published organisation identifiers remain. Official notice links remain so users can consult the publisher under its terms.

Unstructured prose can contain personal information the publisher has not labelled; automated redaction is best-effort, not a complete person-name recogniser. Do not treat this feed as a contact list. Raw source documents are not retained by the Actor. Test fixtures use synthetic contacts; the real sample is sanitised before writing.

### Pricing

Pay per event: **$0.005 per delivered notice ($5 per 1,000)** plus **$0.005 per run start** (Apify counts one start event per GB of run memory, minimum one; the default 256–512 MB is one event). Only notices saved to the dataset are charged. A run that finds nothing costs just the $0.005 start fee. Example: a daily run delivering 40 new notices costs 40 × $0.005 + $0.005 = $0.205.

**Monitor mode charges only new notices.** In `mode: "monitor"` the Actor remembers every notice version it has already delivered (in the `uk-tenders-monitor` key-value store under your `monitorStateKey`). Later runs skip those versions without pushing them, so you are not charged again for notices you have already received; only new notices, or notices whose material content has changed, are delivered and billed. Scheduled monitor runs still pay the $0.005 start fee each time.

Notices that do not match your filters are never pushed and never charged. `maxItems` caps the number of billed notices per run, and if you set a maximum cost per run in Apify the Actor stops cleanly before exceeding it (a run stopped by the limit keeps the notices already delivered). Apify platform usage is included in these prices.

### Local development and acceptance

Use Node 22:

```sh
npm ci --cache .npm-cache
npm test
npm run check
npm run validate
npm run smoke -- live
npm run smoke -- empty
npm run smoke -- budget
npm run smoke -- zero-limit
npm run smoke -- zero-budget
npm run smoke -- invalid-input
npm run smoke -- monitor-twice
```

In this workspace, prepend the supplied Node path if needed:

```sh
export PATH="$PWD/../.tools/node-v22.23.4-darwin-arm64/bin:$PATH"
```

The cache is inside this Actor folder to respect the task's write boundary. Unit tests use injected HTTP and make no network calls. Non-live smoke modes use synthetic fixtures with the **real local SDK, storage and billing simulation**. Live smoke gently queries the historical 20 October 2026 window: FTS + CF + one PCS month/type, max 20 delivered rows and at most 20 source attempts. It refreshes `SAMPLE_OUTPUT.json`. Smoke subprocesses use an environment allowlist without account tokens/cloud identity. Reports are saved in `research/smoke-*.json`; `monitor-twice` uses fresh datasets and shared named state and asserts the second dataset is empty.

The budget smoke uses the SDK's synthetic **$1/item** local test event and a $2 cap; it verifies two automatic item events and spends no money. The additional `zero-budget` smoke exercises the real main entrypoint with an explicit off-platform $0 cap and asserts no source requests. Those synthetic prices are not the proposed production prices. Restricted local hosts can set `CRAWLEE_LOCAL_PROCESS_METRICS=true` for process-only metrics; cloud runs keep standard platform metrics. Put manual input in `storage/key_value_stores/default/INPUT.json` and run `npm start`. Leave `APIFY_IS_AT_HOME` unset locally (the pinned SDK treats any nonempty string, including `false`, as cloud mode).

The Dockerfile uses `apify/actor-node:22`, a lockfile and `npm ci --omit=dev`. No publishing/login command is part of this repository's scripts. [STATUS.md](STATUS.md) records acceptance and the owner-approved steps still needed before any deployment.

### FAQ

**Can I call the APIs myself?** Yes. They are public and keyless. This Actor adds a common output, Scottish matching, local filters and persistent monitoring.

**Why fewer results than requested?** Filters, missing classifications, seen versions, a spending limit, PCS truncation or an unfinished source scan can reduce output. Read `RUN_SUMMARY`, particularly `stopReason`, `resumeNextRun` and `truncatedShards`.

**Does monitoring re-charge old notices?** Previously delivered content versions within retained state are suppressed. Material updates are new results. Start events are separate; deletion/expiry of state and hard-kill recovery have the limitations described above.

**Does a notice imply I can still bid?** No. Awards, planning and cancelled processes are included by default. Filter `stages` and `deadlineAfter`, and verify the current official notice and documents.

### Attribution and legal note

Contains public sector information licensed under the [Open Government Licence v3.0](https://www.nationalarchives.gov.uk/doc/open-government-licence/version/3/). Sources: Cabinet Office Find a Tender and Contracts Finder, and Scottish Government Public Contracts Scotland. Every row retains that licence label and attribution. The licence does not grant rights to personal data, third-party content or official logos beyond its terms.

This independent tool is not endorsed by those publishers. Data is provisional, may be incomplete or delayed, and is supplied without a completeness guarantee. This is not legal, procurement or bidding advice. Consult the official notice and applicable terms before relying on or redistributing information.

# Actor input Schema

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

Official feeds to combine. No API key is needed.

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

snapshot exports the window. monitor persists cursors, CPV context and delivered content versions in a named store.

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

Inclusive UTC start date, YYYY-MM-DD. Omit for yesterday (two calendar days including today). Monitoring without an explicit start uses its high-water mark with a two-day overlap.

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

Inclusive UTC end date, YYYY-MM-DD. Omit for today. PCS fetches complete calendar months then filters locally.

## `pcsNoticeTypes` (type: `array`):

PCS monthly notice types. Default covers contract/award forms and site/Quick Quote awards.

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

Match any whole word or phrase in the full title and description; case insensitive.

## `keywordsAll` (type: `array`):

Require every whole word or phrase in title and description.

## `excludeKeywords` (type: `array`):

Exclude any matching whole word or phrase.

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

Match any CPV prefix, such as 72 or 4521. Use strings to preserve leading zeros.

## `itlPrefixes` (type: `array`):

Match buyer ITL/NUTS code prefixes, such as UKM or UKI.

## `nations` (type: `array`):

Match buyer location: England, Scotland, Wales or Northern Ireland. This is not necessarily the delivery location.

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

Keep planning, tender, award, contract, change, termination or other stages; empty means all.

## `buyerContains` (type: `string`):

Case-insensitive substring in the organisation buyer name.

## `minValue` (type: `number`):

Minimum value in GBP. Non-GBP valued rows fail numeric value filters.

## `maxValue` (type: `number`):

Maximum value in GBP; no currency conversion is performed.

## `includeNoValue` (type: `boolean`):

Retain rows without a published value, including when value bounds are supplied.

## `belowThresholdOnly` (type: `boolean`):

Best-effort signal: explicit aboveThreshold=false, PCS site types 102/103/104, or an explicit below-threshold declaration. Not a legal threshold determination.

## `deadlineAfter` (type: `string`):

Require a tender deadline strictly after this ISO date or timezone-qualified timestamp.

## `dedup` (type: `string`):

exact merges same-source stage versions and Scottish FTS/PCS reference matches. off retains releases.

## `fuzzyCrossSource` (type: `boolean`):

Optional FTS/CF match: identical normalized buyer/title/value/currency, same stage and dates within three days. Confidence 0.85; may produce false matches.

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

Maximum notices delivered this run. Zero makes no source requests; monitor retains undelivered work.

## `includeDescription` (type: `boolean`):

Include the sanitized description in output. Filters still use the full sanitized text.

## `descriptionMaxChars` (type: `integer`):

Maximum output description length; matching and content versioning use full sanitized text.

## `monitorStateKey` (type: `string`):

Key in the named uk-tenders-monitor store. Reuse it across fresh default datasets. Use one serial writer per key.

## `requestPacingMs` (type: `integer`):

Minimum interval between request starts per host, including retries.

## `maxRetries` (type: `integer`):

Retries after the first attempt. Exhaustion saves the checkpoint and ends cleanly.

## `proxyConfiguration` (type: `object`):

Optional user-supplied Apify/custom proxy configuration. Default is a direct connection; proxy services may have separate costs.

## Actor input object example

```json
{
  "sources": [
    "fts",
    "cf",
    "pcs"
  ],
  "mode": "snapshot",
  "pcsNoticeTypes": [
    102,
    104
  ],
  "keywords": [],
  "keywordsAll": [],
  "excludeKeywords": [],
  "cpvPrefixes": [],
  "itlPrefixes": [],
  "nations": [],
  "stages": [],
  "includeNoValue": true,
  "belowThresholdOnly": false,
  "dedup": "exact",
  "fuzzyCrossSource": false,
  "maxItems": 20,
  "includeDescription": true,
  "descriptionMaxChars": 2000,
  "monitorStateKey": "UK_TENDERS_STATE",
  "requestPacingMs": 1000,
  "maxRetries": 2
}
```

# Actor output Schema

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

Dataset items produced by the run.

# 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 = {
    "sources": [
        "fts",
        "cf",
        "pcs"
    ],
    "pcsNoticeTypes": [
        102,
        104
    ],
    "maxItems": 20,
    "maxRetries": 2
};

// Run the Actor and wait for it to finish
const run = await client.actor("resourcefully_dialect/uk-tenders").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 = {
    "sources": [
        "fts",
        "cf",
        "pcs",
    ],
    "pcsNoticeTypes": [
        102,
        104,
    ],
    "maxItems": 20,
    "maxRetries": 2,
}

# Run the Actor and wait for it to finish
run = client.actor("resourcefully_dialect/uk-tenders").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 '{
  "sources": [
    "fts",
    "cf",
    "pcs"
  ],
  "pcsNoticeTypes": [
    102,
    104
  ],
  "maxItems": 20,
  "maxRetries": 2
}' |
apify call resourcefully_dialect/uk-tenders --silent --output-dataset

```

## MCP server setup

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

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/eMv4Fm42cQWFJwxQW/builds/0vawsRi0ga6G7qorb/openapi.json
