# Polish Public Tenders – BZP & TED + Winners (`matikitli/pl-public-tenders`) Actor

Polish public tenders from official BZP (e-Zamówienia) and EU TED: open tenders and awards with buyer, CPV, values, deadlines and winners per lot. Filter by CPV, province, keywords; daily monitor returns only new notices; optional KRS/VAT data on winners. $0.002 per notice.

- **URL**: https://apify.com/matikitli/pl-public-tenders.md
- **Developed by:** [Mateusz Kitlinski](https://apify.com/matikitli) (community)
- **Categories:** Business, Lead generation, AI
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 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?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

### What does Polish Public Tenders do?

**Polish Public Tenders** gives you one clean, English-keyed feed of **Polish public procurement notices** from the two official sources:

- **BZP / e-Zamówienia** (Biuletyn Zamówień Publicznych, Urząd Zamówień Publicznych): national notices below the EU thresholds, where most SME opportunities are.
- **TED** (Tenders Electronic Daily, European Union): notices of Polish buyers above the EU thresholds.

Choose **open tenders** (you can still bid) or **awarded contracts** (who won, for how much), filter by **CPV code**, **province**, **keywords** and **dates**, and get **one row per notice** with buyer, CPV codes, estimated value, offer deadline, lots, and for awards the **winners of every lot** with their tax number (NIP/REGON) and awarded value. Notices published in both sources are merged into one row.

Optional extras:

- **Monitor mode**: schedule the actor daily and get only notices you have not received before.
- **Winner enrichment**: every winning Polish company gets a company profile from the official KRS court register and the VAT white list (legal form, address, status, VAT status, main activity, risk signals), the same data as our [Polish Company Dossier](https://apify.com/matikitli/pl-company-dossier).
- **Detailed notices**: buyer contacts (institutional e-mail, phone, website), award criteria with weights, bid deposit (wadium), contract duration, lowest and highest offers.

Official sources only. No scraping of portals, no personal data: sole traders that win contracts are listed by tax number only, without their name.

### Who is it for?

- **B2B sales teams selling to the public sector**: a daily list of new tenders in your CPV codes and regions, straight into your CRM, Slack or e-mail.
- **Bid consultants**: who wins what, at which price, against how many offers.
- **Competitor and market tracking**: which companies win public contracts in your market, with their company profile.
- **Subcontracting, financing and insurance**: find companies that just won public contracts and need partners, guarantees or credit.
- **AI agents** (via the Apify MCP server): "find open Polish tenders for medical equipment in Małopolska".

### How to use it

1. Choose **Notice kind**: open tenders, awarded contracts, or both.
2. Set **Published from / to** (relative dates like `-3 days` work) and add **CPV codes** (for example `33` medical equipment, `45` construction works, `48` software).
3. Optionally pick **provinces** and **keywords**.
4. Run it. Use the **Overview**, **Open tenders** or **Lots and winners** table, or download JSON, CSV or Excel.
5. For a daily feed: turn on **Monitor mode**, save the input as a task and add an Apify **schedule** (for example every morning at 7:00), then an integration (e-mail, Slack, Google Sheets, webhook).

### Input

```json
{
  "noticeKind": "award",
  "sources": ["BZP", "TED"],
  "dateFrom": "-3 days",
  "cpvCodes": ["33", "45000000-7"],
  "provinces": ["malopolskie", "slaskie"],
  "keywords": ["remont"],
  "detailed": false,
  "enrichWinners": true,
  "monitor": false,
  "maxItems": 1000
}
```

| Field | Default | Description |
|---|---|---|
| `noticeKind` | `open` | `open` = contract notices, `award` = result notices with winners, `both` |
| `sources` | both | `BZP` (national), `TED` (EU) |
| `dateFrom` / `dateTo` | `-3 days` / today | Publication dates, at most 90 days per run |
| `cpvCodes` | all | CPV prefixes (2–8 digits) or full codes; any CPV code of the notice may match |
| `provinces` | all | Buyer's voivodeship (BZP) or place of performance (TED) |
| `keywords` | none | Words in the title, case- and accent-insensitive |
| `detailed` | `false` | Buyer contacts, criteria, wadium, duration, offer range |
| `enrichWinners` | `false` | Company profile for every winning Polish company (awards) |
| `monitor` / `resetMonitor` | `false` | Only notices not delivered before for the same filters |
| `maxItems` | 1000 | Stop after this many notices (1–10,000) |

### Output

One record per notice. A shortened award example (real data, 1 October 2026):

```json
{
  "status": "ok",
  "noticeKind": "award",
  "sources": ["BZP"],
  "noticeIds": { "bzp": "2026/BZP 00465838/01", "ted": null },
  "publishedAt": "2026-10-01T09:35:54Z",
  "title": "Zakup i dostawa aparatów EKG …",
  "orderType": "supplies",
  "cpv": [{ "code": "33100000-1", "label": "Urządzenia medyczne", "main": true }],
  "buyer": {
    "name": "\"DOLNOŚLĄSKIE CENTRUM ZDROWIA PSYCHICZNEGO\" SPÓŁKA Z OGRANICZONĄ ODPOWIEDZIALNOŚCIĄ",
    "nip": "8951965126",
    "regon": "021184819",
    "city": "Wrocław",
    "province": { "code": "PL02", "nuts": "PL51", "name": "dolnośląskie" }
  },
  "estimatedValue": { "amount": 18589.5, "currency": "PLN", "vat": "excluded" },
  "lots": [
    {
      "lotNumber": "1",
      "outcome": "awarded",
      "offersReceived": 3,
      "awardedValue": { "amount": 20076.66, "currency": "PLN", "vat": null },
      "winners": [
        {
          "winnerType": "company",
          "name": "Zakmed sp. z o.o. sp. komandytowa",
          "identifier": { "type": "NIP", "value": "8862990766", "valid": true },
          "enrichmentStatus": "enriched",
          "company": {
            "krs": "0000616740",
            "legalFormCategory": "LIMITED_PARTNERSHIP",
            "status": { "active": true, "inLiquidation": false, "inBankruptcy": false, "inRestructuring": false },
            "vatStatus": "Czynny",
            "riskLevel": "NONE"
          }
        }
      ]
    }
  ],
  "winnersAlignment": "lot",
  "links": { "bzp": "https://ezamowienia.gov.pl/mo-client-board/bzp/notice-details/id/…", "ted": null },
  "attribution": ["Biuletyn Zamówień Publicznych, Urząd Zamówień Publicznych (ezamowienia.gov.pl)"]
}
```

Every run also writes an `OUTPUT` summary to the key-value store: notices fetched per source, matched, merged, delivered, skipped by the monitor, per-source status, whether more results exist, and the charged events.

### Pricing

Pay per event: you pay only for what is delivered.

| Event | Price | When |
|---|---|---|
| Notice | **$0.002** | each delivered notice |
| Detailed notice | **$0.01** | each delivered notice with details (instead of $0.002) |
| Winner enrichment | **$0.015** | each unique winning company enriched with a company profile, once per run |

Never charged: problem rows, notices already delivered in monitor mode, the second copy of a notice found in both sources, and sole-trader, civil-partnership, foreign or unidentifiable winners.

**Worked example:** a daily monitor delivers 500 new open tenders a month ($1.00) plus one awards run with 40 enriched winners ($0.60 for the enrichment and 120 award notices $0.24): **$1.84** for the month. Set *Maximum cost per run* to cap any run; the actor stops cleanly at the limit and the summary says so.

### Data sources and legal

- **BZP / e-Zamówienia API** (Urząd Zamówień Publicznych): public information, open to re-use; read access needs no registration.
- **TED Search API** (Publications Office of the European Union): notices are free to re-use, including commercially (Decision 2011/833/EU). Source: TED (ted.europa.eu), © European Union, CC BY 4.0. Every TED row carries this attribution.
- **KRS Open API** (Ministry of Justice, CC0) and the **VAT white list** (Ministry of Finance) for winner type and enrichment.

Company-level data only: names of people (contact persons, data-protection officers, committee members) are never copied; free text is never copied. Sole traders and civil partnerships are people running a business, so their names are withheld (`name: null`) and only their tax number and awarded value are kept. When the actor cannot confirm that a winner is a company, the name is withheld too.

### Limits

- Notice types: contract notices and result notices. Corrections, plan notices, design contests, concessions and contract modifications are not included yet.
- At most 90 days and 10,000 notices per run; run several times for longer back-fills.
- Estimated values are published in only about 1 in 10 BZP contract notices; amounts are never converted between currencies.
- Winner enrichment uses the VAT white list, which allows about 100 searches per day per IP address (30 companies each). When the quota runs out, remaining winners are marked `quota_exceeded` and are not charged.
- TED gives a publication date only (no time).

### FAQ

#### How does monitor mode avoid duplicates?

It remembers, per filter set, the newest publication time and the notices delivered in the last 48 hours, in a key-value store in your own Apify account. The next run starts a few hours before that point and skips what you already have. Changing filters starts a new history; `resetMonitor` clears it.

#### Why do some winners have no name?

They are sole traders or civil partnerships (natural persons), or winners the actor could not confirm as companies. You still get the tax number, the lot and the awarded value.

#### Can I get the full notice?

Each row links to the official notice. For BZP the PDF is also available at `https://ezamowienia.gov.pl/mo-board/api/v1/Board/GetNoticePdfById?noticeId=<id>`.

#### Can I use it from my code, Zapier, Make or an AI agent?

Yes: call it through the Apify API, any Apify integration, or the Apify MCP server. The input fields have examples for agents.

#### I found a problem or need another field.

Open an issue on the actor page. Feature requests from paying users go first.

### Polski — krótko

Ogłoszenia o zamówieniach publicznych z BZP (e-Zamówienia) i TED dla zamawiających z Polski: otwarte przetargi i wyniki z wykonawcami dla każdej części, filtrowane po CPV, województwie i słowach kluczowych. Tryb monitorowania zwraca tylko nowe ogłoszenia; opcjonalnie dane firm-zwycięzców z KRS i białej listy VAT.

### Other actors from this developer

- [Polish Company Dossier](https://apify.com/matikitli/pl-company-dossier): KRS, VAT white list and risk signals for Polish companies by NIP, KRS or REGON.
- [Slovak Company Financials](https://apify.com/matikitli/sk-company-financials): financial statements of Slovak companies from the official RÚZ register, with ratios and 5-year history.

# Changelog

This Actor's version history is a separate document: https://apify.com/matikitli/pl-public-tenders/changelog.md

# Actor input Schema

## `noticeKind` (type: `string`):

`open` = open tenders you can still bid in (contract notices). `award` = awarded contracts with winners per lot (result notices). `both` = both kinds. Example: `open`.

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

BZP = national bulletin (below EU thresholds, most SME opportunities); TED = EU Tenders Electronic Daily (above thresholds). Example: \["BZP", "TED"].

## `dateFrom` (type: `string`):

First publication date (Europe/Warsaw), absolute or relative. Example: `-3 days` or `2026-09-01`. A run covers at most 90 days.

## `dateTo` (type: `string`):

Last publication date (inclusive). Empty = today. Example: `2026-09-30`.

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

What is being bought: CPV prefixes (2–8 digits) or full codes; a notice matches if any of its CPV codes starts with any of these. Example: `33` (medical equipment), `45` (construction works), `48000000-8` (software). Empty = all.

## `provinces` (type: `array`):

Only notices from these voivodeships: the buyer's province for BZP, the place of performance for TED. Example: \["malopolskie"]. Empty = all of Poland.

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

Only notices whose title contains any of these words (case- and accent-insensitive). Example: `remont`, `analizator`. Empty = no keyword filter.

## `detailed` (type: `boolean`):

Add buyer contacts (institutional e-mail, phone, website), award criteria with weights, bid deposit (wadium), contract duration and lowest/highest offers. Charged as `notice-detailed` ($0.01) instead of `notice` ($0.002).

## `enrichWinners` (type: `boolean`):

Awards only. Attach a company profile from official registers (KRS court register, VAT white list) to every winning Polish company: legal form, address, status, VAT status, main PKD activity, risk signals. Charged once per unique company per run ($0.015). Sole traders and foreign winners are never enriched or charged.

## `monitor` (type: `boolean`):

Return only notices not delivered by a previous run with the same filters. Schedule the actor daily and connect it to e-mail, Slack or your CRM. The first run uses the date range above.

## `resetMonitor` (type: `boolean`):

Forget what monitor mode delivered for these filters and start again from the date range.

## `maxItems` (type: `integer`):

Stop after this many delivered notices (1–10,000). The run summary says when more results exist. Example: 1000.

## Actor input object example

```json
{
  "noticeKind": "open",
  "sources": [
    "BZP",
    "TED"
  ],
  "dateFrom": "-2 days",
  "cpvCodes": [
    "33"
  ],
  "detailed": false,
  "enrichWinners": false,
  "monitor": false,
  "resetMonitor": false,
  "maxItems": 50
}
```

# Actor output Schema

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

Dataset items produced by the run (one per notice).

## `winners` (type: `string`):

One row per winner per lot (award notices).

## `summary` (type: `string`):

Machine-readable run summary (counts per source, per-source status, whether more results exist, charged events).

# 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 = {
    "noticeKind": "open",
    "dateFrom": "-2 days",
    "cpvCodes": [
        "33"
    ],
    "maxItems": 50
};

// Run the Actor and wait for it to finish
const run = await client.actor("matikitli/pl-public-tenders").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 = {
    "noticeKind": "open",
    "dateFrom": "-2 days",
    "cpvCodes": ["33"],
    "maxItems": 50,
}

# Run the Actor and wait for it to finish
run = client.actor("matikitli/pl-public-tenders").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 '{
  "noticeKind": "open",
  "dateFrom": "-2 days",
  "cpvCodes": [
    "33"
  ],
  "maxItems": 50
}' |
apify call matikitli/pl-public-tenders --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,matikitli/pl-public-tenders"
        }
    }
}
```

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/KAq8PgJdn2aPsOsu4/builds/uf7cwW248B7msR4lC/openapi.json
