EU tender screener — AI bid/no-bid decision from TED notices avatar

EU tender screener — AI bid/no-bid decision from TED notices

Pricing

$50.00 / 1,000 tender screeneds

Go to Apify Store
EU tender screener — AI bid/no-bid decision from TED notices

EU tender screener — AI bid/no-bid decision from TED notices

Describe your company in plain language, get back a justified bid/no-bid verdict for each matching EU public tender from TED (Tenders Electronic Daily) — no CPV codes to know, no notices to read yourself.

Pricing

$50.00 / 1,000 tender screeneds

Rating

0.0

(0)

Developer

matheo daney

matheo daney

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

4 days ago

Last modified

Categories

Share

Describe your company in plain language, get back a justified bid/no-bid decision for every matching EU public tender — pulled live from TED (Tenders Electronic Daily, the EU's official public procurement journal), scored and explained by Claude Haiku. No CPV codes to learn, no notices to read one by one, no API key to obtain: a short, justified DECISION per notice, not a summary, at one flat price that already includes the AI cost.

Use this Actor when…

  • You run a small or mid-sized company and receive (or could receive) far more EU tender notices than you have time to read — most don't concern you, and finding the three that do costs hours of manual triage.
  • You want a first-pass filter, not a legal or eligibility guarantee (see Honesty & limits below) — a ranked shortlist of "pertinent" / "à examiner" / "non pertinent" notices with concrete reasons, so a human only reads the notices actually worth reading.
  • You need this as a tool an AI agent can call directly — via the Apify API, the Apify MCP server, or an n8n workflow — feeding it a company description and getting back structured decisions to act on (alert a human, log to a CRM, trigger a "prepare a bid" workflow).

This Actor does not scrape anything. Every notice comes from TED's own official Search API — see Honesty & limits below for exactly what that does and does not cover.

How this is different from a plain TED scraper

At least two other Apify Store Actors already fetch raw TED notices by filter (checked 2026-09-04 via apify actors search "tender" — see the closest match, foxlabs/ted-tenders, priced per raw result and requiring you to already know CPV codes/filters yourself). This Actor is not a competitor to those on raw data volume — it does something different: it takes a plain-language description of your business, translates it internally into CPV search codes, and returns a justified decision per notice rather than a raw filtered feed. If all you need is bulk structured TED data with filters you already know how to build, a raw scraper is cheaper per notice; if you need "tell me which of these are actually worth my time, and why," that decision layer is this Actor's whole purpose.

Input

FieldTypeDefaultDescription
companyDescriptionstring(required)What your company actually does, in plain language — no CPV codes needed. Translated internally into CPV codes by Claude Haiku; the codes chosen and why are always in the run log and in each output record's matchedCpvCodes.
countriesarray of strings(required)Target buyer countries — full name, 2-letter, or 3-letter code all work ("France", "FR", "FRA").
minValue / maxValueinteger(none)Skip notices below/above this estimated value, in EUR.
publishedAfter / publishedBeforestring (YYYY-MM-DD)14 days ago / todayPublication window. A narrower window keeps both the TED query and the AI-analysis cost bounded.
maxNoticesToAnalyzeinteger20Hard cap on how many notices are sent to Claude Haiku this run (1–50). This is the Actor's central cost-control setting — see Cost control below.

Full field-level descriptions are in .actor/input_schema.json.

Nothing else to configure

This is the whole input — no API key of any kind, no account to link. The AI model this Actor uses internally (Claude Haiku) runs on this Actor's own key, already paid for out of the flat per-notice price (see Pricing below). If you are integrating this as a tool for an AI agent, that agent needs nothing beyond the fields above.

Example input

{
"companyDescription": "We are a small IT services company (12 employees, based in Lyon, France). We build and maintain custom web applications, do systems integration work, and provide IT helpdesk/support services for small and mid-sized organizations. We do not do hardware manufacturing, telecom infrastructure, or large-scale data-center operations.",
"countries": ["France", "Belgium"],
"maxNoticesToAnalyze": 5
}

Output example

Real output from a local test run (2026-09-04, model claude-haiku-4-5-20251001):

{
"reference": "578265-2026",
"title": "Belgium – IT services: consulting, software development, Internet and support – e-Market 905 - SAP HR / PM integration expert",
"buyer": "Infrabel sa",
"country": "BEL",
"estimatedValue": 1294216.25,
"currency": "EUR",
"deadline": null,
"url": "https://ted.europa.eu/en/notice/-/detail/578265-2026",
"verdict": "à examiner",
"score": 52,
"reasons": [
"CPV 72000 (IT services) and title mention software development and integration, which aligns with your custom web applications and systems integration work.",
"Belgium is a target country and Infrabel is a major Belgian transport/infrastructure operator, a plausible client type for SME IT services.",
"Estimated value of €1.29M is very large for a 12-person company to deliver alone without subcontracting or consortium partners.",
"No submission deadline stated in summary, making it impossible to assess if you have time to prepare a competitive bid."
],
"blockingPoints": [
"Estimated value (€1.29M) significantly exceeds typical project scale for a 12-person IT services firm unless you partner or subcontract.",
"No submission deadline provided; unable to assess feasibility of bid preparation timeline."
],
"matchedCpvCodes": ["72000000"],
"charged": true,
"error": null
}

Same test run, a notice correctly identified as unrelated despite matching the broad CPV search (real AI discrimination, not a rubber stamp — verdicts across the 5-notice test batch ranged from 15 to 52):

{
"reference": "578635-2026",
"verdict": "non pertinent",
"score": 15,
"reasons": [
"CPV codes (30230000 computer equipment, 50312000 computer maintenance, 72100000 hardware consultancy) center on hardware, which the company explicitly does not do.",
"The company's core activity is custom software development and IT support services, not hardware supply or equipment maintenance contracts."
]
}
FieldMeaning
referenceTED publication number (e.g. "578265-2026").
title, buyer, countryFrom the notice itself; country is the buyer's country, ISO 3166-1 alpha-3.
estimatedValue, currencySee Honesty & limits for how this is derived and why it is sometimes null.
deadlineSubmission deadline, or nulloften null on real notices even though TED's own field exists (see below).
urlThe official TED notice page — always verify anything decision-critical there, not from this record alone.
verdict"pertinent", "à examiner", or "non pertinent".
score0–100, roughly: 70–100 pertinent, 30–69 à examiner, 0–29 non pertinent.
reasons2–4 short, concrete reasons for the verdict.
blockingPointsConcrete blockers found in the notice summary (value too large, deadline too tight, etc.), [] if none.
matchedCpvCodesThe notice's own CPV codes (deduplicated — TED's own data can repeat a code across lots).
chargedtrue if this record triggered a tender-screened charge.
errorSet (implies charged: false) if this notice could not be screened — e.g. a model response this Actor could not parse even after its own retry.

Pricing

This Actor uses Apify's pay-per-event (PPE) pricing model — see Apify's PPE documentation. There is a single, all-inclusive billable event:

  • tender-screened — charged once per notice for which a decision was genuinely rendered: Claude Haiku returned a valid, parseable verdict for that notice. This price covers everything — the TED lookup and the AI analysis are both already included. There is no separate API key to obtain and no second bill from anywhere else.

Target price: $0.05 per tender-screened event — configured on the Actor's Pricing page in Apify Console, not in this code. In the code, the event is declared with the Actor.pushData(item, 'tender-screened') shortcut (see src/main.js and src/record.js).

You are never charged for:

  • a run that fails before any notice is screened (bad input, the CPV-translation call failing, TED being unreachable, or an Actor misconfiguration on the operator's side) — the whole run fails with a clear error and nothing has been pushed to the dataset yet;
  • a query that matches zero notices — the run ends cleanly, nothing charged;
  • a specific notice whose Claude Haiku call failed or returned unparseable JSON even after this Actor's own one retry — that notice is still pushed to the dataset (with error set) so you can see it happened, but charged is false.

Cost control

This Actor runs on its own operator-provided Anthropic key (see Nothing else to configure above) — the AI cost of every notice screened is the operator's own cost, already priced into the flat $0.05, never something a caller sees or pays separately. That is exactly why the safeguards below exist: this is the operator's own money being spent on every run, so it is bounded in code, not just described in a comment (see src/main.js and src/claude.js file headers for the full reasoning behind each one):

  1. Hard absolute cap: 50 notices per run, enforced in code (ABSOLUTE_MAX_NOTICES in src/main.js), regardless of what maxNoticesToAnalyze is set to — a direct API caller bypassing the input schema's own maximum: 50 cannot bypass this one. Default is 20.
  2. At most 2 Anthropic calls per step, never more (MAX_CALLS_PER_JSON_REQUEST in src/claude.js): one attempt, and one retry only if that attempt's failure was specifically a JSON-parsing problem — there is no loop, so this bound cannot be exceeded by any code path. This applies to the one-time CPV-translation step and to each notice's screening step independently.
  3. Model: Claude Haiku (claude-haiku-4-5-20251001, verified live 2026-09-04 on Anthropic's own docs — see src/claude.js), Anthropic's cheapest and fastest current model — this is a triage task run at volume, not one that needs frontier-model reasoning depth.
  4. Truncated input per notice: this Actor sends TED's own structured search-result fields (title, buyer, CPV codes, value, deadline — see Honesty & limits for why it never fetches a notice's full multi-page body text), each field capped at 300 characters as an extra safety margin (MAX_FIELD_CHARS in src/claude.js).
  5. A live, running spend cap independent of the notice count: before starting each new notice, this Actor checks its estimated spend so far (computed from real token usage) against MAX_RUN_SPEND_USD ($0.20, see the reasoning below) — if reached, the run stops cleanly. Every decision already rendered and charged before that point stays exactly as charged; this is reflected in the run's final summary log.
  6. Real, logged cost per run: every run logs its exact input/output token counts and an estimated USD cost at Haiku's published rate — not a guess, and directly comparable to what Apify separately bills for the run's tender-screened events.

Two numbers, both real, not estimates:

  • Worst-case theoretical ceiling for one run: ≈ $0.41. This is a genuine mathematical bound, computed from the code's own hard limits — 50 notices (point 1) × up to 2 calls each (point 2) × each call's exact max_tokens output ceiling, plus the exact worst-case input-token count measured live against the real Anthropic tokenizer for the longest prompt this code can build (see the *_WORST_CASE_INPUT_TOKENS constants in src/claude.js, measured 2026-09-04 via client.messages.countTokens). It assumes every single call, including the one-off CPV step, hits the rare JSON-retry path and consumes its full output budget — an extremely pessimistic scenario. src/main.js computes and logs this exact figure at the start of every run (WORST_CASE_RUN_COST_USD), so it is never a stale number copied into this README.
  • Real measured cost (2026-09-04, local test run, 5 notices, zero retries): 3,786 input + 1,227 output tokens, ≈ $0.0099 total — about $0.002 per notice. At the 50-notice absolute cap, that scales to roughly $0.10 for a full run under ordinary conditions.

MAX_RUN_SPEND_USD ($0.20) sits deliberately between these two numbers — about double the realistic full-run cost (so it never fires in ordinary operation) and meaningfully below the $0.41 worst case (so it still cuts a genuinely anomalous run — e.g. one where every notice happens to trigger a JSON-retry — roughly in half rather than letting it run all the way to the theoretical ceiling).

This is a different economic shape from the sibling Actors in this portfolio (eu-vat-siren-check, cve-exploited-check): there, the developer's cost of fulfilling a paid event is the (free or near-free) government API calls those Actors make. Here, the developer's cost of fulfilling one tender-screened event is a real, metered LLM call — the margin at $0.05 is $0.05 minus that real Anthropic cost (≈$0.002/notice measured), not $0.05 minus a negligible platform overhead.

Honesty & limits

This is a decision aid produced by a language model, not legal advice, not a guarantee of eligibility to bid, and not a substitute for reading the actual tender documents before submitting anything. A "pertinent" verdict is a strong first-pass signal to go read the real notice (via url); it is never a recommendation you should act on without human review, and a "non pertinent" verdict can still be wrong on an edge case the model's limited input didn't capture.

Decisions are based on TED's structured notice summary (title, buyer, CPV codes, value, deadline), not the full tender documents. TED's Search API — the only endpoint this Actor uses — returns structured fields, not a notice's full multi-page eForms body text; fetching and analyzing the complete body of every candidate notice would multiply this Actor's TED calls and, more importantly, the AI token cost (see Cost control) for a triage task that does not need it. This is a deliberate trade-off, not an oversight — but it does mean the model is triaging on the same summary information a person would scan in a few seconds, not doing deep tender analysis. If sorting quality on your specific sector turns out to be too coarse for this trade-off, that is the first place to look.

The submission deadline (deadline) is frequently null, even on real, currently-active notices. TED's own field for this (deadline-receipt-tender-date-lot) is a real, valid field — confirmed live against the API's own error message listing every supported field — but it is simply not populated on every notice returned by a search query (observed on all 5 notices in this Actor's own local test run). Never treat a null deadline as "no deadline" — always check the notice at url directly.

TED only lists contracts above the EU's own procurement thresholds. A local or small-value contract that never has to be published EU-wide will never appear here, however well it might match your company — this Actor cannot see contracts that are never on TED in the first place. If most of your realistic business is below-threshold/local, TED (and therefore this Actor) is structurally the wrong tool for the bulk of it.

CPV code translation is AI-assisted, not a lookup against the full official CPV registry. The full CPV list runs to roughly 9,000 entries (Regulation (EC) No. 213/2008, published by the EU Publications Office at simap.ted.europa.eu/web/simap/cpv, verified live 2026-09-04) — this Actor does not embed or download that full registry. Instead, Claude Haiku is asked to propose 1–5 CPV codes (a broad 2-digit division, e.g. 72 for IT services, or a full 8-digit code when confident) directly from your plain-language description, deliberately erring toward a broader code over an overly narrow guess (a missed match from too-narrow a code is worse than a slightly too-broad search this Actor's own AI screening step then filters down). The codes chosen, and a plain-English explanation of why, are always shown in the run log and in every output record's matchedCpvCodes — check them if a search surfaces obviously wrong-sector notices, or none at all.

Estimated value: TED provides both a per-lot estimated-value-lot (used when present, summed across lots) and a total-value field; this Actor prefers the former (the more precise pre-award figure) and falls back to the latter. Either can be null on notices that don't state a value in the fields this Actor requests.

Country codes: TED's buyer-country field uses standard ISO 3166-1 alpha-3 codes (verified live 2026-09-04 against real notices, e.g. a French buyer returns "FRA") — src/countries.js accepts common English names, 2-letter, or 3-letter codes for the EU/EEA members plus the UK and Switzerland (both still appear as real TED buyer countries) and converts them internally; an unrecognized entry fails the run immediately with the exact list of what is recognized, rather than silently dropping a country you asked for.

Reuse/licensing (verified live 2026-09-04 by reading the rendered legal notice at ted.europa.eu/en/legal-notice, "Copyright notice" section): "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." This Actor only ever reuses the notices themselves — exactly what that notice describes as freely reusable.

Rate limits / pagination: TED's Search API is unauthenticated with no published requests-per-second limit found (checked docs.ted.europa.eu/api/latest, 2026-09-04); its own documented ceiling is on pagination volume — up to 250 notices per page and 10,000 "fields" per page (fields.length × limit), per the API's own OpenAPI spec (api.ted.europa.eu/api-v3.yaml, read the same day). This Actor never approaches either ceiling at its 50-notice absolute cap.

This Actor returns public procurement notice data: buyer organization names, notice titles, official published values and deadlines, and an AI-generated bid/no-bid opinion about your own company's fit. It does not return, request, or process personal data about identifiable natural persons.

Integrations (API, MCP, n8n)

  • Apify API — run this Actor from any HTTP client via POST https://api.apify.com/v2/acts/<your-username>~eu-tender-screen/run-sync-get-dataset-items (or the async run + get-dataset-items pair) with your Apify API token — nothing else to configure (see Nothing else to configure above). See the Actor's API tab in Apify Console for ready-to-copy snippets.
  • MCP (Model Context Protocol) — expose this Actor as a tool to any MCP-compatible AI agent via the Apify MCP server. An agent can call it directly with a natural-language company description and target countries.
  • n8n — use the official Apify node for n8n to run this Actor as a workflow step — e.g. on a schedule, feeding verdict === "pertinent" results into an alert or CRM step.