EU Procurement Award Intelligence avatar

EU Procurement Award Intelligence

Pricing

Pay per usage

Go to Apify Store
EU Procurement Award Intelligence

EU Procurement Award Intelligence

Track normalized TED result notices and notice-level buyer, winner, date, identifier, and value sets.

Pricing

Pay per usage

Rating

0.0

(0)

Developer

Atlas

Atlas

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

9 days ago

Last modified

Categories

Share

Turn official EU Tenders Electronic Daily (TED) result notices into a normalized, change-tracked stream of notice-level buyer and winner sets, result-lot identifiers, dates, and value sets.

This Actor is built for bid-intelligence teams, suppliers, procurement consultancies, and market analysts who need to answer questions such as:

  • Which organizations are winning contracts from a target buyer or country?
  • Which suppliers are active in a CPV category?
  • What changed in a recently published award?
  • Which result notices and values should be loaded into a CRM, warehouse, competitor dashboard, or analyst queue?

The reason to pay is not access to public TED data. It is the production workflow around that data: safe filtering, bounded exhaustive traversal, deterministic normalization, ambiguity-aware relationship modeling, stable IDs, deduplication, edit detection, replay-safe incremental state, rate limits, retry handling, and concurrency protection.

Output

Each dataset row is one normalized result notice with output schemaVersion 1.0.0:

  • stable relationshipId (SHA-256) derived only from the TED publication number, so it survives notice versions and content corrections;
  • contentDigest, which changes when normalized source content changes and is separate from logical identity;
  • TED noticeId, noticeVersion, canonical notice URL, title, language, form/notice type, and publication date;
  • award dates from the official winner-decision-date and contract-conclusion-date fields;
  • buyer names, identifiers, and countries;
  • winning supplier names, identifiers, and countries;
  • CPV codes and buyer/supplier/performance geography;
  • result-lot identifiers with stable awardId values derived only from publication number and result-lot ID;
  • separate notice-level sets for lot titles, notice/tender lot identifiers, contract/tender identifiers, and contract-to-tender IDs;
  • notice-result, lot-result, and tender amount/currency sets without amount-to-currency or value-to-lot joins;
  • procedure type and identifier;
  • associationCompleteness and associationWarnings;
  • explainable relevance score/signals;
  • changeType, changedFields, fetchedAt, and explicit TED attribution.

Logical IDs are deterministic, source-namespaced, and independent of output schema version, notice version, and mutable content. They are not identifiers issued by TED. The original TED notice, lot, contract, tender, organization, and procedure identifiers remain separately available.

Source-shape safety

The Actor uses only fields listed in the official TED Search Field List and verified against the anonymous live v3 endpoint.

TED Search API results flatten nested eForms structures. Arrays that look related may have unequal cardinalities. A live result notice can expose four lot results and four winner-name occurrences while returning only three unique winner identifiers. Treating all arrays as positional would invent false company/lot relationships.

This Actor therefore:

  • emits buyers and winning suppliers as separate notice-level sets;
  • never assigns an identifier or country to an individual organization by array position;
  • creates lots entries only from stable result-lot-identifier values, and each entry contains only lotId plus its logical awardId;
  • never uses equal cardinality or source array order to attach titles, contract/tender IDs, dates, amounts, or currencies to a lot or one another;
  • preserves those flattened fields as explicit notice-level entity sets;
  • always reports associationCompleteness: "notice-level-only" and explains the non-association in associationWarnings.

This is intentionally conservative. It is safer for competitive intelligence than a plausible-looking but fabricated join.

Run modes

full emits every matching relationship as snapshot.

incremental emits only new and updated relationships. It overlaps the last completed publication watermark (three days by default) so later TED edits are detected.

diff tracks the same durable state but also emits unchanged relationships for reconciliation and warehouse snapshots.

The change digest is keyed by TED notice ID. A changed winner, buyer, value set, award date, lot identifier, procedure, URL, or association warning is reported as an update. changedFields identifies the changed top-level normalized fields. The row's stable relationshipId remains unchanged while contentDigest changes.

Safe filtering

Supported business filters include:

  • notice-title/buyer keywords;
  • winner/supplier keywords;
  • CPV prefixes;
  • buyer, winner, and performance countries;
  • inclusive publication and award-date ranges, with one award date required to satisfy both bounds;
  • minimum contract value in one exact currency;
  • TED result notice types;
  • optional inclusion of result notices that expose no winner name;
  • preferred output language with English and deterministic fallback.

Keyword groups use OR semantics; different filter groups combine with AND. minimumValue and minimumValueCurrency must be supplied together. No FX conversion is performed. Because TED values are flattened, the value filter is intentionally strict: only a scope containing exactly one amount and exactly one currency can satisfy it.

User strings are never inserted into TED expert-query syntax. The server-side query contains only strictly validated calendar dates plus the fixed, live-verified form-type = result predicate. All variable business filtering occurs against normalized rows inside the Actor.

An optional relevance profile can add or subtract weights across title, buyer, winner, cpv, country, place, and procedure. Every contribution is emitted in relevance.signals.

Example input

{
"mode": "incremental",
"winnerKeywords": ["atos", "capgemini"],
"cpvPrefixes": ["72"],
"buyerCountries": ["DEU", "FRA", "BEL"],
"winnerCountries": ["FRA", "DEU"],
"publicationFrom": "2026-01-01",
"awardDateFrom": "2025-12-01",
"minimumValue": 250000,
"minimumValueCurrency": "EUR",
"noticeTypes": ["can-standard"],
"language": "eng",
"maxItems": 500,
"relevance": {
"include": [
{ "term": "cloud", "fields": ["title"], "weight": 15 },
{ "term": "72000000", "fields": ["cpv"], "weight": 8 }
],
"exclude": [],
"minimumScore": 0,
"requireIncludeMatch": false
}
}

Traversal, caps, and resume

The Actor uses TED ITERATION mode, which the official documentation describes as unbounded traversal with a maximum of 250 notices per page and 10,000 requested fields per page.

maxItems counts matched notices, not source rows. Sparse searches continue behind rejected result notices. Cost and forward progress are independently bounded by maxPages and maxScannedItems. Duplicate-only pages and rows revisited after an expired token do not consume those forward budgets; replay has separate hard page/row ceilings to stop malformed endless loops.

If a cap lands inside a page, durable state records the exact query window, run mode, original page size, inbound opaque token, row offset, and compact source ledger. The next run completes that same window even if the date, page size, or operational caps changed. Expired or invalid iteration tokens replay the same window from its start; the ledger prevents already handled rows from hiding an unprocessed row. Switching an unfinished incremental cursor to diff restarts that window without the incremental source ledger so previously handled rows are emitted as unchanged. Repeated tokens, replay ceilings, oversized pages, conflicting duplicate notice versions, malformed envelopes, and timedOut: true fail closed.

HTTP 429, 5xx, and network errors receive bounded exponential-backoff retries. Requests are sequential and conservatively rate-limited. A failure after partial dataset output never advances durable state.

Write ordering and recovery

Before contacting TED, the Actor reserves enough space for the maximum new replay-ledger entries permitted by the run. If admission cannot fit the 3.5 MB durable-state budget, source processing and dataset writes do not start.

After admission, the write order is strict:

  1. dataset rows;
  2. default key-value-store OUTPUT summary;
  3. durable cursor/digest state last.

A source, dataset, summary, lease, or state failure before step 3 leaves the work replayable. Replays may duplicate already written dataset rows. Consumers should upsert by stable relationshipId; use contentDigest, changeType, and fetchedAt to distinguish revisions. Do not use noticeVersion or contentDigest as the logical upsert key.

The OUTPUT record includes scan/match/emission/duplicate counts, replayed page/row counts, change counts, stop reason, status (succeeded or partial), query window, configuration hash, dataset ID, timestamp, and attribution.

Isolated bounded state and concurrency

Business state is keyed by a SHA-256 fingerprint of all selection, language, value, and relevance settings. Operational caps do not fork state. Full-snapshot and change-tracking resume cursors are separate.

This Actor uses its own resources:

  • named state store: eu-procurement-award-intelligence-state-v1;
  • state key namespace: EU_PROCUREMENT_AWARD_STATE_V1;
  • lock queue: eu-procurement-award-intelligence-lock-v1.

State commits are immutable uniquely keyed snapshots. A persistent Request Queue entry provides exclusive writer leases, periodic prolongation, ownership checks, and server-side expiry. Snapshot selection compares semantic document revisions before key ordering so a stale writer cannot win merely through a later random key. Release is best-effort after a successful commit.

Each configuration keeps compact digests for 180 days and 5,000 notices by default. Retention is configurable from 7–730 days and 100–12,000 entries. The complete state document is measured against a conservative 3.5 MB budget; old completed configurations and then old digests are pruned. Before a new run is admitted, old ledgers in other saved configurations or resume slots that prevent a safe commit are converted to small recovery cursors: their exact saved windows remain, while their token, offset, and source ledger are cleared so they safely restart from row zero when next selected. The selected active resume is never discarded for admission; if it cannot grow safely, the run fails before reading TED or writing dataset rows. Snapshot listing/cleanup is bounded and tolerant of eventual consistency; any repeatedly unreadable listed candidate that could be newest makes loading fail closed.

Schedule non-overlapping runs where possible. Separate dataset, OUTPUT, and state writes are not one cloud transaction, so overlapping runs can still create replayed dataset rows even though stale state commits are rejected.

Cost expectations

The default memory is 1024 MB, which consumes 1 compute unit (CU) per hour of runtime. At an example rate of $0.20/CU, a 10-minute run costs about $0.033 in compute and a one-hour run about $0.20, before storage operations and data transfer.

These are planning examples, not quoted prices. Actual rates depend on the Apify plan, discounts, pricing model, memory override, storage, transfer, source volume, and run duration. Start with a short publication window and conservative caps, then inspect the run Usage details.

Limitations

  • Coverage and quality are limited to what the official TED Search API exposes. Source omissions and incorrect source data remain omissions/incorrect data.
  • Flattened arrays cannot recreate the original eForms buyer–contract–tender–winner graph without documented keys. Output fields are notice-level sets and never use array position as a join.
  • Winner details can be absent from result notices; these are excluded by default.
  • Organization identifiers may be national IDs, European IDs, UUID-like internal values, or other source strings. The Actor preserves them without relabeling their type.
  • Contract currencies are not converted or inflation-adjusted.
  • Stable relationship/award IDs do not change with notice versions or mutable normalized content. A corrected result-lot identifier is a different logical lot and therefore receives a different awardId.
  • This Actor is not legal, procurement, sanctions, or supplier-due-diligence advice.

Local development and release checks

Requires Node.js 22.

npm ci
npm run lint
npm run typecheck
npm run build
npm test
npm run smoke:local
npm run smoke:live
npm audit --omit=dev
npm audit
apify validate-schema

npm run smoke:live boundedly scans up to 500 recent production TED rows, requires one representative result with non-empty buyer and winner names, an award date, and a documented result/tender amount, then validates the normalized row against the dataset schema. The normal fixture/adversarial suite needs no network, cloud storage, credentials, or secrets.

The production Docker image builds TypeScript in an isolated Node 22 stage and installs only runtime dependencies in the final Apify Node 22 image.

Data source and attribution

Source: TED — Tenders Electronic Daily via the anonymous TED Search API v3.

The API is officially documented as anonymously accessible for published-notice reuse. Preserve the attribution included with every row and review the current TED legal notice for your use case. This Actor does not claim ownership of TED source data.