# TED, SAM.gov, UK & Brazil Tenders Scraper – Public Procurement (`openharvest/public-tenders-scraper`) Actor

Public procurement tenders from EU TED, US SAM.gov, UK Find a Tender, UK Contracts Finder and Brazil PNCP in one unified format. Filter by keywords, CPV codes, countries, publication dates, notice type (tender, planning, award) and minimum value. Official APIs, pay per notice.

- **URL**: https://apify.com/openharvest/public-tenders-scraper.md
- **Developed by:** [Enes Bulanık](https://apify.com/openharvest) (community)
- **Categories:** Business, Lead generation, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$3.00 / 1,000 tender 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

## TED, SAM.gov, UK & Brazil Tenders Scraper – Public Procurement

Public procurement tenders from EU TED, US SAM.gov, UK Find a Tender, UK Contracts Finder and Brazil PNCP in one unified format. Filter by keywords, CPV codes, countries, publication dates, notice type (tender, planning, award) and minimum value. Official APIs, pay per notice.

**Price: $3.00 per 1,000 notices.** Uses the official open-data APIs only, with no scraping of web pages, no proxies and no login. Skipped sources and empty results are free.

### What data do you get?

Every notice, whatever its source, has the same flat fields:

| Field | Example |
|---|---|
| `source` / `sourceName` | `ted` / `EU TED`, `find-a-tender`, `contracts-finder`, `sam-gov`, `pncp` |
| `noticeId`, `url` | `692797-2026`, link to the official notice page |
| `title`, `description` | original title and trimmed description |
| `buyerName`, `buyerCountry` | contracting authority and ISO country (`SE`, `GB`, `US`, `BR`…) |
| `cpvCodes` | `["72000000", "72227000"]` |
| `procedureType` | `open`, `restricted`, `Competitive flexible procedure`, `Pregão - Eletrônico`… |
| `noticeType` | unified: `tender`, `planning`, `award`, `other` (+ `noticeTypeOriginal`) |
| `contractType` | `works`, `services`, `supplies` / `goods` |
| `publishedAt`, `deadline` | publication date and tender submission deadline |
| `estimatedValue`, `currency` | `2000000`, `SEK`, `BRL` (awarded value for award notices) |
| `lotsCount` | number of lots |
| `documentsUrl` | where to download the tender documents (e-procurement platform) |

Source-specific extras are always present (null if not applicable): `language` (TED), `ocid` and `status` (UK), `solicitationNumber`, `naicsCode`, `pscCode`, `setAside`, `placeOfPerformance`, `awardee` (SAM.gov). For Brazil PNCP: `status`, `language` (`por`), `solicitationNumber` (process number), `placeOfPerformance` (municipality, state, BR) and `awardee` (companies only, on contracts).

### Why this tender scraper?

- **5 portals, 1 schema.** EU + EEA + UK + US + Brazil public procurement in one dataset. You don't have to merge five different formats yourself.
- **Official APIs only.** Retries with backoff and rate limiting. If a source fails or is skipped, you get a free status row that explains why, and the other sources keep running.
- **Fair interleaving.** With `maxItems: 100` you get notices from every source, not 100 from TED alone.
- **Server-side filtering on TED.** Keywords (full-text, all languages), CPV codes, countries and notice types go straight into TED's expert query, so results are fast.
- **Brazil included.** PNCP is Brazil's national procurement portal (Lei 14.133/2021): pregões, concorrências, dispensas with a bidding window, credenciamentos and signed contracts from federal, state and municipal buyers, with no API key.
- **$3 per 1,000 notices** for all five sources. Status rows and empty sources are free.

### Use cases

- **Bid / tender monitoring.** Schedule a daily run with your keywords and CPV codes and get new opportunities in Slack, email or your CRM.
- **Sales intelligence.** Find public buyers that purchase your product category and see their deadlines and budgets.
- **Competitor and market analysis.** Use award notices to see who wins which contracts, at what value and in which countries.
- **Consultancies and bid writers.** Build tender alert services for clients.
- **Research and journalism.** Analyse public spending across the EU, UK, US and Brazil.
- **Brazilian B2G suppliers.** Monitor licitações from all 27 states in one feed, filtered by state and Portuguese keywords.
- **AI agents.** Give an LLM a single tool that answers "find open IT tenders in Germany over €1M".

### How to use it

1. Optionally enter **Keywords** (e.g. `software`, `cloud hosting`) and/or **CPV codes** (e.g. `72000000`).
2. Choose **Sources**, **Notice types** (default: open tenders), **Buyer countries** and the **Published from / to** window (default: last 7 days).
3. Optionally set a **Minimum estimated value** and, for US tenders, your free **SAM.gov API key**.
4. Click **Start** and export as JSON, CSV or Excel, or connect via API, webhooks, Make, Zapier, n8n or Google Sheets.

Tip: for monitoring, schedule the Actor daily with `publishedFrom: "1 day"`.

### Input

| Field | Type | Description |
|---|---|---|
| `keywords` | array | ANY of these words/phrases (case- and accent-insensitive). |
| `sources` | array | `ted`, `find-a-tender`, `contracts-finder`, `sam-gov`, `pncp`. Default: all. |
| `noticeTypes` | array | `tender` (default), `planning`, `award`, `other`. |
| `cpvCodes` | array | CPV codes or prefixes, hierarchical (`72000000`, `45`). |
| `countries` | array | Buyer countries, ISO 2-letter (DE, FR, GB, US, BR). |
| `brazilStates` | array | PNCP only: Brazilian states (UF), e.g. `SP`, `RJ`. Speeds up Brazilian searches. |
| `publishedFrom` / `publishedTo` | string | `2026-10-01` or `7 days`. Default: last 7 days. |
| `minValue` | integer | Minimum estimated value (notice currency). |
| `maxItems` | integer | Max notices in total. Default `100`. |
| `samApiKey` | secret string | Free SAM.gov public API key (only for US). |
| `descriptionMaxLength` | integer | Trim descriptions. Default `1000`, `0` = full. |

Example:

```json
{
    "keywords": ["software", "cloud hosting"],
    "cpvCodes": ["72000000"],
    "countries": ["DE", "FR", "GB"],
    "noticeTypes": ["tender"],
    "publishedFrom": "14 days",
    "minValue": 100000,
    "maxItems": 200
}
```

An empty input (`{}`) returns the newest open tenders of the last 7 days from all sources (SAM.gov is skipped without a key).

### Output

Real sample (description shortened):

```json
{
    "type": "tender",
    "source": "find-a-tender",
    "sourceName": "UK Find a Tender",
    "noticeId": "094532-2026",
    "url": "https://www.find-tender.service.gov.uk/Notice/094532-2026",
    "title": "003726 - Internal Audit Management System",
    "description": "Replacement of Internal Audit Software system. Full requirements can be found in Document 3a…",
    "buyerName": "Durham County Council",
    "buyerCountry": "GB",
    "cpvCodes": ["48100000"],
    "procedureType": "Below threshold - open competition",
    "noticeType": "tender",
    "noticeTypeOriginal": "tenderUpdate",
    "contractType": "goods",
    "publishedAt": "2026-10-07T09:57:17+01:00",
    "deadline": "2026-11-05T10:00:00Z",
    "estimatedValue": 170000,
    "currency": "GBP",
    "lotsCount": 1,
    "documentsUrl": "https://www.find-tender.service.gov.uk/Notice/094532-2026",
    "status": "active",
    "language": null,
    "ocid": "ocds-h6vhtk-07802a",
    "solicitationNumber": null,
    "naicsCode": null,
    "pscCode": null,
    "setAside": null,
    "placeOfPerformance": null,
    "awardee": null,
    "scrapedAt": "2026-10-07T19:35:00.079Z"
}
```

```json
{
    "type": "tender",
    "source": "ted",
    "sourceName": "EU TED",
    "noticeId": "692797-2026",
    "url": "https://ted.europa.eu/en/notice/-/detail/692797-2026",
    "title": "IT-Säkerhetsarkitekt",
    "buyerName": "Löf regionernas ömsesidiga försäkringsbolag",
    "buyerCountry": "SE",
    "cpvCodes": ["72000000", "72227000"],
    "procedureType": "open",
    "noticeType": "tender",
    "noticeTypeOriginal": "competition / cn-standard",
    "contractType": "services",
    "publishedAt": "2026-10-07",
    "deadline": "2026-11-06T00:00:00+01:00",
    "estimatedValue": 2000000,
    "currency": "SEK",
    "lotsCount": 1,
    "documentsUrl": "https://www.e-avrop.com/lof/e-Upphandling/NoticeLink.aspx?id=135558",
    "language": "swe"
}
```

Free status rows (`type: "status"`) explain skipped or empty sources:

```json
{ "type": "status", "source": "sam-gov", "sourceName": "US SAM.gov", "errorCode": "NO_API_KEY", "error": "US SAM.gov skipped: it requires a free personal API key. ..." }
```

`errorCode` values: `NO_API_KEY`, `INVALID_API_KEY`, `RATE_LIMITED`, `NOT_APPLICABLE` (e.g. country filter excludes the source), `NO_RESULTS`, `BAD_QUERY`, `SOURCE_FAILED`.

Brazil PNCP sample (real notice):

```json
{
    "type": "tender",
    "source": "pncp",
    "sourceName": "Brazil PNCP",
    "noticeId": "82827148000169-1-000075/2026",
    "url": "https://pncp.gov.br/app/editais/82827148000169/2026/75",
    "title": "CONTRATAÇÃO DE EMPRESA ESPECIALIZADA PARA EXECUÇÃO DE OBRAS DE INFRAESTRUTURA URBANA NO LOTEAMENTO SÃO JOSÉ III NO MUNICÍPIO DE PINHEIRO PRETO/SC",
    "buyerName": "MUNICIPIO DE PINHEIRO PRETO",
    "buyerCountry": "BR",
    "cpvCodes": [],
    "procedureType": "Concorrência - Eletrônica",
    "noticeType": "tender",
    "noticeTypeOriginal": "Concorrência - Eletrônica / Edital",
    "publishedAt": "2026-10-08T00:00:35-03:00",
    "deadline": "2026-10-23T08:15:01-03:00",
    "estimatedValue": 1900479.41,
    "currency": "BRL",
    "status": "Divulgada no PNCP",
    "language": "por",
    "solicitationNumber": "12CC2026",
    "placeOfPerformance": "Pinheiro Preto, SC, BR"
}
```

Console views: **Overview**, **Details**, **Source status**.

### Pricing

Pay-per-event pricing: you only pay for notices you receive. Platform usage is included.

| Event | Price | When |
|---|---|---|
| `tender` | **$0.003** per notice ($3.00 / 1,000) | Each tender notice saved to the dataset |
| Status rows | **Free** | Skipped sources, no results, errors |

| Job | Cost |
|---|---|
| Daily alert, ~30 new matching notices | **$0.09** per day |
| 1,000 notices | **$3.00** |
| 10,000 award notices for market analysis | **$30.00** |

Set **Max cost per run** in run options and the Actor stops cleanly when your budget is reached.

### Use with AI agents (MCP)

Connect this Actor to Claude, ChatGPT, Cursor or n8n through the [Apify MCP server](https://mcp.apify.com). The input is small and typed and the output is flat JSON, which works well for tool calls. Example input an agent can send:

```json
{
    "keywords": ["cybersecurity"],
    "countries": ["DE", "NL"],
    "noticeTypes": ["tender"],
    "publishedFrom": "7 days",
    "minValue": 500000,
    "maxItems": 20
}
```

Typical prompts: *"Find open construction tenders in Poland published this week"*, *"Which UK councils tendered for waste collection over £1M this month?"*, *"List recent US federal solicitations for drones"* (needs a SAM.gov key), *"Find pregões for software in São Paulo state published yesterday"*.

### FAQ

**Do I need API keys?** Not for TED, Find a Tender, Contracts Finder or Brazil PNCP. SAM.gov requires a free personal key: sign in at sam.gov, go to **Account Details**, then **Public API Key**. Paste it into `samApiKey` (stored encrypted). Personal SAM.gov keys allow about 10 requests per day. Each request returns up to 1,000 notices, so one or two runs per day are fine.

**How do keywords work?** On TED they use TED's own full-text search, which covers every language and every notice field. On UK and US sources they match the title, description and buyer name. Keywords are OR-ed. TED notices are in the buyer's language, so add local terms if you need them (`Software`, `logiciel`, `oprogramowanie`).

**How does Brazil PNCP work?** The Actor reads PNCP's official open-data API (consulta v1). Notice types map like this: pregão, concorrência, concurso, diálogo competitivo, credenciamento and pré-qualificação are `tender`; a dispensa is `tender` when it has a bidding window and `other` when it is a direct purchase; inexigibilidade, auctions (leilão), revoked or annulled processes are `other`; manifestação de interesse is `planning`; signed contracts are `award`. Values are in BRL and times are Brasília time (`-03:00`). PNCP has no CPV codes, so it is skipped when you filter by CPV.

**Why are Brazilian keyword searches slower?** PNCP has no keyword search in its open API and limits request rates, so the Actor reads every notice of the window (about 1,000 notices per minute) and filters locally. Brazil publishes about 5,000 tender-type notices and 8,000 contracts per working day. For keyword alerts, use a short window (`publishedFrom: "1 day"`), add `brazilStates`, and use Portuguese keywords (`software`, `limpeza`, `merenda`). Without keywords the first results arrive within seconds.

**Why are some values or deadlines empty?** Buyers don't always publish an estimated value. Planning and award notices have no submission deadline. If you set `minValue`, notices without a value are excluded.

**Why are TED dates without a time?** TED publishes notices once a day, so `publishedAt` is a date (`2026-10-07`). Deadlines include the time and time zone.

**Are UK below-threshold contracts included?** Yes. Contracts Finder covers lower-value UK contracts. Find a Tender covers above-threshold contracts and Procurement Act 2023 notices. The same procedure can appear in both.

**How far back can I go?** As far as each API allows (TED and the UK services go back years, PNCP to 2021). SAM.gov limits one query to a 1-year window.

**Can I monitor tenders daily?** Yes. Create an Apify Schedule with `publishedFrom: "1 day"` and connect a webhook, Slack, email or Google Sheets integration.

### Is it legal?

All five sources are **official open-data APIs** that governments publish so the public can reuse procurement data: TED (EU Publications Office, reuse allowed), Find a Tender and Contracts Finder (UK Open Government Licence), SAM.gov (US public data) and PNCP (Brazilian federal open data under the Access to Information Law).

The Actor does not collect personal data. It does not output contact persons, e-mails or phone numbers from the notices. Brazilian contracts signed with natural persons or sole traders are left out entirely, and CPF numbers, e-mail addresses, phone numbers and "Sr./Sra." names are removed from Brazilian notice texts. Follow each source's terms of use when you redistribute the data.

### Related actors

Related actors by the same developer:

- *GLEIF LEI Lookup – Legal Entity Identifier & Parent Companies* (look up the legal entities behind buyers and suppliers)
- *PDF to Markdown – DOCX, PPTX, XLSX & HTML for LLM & RAG* (turn downloaded tender documents into text for an LLM)
- *Bulk WHOIS Lookup – RDAP, DNS Records, SSL & Redirects* (check the websites of suppliers and buyers)
- *Google News Scraper – Full Article Text & Real Publisher URLs* (follow news about buyers and awarded contracts)

### Support & feedback

Missing a source or field? Open an issue in the **Issues** tab.

# Actor input Schema

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

Optional. Return notices that contain ANY of these words or phrases in the title or description (case- and accent-insensitive). A multi-word entry is matched as a phrase, e.g. <code>cloud hosting</code>. TED searches its full notice text in all languages, so also try local-language terms (e.g. <code>Software</code>, <code>logiciel</code>). For Brazil PNCP use Portuguese terms (e.g. <code>software</code>, <code>limpeza</code>, <code>pavimentação</code>).

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

Which procurement portals to search. SAM.gov needs your free API key (see below) - without it SAM.gov is skipped and a free status row explains why. Brazil PNCP (licitações) needs no key.

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

<b>tender</b> = open calls for tender / solicitations (default), <b>planning</b> = prior information, market engagement, sources sought, <b>award</b> = contract award notices, <b>other</b> = modifications, cancellations, voluntary transparency notices.

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

Optional. Common Procurement Vocabulary codes - a notice matches if any of its codes falls under one of these (hierarchical). Use full codes like <code>72000000</code> (IT services) or prefixes like <code>45</code> (construction). Not available for SAM.gov (US uses NAICS), so SAM.gov is skipped when CPV codes are set. Same for Brazil PNCP (Brazil uses CATMAT/CATSER).

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

Optional. 2-letter ISO codes of the buying authority's country, e.g. <code>DE</code>, <code>FR</code>, <code>PL</code>, <code>GB</code>, <code>US</code>, <code>BR</code>. UK sources are only searched when GB is included (or the list is empty), SAM.gov only with US, PNCP only with BR.

## `brazilStates` (type: `array`):

Optional. Only Brazilian notices from these states (2-letter UF codes, e.g. <code>SP</code>, <code>RJ</code>, <code>MG</code>, <code>DF</code>). Filtered on the PNCP server for tenders, which also makes keyword searches much faster. Ignored by the other sources.

## `publishedFrom` (type: `string`):

Only notices published on or after this date. Absolute (<code>2026-10-01</code>) or relative (<code>7 days</code>, <code>2 weeks</code>, <code>1 month</code>). Default: 7 days ago.

## `publishedTo` (type: `string`):

Only notices published on or before this date (inclusive). Default: now.

## `minValue` (type: `integer`):

Optional. Only notices with an estimated (or awarded) value of at least this amount, in the notice's own currency (EUR, GBP, USD, SEK...). Notices without a published value are excluded when this is set.

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

Maximum number of notices in total across all sources (sources are interleaved fairly). You pay per notice, so this also caps your cost. 0 = no limit.

## `samApiKey` (type: `string`):

Optional, only for US SAM.gov. Free personal key: sign in at sam.gov -> Account Details -> Public API Key. Stored encrypted. Personal keys allow about 10 requests per day; each request returns up to 1,000 notices.

## `descriptionMaxLength` (type: `integer`):

Descriptions are trimmed to this many characters (0 = full text).

## Actor input object example

```json
{
  "keywords": [
    "software",
    "cloud hosting",
    "cybersecurity"
  ],
  "sources": [
    "ted",
    "find-a-tender",
    "contracts-finder"
  ],
  "noticeTypes": [
    "tender",
    "award"
  ],
  "cpvCodes": [
    "72000000",
    "48000000",
    "45"
  ],
  "countries": [
    "DE",
    "FR",
    "GB"
  ],
  "brazilStates": [
    "SP",
    "RJ"
  ],
  "publishedFrom": "7 days",
  "publishedTo": "2026-10-07",
  "minValue": 100000,
  "maxItems": 100,
  "descriptionMaxLength": 1000
}
```

# Actor output Schema

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

All scraped items in the default dataset (JSON, CSV, Excel and more via the dataset export).

## `files` (type: `string`):

Records saved in the default key-value store, e.g. the run summary.

# 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 = {
    "maxItems": 30
};

// Run the Actor and wait for it to finish
const run = await client.actor("openharvest/public-tenders-scraper").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 = { "maxItems": 30 }

# Run the Actor and wait for it to finish
run = client.actor("openharvest/public-tenders-scraper").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 '{
  "maxItems": 30
}' |
apify call openharvest/public-tenders-scraper --silent --output-dataset

```

## MCP server setup

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

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/xKWheiIlM5IlflONC/builds/tb9LoPnZYomlq0AVo/openapi.json
