Recipe: Monitor EU public tenders

The task

A business-development or public-affairs team wants a recurring (daily or weekly) check for new government tenders across the EU in their sector — the “tell me when something new opens” version of tender search, run on a schedule.

Tools used: per-country tender packs — france_search_tenders, germany_search_tenders, nl_tender_search, es_tender_search, dk_tender_search — plus oc_tender_search for Italy and Croatia. Not eu_search_tenders — see below.

Copy-paste prompt

Set up a recurring check for new public-procurement tenders in "<sector/keyword>" across
the EU member states Pipeworx actually covers (France, Germany, Netherlands, Spain,
Denmark, Italy, Croatia). For each covered country, run its national tender search tool
with the keyword and today's date window, and list new notices with title, buyer,
deadline, and URL. Explicitly tell me which EU member states are NOT covered so I know
this isn't a full-EU sweep.

What a good answer looks like

france_search_tenders({ query: "informatique", limit: 3 })

returns (live call, 2026-08-10 — trimmed to 1 of 3):

{
  "total_count": 29445,
  "notices": [
    {
      "id": "26-79055",
      "object": "Accord-cadre relatif au développement et au maintien en condition opérationnelle (MCO) des outils informatiques composant le Domaine Civil",
      "buyer": "Ministère de la justice",
      "publication_date": "2026-08-09",
      "contract_type": ["Services"],
      "status": "INITIAL",
      "url": "https://www.boamp.fr/pages/avis/?q=idweb:26-79055"
    }
  ]
}

paired with:

germany_search_tenders({ query: "Software", date_from: "2026-08-03", date_to: "2026-08-10", limit: 3 })
// → 3 real German federal-procurement notices, newest first, published 2026-08-09/10

A trustworthy recurring-monitor answer:

  • names which specific national portals were actually queried this run (BOAMP for France, oeffentlichevergabe.de for Germany, etc.) — not “the EU tender database”
  • states the date window actually fetched, not just the window requested — see the Germany caveat below, where these can silently differ
  • lists, by name, the EU member states not covered, so a reader can’t mistake a 7-country sweep for a 27-country one

The plausible-sounding failure: asking for “EU tenders” and getting eu_search_tenders results that look like exactly what was asked for, but aren’t. Live call, no query text, status “open”:

eu_search_tenders({ status: "open", limit: 5 })

returns real-looking procurement notices — reference numbers, EUR budgets, deadlines, portal URLs:

{
  "total_results": 21,
  "results": [
    { "reference": "EuropeAid/186661/DD/ACT/JM", "country": "JM",
      "title": "Human Rights and Democracy Support in Jamaica 2026 and 2027",
      "budget": "600000", "currency": "EUR" },
    { "reference": "EuropeAid/186614/DD/ACT/Multi", "country": "Multi",
      "title": "Papua New Guinea (PNG) — Civic Participation and Women's Political and Decision-making Participation",
      "budget": "1381333", "currency": "EUR" }
  ],
  "source": "EU Funding & Tenders Portal (SEDIA), external-action tenders and calls"
}

Every one of the 21 open results is an EU external-action development-aid contract to a non-EU country (Jamaica, Papua New Guinea, South Africa, Palestine, North Macedonia were the top live results). eu_search_tenders searches the EU Funding & Tenders Portal — European Commission external-action and EuropeAid grants — not member-state public procurement (the TED / Tenders Electronic Daily universe). A caller who asks “monitor EU public tenders,” gets this tool by name-match, and doesn’t read the source field carefully will build a recurring monitor on the wrong dataset and never notice, because nothing about the response looks like an error. Filed as fleet #216 (naming/discoverability issue); documented here so it doesn’t cost you the same way in the meantime.

Step-by-step tool calls

1. Query each covered country separately

There is no single call that sweeps the whole EU. Run one call per covered country:

france_search_tenders({ query: "<keyword>", limit: 20 })       // BOAMP
germany_search_tenders({ query: "<keyword>", date_from: "<today-7d>", date_to: "<today>", limit: 20 })  // oeffentlichevergabe.de
nl_tender_search({ query: "<keyword>", limit: 20 })             // TenderNed
es_tender_search({ query: "<keyword>", limit: 20 })             // PLACSP (use Spanish keywords)
dk_tender_search({ query: "<keyword>", limit: 20 })              // udbud.dk (use Danish keywords)
oc_tender_search({ query: "<keyword>", country: "Italy", days: 7, limit: 20 })
oc_tender_search({ query: "<keyword>", country: "Croatia", days: 7, limit: 20 })

Spain and Denmark rank on keyword recall in their own language — an English keyword will under-match. Translate the term before querying, or accept lower recall.

2. For Germany specifically, mind the per-call fetch cap

germany_search_tenders({ query: "Software", date_from: "2026-07-01", date_to: "2026-08-10", limit: 3 })
// → days_fetched: ["2026-08-10"]  (only ONE day actually fetched, even though a
//    40-day window was requested)

The tool fetches at most 7 days per call (newest first), and stops early once it has collected limit matching results — so a low limit on a day with plenty of hits can mean only the most recent day was ever queried, silently. For a genuine recurring daily monitor this is fine (you only need the last day or two each run); for a one-off backfill over a longer window, raise limit well above what you expect per day, or narrow date_from/date_to to walk the range in 7-day chunks.

3. Recurring cadence

Run the covered-country calls on a schedule (daily is safe for all of them; France and Germany publish daily). Track which notice id/ocid values you’ve already surfaced between runs — none of these tools take a “since last check” cursor, so dedup is on you.

4. State the gap every time

Of the EU’s 27 member states, Pipeworx has real national tender-portal coverage for France, Germany, Netherlands, Spain, Denmark, Italy, and Croatia — 7 of 27. The other 20 (Poland, Belgium, Sweden, Austria, Portugal, Ireland, Greece, Czechia, Hungary, Romania, Bulgaria, Slovakia, Slovenia, Lithuania, Latvia, Estonia, Finland, Luxembourg, Malta, Cyprus) have no dedicated tool in the catalog today. A monitor built only from the covered 7 is legitimate and useful — as long as it’s labeled as 7 countries, not “the EU.”

Caveats

  • eu_search_tenders is EU external-action/EuropeAid aid contracts, not member-state procurement. Repeated from above because it’s the single most important thing to get right in this recipe — don’t use it for a “monitor EU public tenders” ask.
  • No TED-wide tool exists in the catalog. TED (Tenders Electronic Daily) is the EU’s actual above-threshold procurement-wide notice system; Pipeworx doesn’t mirror it directly, only 7 national portals plus a UK post-Brexit equivalent (find_a_tender_recent — UK is not in the EU, include it only if the ask covers the UK too).
  • Per-country result shapes differ. France returns object (not title), Germany returns ocid+OCDS fields, Netherlands returns Dutch notice-type codes, Spain and Denmark are native-language. Don’t assume a uniform schema across countries when merging results into one list.
  • Language matters for recall, not just for reading results — Spanish, Dutch, Danish, and German portals all rank best on native-language keywords per their own tool descriptions.
  • “Open” status can lag the deadline slightly. eu_search_tenders itself notes a handful of tenders keep status Open past their nominal deadline; the per-country tools don’t all filter this the same way — check response_deadline/deadline fields rather than trusting a status word alone when the ask is “still open to bid.”

Last reviewed August 10, 2026