# Tender Early Signal — upcoming EU (TED) + UK procurements (PIN) (`handa-labs/eu-tender-early-signal`) Actor

Prior information notices from TED (EU) and planning-stage UK releases: what public buyers intend to procure before the formal tender. Keyword, CPV and country filters, English titles, buyer contacts, estimated value, planned dates — only what is new since your last run. Official APIs, no scraping.

- **URL**: https://apify.com/handa-labs/eu-tender-early-signal.md
- **Developed by:** [tatsuya handa](https://apify.com/handa-labs) (community)
- **Categories:** Business, Lead generation, News
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $10.00 / 1,000 upcoming procurement notices

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Tender Early Signal — upcoming EU (TED) + UK procurements (PIN)

**Hear about public contracts before they are tendered.** Public buyers in the EU and UK publish *prior information notices* (PIN) and planning-stage notices weeks or months before the formal call for competition — "we intend to buy X next year". This Actor filters them by keyword, CPV code and country and returns **only what is new since your last run**.

Why this beats watching tenders: when the tender is out, the specification is fixed and the deadline is close. At the PIN stage you can still talk to the buyer, shape requirements, line up partners, and plan capacity.

### Sample output

```json
{
  "type": "notice",
  "change": "new",
  "publicationNumber": "590531-2026",
  "noticeType": "pin-cfc-standard",
  "title": "Poland – System and support services – Usługa utrzymania i rozwoju systemu Softlab ERP",
  "publicationDate": "2026-08-27",
  "plannedPublicationDate": null,
  "expressionsDeadline": "2026-09-28",
  "deadline": null,
  "buyerName": "POLSKIE RADIO - SPÓŁKA AKCYJNA",
  "buyerCountry": "POL",
  "buyerCity": "Warszawa",
  "buyerEmail": "zamowienia@polskieradio.pl",
  "cpv": ["72250000"],
  "estimatedValue": null,
  "currency": null,
  "htmlUrl": "https://ted.europa.eu/en/notice/-/detail/590531-2026",
  "llmSummary": "POLSKIE RADIO - SPÓŁKA AKCYJNA (POL) published \"Poland – System and support services – …\" on 2026-08-27. CPV 72250000."
}
```

A `summary` record per run carries the executed query, counts by country and CPV division, and a one-sentence `llmSummary`.

### Fields

| Field | Meaning |
|---|---|
| `noticeType` | `pin-only` (pure PIN), `pin-cfc-standard` / `pin-cfc-social` (PIN used as call for competition — expressions of interest accepted), `pin-buyer` (buyer profile), `pin-rtl` (reduced time limits), `pin-tran`; UK: `uk-cf-planning`, `uk-fts-planning` |
| `plannedPublicationDate` | when the buyer expects to publish the tender (when stated) |
| `expressionsDeadline` | deadline for expressions of interest (PIN-as-call-for-competition) |
| `buyerName`, `buyerCountry`, `buyerCity`, `buyerEmail`, `buyerWebsite` | the contracting authority and how to reach it |
| `estimatedValue`, `currency` | estimated value when stated |
| `cpv`, `contractNature`, `placeOfPerformance` | classification |
| `description` | procedure description (original language, up to 1,500 chars) |
| `htmlUrl`, `pdfUrl`, `xmlUrl` | the notice |

### Sources

- **TED (EU)** — prior information notices via the official TED Search API v3.
- **UK Contracts Finder** — planning-stage (pipeline / early engagement) OCDS releases.
- **UK Find a Tender** — planning releases (tender pipeline, preliminary market engagement).

No scraping, no proxies, no login.

### Input

```json
{
  "keywords": ["software", "cloud", "IT"],
  "cpvCodes": ["72*", "48*"],
  "countries": ["DEU", "NLD", "FRA", "GBR"],
  "daysBack": 14,
  "sinceLastRun": true
}
```

| Field | Default | Meaning |
|---|---|---|
| `keywords` | — | full-text terms, any match |
| `cpvCodes` | — | CPV codes, `*` prefix wildcard |
| `countries` | — | buyer countries (ISO alpha-3); GBR enables UK sources |
| `noticeTypes` | all PIN types | narrow to e.g. `pin-cfc-standard` for notices that already accept expressions of interest |
| `sources` | all | `ted`, `uk-contracts-finder`, `uk-find-a-tender` |
| `daysBack` | 14 | publication window |
| `sinceLastRun` | true | only notices not returned before |
| `maxNotices` | 500 | cap per run |
| `includeDescription` | true | include the procedure description |

At least one of `keywords`, `cpvCodes`, `countries` is required.

### Monitor mode, watchlists and the free first run

All handa-labs monitors share the same controls:

| Field | Default | Meaning |
|---|---|---|
| `mode` | `monitor` | `monitor` remembers what was returned and emits only changes on later runs; `snapshot` returns everything matching on every run |
| `watchlistId` | `default` | label for this watchlist; runs with the same ID share memory, different IDs are independent |
| `emitBaseline` | `false` | the first monitor run establishes a **free baseline** (only the Actor-start fee) and returns counts; set `true` to also receive, and pay for, every current item on that first run |

Schedule the Actor with the same input and you get a clean change feed. Nothing is charged for records on the first run unless you ask for them.

### Pricing

Pay-per-event: a small fee per run plus a fee per notice returned. PINs are rarer than tenders, so a daily focused watch returns a few notices per week.

### Notes

- Companion Actors: **Public Tender Monitor** (calls for competition) and **Tender Award Monitor** (who won). Together they cover the whole life cycle: intent → tender → award.
- Estimated values and planned dates are stated by the buyer and are often missing on pure PINs.

***

### 日本語

EU(TED)と英国の「事前情報公告(PIN)」、つまり正式な入札の前に発注者が出す「来期これを買う予定」の通知を、キーワード×CPV×国で絞って新着だけ返します。入札公告が出てからでは仕様も締切も固まっていますが、この段階なら発注者と話せます。SaaS・IT・コンサル営業向け。公式APIのみ、スクレイピングなし。

# Actor input Schema

## `keywords` (type: `array`):

Words or phrases searched in the full text of the notice (any language). Notices matching ANY keyword are returned. Leave empty to filter by CPV / country only.

## `cpvCodes` (type: `array`):

Common Procurement Vocabulary codes, e.g. 72000000 (IT services), 48000000 (software), 45000000 (construction). A trailing \* matches a prefix (72\* = all IT services).

## `countries` (type: `array`):

e.g. DEU, FRA, NLD, ESP, ITA, POL, SWE, BEL, AUT, IRL. Empty = all countries.

## `sources` (type: `array`):

TED = EU prior information notices. UK sources = planning-stage OCDS releases (pipeline / early engagement notices). UK sources are skipped when the countries filter excludes GBR.

## `mode` (type: `string`):

"monitor" (default): remember what was returned and emit only changes on later runs. "snapshot": return everything matching, every run, no memory.

## `watchlistId` (type: `string`):

Label for this watchlist (e.g. "roofing-wa"). Runs with the same ID share memory; use different IDs for independent watchlists.

## `emitBaseline` (type: `boolean`):

The first monitor run establishes a free baseline and returns only counts. Turn this on to also receive (and pay for) every current item on that first run.

## `noticeTypes` (type: `array`):

TED prior-information notice types. pin-only = pure PIN, pin-cfc-\* = PIN used as call for competition, pin-buyer = buyer profile, pin-rtl = reduced time limits, pin-tran = transport.

## `daysBack` (type: `integer`):

Only notices published within the last N days.

## `sinceLastRun` (type: `boolean`):

Legacy switch. Prefer "mode". false = snapshot mode.

## `maxNotices` (type: `integer`):

Safety cap on the number of notices fetched from TED per run.

## `includeDescription` (type: `boolean`):

Adds up to 1500 characters of the procedure/lot description (original language).

## `stateStoreName` (type: `string`):

Named key-value store used to remember already-seen notices.

## Actor input object example

```json
{
  "keywords": [
    "cloud",
    "software as a service"
  ],
  "cpvCodes": [
    "72*",
    "48*"
  ],
  "countries": [
    "DEU",
    "NLD"
  ],
  "sources": [
    "ted",
    "uk-contracts-finder",
    "uk-find-a-tender"
  ],
  "mode": "monitor",
  "watchlistId": "default",
  "emitBaseline": false,
  "noticeTypes": [
    "pin-buyer",
    "pin-cfc-standard",
    "pin-cfc-social",
    "pin-only",
    "pin-rtl",
    "pin-tran"
  ],
  "daysBack": 14,
  "sinceLastRun": true,
  "maxNotices": 500,
  "includeDescription": true,
  "stateStoreName": "tender-early-signal-state"
}
```

# Actor output Schema

## `results` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "keywords": [
        "cloud",
        "software as a service"
    ],
    "cpvCodes": [
        "72*",
        "48*"
    ],
    "countries": [
        "DEU",
        "NLD"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("handa-labs/eu-tender-early-signal").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "keywords": [
        "cloud",
        "software as a service",
    ],
    "cpvCodes": [
        "72*",
        "48*",
    ],
    "countries": [
        "DEU",
        "NLD",
    ],
}

# Run the Actor and wait for it to finish
run = client.actor("handa-labs/eu-tender-early-signal").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "keywords": [
    "cloud",
    "software as a service"
  ],
  "cpvCodes": [
    "72*",
    "48*"
  ],
  "countries": [
    "DEU",
    "NLD"
  ]
}' |
apify call handa-labs/eu-tender-early-signal --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,handa-labs/eu-tender-early-signal"
        }
    }
}

```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/0F0R3PViqD0aZxU8k/builds/eRKK0fmSMxjwH2ihN/openapi.json
