UK Tenders Scraper: Contracts Finder & Find a Tender Notices avatar

UK Tenders Scraper: Contracts Finder & Find a Tender Notices

Pricing

from $3.00 / 1,000 notices

Go to Apify Store
UK Tenders Scraper: Contracts Finder & Find a Tender Notices

UK Tenders Scraper: Contracts Finder & Find a Tender Notices

Search UK tenders and public sector contract notices from Find a Tender and Contracts Finder in one schema: buyer, value, CPV codes, dates, region. New-notice alerts for daily schedules and a renewals mode for contracts ending soon. Not affiliated with the Government.

Pricing

from $3.00 / 1,000 notices

Rating

0.0

(0)

Developer

Russell Yapp

Russell Yapp

Maintained by Community

Actor stats

0

Bookmarked

1

Total users

1

Monthly active users

9 hours ago

Last modified

Categories

Share

UK Public Contracts Lookup: Find a Tender and Contracts Finder notices in one schema

You get UK public procurement notices published on Find a Tender and Contracts Finder (and Public Contracts Scotland if you choose it), one fixed row per notice.

A row holds the notice title, the buyer (an organisation), value, currency, CPV codes, regions, stage, dates, a link to the notice and notice ids. suppliers is reserved for organisation supplier names, pending a review; it is null in this version. A row has no contact, address or description field. A title is free text copied as published. Email addresses, UK phone numbers and a name written straight after cue words such as "contact", "FAO" or "write to" are replaced with [redacted] by pattern, so a name written another way, including a supplier named in a title, can remain. The notice link opens the source notice, which we do not filter.

A first run from the input form (maxItems prefilled at 3) costs up to $0.020: $0.005 for the run and $0.005 for each of the 3 newest notices, and usually takes a minute or two. Runs refused before anything is read (invalid input, or a window over 92 days) are not charged. A run that reads data and finds nothing still pays the $0.005 run fee.

Through the API, if you leave out maxItems, the cap is 1,000 notices, which can cost up to $5.005 ($20.005 in the renewals modes). The input form prefills 3. Set maxItems to what you need.

ModeYou giveA question it answers
searchFilters: keywords, buyers, cpvCodes, valueMin, regions, stages, deadlineFrom, a publication windowWhich NHS tenders still open for bids are worth at least 100,000 pounds? (within the publication window you set, 31 days by default)
pipelineThe search filters, and optionally expectedFrom and expectedToWhich IT procurements do buyers expect to bring to tender in the next three months? (planning notices published in the window you set)
lookupnoticeIds: up to 20What are the title, buyer, value and deadline of notice 094494-2026?
alertalertId and filtersWhich highways tenders in the North West are new since my last run?
profilebuyers: 1 to 10What did this buyer put out to tender and award on Contracts Finder and Find a Tender over the last 365 days?
renewalsendWithinMonths (or endFrom and endTo) and filtersWhich cleaning contracts in the South East have a stated end date in the next 12 months?
renewalsAlertalertId and the renewals filtersWhich contracts have newly entered that list, or had their dates changed, since my last run?
publishedAtsourcetitlebuyervaluecurrencystagedeadlineregions
2026-09-09T00:00:00ZftsChildren Affected by Parental Offending - Expression of InterestBristol City Council80000GBPtender2026-09-30T11:00:00ZSouth West

A default run (search, the last 31 days, both default services, with maxItems prefilled at 3) returns up to the 3 newest notices it can read and costs up to $0.020 ($0.005 for the run plus 3 x $0.005). It usually takes a minute or two. Find a Tender and Contracts Finder are read for the whole window from their published daily files, with today from their APIs (Find a Tender's file for yesterday appears by about 03:05 UTC, Contracts Finder's by about 02:00 UTC). API requests are paced at one every 15 seconds, so a run that reaches its cap of 12 API requests spends about 3 minutes on them, more if a service asks it to wait, and more with pcs (see Limits). RUN_SUMMARY names any day not covered. Raise maxItems in the input, up to 100,000, to get more.

Dates. A row carries the notice's publication time (publishedAt), not the time the Actor read it; there is no scrape date on the row. Each run's RUN_SUMMARY records startedAt and finishedAt, and notices are read during the run, from the Find a Tender and Contracts Finder daily bulk files and from their APIs (see Freshness and coverage), so a notice published after the run reads its day is not included.

When to use it, and when not to

Use it to:

  • list the notices that match your filters (keywords, buyer, CPV code, value, region, stage, deadline);
  • look up named notices by id;
  • be told once about each new matching notice, on a schedule;
  • list contracts whose notice states an end date in a window, and be told when one is new or its dates change (renewals).

Do not use it:

  • to find the suppliers of a contract or to search by supplier: suppliers is reserved for organisation supplier names, pending a review, and is null in this version; there is no supplier filter, by design;
  • for contact fields or the full notice text: there are no contact name, email, phone or description fields (a title can still contain a name);
  • as proof that a notice does not exist, or as a real-time feed: it returns what the services published and what it could read within its request limits (see Freshness and coverage);
  • for notices from services other than Find a Tender, Contracts Finder and (if you choose it) Public Contracts Scotland.

What you get

One row per notice, the same fields for every service. A missing value is null (or [] for lists), never an absent key.

FieldTypeMeaning
source"fts", "cf" or "pcs"The service the notice came from: Find a Tender, Contracts Finder or Public Contracts Scotland
noticeIdstringFind a Tender id (094494-2026), Contracts Finder notice GUID, or Public Contracts Scotland notice id (SEP565172; SEP564648-1 for a notice split into lots)
ocidstring or nullThe contracting-process id. For a Find a Tender legacy form (the pre-Procurement Act forms, about 15% of its 2026 notices): null when the notice is read from its daily file, which carries no OCID (search, alert, renewals and profiles read past Find a Tender days from those files); set when search, alert or lookup read it from the API (today's notices, lookup); and in renewals and the renewals alert always null, because those modes read legacy notices from the daily files only. Find a Tender Procurement Act notices carry it on both routes, and pcs rows always carry theirs
relatedOcidsarray of stringsOCIDs of the same procurement on another service, taken only from explicit references in the notice. Nearly always []
reconcileKeystring or nullProbably the same procurement: join it yourself. A hash of the normalised buyer and title; two rows with the same key, from different services, are likely one procurement. It misses pairs worded differently, and generic titles from one buyer can collide. null if buyer or title is empty
releaseIdstringId of the notice version returned (Find a Tender: the notice id; Contracts Finder: {guid}-{n}, the latest; Public Contracts Scotland: the same as noticeId)
titlestring or nullNotice title, with email addresses, UK phone numbers and some contact names redacted by pattern. null for follow-up notices that have no title of their own
buyerstring or nullBuyer organisation name as published
valuenumber or nullEstimated value; for award and contract notices, the sum of the awarded or contracted amounts. null where currencies are mixed. As published, including placeholders
currencystring or nullISO 4217 code of value
cpvCodesarray of stringsThe CPV codes on the notice, 8 digits, de-duplicated and sorted
regionsarray of stringsUK ITL1 regions of delivery, or Outside UK. A UK-wide location lists all twelve regions
publishedAtstringPublication time (ISO 8601, UTC) of the version returned. For a Find a Tender legacy form read from its daily file (past days) it is the date at T00:00:00Z, because the file gives no time; in renewals, which reads legacy notices from the daily files only, it is always the UK publication date at T00:00:00Z. So for a legacy notice published between 00:00 and 01:00 UK summer time the shown publishedAt can be up to an hour later than the real time. For pcs rows it is almost always a date at midnight UTC, because Public Contracts Scotland publishes dates, not times (quick quote awards are the exception)
deadlinestring or nullTender deadline (ISO 8601, UTC); null if none or unreadable
contractEndDatestring or nullWhen the contract ends (ISO 8601, UTC). For a planning or tender notice, the planned end date (the latest across its lots when the notice has lots); for an award, contract or termination notice, the latest end date of the awards and contracts, falling back to the planned one. null where the notice gives none. Patchy: many notices do not state it
awardDatestring or nullThe latest award date on the notice (ISO 8601, UTC). null if there is no award or no date
procurementMethodstring or nullopen, selective, limited or direct (the OCDS procurement-method codes), as the notice states it. null where not stated. Find a Tender legacy forms read from its daily files (search and alert, past days) carry none. The free-text procedure description is not returned
smeSuitableboolean or nulltrue where the notice says it is suitable for small and medium-sized enterprises. null otherwise: Contracts Finder's bulk files write "not suitable" and "not stated" the same way, so null does not mean "not suitable"
stagestringplanning, tender, award, contract or termination
noticeUrlstringThe public notice page (for pcs, on the Public Contracts Scotland website)
alertFingerprintstring or nullSet only in alert mode; null otherwise
daysToDeadlineinteger or nullWhole days from the day the run started (UTC) to the deadline's UTC date: 0 on the day, negative once the deadline has passed, null when the notice has no deadline. Worked out when the run delivers the row, so the same notice read tomorrow shows one day less. A deadline of 00:30 on 31 October in British Summer Time is 2026-10-30T23:30:00Z, so its UTC day is 30 October
lotsCountinteger or nullHow many lots the notice lists. Find a Tender and Public Contracts Scotland notices state them; Contracts Finder notices do not, so cf rows are null. null when the notice lists none, which does not mean it has no lots. Only the count is read, never a lot's text
suppliersnullReserved for organisation supplier names, pending a review; null in this version, on every row. No supplier name is read. There is no supplier filter
noticeTypestring or nullThe Procurement Act form of a Find a Tender notice: UK1 pipeline, UK2 preliminary market engagement, UK3 planned procurement, UK4 tender, and so on. null for Find a Tender notices on the older forms, and for cf and pcs rows
futureNoticeDatestring or nullWhen the buyer expects to publish its next notice for this procurement, usually the tender (ISO 8601, UTC), as the notice states it. Planning notices carry it: Find a Tender UK1 to UK3 and older prior information notices, and planning notices on Contracts Finder and Public Contracts Scotland. null where the notice gives none. Pipeline mode sorts and filters on it

All dates and times are UTC (deadline, contractEndDate, awardDate, publishedAt, futureNoticeDate). UTC is an hour behind British Summer Time, so 23:59:59 BST on 31 March is 2025-03-31T22:59:59Z, and midnight BST at the start of a day appears as 23:00 the previous evening.

Three ids, three jobs: noticeId identifies one notice on one service (use it to look the notice up); ocid identifies the whole contracting process across its notices on that service (a tender, its award and its contract share one ocid); reconcileKey is a hash of the normalised buyer and title that two services' rows for the same procurement are likely to share (use it to join rows yourself; it can miss a pair and can, rarely, join two different procurements).

Illustrative row (the values are made up):

{
"source": "fts",
"noticeId": "012345-2026",
"ocid": "ocds-h6vhtk-0a1b2c",
"relatedOcids": [],
"reconcileKey": "3f9a1c7e5b2d4a60",
"releaseId": "012345-2026",
"title": "Highways Maintenance Framework",
"buyer": "Example County Council",
"value": 4500000,
"currency": "GBP",
"cpvCodes": ["45233141", "50230000"],
"regions": ["North West"],
"publishedAt": "2026-10-06T09:30:00Z",
"deadline": "2026-11-13T12:00:00Z",
"contractEndDate": "2029-03-31T00:00:00Z",
"awardDate": null,
"procurementMethod": "open",
"smeSuitable": true,
"stage": "tender",
"noticeUrl": "https://www.find-tender.service.gov.uk/Notice/012345-2026",
"alertFingerprint": null,
"daysToDeadline": 16,
"lotsCount": 3,
"suppliers": null,
"noticeType": "UK4",
"futureNoticeDate": null
}

Rows come out newest publishedAt first, then by source and notice id, so the same input on the same data gives the same order. Pipeline mode sorts by futureNoticeDate instead (see Pipeline).

Modes

sources (default ["fts","cf"]) chooses which service to read. Public Contracts Scotland is opt-in and is read only when chosen: "sources": ["pcs"], or ["fts","cf","pcs"] for all three. Public Contracts Scotland's API is currently not working for anyone (PCS support confirmed on 28 Oct 2026; no fix date), so pcs returns nothing and is not charged. Above-threshold notices from Scottish bodies also appear on Find a Tender, which this Actor reads; Scotland-only notices below that threshold are unavailable while PCS is down. A run that includes pcs stops asking it after usually about a minute (a few minutes at most if the server accepts the connection but never replies), finishes from the other services you chose (with "sources": ["pcs"] alone it finishes with no rows), names every list it could not read in RUN_SUMMARY.sources.pcs.missingLists, and is not charged for Public Contracts Scotland (a run that reads nothing is not charged); a lookup lists the OCIDs it could not reach under unavailable. Notices are charged only when returned; the run fee follows the Pricing section. A procurement published on two services is two notices and two rows.

There are seven modes: search, pipeline (planning notices by expected tender date; see Pipeline below), lookup, alert, profile (one summary row per buyer, from Contracts Finder and Find a Tender; see Buyer profiles below), renewals and renewalsAlert (contracts by stated end date, one row per contract; see Renewals and Renewals alert below). The renewals modes have their own row, set out under Renewals, and their own price.

{
"mode": "search",
"keywords": ["bridge"],
"cpvCodes": ["45"],
"regions": ["Scotland"],
"deadlineFrom": "2026-10-07",
"maxItems": 200
}
  • Window: publishedFrom and publishedTo (UTC days, inclusive). Default is 31 days: today and the 30 days before. Maximum 92 days. A longer window is refused before anything is read, and nothing is charged. A publishedTo in the future counts as today.
  • Relative window: lastDays (a whole number from 1 to 92) instead of the two dates: the last N UTC days, today included, worked out when the run starts (7 is today and the 6 days before it; 92 is the largest window). A saved Task with lastDays: 7 therefore always reads the last week, where fixed dates would go stale. lastDays together with publishedFrom or publishedTo is refused, and so is 0 or a number over 92, before anything is read; nothing is charged. Alert mode (a fixed 14-day window) and the renewals modes refuse lastDays.
  • Filters are combined with AND; within a list, any match counts.
    • buyers: case-insensitive part of the buyer name.
    • keywords: whole words in the title and description. The description is matched but never returned.
    • cpvCodes: prefixes. 72 matches all of division 72; 72212000 matches itself and the codes beneath it.
    • valueMin, valueMax: GBP. Notices in another currency or without a value are left out when either is set.
    • regions: the 12 UK ITL1 regions, plus Outside UK.
    • stages: planning, tender, award, contract, termination.
    • deadlineFrom: deadline on or after this day. Notices without a deadline are left out when it is set.
    • ocids (alert mode only): 1 to 200 OCIDs, matched exactly against the row's ocid; a repeated OCID counts once (the input form takes at most 200 entries, repeats included). Refused in all other modes, before anything is read. See Track specific procurements, under Alert.
    • maxItems: cap on rows and so on notice charges. Prefilled at 3 in the input form. When it is left out, as in an API call with no maxItems, it is 1,000. If the platform restarts an alert run, that run can return up to maxItems more notices, each charged once; set a maximum cost per run as well, which the run is designed to keep within across a restart.

Pipeline

{
"mode": "pipeline",
"cpvCodes": ["72"],
"lastDays": 92,
"expectedFrom": "2026-11-01",
"expectedTo": "2027-01-31",
"maxItems": 50
}
  • What it returns: planning notices, sorted by when the buyer expects to go to tender. On Find a Tender these are the Procurement Act pipeline (UK1), preliminary market engagement (UK2) and planned procurement (UK3) notices, plus prior information notices on the older forms; on Contracts Finder (and Public Contracts Scotland, if you choose it) its planning notices.
  • A search in all other respects: the same publication window (31 days by default, lastDays or publishedFrom and publishedTo, 92 days at most), the same filters (keywords, buyers, cpvCodes, valueMin, valueMax, regions, deadlineFrom, sources, maxItems), the same row and the same price: run once plus one notice per row. stages is set to planning for you; any other stage is refused before anything is read, and nothing is charged.
  • Order: futureNoticeDate soonest first, then notices that state no expected date; ties go newest publishedAt first. maxItems is applied after sorting, so it keeps the soonest.
  • Expected window: expectedFrom and expectedTo (YYYY-MM-DD, inclusive; either or both) keep notices whose futureNoticeDate falls on those days in UK time (a date written as midnight British Summer Time, which the row shows as 23:00 UTC the evening before, counts on its own UK day). A full timestamp such as 2026-11-01T00:00:00Z is also accepted; its date part is the day. With either set, notices that state no expected date are left out and counted in RUN_SUMMARY.noFutureNoticeDate, and notices with a date outside the days in outsideExpectedWindow. Search, alert, renewals and renewals alert refuse these two inputs.
  • Read this before you rely on it: only notices published inside the publication window are read, so a pipeline notice published four months ago is not found; use lastDays: 92 for the widest view. The expected date is the buyer's estimate as published and can move or pass without a tender. A date of midnight British Summer Time shows in the row as 23:00 UTC the evening before; the expected window still counts it on its UK day.

Lookup

{
"mode": "lookup",
"noticeIds": ["094494-2026"]
}
  • Up to 20 ids per run: a Find a Tender notice id, a Find a Tender OCID (its latest notice is returned), a Contracts Finder notice GUID, or a Public Contracts Scotland OCID. Contracts Finder OCIDs are not supported.
  • A Public Contracts Scotland OCID is ocds-r6ebe6- plus 10 digits (for example ocds-r6ebe6-0000791963), optionally with a lot suffix such as -1. A Public Contracts Scotland notice id such as SEP565172 cannot be looked up, because its API has no call for it: it is refused with a message asking for the OCID. Every pcs row carries its OCID, so take it from there.
  • An id that is not found gives no row and no notice charge, and is listed in RUN_SUMMARY.notFound. The source still answered, so the run is still charged the run event once, as for any run that read data.
  • If a source rate-limits the run, lookup stops at once. Ids already found are returned; every id not yet looked up is listed in RUN_SUMMARY.retryAfter as seconds, until and ids, with no row and no charge for them. The run itself succeeds, so a script or agent can read the summary and retry after until.

Alert

{
"mode": "alert",
"alertId": "highways-north-west",
"keywords": ["highway"],
"regions": ["North West"],
"firstRunLookbackDays": 1,
"maxItems": 20
}
  • alertId is yours to choose: lower-case letters, digits and hyphens, 1 to 40 characters.
  • State is kept in a key-value store named contracts-alert-<alertId> in your own Apify account.
  • Each run looks at the last 14 days of notices. Anything that matches your filters and is not already in the store is new, so a notice that reached the source late is still caught.
  • First run: notices from the last firstRunLookbackDays days (default 1, maximum 14) are returned and charged. The rest of the 14-day window is recorded as already seen, without charge.
  • Alerts created before 0.1.13, which reads Find a Tender from its published daily files, do not receive a backlog of older Find a Tender notices: on their first run under 0.1.13 they only send Find a Tender notices published after their last run, and the older ones are left out without charge (counted in RUN_SUMMARY.ftsBeforeAlertFloor); that first run may also leave out Find a Tender notices that the earlier run held back for maxItems, could not read, or that were published around its last run, so such notices can be missed but no backlog is ever sent or charged.
  • Each notice is sent once per alertId. A Contracts Finder amendment is not sent again. A Find a Tender award or change is its own notice with its own id, so it is new. Changing the filters keeps the store, so nothing already sent comes back.
  • A second run for the same alertId that starts while one is active stops before reading anything and charges nothing; its summary says locked.
  • Safe to schedule daily.

Getting alerts where you work

The Actor itself sends no email or message. It writes the new notices to the run's dataset, and Apify's own features do the delivering. In outline (check each against Apify's documentation, which you can reach from your Apify Console):

  • Save your alert input as a Task, one Task per alert, each with its own alertId.
  • To run it every day, open Schedules in the Console, create a schedule, add the Task and check the schedule's Enabled switch.
  • To be told when a run finishes, open the Task's Integrations tab and choose one of the available notification integrations. The message tells you the run finished; the notices are in the run's dataset.
  • A webhook on the Task can call your own system when a run finishes (the API events are ACTOR.RUN.SUCCEEDED and ACTOR.RUN.FAILED). Its payload carries the run's details, not the notices; the dataset id is resource.defaultDatasetId, so your system then reads the run's dataset. Refused inputs end SUCCEEDED with RUN_SUMMARY.status refused, so read that field rather than relying on ACTOR.RUN.FAILED; a run that charged and then could not continue ends FAILED.
  • A notification may arrive on a day with no new notices, because a run that read data and found nothing still succeeds.
  • A run that finds nothing new still pays the $0.005 run fee, so a daily alert costs at least about $0.15 a month. Set Apify's maximum-charge setting on the run.
  • Do not put secrets in a webhook URL or payload template.

A weekly feed. For a bid team, the same alert on a weekly schedule gives one batch of new notices a week. For example, NHS software tenders:

{"mode": "alert", "alertId": "bid-it-nhs-weekly", "buyers": ["NHS"], "cpvCodes": ["72"], "stages": ["tender"], "firstRunLookbackDays": 7, "maxItems": 100}

The first run returns the last 7 days (today included); each later run returns only what is new since the run before. Keep the schedule at 14 days or less, the alert's window, or notices published in between are missed. It costs $0.005 a run plus $0.005 a notice on the Free plan (notices cost less on higher plans; see Pricing), so a week of about 20 new notices is about $0.105, and a quiet week still pays the $0.005 run fee. maxItems 100 keeps a week at $0.505 or less on the Free plan.

Track specific procurements

Give the OCIDs of the procurements you follow in ocids, and the alert sends their new notices only (an award, a change, a contract notice), with the same window, store, charges and digest as any alert:

{"mode": "alert", "alertId": "my-tracked-bids", "ocids": ["ocds-h6vhtk-06ef19", "ocds-b5fd17-22c262e6-9f52-43d3-9054-6fec036fe46d"], "firstRunLookbackDays": 14, "maxItems": 50}
  • An OCID is the row's ocid from a search or lookup. Up to 200 a run (the input form takes at most 200 entries, repeats included; through the API a repeated OCID counts once); they are matched exactly, and combined with any other filter you set (keywords, buyers and the rest).
  • Adding OCIDs to an existing alertId takes effect on its next run: matching notices from the last 14 days that this alert has not sent before are sent then, and charged once each, as any new notice.
  • One procurement can carry a different OCID on Find a Tender and on Contracts Finder. Track each one you see.
  • Find a Tender's older-regulations notices read from its daily files carry no OCID, so they cannot be tracked this way.
  • The alert reads the last 14 days on each run: run it at least once in 14 days and no notice of these procurements is missed.
  • As in any alert, each notice is sent once; a Contracts Finder amendment of a notice already sent is not sent again.
  • RUN_SUMMARY.ocids gives requested (how many OCIDs) and matchedProcesses (how many had a matching notice in the 14 days, sent now or earlier). The OCIDs are not listed back.

Digest

Each alert run also writes a short summary, ALERT_DIGEST, to the run's key-value store next to RUN_SUMMARY, as Markdown text (text/markdown), so a person, a webhook or a connector can read one small record instead of the dataset. It lists only the notices that run returned:

  • a header with the alertId, the run's UTC date, the number of new notices and the count per stage;
  • the notices whose deadline falls within 7 days of the run date;
  • the notices grouped by CPV division (the first two digits of the first CPV code), then by region, each as one line with title, buyer, value and currency, deadline and noticeUrl;
  • the Open Government Licence attribution.

It uses only those row fields: no description, contact, address or supplier. It stops at 200 lines or 50 KB and then says how many more notices are in the dataset. A run with nothing new writes one line ending "no new notices". A run that found new notices but returned none or only some, because your spending limit was reached, says how many it found and did not return, for example "3 new notices found, none returned (spending limit reached)"; those are sent on a later run while they are still inside the 14-day window. A run that was refused, found its alert locked or lost its lock writes none, and so does a renewals alert. The digest is part of the run and is not charged separately; if it cannot be written, the run, its summary and its charges are unchanged.

Buyer profiles

"mode": "profile" returns one summary row per buyer you name: what that buyer put out to tender and awarded on Contracts Finder and Find a Tender over the last 365 days, by stage, CPV code and month. It is an aggregate of fields the notice rows already carry, not a list of notices.

{"mode": "profile", "buyers": ["Bristol City Council", "GB-CFS-322528"]}
  • Buyers: 1 to 10 in buyers. Each is an exact buyer name or a buyer id: a Contracts Finder one such as GB-CFS-53257, or the id a Find a Tender Procurement Act notice gives its buyer (such as GB-PPON-PNXX-8585-GQTH). Find a Tender's older-regulations forms are matched by name only.
  • Matching: a name matches a buyer published under exactly that name, ignoring case, punctuation and a leading "the", with "&" read as "and". It never matches part of a name, so NHS alone matches only a buyer published exactly as "NHS". An id is matched exactly, ignoring case. The row lists what was joined in matchedNames and matchedIds.
  • Window: fixed at the 365 days ending the day before yesterday (yesterday's file appears only about 02:00 UTC). publishedFrom and publishedTo are not used, and neither are sources or the search filters.
  • Coverage: Contracts Finder and Find a Tender, each from its daily files over the same 365 days. Since 24 February 2025, procurements under the Procurement Act 2023, including below-threshold contracts, are published on Find a Tender; Contracts Finder carries procurements begun under the earlier regulations (on one day, 9 September 2026, Contracts Finder had 128 notices and Find a Tender 444). Find a Tender notices are read as search reads them, its older-regulations forms included. Public Contracts Scotland is not included. Each profile says what was read in coverage, which comes before any total: read it first. No API is called. A day file that cannot be read is listed in coverage.cf.missingDays or coverage.fts.missingDays, with the first in staleSince; a Find a Tender file over the size limits or not a valid archive is also named in coverage.fts.rejectedDays with the reason. Day files not read within 25 minutes count as missing.
  • Values: notice values, not payments. awarded covers award and contract notices; tendered covers tender notices (an estimate). They are kept apart and never added together. GBP only: values in another currency are counted in otherCurrency. Framework call-offs are counted. A notice with CPV codes in several divisions counts in each.
  • Not in a profile: supplier names or counts, contacts, addresses, descriptions, or any ranking of buyers.
  • Too few days: a profile needs at least 85% of the year's day files of each service: Contracts Finder's and Find a Tender's. Contracts Finder publishes files for working days, so its share is taken over its expected days: weekdays that are not bank holidays in England and Wales, plus any weekend or bank-holiday day whose file was read (coverage.cf.daysExpected); a weekend or bank-holiday day with no file does not count (quietDaysWithoutFile). Find a Tender publishes a file each day, so its share is over all the days. If either falls short, no profile is made and nothing is charged; the status message and RUN_SUMMARY.coverageTooLowFor (cf, fts or both) name the service and the shortfall in days, for example "Contracts Finder: 210 of 253 expected day files read (83.0%, 85% needed: 6 more days were needed)". Run again later. coverage.cf.percentRead and coverage.fts.percentRead give each share.
  • No profile, no charge: the run event is charged only when the run returns at least one profile. A run that returns none (no notices for your buyers, too few days) costs nothing.
  • Refused, with nothing read or charged: no buyers, more than 10, a name under 3 or over 200 characters, or a name that reads like a person's (no organisation or public-body word in it). A matched buyer that publishes such a name also gets no profile and no profile charge.
FieldMeaning
profileOfThe names or ids you asked for that found these notices (a name and its id give one profile, charged once)
buyerThe buyer name as most often published
matchedNames, matchedIdsEvery published name and buyer id that was matched
windowfrom and to (UTC days)
coveragecf (daysRead, daysInWindow (calendar days), daysExpected (the share's denominator, above), quietDaysWithoutFile, missingDays (working days, and weekend or bank-holiday days whose file could not be read), staleSince, complete, percentRead (daysRead / daysExpected), minimumPercent, incomplete), fts (daysRead, daysInWindow, missingDays, staleSince, complete, plus rejectedDays when a file was refused, percentRead, minimumPercent and incomplete), then pcs as text saying it is not included
valuesNoteA reminder that values are notice values, not payments
noticesCount in the window: total, then one count per stage
awardedcount, valueGbp, medianGbp, withValue, noValue, otherCurrency, frameworkCallOffs
tenderedcount, estimatedValueGbp, withValue, noValue, otherCurrency
byCpvPer CPV division (2 digits) and group (3 digits, the top 30): cpv, level, notices by stage, awardedValueGbp, estimatedValueGbp. Sorted by awarded value
byMonthPer month: month and notices by stage
topNoticeslargestAwards and latestTenders, up to 10 each: noticeId, title, stage, value, currency, publishedAt, noticeUrl, frameworkCallOff
  • Price: profile is $0.10 flat for each buyer profile delivered, plus the run event ($0.005) when at least one profile is returned. From 0.1.21 a buyer that publishes only on Find a Tender gets a profile, charged as one, where earlier releases returned "no notices" free of charge; and a run below 85% of either service's day files makes no profile and charges nothing. If you set a maximum cost per run, profiles are delivered first and the run fee is charged only if what is left of the maximum covers it, so a maximum that covers only the profiles delivers them without the run fee (RUN_SUMMARY.runFeeRefusedByLimit is then true). If the platform restarts a profile run, a buyer's notices may be delivered again inside a new profile; that new profile is charged as one profile. A buyer with no notices in the window gets no row and no profile charge; a run that returns no profile at all is not charged. Ten buyers in one run cost at most $1.005. The run stops before reading if run or profile has no flat price. The notice event is not used in this mode.
  • Run summary: buyers gives the outcome for each buyer by its position in your input: profile, sameAsEarlier (the same notices as an earlier input: one profile, charged once), noNotices, personLike, noName or coverageTooLow (with coverageTooLowFor naming the service below 85%). coverage is repeated there, and ftsDayFiles counts what the Find a Tender day files held that was skipped or refused.

Renewals

"mode": "renewals" lists contracts whose notice states an end date inside a window you choose, one row per contracting process.

{"mode": "renewals", "endWithinMonths": 12, "cpvCodes": ["90"], "regions": ["South East"], "maxItems": 200}

What a row means. endDate is the end date as the notice states it. It is not a confirmed re-tender: an option can be used without a new notice, and a contract can end without one. A contract on both services gives two rows, one for Find a Tender and one for Contracts Finder. With several contracts, awards or lots in the notice, endDate is the latest of them. The mode has no supplier data and no supplier filter: a supplier input is refused. An end date is never worked out from a start date and a duration.

FieldMeaning
source, noticeId, ocid, noticeUrl, publishedAt, title, buyer, regions, value, currency, cpvCodesAs in the notice row, for the notice the row was built from
noticeTypeUK7, UK10, UK6 or UK5 (UK1 to UK4 with includePlanned) for Find a Tender Procurement Act notices; null for Contracts Finder and legacy Find a Tender forms
endDateThe latest end date across the notice's contract, award or lot records (ISO 8601, UTC)
maxExtentDateThe latest maximum extension date across the same records. null means no extension date is stated. Only Find a Tender Procurement Act notices publish it; Contracts Finder has none
hasRenewaltrue if any record says the contract can be renewed; false if records state it and none says true; null if none states it. Only Find a Tender Procurement Act notices publish it
recordsHow many contract, award or lot records the dates came from
confidenceThe kind of evidence behind the row, not a probability: changed (a contract change notice with a period), signed (a contract details notice: the contract has been entered into), awarded (an award notice, before signature: dates can still move), intended (a direct award notice, stated in advance), cf (a Contracts Finder award, which has a period but no extension fields), legacy (an older-regulations Find a Tender notice with a stated end date; from its daily file only the explicit end date is read, never a start date plus a duration, and such a row has no ocid and a midnight publishedAt), planned (a planned period, only with includePlanned)
alertFingerprintSet only in renewals alert mode; null otherwise

Rows come out by endDate ascending, then source and notice id. One row per contracting process: where a process has several notices in the run, the strongest wins (changed, then signed, then awarded, then intended; the newest on a tie). A process with a termination notice in the run is left out and counted in terminatedInRun.

Inputs.

  • End window: endWithinMonths (1 to 24; 12 if you give nothing), or endFrom and endTo (UTC days; endFrom defaults to today, endTo to 12 months after it; at most 24 months). endWithinMonths cannot be combined with endFrom or endTo.
  • matchOn: endDate (default), maxExtentDate or either. either also catches a contract past its first end date but inside an extension. A contract with no maxExtentDate never matches on it.
  • Filters, as in search: cpvCodes, regions, valueMin, valueMax, buyers (case-insensitive part of the buyer name). buyerIds: the buyer's own published reference, matched exactly (case aside), for example GB-CFS-53257. It is a filter only and is not returned.
  • sources: fts, cf (both by default). pcs is refused: Public Contracts Scotland rows carry no end dates.
  • lookbackMonths: how many months of Contracts Finder and Find a Tender day files are read, by publication date (default 12). When Find a Tender is among the sources (it is by default), at most 12 months are read: 1 to 24 are accepted, so saved Tasks keep working, but a value above 12 is cut to 12, and the run says so (lookbackClampedFrom in RUN_SUMMARY, and a sentence in the status message). A run with "sources": ["cf"] reads up to 24 months, as before. This cuts Contracts Finder too: an existing renewals alert or saved Task set to 24 months on the default sources now reads 12 months of Contracts Finder as well, so a contract first published 13 to 24 months ago whose end date later moves into the window is not sent. To keep 24 months of Contracts Finder, use "sources": ["cf"] (Contracts Finder only). A Contracts Finder-only run of 24 months may not finish within the 25-minute limit: unread days then count as missing, and a renewals alert below 85% coverage sends nothing (this release has not measured that case). In a measured run, 12 months of both services' day files took about 17 minutes; 24 months did not finish within the 25-minute limit and fell below 85% coverage.
  • includePlanned: also list the planned periods of Find a Tender planning and tender notices (UK1 to UK4). These are new procurements, not current contracts. Off by default.
  • maxItems: at most 20,000 (1,000 if left out).
  • Refused, with nothing read or charged: keywords, stages, deadlineFrom, publishedFrom, publishedTo, lastDays and noticeIds (they would be ignored and widen the paid query), a supplier input, pcs, an end window over 24 months, and endWithinMonths together with endFrom or endTo.

Coverage. Read it before relying on a list.

  • Find a Tender is read from its daily files over the look-back, as Contracts Finder is, plus yesterday's file once it is out (about 03:05 UTC). Today, and yesterday before its file appears, come from its API (Procurement Act notices only: older-regulations notices wait for the next day's file, below). A day in the look-back whose file is missing, over the size limits or not a valid archive is listed as missing (with the reason in coverage.fts.rejectedDays), not filled from the API. coverage.fts.recentDays says how yesterday and today were read. Contracts ending in the next 12 months were mostly awarded one to four years ago, so a longer look-back finds more of them.
  • Older-regulations Find a Tender notices read from a daily file give an end date only where the notice states one (its DATE_END); one that states only a duration gives no row. Renewals reads these notices from the daily files only, never from the API: today's and yesterday's older-regulations notices are skipped there (counted in sources.fts.ftsLegacyFromApiSkipped) and arrive with the next day's file, so they reach renewals a day later than Procurement Act notices. (Their API record can differ from the file, for example a modification carrying the original contract's end date, which would make a renewals alert send and charge it twice.) Their daily files carry no OCID, so such a row has ocid null and, as publishedAt, the UK publication date at midnight UTC (not the time), and a renewals alert sends and charges it once. So an older-regulations award and its later modification notice are always two separate rows, which 0.1.20 and earlier joined into one process by their OCID when both came from the API. Two versions of one older-regulations notice from the same day have the same publishedAt and the same release number (a Find a Tender release number is its notice id's year), so the first read is kept; Find a Tender gives a change its own notice id, so this concerns a re-publication of the same notice only. A change notice read from a daily file takes its title, and its buyer if it names none, from another notice of the same process read in the run (followUpsCompleted); with none, its title is null (followUpsWithoutTitle).
  • Contracts Finder is read from its daily files over the look-back. Its share is falling: notices under the Procurement Act 2023 go to Find a Tender only, and Contracts Finder carries procurements begun under the earlier regulations. Contracts Finder awards carry no extension dates.
  • Changes and terminations are seen only if published inside the look-back or on the days read after it. A contract that was changed or terminated outside it can still appear with its older dates.
  • Public Contracts Scotland is not read. The list is what the run could read, not a record of every contract.
  • One-off mode below 85% coverage: if fewer than 85% of the look-back's Contracts Finder day files, or fewer than 85% of its Find a Tender day files, could be read, the run still returns rows and charges as usual, and the status message and coverage.cf or coverage.fts say it is incomplete, with the day files read, the expected days, the percentage and how many more days were needed. Contracts Finder's share is over its expected days (working days, plus weekend or bank-holiday days whose file was read; see Buyer profiles); today and yesterday are not part of the Find a Tender share.
  • Day files not read within 25 minutes count as missing, and coverage.cf and coverage.fts list them.

Renewals alert

"mode": "renewalsAlert" takes the renewals inputs plus alertId and sends a contract when it first matches, then again only if it changes.

{"mode": "renewalsAlert", "alertId": "cleaning-south-east", "endWithinMonths": 12, "cpvCodes": ["90"], "regions": ["South East"], "maxItems": 500}
  • Run it weekly. Every run re-reads the whole Contracts Finder look-back, so a daily schedule costs about seven times as much for little change. Schedule it as described under Getting alerts where you work.
  • alertId is yours to choose, as in alert mode (lower-case letters, digits and hyphens, 1 to 40 characters; not a single hyphen). State is kept in a key-value store named contracts-renewals-<alertId> in your own Apify account, apart from a notice alert's store.
  • The first run sends the whole current backlog, up to maxItems. If more match, the rest are sent on later runs (truncatedByMaxItems counts them).
  • A contract is sent again, and charged again, only when its end date, maximum extension date or renewal flag changes. A stronger notice with the same three values is not sent again. The exception is Find a Tender's older-regulations forms: they carry no contracting-process id here, so each such notice is its own row, and a modification notice (F20) of an older-regulations contract is sent and charged as a new row even when its dates are the same as the award's (0.1.20 and earlier joined the two by their OCID).
  • Find a Tender is read from its daily files over the whole look-back. A renewals alert created before this release does not send Find a Tender contracts whose notice was published before its first run of this release, more exactly at or before the end of its last run under the earlier release (counted in ftsBeforeAlertFloor, not sent or charged; the time is ftsFilesSince): its earlier runs could read only Find a Tender's last few days, and sending the rest at once would charge for a backlog it never asked for. Start a new alertId to get them; a new alert receives the whole backlog. Contracts Finder rows are not affected. Because that time is the end of the last earlier run, Find a Tender notices published while that run was going (up to about 25 minutes) are left out too, and so are older-regulations notices published later on that same day (their daily file gives the date, not the time): the alert prefers never charging a contract twice to never missing one.
  • Below 85% of either service's day files the alert sends nothing and charges nothing, not even the run fee: it needs 85% of the look-back's expected Contracts Finder day files (working days, plus weekend or bank-holiday days whose file was read) and 85% of its Find a Tender day files. It leaves its record unchanged, apart from settling an interrupted earlier run. status is incompleteSourceCoverage and the status message says "Incomplete source coverage", with the shortfall in days (for example "Contracts Finder: 210 of 253 expected day files read (83.0%, 85% needed: 6 more days were needed)"). Run it again later.
  • Capacity: the alert's record holds about 27,600 entries. A contract whose dates change uses one entry per version. When it is full, a run sends only what still fits and reports ledgerFull with leftOutLedgerFull (how many were left out); nothing beyond that is sent or charged. If no row can be sent, the run charges nothing. Room returns when an entry has not been seen again for 800 days.
  • A second run for the same alertId that starts while one is active stops before reading and charges nothing (locked).
  • skippedUntokenisable in the run summary: rows skipped because an id could not be turned into a fingerprint; they are counted, not sent, not charged.
  • pendingUnverified: rows an earlier interrupted run had queued whose delivery could not be checked; they are treated as delivered and are not sent or charged again.

Pricing

Pay per event. Platform usage is included, so this is what you pay.

EventChargedPrice on the Free planBronzeSilverGold and above
runOnce per run that read data (profile mode: only when it returns a profile; renewals modes: when Contracts Finder day files were read or the Find a Tender API answered, so a Find a Tender-only run whose API gave no answer pays for its rows but not this fee; renewals alert: not charged when it sends nothing because of incomplete coverage or a full record)$0.005samesamesame
noticeEach row returned (search, pipeline, lookup and alert)$0.005 ($5.00 per 1,000)$0.0045$0.004$0.003
profileEach buyer profile returned (profile mode)$0.10samesamesame
renewalEach row returned (renewals and renewals alert)$0.02 ($20.00 per 1,000)$0.018$0.016$0.012

notice and renewal cost less on higher Apify plans, as in the table; run and profile are the same on every plan. The worked costs below use Free-plan prices.

Runs refused before anything is read cost nothing: a window over 92 days, invalid input, a lookup rate-limited before any answer, or an alert that finds its store locked. "Not found" counts as read, because the source answered.

Notices from Public Contracts Scotland are charged as notice events like the others, and its answers count as data read for the run event.

Renewals and renewals alert: $0.005 for the run plus $0.02 for each row, and the notice event is not used. 20 rows cost $0.405, 1,000 rows $20.005 and 20,000 rows (the most maxItems allows) $400.005. From 0.1.21 Find a Tender is read over the whole look-back (about 12 months by default) instead of about its last 8 days, so a run returns, and charges, more rows than before, up to maxItems. The run fee is charged when the run read Contracts Finder day files or got an answer from the Find a Tender API: a run with "sources": ["fts"] whose API gave no answer charges its rows but not the run fee. A renewals alert charges again for a contract only when its end date, maximum extension date or renewal flag changes, except that a modification notice of a Find a Tender older-regulations contract is its own row and is charged as a new one even with unchanged dates (see Renewals alert). Set maxItems and Apify's maximum-charge setting; the first run of an alert can be large.

Typical costs: looking up one notice costs $0.01; a daily alert returning about 20 new notices costs about $0.105 a run. Cap spend with maxItems and with Apify's maximum-charge setting on the run; if your maximum left rows out, the summary reports chargeLimitReached.

Freshness and coverage

  • Contracts Finder: its daily file first. Contracts Finder publishes one file per day, the day after, at about 02:00 UTC. Days with a file are read from it, with no API call. Today, and any day whose file is missing, comes from its API.
  • Find a Tender: the whole window from its published daily files (yesterday's file appears by about 03:05 UTC; today from its API). In search and alert, each past day is read from Find a Tender's daily file, with no API call; today, and any day whose file is missing, comes from its API. An alert reads all 14 days of its window this way. A day file over the size limits (see Limits) or not a valid archive is not read and not filled from the API: RUN_SUMMARY.sources.fts.missingDays names the day and rejectedDays gives the reason. Notices in the older, pre-Procurement Act forms read from a daily file have no ocid, no publication time (the date at midnight UTC) and no procurementMethod, smeSuitable, awardDate, contractEndDate or lotsCount. Follow-up notices (contract changes, terminations and performance) take their title and buyer from an earlier notice of the same procurement read in the same run, and otherwise have none (followUpsWithoutTitle). Renewals and buyer profiles read Find a Tender's daily files too (below).
  • When the source limits the run, the run still finishes from what it has read. RUN_SUMMARY.sources.<source>.staleSince is the first day not covered, and missingDays lists them. An alert picks those notices up on its next run.
  • Later versions. A notice first published inside your window can carry a later publishedAt if a newer version has since been published; the row is returned and counted in laterVersions.
  • Public Contracts Scotland has no bulk files. It is read as month lists: one list per notice type per month (21 types), so a search reads every notice type for each month the window touches. A window spanning 2 months is 42 lists and one spanning 4 months is 84. Large lists are slow; when measured in October 2026 from the developer's machine, one month's 21 lists took about 3.5 minutes of response time plus about 1 minute of pacing, so a search that includes pcs takes minutes longer.
  • A past month's list can fail on the first request. The Actor tries each list three times, 30 seconds apart. A list that still fails is named in RUN_SUMMARY.sources.pcs.missingLists (for example 2026-09:102, month and notice type), never silently dropped, and the run finishes from everything else. The same happens if the service cannot be reached.
  • Renewals reads the Contracts Finder and Find a Tender daily files over its look-back (12 months by default), the way profile mode does, and Find a Tender's API only for today and for yesterday until its file is out. A look-back day whose file cannot be read is listed as missing, not filled from the API. The Contracts Finder share of upcoming expiries falls as new notices go to Find a Tender only. Changes and terminations are seen only if published inside what the run read.
  • Buyer profiles read the Contracts Finder and Find a Tender daily files over their 365 days, with no API call.

Run summary

Every run writes a RUN_SUMMARY record to its key-value store; an alert run also writes ALERT_DIGEST there (see Digest, under Alert). Main fields:

FieldMeaning
statusok, refused (input rejected; reason says why; the run ends as succeeded and nothing is charged; a pricing set up wrongly on the Actor also shows refused, but the run fails), locked (alert already running) or failed (the run ends FAILED: a check that could not be made, or a run the platform restarted after it had charged whose input was then refused; the status message says what was charged)
pushedRows returned
readDataWhether the run read any data
runChargedWhether the run event was charged; on a restarted run, whether an earlier start is treated as having charged it (so it is never charged twice)
chargeLimitReachedtrue only when your maximum cost per run left rows out
runFeeRefusedByLimitPresent and true when the run fee did not fit your maximum and was not charged
restartedWhether the run found signs that the platform had restarted it. A restarted run is designed to skip the run charge if this run already made it. In search and lookup it leaves out the notices already in this run's dataset (alreadyStored counts them), and a restarted search stops at maxItems in total (cutAfterRestart counts the rest). If you set a maximum cost per run, the run is designed to keep within it across a restart
sources.fts, sources.cfPer service: bulkDays, apiDays, missingDays, staleSince, noticesRead, and rejectedDays (day files refused by a size or archive limit, with the reason) when there are any. In alert mode these sit under search.sources
sources.pcsPublic Contracts Scotland: listsRead and missingLists (month lists that could not be read, as YYYY-MM:type). In alert mode this sits under search.sources
apiAPI use: requests, answers, budget, refusals, waitedSeconds, stopped, retryAfter (seconds)
pcsApiThe same kind of API use figures, for Public Contracts Scotland, which has its own client and pacing
bulkBytes, bulkErrors, bulkRetriesDaily files: bytes read; bulkErrors, the requests that ended with neither a file nor a "no file for that day" answer (403 or 404): a network error, a server error (5xx) or a "too many requests" answer (429), counted after the retry where there is one, and any other answer such as 400; and bulkRetries, present when a request was tried a second time, about 2 seconds after a network error, a 5xx or a 429. Only buyer profiles and the renewals modes retry, because they read their daily files within a 25-minute limit; search and alert do not. A 403, a 404, any other 4xx and a file over the size limit are never retried
retryAfterLookup only: seconds, until, ids still to look up
notFoundLookup only: ids that returned nothing
laterVersionsRows whose publishedAt is after your window
followUpsCompleted, followUpsWithoutTitleFollow-up notices that borrowed a title and buyer from another row with the same OCID in the run, and those that found none
matched, alreadySentAlert: notices in the 14-day window that match your filters, and those not sent because an earlier run of this alertId already sent them or recorded them as seen
ocidsAlert with ocids only: requested (how many different OCIDs were given) and matchedProcesses (how many of them had at least one matching notice in the 14-day window, sent now or earlier). The OCIDs themselves are not listed
seenWithoutChargeAlert, first run only: matching notices older than firstRunLookbackDays, recorded as seen without charge and never sent
truncatedByMaxItemsAlert: new notices beyond maxItems, sent on later runs
expected, noFutureNoticeDate, outsideExpectedWindowPipeline only: the expectedFrom and expectedTo you gave (from, to), and, when either was given, the matching notices left out because they state no expected date or one outside those days. mode is pipeline

Renewals and renewals alert add these (in the alert, the read's own summary sits under renewals):

FieldMeaning
statusAlso incompleteSourceCoverage (renewals alert below 85% of the look-back's Contracts Finder day files or below 85% of its Find a Tender day files: nothing sent or charged; reason names the service, the day files read of the expected days, the percentage and how many more days were needed), and lockLost (the alert's lock expired and another run took it: this run sent nothing)
endWindowfrom, to (UTC days) and matchOn
includePlannedWhether planned periods were included
lookbackClampedFromThe lookbackMonths you asked for, when it was over 12 and cut to 12 (at most 12 months are read when Find a Tender is among the sources); absent when nothing was cut. In the renewals alert it is also at the top level
coverageRead it first. cf and fts: from, to, lookbackMonths, the day-file counts as in profile mode (for cf also daysExpected and quietDaysWithoutFile; its percentRead is over daysExpected), percentRead, minimumPercent (85), incomplete. fts also has route (files+api), rejectedDays (a file refused, with the reason), recentDays (yesterday and today: file, api or missing), text (the day files read and how yesterday and today were read) and counts of what its files held that was skipped. pcs: text saying it is not included. A service not asked for says "not requested"
processes, matched, returnedContracting processes found, those matching your filters and window, and rows returned
terminatedInRunProcesses left out because a termination notice for them was read in the run
supersededNotices, olderVersionsNotices set aside because a stronger notice for the same process, or a newer version of the same notice, was read
ftsDaysNotReachedFind a Tender days not tried because the API stopped or the request budget ended
ftsApiDaysPastDeadlineFind a Tender days with no file yet (today, yesterday) not asked of the API because less than 130 seconds of the 25 minutes were left; they are missing days
sources.fts.ftsLegalBasisUnknownFind a Tender notices from the API whose legal basis is neither the Procurement Act nor an EU directive: no row from the API, so it cannot be identified differently from its daily file; the next run reads it from that file
sources.fts.ftsLegacyFromApiSkippedFind a Tender older-regulations notices from the API (today's and yesterday's), not read there: renewals reads them from their daily file only, so they arrive with the next day's file
ftsBeforeAlertFloor, ftsFilesSinceRenewals alert: Find a Tender rows left out (not sent or charged) because their notice was published at or before the alert's ftsFilesSince, the end of its last run before this release (for a new alert, a time before anything it can read)
followUpsCompleted, followUpsWithoutTitleFind a Tender change notices read from a daily file that took their title from another notice of the same process in the run, or found none
truncatedByMaxItemsMatches beyond maxItems: not returned (renewals), or sent on later runs (renewals alert)
alreadyStored, cutAfterRestartAfter a platform restart: rows already in this run's dataset and left out, and rows left out because maxItems was already reached in total
ledgerFull, leftOutLedgerFullRenewals alert: the alert's record is full; leftOutLedgerFull rows were left out, not sent or charged
emitted, alreadySentRenewals alert: rows sent this run, and matched rows not sent because they were already sent with the same dates and flag
skippedUntokenisableRenewals alert: rows skipped because an id could not be made into a fingerprint
pendingUnverifiedRenewals alert: rows queued by an interrupted earlier run whose delivery could not be checked; treated as delivered
pendingRecovered, ledgerMigratedRenewals alert: what was settled from an interrupted earlier run (committed, resend), and the one-time move of an older record to the current version

Data and licence

  • Contracts Finder's notice data is published under the Open Government Licence v3.0. Find a Tender's notice data, including its daily files, is published under the Open Government Licence (confirmed by the Find a Tender operator on 28 Oct 2026, in answer to a question about its daily files: all content on Find a Tender falls under the OGL); the packages its API returns name Open Government Licence v3.0 in their license field. Public Contracts Scotland data is published by the Scottish Government (Scottish Procurement and Commercial Directorate) under the same licence: the packages its API returns carry the licence as Open Government Licence v3.0 in their license field. The licence does not extend to personal data. Please keep this attribution: Contains public sector information licensed under the Open Government Licence v3.0.
  • Rows have no contact, address, identifier or description fields. suppliers is reserved for organisation supplier names, pending a review; it is null in this version and no supplier name is read. Titles and buyer names are copied as published, and a title can still contain a name. In titles, email addresses, UK phone numbers and a person's name written straight after "contact", "speak to", "email", "FAO", "attention of" or "write to" are replaced with [redacted]. That redaction works by pattern, so a name written some other way is not caught.
  • Sources: Find a Tender, Contracts Finder and Public Contracts Scotland only. No proxies are used.
  • This Actor is not affiliated with or endorsed by the operators of Find a Tender, Contracts Finder or Public Contracts Scotland.
  • Removal and objection: email info@yappman.com with the notice id or link from Find a Tender or Contracts Finder; if you don't have it, tell us the product and the name as it appears. We will reply within one month.

Limits

  • Search window: 31 days by default, 92 days at most.
  • Lookup: 20 ids per run.
  • Renewals: end window at most 24 months; lookbackMonths 1 to 24 accepted, at most 12 read when Find a Tender is among the sources (a larger value is cut to 12 and the run says so; Contracts Finder alone reads up to 24); maxItems at most 20,000; Contracts Finder and Find a Tender day files not read within 25 minutes count as missing; at most 733 Find a Tender day files a run (a safety cap; a 12-month run reads about 366).
  • Renewals alert: run weekly; the alert's record holds about 27,600 entries, kept until not seen again for 800 days.
  • Alert: 14-day window; firstRunLookbackDays 1 to 14.
  • maxItems: prefilled at 3, 1,000 when left out, maximum 100,000 (20,000 in the renewals modes). A search reads only the days it needs: once it has maxItems notices newer than a day still to be fetched from an API, that day and older ones are skipped, because they could not appear in the newest-first result.
  • Scottish duplicates: an above-threshold Scottish notice can appear as both a pcs row and an fts row. That is two rows and two charges; join them with reconcileKey.
  • pcs dates: publishedAt is almost always a date only (midnight UTC), so Public Contracts Scotland rows are day-precise, not time-precise.
  • API pacing: Find a Tender and Contracts Finder share one rate limiter, so the Actor makes at most one API request every 15 seconds, across both. Public Contracts Scotland is a different host with its own pacing: one request every 3 seconds, and a refusal from one client does not stop the other.
  • Public Contracts Scotland request budget: months touched × 21, plus 10 (a 92-day window touches up to 5 months). An alert's 14-day window touches 1 or 2 months, and all of its month lists are read on every run. Reading Public Contracts Scotland stops after 40 minutes in any run; lists not read by then are named in missingLists.
  • Public Contracts Scotland's API is currently not working for anyone (PCS support confirmed on 28 Oct 2026; no fix date), so pcs returns nothing and is not charged. Above-threshold notices from Scottish bodies also appear on Find a Tender, which this Actor reads; Scotland-only notices below that threshold are unavailable while PCS is down. A run that includes pcs stops asking it after usually about a minute (a few minutes at most if the server accepts the connection but never replies) (the first list's 3 tries, 30 seconds apart), reports the lists it could not read in missingLists, and is not charged for Public Contracts Scotland; a run that reads nothing is not charged.
  • Request budget per run: lookup makes one request per id (20 ids takes about 5 minutes). Searches and alerts have a fixed cap of 12 API requests a run (today's pages for both services, or a missing day; about 3 minutes at the paced rate). Renewals has the same 12 (Find a Tender's pages for today, and for yesterday until its file is out). When the cap is reached the run ends normally and reports the days it did not cover.
  • Find a Tender daily files (search, alert, renewals and profiles): at most 25 MB compressed, 50 MB uncompressed and 5,000 notices per file; a file over a limit is reported as a missing day, with the reason in rejectedDays. A search or alert reads at most 184 day files (two services over the longest window, 92 days).
  • The input takes no URLs, headers or query strings: the Actor builds every request itself.

What changed

  • 0.1.21 (4 Nov 2026): Find a Tender's daily files in renewals and buyer profiles, and pipeline mode.
    • Renewals, renewals alerts and buyer profiles read Find a Tender from its daily files over the whole look-back (12 months; 365 days for profiles), not only its last few days. When Find a Tender is among the sources, renewals now reads at most 12 months: a lookbackMonths of 13 to 24 is still accepted, so saved Tasks keep working, but is cut to 12, and the run says so (lookbackClampedFrom). Contracts Finder alone still reads up to 24. This cuts Contracts Finder too: an existing renewals alert or saved Task set to 24 months on the default sources now reads 12 months of Contracts Finder as well, so a contract first published 13 to 24 months ago whose end date later moves into the window is not sent. To keep 24 months of Contracts Finder, use "sources": ["cf"] (Contracts Finder only). A Contracts Finder-only run of 24 months may not finish within the 25-minute limit: unread days then count as missing, and a renewals alert below 85% coverage sends nothing (this release has not measured that case). Renewals reads Find a Tender's API only for today, and for yesterday until its file is out, and only for Procurement Act notices: older-regulations notices come from the next day's file. One-off renewals runs now return about 12 months of Find a Tender rows instead of about 8 days, charged at $0.02 each up to maxItems. A buyer that publishes only on Find a Tender now gets a charged profile ($0.10) instead of a free "no notices".
    • Profiles and renewals need 85% of each service's day files: below it no profile is made (nothing charged), a renewals alert sends and charges nothing, and a one-off renewals run says it is incomplete.
    • A renewals alert created before 0.1.21 does not send Find a Tender contracts published before its first 0.1.21 run (ftsBeforeAlertFloor); start a new alertId to get them. Older-regulations rows carry no ocid, so such an award and its modification are separate rows, each charged.
    • New mode pipeline: planning notices sorted by futureNoticeDate (soonest first), with expectedFrom and expectedTo to keep the expected tender dates you want; see Pipeline. Two new fields on each notice row: noticeType (the Find a Tender Procurement Act form) and futureNoticeDate. Search, alert, renewals and renewals alert refuse expectedFrom and expectedTo.
  • 0.1.20 (4 Nov 2026): Find a Tender, two days' notices were missing from searches. Find a Tender re-published two of its daily files with their notices inside a folder: the file for 28 October 2026, re-published around 2 to 3 November, and the file for one day between 4 and 14 October. Our reader expected the notices at the top of the file, so from each re-publication until 4 November it skipped them. Searches that covered either day returned no Find a Tender notices from that day's file; the run summary counted them in sources.fts.skippedEntries. Contracts Finder and Public Contracts Scotland were not affected, and nothing was charged for notices that were not returned.
    • Alerts had already received both days' notices before the files were re-published, so they missed nothing and do not receive them again. An alert started after a re-publication (for 28 October: after about 06:45 UTC on 3 November) receives that day's matching notices on its next run, as a late delivery.
    • From 0.1.20 the notices are read wherever they sit in the file. If you searched either day during that period, run the search again to get the full results.

About

From Yappman Data, a trading name of Abley-Yapp Consulting Limited. Contact: info@yappman.com.