# Changelog of EU & UK Public Tenders Search: TED + Find a Tender (`humble-echidna/eu-ted-tenders`) Actor

- **URL**: https://apify.com/humble-echidna/eu-ted-tenders/changelog.md
- **Full Actor documentation**: https://apify.com/humble-echidna/eu-ted-tenders.md

## Changelog

Versions follow MAJOR.MINOR.PATCH (`src/version.py`); Apify shows MAJOR.MINOR from `.actor/actor.json`.
Every run logs its version and records it in the `RUN_STATS` key-value record.

### 1.1.1 (2026-09-25)

- Input field descriptions rewritten for AI agents (Apify's MCP server shows agents only the description, not the
  form): each now states its default, its allowed range, the value of each option and how it combines with other
  fields. No change to field names, types, defaults or behaviour.
- `queries` says that a left-out `queries` takes its default (`software`), so a CPV- or buyer-only search passes
  `"queries": []`; the README's MCP answer says the same.

### 1.1.0 (2026-09-25)

**UK public tenders from Find a Tender, next to TED.** New title: "EU & UK Public Tenders Search: TED + Find a Tender".

- New input **Sources**: `ted` (EU) and/or `uk` (Find a Tender); the console pre-fills both. Every filter applies to both; a
  buyer-country filter without `GB`/`UK` skips Find a Tender without a request.
- UK notices come in the same record as TED's, plus a new `source` field on every record (`ted` or `find-a-tender`)
  and ids `fts:<notice ID>` so they never collide with TED's publication numbers. Mapping (OCDS 1.1 release ->
  record): `tender.title` (title and titleOriginal), `language` (originalLanguage), first release tag (noticeType)
  and its category (tender -> competition, award -> award, planning -> prior, contractAmendment -> modification,
  the rest null), `procurementMethodDetails` (procedureType), `mainProcurementCategory` (goods -> supplies),
  `tenderPeriod.endDate` (deadline), `expressionOfInterestDeadline` (participationRequestDeadline: the UK OCDS
  extension defines it as "also called a request to participate"), the buyer party's name, country, locality and
  website, CPV codes from the tender, award and contract items, ITL regions from their delivery addresses,
  `tender.value` net of VAT (estimatedValue), the sum of the awards in one currency (awardedValue), the notice page
  and its PDF. Contact points, suppliers and bids are never read; descriptions are scrubbed of e-mail addresses and
  phone numbers as TED's are.
- Find a Tender's API has no keyword search: it lists notices by day. UK searches read day windows from the newest
  back (all pages, by the API's cursor link), filter them here with the same keyword syntax as TED's (whole words,
  phrases, OR, NOT, \*), CPV prefixes, buyer name, notice category, open deadlines and publication dates, and stop at
  "Max notices per search" matches or 14 days back. Day windows are fetched once per run and shared by all search
  lines.
- Paced to Find a Tender's measured limit: one request every 10 seconds, one at a time (about a day of UK notices
  per minute). A 429 asks for 120 s, more than the shared client waits, so it fails that run's UK searches with the
  reason; TED is unaffected.
- Sources default to TED only when left out of the input (the console pre-fills both): a UK search takes minutes,
  and Apify's daily default-input test allows 5.
- "Only new notices" is remembered per source: TED keeps the memory keys 1.0 wrote, Find a Tender has its own, so
  adding or dropping a source never resets the other. RUN\_STATS lists UK searches as `<line> (UK)`, with the days
  searched.
- Failure isolation per source: Find a Tender down, throttling or changing format fails only the UK searches.
- "Max notices per search" is now per source (the pre-filled input returns up to 20 + 20).

Source checked before building (2026-09-25):

- API for machines: https://www.find-tender.service.gov.uk/Developer/Documentation, "Data outputs": "You can
  download notices in Open Contracting Data Standard (OCDS) JSON format using our API"; the endpoint is documented at
  https://www.find-tender.service.gov.uk/apidocumentation/1.0/GET-ocdsReleasePackages (limit up to 100, cursor,
  updatedFrom/updatedTo, stages). Keyless: 200 with our User-Agent and no key; the "Authentication is required"
  section of https://www.find-tender.service.gov.uk/apidocumentation is about the eSender API for submitting and
  searching one's own notices. /robots.txt: 404 (allow all). The `stages` filter was left unused: on 2026-09-24 it
  returned 2 tender releases where the day had 58.
- Licence: the same page: "Notice data is available under the Open Government Licence"; every release package
  carries `license: http://www.nationalarchives.gov.uk/doc/open-government-licence/version/3/`. OGL v3.0: "You are
  free to: copy, publish, distribute and transmit the Information; adapt the Information; exploit the Information
  commercially and non-commercially", on condition of the attribution "Contains public sector information licensed
  under the Open Government Licence v3.0." (in the README); exempt: "personal data in the Information" (hence no
  contact points); "Non-endorsement" (the README says it isn't affiliated).
- Terms (https://www.find-tender.service.gov.uk/Home/TermsAndConditions, last updated 24 February 2025, read
  2026-09-25): "You can reproduce content published on Find a Tender under the OGL as long as you follow the
  licence's conditions." and "We make most of the content on Find a Tender available through feeds for other
  websites and applications to use." Prohibited: "Monitoring or crawling of a System that impairs or disrupts the
  System being monitored or crawled" and "Avoiding system restrictions" (hence the pacing below and no retries around
  the limit). "You must contact us for permission if you want to ... charge your website's users to click on a link
  to any page on Find a Tender": not what this does (it charges per notice returned; the links are free to follow).
- Limits: none published; the API enforces one: HTTP 429 "Rate limit of 12 exceeded. Please retry after 120
  seconds." with Retry-After: 120. Measured 2026-09-25: requests about 7 s apart were refused at the 17th, so the
  window is longer than a minute; 12 per 2 minutes is the reading used.
- Demand: ~51 users/30 days across 40 UK tender actors (RESEARCH-candidates.md, "uk-tenders"), too small alone, so
  folded into this actor. Not added: Contracts Finder (its API docs state no licence).

### 1.0.0 (2026-09-24)

First release.

- Searches EU public procurement notices on TED (Tenders Electronic Daily) through its official, keyless Search
  API (`POST https://api.ted.europa.eu/v3/notices/search`), documented for reusers at
  https://docs.ted.europa.eu/api/latest/search.html.
- Keywords (one search per line, full text, phrases in quotes, AND / OR / NOT, \* wildcard), or filters alone.
- Filters: CPV codes (a broad code includes every code below it), buyer countries (two- or three-letter codes),
  buyer name, notice types (open calls for tenders, award notices, prior information, modifications), published
  from/to (a date or a number of days back), and only tenders still open for bids.
- Normalized notice records: TED's translated title in any of the 24 EU languages plus the buyer's own title,
  notice type and category, procedure, contract nature, publication date, earliest tender deadline and deadline for
  requests to participate, buyer name, country, city and website, CPV codes, place of performance (NUTS and
  countries), estimated and awarded value with currency, the buyer's description, and links to the official
  notice page, PDF and XML.
- No personal contact data: none of TED's contact-person, e-mail, phone, fax or winner fields are requested, and
  e-mail addresses and phone numbers are removed from the free text.
- "Only new notices": each search (keyword line + filter set) remembers the notices it returned, in the user's own
  account, for scheduled tender alerts. Relative dates ("7 days") keep the same memory from run to run.
- Paced to stay under TED's fair usage policy (700 requests a minute; this actor makes at most 600, 3 at a time),
  up to TED's 15,000 notices per search; a notice repeated across pages (a new journal edition landing mid-search)
  is returned once.
- Charged per notice returned, through Apify's standard `apify-default-dataset-item` event.
- "Max results per run" input, and the maximum cost per run is honoured: once either is covered, searches still
  being fetched are cancelled and the rest are skipped (listed as `queriesSkipped` in `RUN_STATS`).
- Failure isolation: a failing search (including one TED rejects) only affects itself.

Sources checked before building (2026-09-24):

- API for machines: "The Search API does not require a key" (https://docs.ted.europa.eu/api/latest/index.html);
  "this API is primarily targeted at data reusers and does not require authentication"
  (https://docs.ted.europa.eu/api/latest/search.html). api.ted.europa.eu has no robots.txt (404: allow all).
- Terms (https://ted.europa.eu/en/legal-notice, read 2026-09-24): "The European Commission's reuse policy is
  implemented by the Commission Decision of 12 December 2011 on the reuse of Commission documents. Unless otherwise
  noted, the procurement notices published in the Supplement to the Official Journal of the European Union can be
  freely reused, for commercial or non-commercial purposes." Editorial content is CC BY 4.0 (credit given in the
  README), metadata CC0. The same notice warns that content depicting identifiable private individuals may need
  additional rights, hence the personal-data rules above.
- Limits: fair usage policy (https://ted.europa.eu/en/news/fair-usage-policy-on-ted): 700 HTTP requests a minute,
  600 notice views/downloads per IP in under 6 minutes, 3 concurrent bulk-package downloads. Search API (OpenAPI,
  https://api.ted.europa.eu/api-v3.yaml): 15,000 notices per query in page mode, 250 notices and 10,000 fields per
  page.
