The Actor "UK Public Contracts Lookup" returns UK public procurement notices from Find a Tender and Contracts Finder in one fixed row per notice, newest first. Public Contracts Scotland is an opt-in third source.
The two services publish the same kind of thing in different shapes: different ids, different fields, a different idea of what a "value" is. The Actor reads each service's official feed and writes every notice into the same 17 fields, so a script or an AI agent does not need to know which service a notice came from.
What it answers
- Search: which notices were published in a window (31 days by default, 92 at most) that match your keywords, CPV codes, regions, stages, value range or deadline?
- Lookup: what do these notices say? Give up to 20 ids (a Find a Tender notice id or OCID, a Contracts Finder notice GUID, or a Public Contracts Scotland OCID).
- Alert: which notices are new since my last run? State is kept in a store in your own Apify account, so a daily schedule returns each notice once.
Who it is for
People who need to see tenders without reading two websites: bid writers and small suppliers watching a sector, analysts counting contracts by buyer or region, journalists following a public body, and developers whose agents need a procurement tool that returns a stable shape.
A worked input
This is the Actor's default, capped at 20 notices, run with the Apify Python client and a hard spend cap:
from datetime import timedelta
from decimal import Decimal
from apify_client import ApifyClient
client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("yappman/contracts-lookup").call(
run_input={"mode": "search", "sources": ["fts", "cf"], "maxItems": 20},
max_total_charge_usd=Decimal("0.11"),
run_timeout=timedelta(minutes=10),
)
rows = list(client.dataset(run.default_dataset_id).iterate_items())
Add "keywords": ["bridge"], "cpvCodes": ["45"] (a prefix: 45 is all of construction) or "regions": ["Scotland"] to narrow it. Every row has the same fields. This one, from a recorded Contracts Finder response on 9 September 2026, shows the shape:
{
"source": "cf",
"noticeId": "5c68738f-b26d-4b6c-a2b3-9f7b02a44a2f",
"ocid": "ocds-b5fd17-598522e1-32d9-4592-9a3c-f35ad712e5be",
"relatedOcids": [],
"reconcileKey": "1800b7214f7010a3",
"releaseId": "5c68738f-b26d-4b6c-a2b3-9f7b02a44a2f-913395",
"title": "Children Affected by Parental Offending",
"buyer": "Bristol City Council",
"value": 80000,
"currency": "GBP",
"cpvCodes": ["98000000"],
"regions": ["South West"],
"publishedAt": "2026-09-09T09:37:55Z",
"deadline": null,
"stage": "planning",
"noticeUrl": "https://www.contractsfinder.service.gov.uk/Notice/5c68738f-b26d-4b6c-a2b3-9f7b02a44a2f",
"alertFingerprint": null
}
A missing value is null, never an absent key. stage is one of planning, tender, award, contract and termination. value is the estimate, or for award and contract notices the sum of the awarded amounts, as published (including placeholders). A procurement that appears on both services is two rows; reconcileKey is a hash of the normalised buyer and title that probably matches them, and you join on it yourself.
Every run also writes a RUN_SUMMARY record. It says how many rows were returned and, per service, which days it could not cover.
Pricing
Pay per event, with no start fee and the same price on every plan.
| Event | Charged | Price |
|---|---|---|
notice |
each row returned | $0.005 ($5.00 per 1,000) |
run |
once a run has read data | $0.005 |
The default run above costs at most $0.105: 20 notices at $0.005 and one run at $0.005. A refused input (a window over 92 days, say), a lookup the source rate-limits before it answers and an alert that finds its store locked cost nothing. An id that is not found gives no row and no charge. maxItems caps the rows and Apify's maximum-charge setting caps the bill.
Limits
-
Find a Tender is read from its API only for now. Its daily bulk files are not used yet, so a wide Find a Tender search can come back partial.
RUN_SUMMARY.sources.fts.missingDaysnames the days that were missed, and an alert picks them up on its next run. Contracts Finder is read from its daily files and is not affected. - Titles are redacted by pattern (email addresses, UK phone numbers and a name written after "contact" or "FAO"), so a name written some other way is not caught.
- The two services share a rate limiter, so a run makes at most one API request every 15 seconds. That is why a search spanning many recent days takes minutes, not seconds.
- No documents and no tender text: the row points to the notice page with
noticeUrl.
Data sources and licence
Find a Tender and Contracts Finder (and Public Contracts Scotland, if you choose it), all official services, with notice data published under the Open Government Licence v3.0. If you republish rows, keep this line: Contains public sector information licensed under the Open Government Licence v3.0.
Personal data
Rows are built to hold no personal data: no contact names, emails, phone numbers, addresses, supplier names or descriptions. A buyer is an organisation's name.
Where to find it
"UK Public Contracts Lookup" on the Apify Store: https://apify.com/yappman/contracts-lookup (yappman/contracts-lookup), pay per event: $0.005 a notice plus $0.005 a run. This is not an official service and is not affiliated with or endorsed by the Cabinet Office, the Scottish Government or any publisher of the data. It is a way to read public notices in one shape; check the notice itself before you rely on it for a bid.
If you want a field or a filter that is missing, say so in the comments.
Top comments (0)