ted-tender-change-monitor
Pricing
from $2.00 / 1,000 results
ted-tender-change-monitor
Monitor TED public procurement notices, normalize tender data, and detect NEW, UPDATED, and CORRIGENDUM changes.
Pricing
from $2.00 / 1,000 results
Rating
0.0
(0)
Developer
DataDelta
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
3 days ago
Last modified
Categories
Share
TED Tender Change Monitor
Monitors official EU TED (Tenders Electronic Daily) procurement notices and reports what changed since the previous run.
Instead of re-emitting a raw tender feed, this Actor answers one question: which notices are new, which were updated, and which are corrections?
Source: TED Search API v3 —
POST https://api.ted.europa.eu/v3/notices/search. The API is official, public and keyless. No credential, account or proxy is used.
What it does
- Queries TED for a bounded publication-date window.
- Projects a fixed set of organisation-level fields.
- Computes a deterministic SHA-256 fingerprint per notice.
- Compares against a stored snapshot from earlier runs.
- Emits one dataset row per changed notice, tagged
NEW,UPDATEDorCORRIGENDUM.
Output
One row per emitted notice:
| Field | Meaning |
|---|---|
deltaStatus | NEW, UPDATED, CORRIGENDUM or UNCHANGED |
publicationNumber | TED publication number (stable notice identifier) |
publicationDate | Publication date |
noticeType | TED notice type |
formType | TED form type (corrections are detected from this) |
procedureType | Procedure type |
buyerName | Contracting authority (organisation-level) |
buyerCountry | Buyer country code |
legalBasis | Legal basis |
noticeIdentifier | Notice identifier |
tedNoticeUrl | Link to the notice on TED |
contentFingerprint | SHA-256 over the sorted organisation-level fields, so the change decision can be verified independently |
firstSeenAt / lastSeenAt | When the notice was first and most recently observed |
changeDetectedAt | When the current state was detected |
sourceAttribution | Required attribution for reused TED content |
The auto-attached TED links block is deliberately dropped: it is not stable, so including it would produce false UPDATED results.
Change semantics
Precedence is fixed and deterministic:
| Situation | State |
|---|---|
| Never seen before, and it is a correction | CORRIGENDUM |
| Never seen before, otherwise | NEW |
| Seen before and content changed, and it is a correction | CORRIGENDUM |
| Seen before and content changed, otherwise | UPDATED |
| Seen before and content identical | UNCHANGED |
A correction takes precedence over NEW/UPDATED because that is the more useful fact about it.
Input
Every input is optional. With no input the Actor monitors the last 7 days, which keeps a default run small and cheap.
| Input | Default | Notes |
|---|---|---|
dateFrom | 7 days before dateTo | YYYY-MM-DD |
dateTo | today (UTC) | YYYY-MM-DD |
countries | all | Buyer country codes, e.g. DEU, FRA, LTU |
noticeTypes | all | TED notice-type codes |
includeUnchanged | false | See billing below |
maxNotices | 200 | Bounds runtime and platform cost (hard ceiling 5000) |
snapshotKey | default | Namespace for the stored snapshot, to keep independent pipelines apart |
resetSnapshot | false | Discards the snapshot first, so everything is reported again |
The maximum publication-date window is 366 days.
Billing
You are charged per dataset item, and this Actor writes exactly one item per emitted notice.
With includeUnchanged: false (the default) only NEW, UPDATED and CORRIGENDUM notices are written, so you are charged only for results that carry information. An unchanged re-run produces no rows and no charge.
This Actor defines no custom charge events and never calls Actor.charge(). Monetisation uses only the platform's synthetic per-item event.
resetSnapshot: truedeliberately makes previously reported notices billable again. Use it only when you intend to re-read a window from scratch.
Personal data
Only organisation-level fields are requested. The field list is an allowlist, and it is not user-configurable: because contact fields are never requested, TED never returns them and they cannot reach the output. The TED field enum does contain contact fields (for example organisation-email-tenderer, touchpoint-fax-buyer, ubo-email); none of them are used, and a start-up guard refuses to run if a personal-data field name is ever added to the configuration.
As a second line of defence, every projected value is scanned before output and any email address — or phone-shaped value in a field where digit runs are not legitimate — is redacted and reported in the run summary. Fields such as legalBasis are exempt from phone-shaped matching so that a value like 32014L0024 is preserved.
Resilience
TED explicitly excludes the field list from its API versioning, so a field name can be added, removed or renamed inside v3 without a version change. This Actor therefore validates its field list against the live API at run time and fails soft: if a field is rejected, the offending name is identified, dropped, and the run continues with the remaining fields. Country and notice-type filters are always re-applied locally, so results stay correct even when the query has to be degraded to a plain date range.
Any degradation is recorded in the run's SUMMARY record rather than being silently ignored.
Attribution
TED procurement notices may be reused commercially. Editorial content is licensed CC BY 4.0, which requires credit and an indication of changes — deltaStatus is that indication, and sourceAttribution carries the credit on every row.
Development
The rules live in dependency-free modules (src/normalize.py, src/ted_client.py, src/snapshot.py, src/pipeline.py, src/runparams.py, src/filtering.py). Only src/main.py and src/http_transport.py touch the Apify SDK and HTTP.
$python -m pytest tests -q
The test suite runs fully offline: the HTTP transport is injected, so no network access or credential is required.
Known limitations
- Country and notice-type query predicates are not verified against the live TED API. They are attempted first and degraded away on HTTP 400; the filter is then applied locally, which is correct but may fetch more notices than strictly necessary.
- The format of TED's
buyer-countryvalues is not verified, so an unrecognised code yields no matches rather than an error. - Corrigendum detection relies on returned
form-type/notice-typevalues, not on a TED query filter: the documentedform-type=corrigendumfilter returned HTTP 400 when last tested. UNCHANGEDnotices are still recorded in the snapshot so they cannot age out and be re-billed asNEW. The snapshot is pruned after 180 days.- The Actor reports a failed run if TED returns no notices and reported errors, rather than reporting a clean empty run. A silent "success" would be indistinguishable from "nothing matched" and would hide a broken integration.