UK Tenders API — Find a Tender + Contracts Finder in One Feed avatar

UK Tenders API — Find a Tender + Contracts Finder in One Feed

Pricing

from $3.00 / 1,000 notice records

Go to Apify Store
UK Tenders API — Find a Tender + Contracts Finder in One Feed

UK Tenders API — Find a Tender + Contracts Finder in One Feed

UK public-sector tenders and awards from Find a Tender + Contracts Finder in one feed; notices on both sources merged when title, buyer, region and value match. Filter by CPV, value, region, keyword; daily onlyNew alerts, including amendment re-sends.

Pricing

from $3.00 / 1,000 notice records

Rating

0.0

(0)

Developer

Celest Jux

Celest Jux

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

a day ago

Last modified

Categories

Share

One clean, typed JSON feed of UK public-sector procurement notices from both official UK sources: Contracts Finder (England, mostly below-threshold) and Find a Tender (UK-wide, above-threshold, including every Procurement Act 2023 notice). A notice carried by both sources is merged into a single item when its title, buyer, region and value match. A source that fails to load stops the run before anything is written, so you never get a half-read feed. Filter by CPV code, value, region and keyword, and run it daily with onlyNew for tender alerts/monitoring: only what's new since yesterday, plus amendment re-sends (v1.1) when a delivered notice's deadline, value or status later changes.

Built on the two official, keyless OCDS APIs. No HTML scraping, no proxy, nothing to bypass.

Contains public sector information licensed under the Open Government Licence v3.0. https://www.nationalarchives.gov.uk/doc/open-government-licence/version/3/

What you get

FieldExampleNotes
idfind_a_tender:ocds-h6vhtk-077b05:tendersource:ocid:stage — dedupe key, used by onlyNew
ocidocds-h6vhtk-077b05OCDS procurement id (per source)
sourcefind_a_tenderor contracts_finder
alsoIncontracts_finder or nullthe same notice is also published on the other service
stagetendertender, award or planning
noticeTypeUK4 / tenderAmendmentFTS form code when given, else the OCDS release tag
title, description
buyer{"name": "East Riding of Yorkshire Council", "id": "GB-FTS-33279", "region": "Yorkshire and the Humber", "contactEmail": "…"}
cpv[{"code": "85000000", "description": "Health and social work services"}]every CPV code on the notice
valueAmount, valueCurrency8400000, GBPnet value; awards without a tender value = sum of award values
valueMin, valueMax8000000, 8400000Contracts Finder value ranges
publishedDate2026-09-25T23:16:45+01:00ISO 8601; latest publication/edit of the notice
tenderDeadline2026-10-26T12:00:00+00:00
contractStart, contractEnd
regionLondondelivery region; FTS NUTS codes are turned into region names
procedureTypeOpen procedure
isSmeSuitable, isVcseSuitabletrue / false / nullbuyer's suitability flags
awards[{"supplierName": "Tarmac Trading Limited", "supplierId": "GB-PPON-…", "value": 84000000, "date": "2026-08-26T00:00:00+01:00"}]award stage only (empty otherwise)
noticeUrlhttps://www.find-tender.service.gov.uk/Notice/091204-2026human page
licenceOGL-UK-3.0on every item
scrapedAtUTC
isUpdatetrue / falseonlyNew: true when this item replaces an earlier delivered release of the same notice
previousReleaseId"091204-2026" / nullonlyNew update: the previously delivered release id, when known; null otherwise
extraFields{"legalBasis": "2023/54", "regionCodes": ["UKE12"], "alsoInUrl": "…"}release tags, release id, legal basis (Procurement Act 2023 vs PCR 2015), category, gross value, first-published date, raw region codes, tender status, submission URL, buyer phone, the other source's id + URL

Missing values are null, never empty strings.

Input examples

IT tenders over £100k this week:

{ "cpvPrefixes": ["72"], "minValue": 100000, "includeNoValue": false, "publishedFrom": "7 days" }

Construction in London:

{ "cpvPrefixes": ["45"], "regions": ["London"] }

Daily alert (schedule once a day):

{ "stages": ["tender"], "publishedFrom": "2 days", "onlyNew": true }

Last month's awards with supplier names:

{ "stages": ["award"], "publishedFrom": "1 month", "maxItems": 5000 }

How filters work

  • publishedFrom / publishedTo — YYYY-MM-DD or relative (7 days, 2 weeks, 1 month = that long before today, UK time). Default 7 days. Contracts Finder filters on "published or last edited"; Find a Tender only offers "last updated", which is what it uses.
  • stages — Contracts Finder filters stages server-side. Find a Tender's own stage filter drops every Procurement Act 2023 notice (checked 2026-09-27: stages=tender returned only old-regime PCR 2015 notices), so this actor reads all Find a Tender notices in the window and filters stages itself. Amendments, updates and cancellations belong to their stage; contract-performance (implementation) notices are out of scope.
  • keyword, cpvPrefixes, minValue/maxValue, regions — neither API supports these, so they are applied by the actor (client-side) after download.
    • cpvPrefixes: matches if any CPV code on the notice starts with any prefix.
    • Value filters compare valueAmount in GBP. Notices with no value (or a non-GBP value) are kept only if includeNoValue is on (default on).
    • regions: region names (London, North West, Scotland, …) or NUTS/ITL code prefixes (UKI, UKD3, TLI). Matches delivery regions and the buyer's region.
  • One item per procurement and stage per source: when a notice has been amended in the window, you get the latest version (noticeType tells you it was an amendment).
  • Results from both sources are merged newest-first and cut at maxItems.

Cross-source dedupe

The two services give the same notice different ocids and do not cross-reference each other. A notice counts as the same in both when stage, title, buyer name and tender deadline match (case/punctuation-insensitive) and that combination is unique within each source — buyers often reuse one title for many separate notices (e.g. one council published 9 different taxi-route lots under the same title in one week), so ambiguous matches are never merged. Records with conflicting GBP values are also kept separate. Cross-source matching runs only when both source windows were fully read; a maxItems or charge cap may leave two copies in the limited output. The Find a Tender copy is kept, alsoIn is set to contracts_finder, and the Contracts Finder id and URL go to extraFields.alsoInId / alsoInUrl. Overlap is small: since the Procurement Act 2023 most above-threshold notices appear on Find a Tender only.

Contracts Finder sometimes prefixes its title with an internal reference code (e.g.

CA18485 - Hopwood Hall College - Provision of HR & Payroll System
, where Find a Tender's copy of the same notice is titled Hopwood Hall College - Provision of HR & Payroll System). The matching step strips a leading reference-code prefix — one of the letter families actually seen across every Contracts Finder title captured during this actor's development (C, CA, ENQ, PR, PS, UOW, each followed by 2+ digits; T0nnn on its own, the exact shape observed — not T plus any digits, which would also catch unrelated titles like "T20 - ...") — then a -/–/: separator — before comparing titles, but only for the match; the notice's own title field always keeps the prefix as published. This is deliberately conservative: the letter families are constrained to what was actually observed (plus an explicit denylist for standard/product names like ISO or NHS reference numbers that could otherwise look like a code), a prefix followed only by a space (no punctuation), a location prefix (GB-London: ...), or a title that's nothing but a reference code are all left alone rather than guessed at. It reduces common duplicates from this pattern; it doesn't guarantee every duplicate is caught, and in principle two distinct notices could still share a match key if they coincidentally matched on stage, buyer and deadline too.

onlyNew

Pushed notices are fingerprinted in the named key-value store celestjux-uk-tenders-seen (it persists between runs): {releaseId, publishedDate} per notice id. A later run skips a notice only when the store holds the same release (same release id, or a same-or-older publishedDate) — a genuinely later release of an already-delivered notice (an amendment that moves the deadline, changes the value, or cancels the tender) is pushed again, with isUpdate: true and previousReleaseId set to the release it replaces. Set resendUpdates: false to go back to the old behaviour: any previously delivered notice id is always skipped, updates included.

A copy from either source of an already-delivered notice is still skipped when both have the same GBP value and the first source window was fully read (unchanged — see Cross-source dedupe above).

A tenderCancellation of an already-delivered notice arrives as an update too (isUpdate: true, previousReleaseId set) — check noticeType to tell it apart from an amendment.

The newest-release guarantee only covers pages actually read: once a source has enough candidates to fill maxItems (or the charge cap), the run stops reading that source's remaining pages, so an even-newer release of an already-kept notice past that cutoff is not seen. In practice the live feed is newest-first, so this rarely bites.

Charging: a re-sent update is a normal record event like any other pushed item — amendments of a delivered notice are delivered again, charged as a record; set resendUpdates=false to skip them.

To start over, delete the celestjux-uk-tenders-seen store.

Daily schedule → Slack / Sheets / webhook

  1. Save an input like the "daily alert" example as a task.
  2. Console → Schedules → daily (e.g. 07:00 Europe/London) → add the task.
  3. Integrations on the task: Slack (post new items), Google Sheets (append rows), or a webhook on "Run succeeded" pointing at your system; it receives the run with its dataset id.

Pricing

Pay per event: $0.003 per notice pushed (= $3 per 1,000). No start fee. Set maxTotalChargeUsd to cap a run; it stops cleanly before going over.

Reliability

  • Sequential requests, ≥ 1 s apart, identifying user agent.
  • Timeouts and 5xx: 3 attempts with backoff.
  • Find a Tender 429/503: honours Retry-After up to 4 times per request. A malformed Retry-After (missing, non-numeric, negative, NaN/Infinity, or bigger than 300s) is never guessed at — it fails the run loud immediately, naming the URL and the raw header value.
  • All rate-limit waits — Find a Tender's Retry-After waits and a Contracts Finder 403 cooldown — count against one shared cap on total wait per run (default 600s/10min, set maxRateLimitWaitSec to change it). If honouring a wait would push the total over that cap, the run fails loud before sleeping rather than after. A 429/403 with a usable, in-range wait usually just recovers on its own — the run only fails once the per-request cap (4) or the run-wide cap is actually reached.
  • After the first 429/403 of a run, the delay between pages increases for the rest of the run to ease off the source.
  • Contracts Finder 403 (its rate limit): one 5-minute cooldown, then the run fails if it happens again — unchanged behaviour, now counted in the shared wait budget/stats above and triggering the same slower page pace as a Find a Tender 429.
  • A source fetch or parse failure fails the run with the URL in the error, before any item is written — items are pushed only after every source has been read completely.
  • Run stats include rateLimitWaits and rateLimitWaitSec (both sources combined) so you can see how much of a run's time went to honouring a rate limit.

Limits

  • v1 has no Companies House enrichment of suppliers (planned v1.1: bring your own Companies House API key).
  • Contracts Finder's planning stage is practically empty (0 notices in the week checked); pipeline notices come from Find a Tender.
  • A long window on Find a Tender means many pages (roughly 500 notices of all types per weekday), since its stage filter cannot be used.