DEV Community

Steadfetch
Steadfetch

Posted on Fully Autonomous

Track EU Public Tenders (TED) as JSON: Buyer, Deadline and CPV Codes Without a Scraper

Every morning, thousands of new procurement notices land on TED (Tenders Electronic Daily), the official journal of EU public procurement. If you sell to the public sector, missing a bid deadline is lost revenue — but the TED search UI is built for humans reading one notice at a time, not for scripts that need yesterday's tenders as clean JSON.

This post shows how to get EU tender data as structured JSON with steadfetch/ted-tender-monitor — no scraper to maintain, no HTML parsing to repair when the site changes.

What you get

The Actor queries the official TED public procurement notices and returns one dataset item per tender, validated against a schema before it is stored — so a source change fails loudly instead of writing bad rows into your pipeline. Each item carries the procurement metadata you need for triage: buyer organisation, title, publication and deadline dates, CPV codes, the notice link, and the estimated value with currency. Personal contact fields are scrubbed at the source.

Pricing, in one paragraph

It runs on Apify's pay-per-event model: 2.00 USD per 1,000 tenders (0.002 USD per validated tender delivered) plus a 0.00005 USD charge per run start. You are charged per validated tender actually saved to the dataset — an empty search returns nothing and costs effectively nothing, so a daily "anything new?" check is safe to schedule.

Quickstart: one HTTP call

Create an Apify token in the console (the free tier works), then:

curl -s -X POST \
  "https://api.apify.com/v2/acts/steadfetch~ted-tender-monitor/run-sync-get-dataset-items" \
  -H "Authorization: Bearer $APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"query":"software","maxResults":100}'
Enter fullscreen mode Exit fullscreen mode

query is the free-text search (a keyword or a CPV description); maxResults caps the batch. The call runs the Actor and returns the dataset items as a JSON array.

JavaScript and Python

const resp = await fetch(
  "https://api.apify.com/v2/acts/steadfetch~ted-tender-monitor/run-sync-get-dataset-items",
  {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.APIFY_TOKEN}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ query: "software", maxResults: 100 }),
  }
);
const tenders = await resp.json();
console.log(tenders.length, "tenders");
Enter fullscreen mode Exit fullscreen mode
import os
import requests

resp = requests.post(
    "https://api.apify.com/v2/acts/steadfetch~ted-tender-monitor/run-sync-get-dataset-items",
    headers={"Authorization": f"Bearer {os.environ['APIFY_TOKEN']}"},
    json={"query": "software", "maxResults": 100},
    timeout=300,
)
tenders = resp.json()
print(len(tenders), "tenders")
Enter fullscreen mode Exit fullscreen mode

Both snippets come straight from the examples repository, where each Steadfetch Actor has a folder with a README, an API call, JavaScript and Python clients, and a real example of the output.

New tenders in your spreadsheet every morning

If you would rather not write code at all, the same folder ships an n8n workflow you can import and activate: it runs daily at 07:00, calls the Actor, and appends one row per tender to a Google Sheet — buyer, title, deadline, CPV codes and value, mapped automatically from the JSON fields. A step-by-step Make guide is in the folder too.

Full catalogue

ted-tender-monitor is one of several monitors in the Steadfetch Store profile — UK Companies House records, SEC EDGAR filings and more, all with the same pattern: official public sources, schema-validated JSON, and no scraper for you to maintain.


This article is published by Steadfetch ("web data that doesn't break") and was produced by our automated marketing agent; dev.to labels it as AI-generated.

Top comments (0)