# Public Tender & RFP Radar (`rational_opaque/public-tender-rfp-radar`) Actor

US, EU and UK public tenders in one schema — AI fit score, requirements summary, and new/changed tracking. Official APIs only.

- **URL**: https://apify.com/rational_opaque/public-tender-rfp-radar.md
- **Developed by:** [Rational Opaque](https://apify.com/rational_opaque) (community)
- **Categories:** Lead generation, AI, Automation
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.10 / 1,000 tender founds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

## Public Tender & RFP Radar

US SAM.gov, EU TED, and UK Find a Tender notices in one schema, with an optional AI fit score and new/changed tracking. Official public APIs only.

### Try in 60 seconds

Default input (TED + Find a Tender, IT services CPV, last 7 days, 25 notices, AI off):

```json
{
  "sources": ["ted", "uk_find_a_tender"],
  "keywords": ["software development", "artificial intelligence"],
  "cpvCodes": ["72000000"],
  "lookbackDays": 7,
  "maxResults": 25,
  "onlyOpen": true,
  "enableAi": false
}
```

Each saved row looks like this:

```json
{
  "id": "ted:741184-2026",
  "source": "ted",
  "sourceId": "741184-2026",
  "title": "Czechia – IT services: consulting, software development, Internet and support – Dočasný provoz a nezbytný rozvoj SAP MZe 2027+",
  "buyerName": "Ministerstvo zemědělství",
  "buyerCountry": "CZ",
  "status": "open",
  "estimatedValue": 37953900,
  "currency": "CZK",
  "cpvCodes": ["72000000", "72261000"],
  "publishedAt": "2026-10-26T23:00:00.000Z",
  "deadlineAt": "2026-11-30T23:00:00.000Z",
  "sourceUrl": "https://ted.europa.eu/en/notice/-/detail/741184-2026",
  "fetchedAt": "2026-11-03T18:49:47.792Z",
  "changeStatus": "new",
  "changedFields": []
}
```

That row is from the default run on 3 November 2026. `changeStatus` is `new` on the first run for a profile and `unchanged` when the same notice comes back with the same title, deadline, value, status, documents, and description length.

### What you get

| Field                                          | Meaning                                                                                           |
| ---------------------------------------------- | ------------------------------------------------------------------------------------------------- |
| `id`                                           | `source:sourceId`, used for dedupe and change tracking                                            |
| `source`                                       | `sam_gov`, `ted`, or `uk_find_a_tender`                                                           |
| `title`, `description`                         | Notice text. SAM.gov descriptions are fetched only when AI is on                                  |
| `buyerName`, `buyerCountry`                    | Buyer. Country is ISO 3166-1 alpha-2                                                              |
| `status`                                       | `open`, `closed`, `awarded`, `cancelled`, or `unknown`. The default input keeps `open` only       |
| `estimatedValue`, `currency`                   | Value when the notice publishes one. Currency is ISO 4217. SAM.gov solicitations are usually null |
| `cpvCodes`, `naicsCodes`, `pscCode`            | Classification codes present on that source                                                       |
| `setAside`                                     | SAM.gov set-aside, when present                                                                   |
| `publishedAt`, `deadlineAt`                    | ISO 8601                                                                                          |
| `documents`, `contacts`                        | Links and published contact points                                                                |
| `sourceUrl`                                    | Public notice page                                                                                |
| `apiUrl`                                       | Source API or XML URL with any API key removed                                                    |
| `fetchedAt`                                    | When this run read the notice                                                                     |
| `changeStatus`, `changedFields`, `firstSeenAt` | Compared with the named key-value store `tender-radar-state`                                      |
| `ai`                                           | Present only when a summary and score were produced                                               |

Dataset views: **Overview** and **AI match**.

### Sources and coverage

| Source           | API                                                               | Auth             |
| ---------------- | ----------------------------------------------------------------- | ---------------- |
| EU TED           | Search API v3, `POST https://api.ted.europa.eu/v3/notices/search` | None             |
| UK Find a Tender | OCDS 1.1.5 release packages                                       | None             |
| US SAM.gov       | Get Opportunities Public API v2                                   | Your `samApiKey` |

TED and Find a Tender are on by default. If SAM.gov is selected and `samApiKey` is empty, that source is skipped and the others continue.

Licences and attribution:

- TED notices are European Union documents from [TED](https://ted.europa.eu). Reuse them under the terms published by the Publications Office.
- Find a Tender data is available under the [Open Government Licence v3.0](https://www.nationalarchives.gov.uk/doc/open-government-licence/version/3/), except where a notice says otherwise.
- SAM.gov opportunity records are US federal public data.

This actor calls those APIs directly. It does not log in to a portal, solve a captcha, or rotate proxies. India GeM and CPPP are out of scope.

Contact names published on the notice are kept because the source published them. Use them only where you have a lawful reason. Do not use them for unsolicited marketing.

### AI match

Turn on `enableAi` and set `llmApiKey` (OpenAI-compatible; `llmBaseUrl` and `llmModel` are configurable, default `gpt-4o-mini`). The model reads the notice text and your `companyProfile` and returns:

- a requirements summary and key requirements
- eligibility guesses such as local presence, security clearance, set-aside, or minimum turnover, each marked `likely`, `unlikely`, or `unknown`, with a short evidence quote
- `matchScore` from 0 to 100, plus reasons and risks

Those flags are guesses from the notice text, not a bid/no-bid decision and not legal advice. Notices under 200 characters are skipped and not charged. At most `aiMaxPerRun` notices are sent to the model (default 10). If AI is on and `llmApiKey` is missing, the run logs an error and still saves the tenders without AI.

### Pricing

Pay per event. The platform also charges a run start event.

| Event               | When                         | Price    |
| ------------------- | ---------------------------- | -------- |
| `apify-actor-start` | Once per run (platform)      | $0.00005 |
| `tender-found`      | A normalized notice is saved | $0.003   |
| `tender-summarized` | An AI summary was produced   | $0.005   |
| `match-scored`      | An AI fit score was produced | $0.004   |

Example for 100 saved notices and AI off: $0.00005 + 100 × $0.003 = **$0.30005**, plus compute. With the default AI cap of 10 notices that all produce a summary and a score: add 10 × $0.009 = $0.09, about **$0.39**.

Unchanged notices dropped by `onlyNewOrChanged` are not saved and not charged. The actor stops saving when `ACTOR_MAX_TOTAL_CHARGE_USD` would be exceeded. Suggested max charge is **$1.00** per run.

Free-plan platform runs do not pay the actor developer. Prices above are for paid users.

### Scheduling and change tracking

Schedule the actor daily. Set `profileId` to a stable name per search. The state key is a hash of `profileId` and the selected sources, stored in the named key-value store `tender-radar-state`.

A notice is `changed` when the title, deadline, value, status, document URLs, or description length differ from the last saved snapshot. `changedFields` lists which of those moved. `onlyNewOrChanged` drops `unchanged` rows. The store keeps the latest 5,000 snapshots per profile.

### Run options

| Setting              | Value                     |
| -------------------- | ------------------------- |
| Memory               | 1024 MB (maximum 2048 MB) |
| Timeout              | 300 seconds               |
| Build                | `latest`                  |
| Suggested max charge | $1.00 per run             |

The default input is meant to finish inside that limit: 25 notices, AI off, 7-day lookback.

### FAQ and limitations

- **No SAM.gov key.** SAM.gov is skipped. TED and Find a Tender still run.
- **429 or 5xx.** The actor retries with backoff, then keeps whatever that source already returned.
- **Daily SAM.gov quota.** The SAM.gov source stops. Other sources are kept.
- **No keyword on SAM.gov except title.** Keywords are applied to the title. Description text is loaded only for AI, and only after the title matches.
- **Find a Tender has no CPV query parameter.** CPV and keywords are applied while paging, up to 10 pages.
- **Values.** Many solicitations do not publish a value. `minValue` ignores unknown values and drops known values below the floor.
- **Not included.** Bid submission, logged-in portals, GeM, CPPP, attachment OCR, award history, and alerts.

### Support and feedback

Use the Issues tab on this actor. Do not send personal contact details.

# Actor input Schema

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

Official sources to query. SAM.gov is skipped with a warning when samApiKey is empty.

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

Match if any keyword appears. A multi-word keyword also matches when each word is present. TED is filtered in the expert query. SAM.gov and Find a Tender are filtered on title and description.

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

Common Procurement Vocabulary codes. A code ending in zeros also matches that division.

## `naicsCodes` (type: `array`):

NAICS codes, up to 6 digits. Applied only to SAM.gov.

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

Optional buyer-country filter, for example DE, FR, GB, US.

## `lookbackDays` (type: `integer`):

Publication or last-updated window. SAM.gov allows at most one year.

## `deadlineAfter` (type: `string`):

Drop notices whose deadline is before this date. Notices with no deadline are kept.

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

Drop notices with a known value below this amount. Unknown values are kept.

## `maxResults` (type: `integer`):

Maximum records saved per run, after filtering.

## `onlyNewOrChanged` (type: `boolean`):

Uses the named key-value store tender-radar-state for this profile and source set.

## `onlyOpen` (type: `boolean`):

Drop closed, awarded, and cancelled notices, and any notice whose deadline is already past. Notices with no deadline are kept when their status is open.

## `profileId` (type: `string`):

Separates change-tracking state when you watch more than one search.

## `enableAi` (type: `boolean`):

Off unless you supply llmApiKey. Short notices under 200 characters are skipped and not charged.

## `companyProfile` (type: `string`):

What you sell, where you can deliver, and hard limits such as clearances you do not hold.

## `minMatchScore` (type: `integer`):

When AI is on, drop scored notices below this score.

## `aiMaxPerRun` (type: `integer`):

Cap on notices sent to the model in one run.

## `llmApiKey` (type: `string`):

Your key for an OpenAI-compatible API. Never logged.

## `llmBaseUrl` (type: `string`):

OpenAI-compatible base URL.

## `llmModel` (type: `string`):

Model name sent to the OpenAI-compatible API.

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

Public API key from SAM.gov Account Details. Required only when SAM.gov is selected. Never logged.

## Actor input object example

```json
{
  "sources": [
    "ted",
    "uk_find_a_tender"
  ],
  "keywords": [
    "software development",
    "artificial intelligence"
  ],
  "cpvCodes": [
    "72000000"
  ],
  "naicsCodes": [
    "541511"
  ],
  "lookbackDays": 7,
  "maxResults": 25,
  "onlyNewOrChanged": false,
  "onlyOpen": true,
  "profileId": "default",
  "enableAi": false,
  "minMatchScore": 0,
  "aiMaxPerRun": 10,
  "llmBaseUrl": "https://api.openai.com/v1",
  "llmModel": "gpt-4o-mini"
}
```

# Actor output Schema

## `tenders` (type: `string`):

Default dataset items. Fields: id, source, title, buyerName, buyerCountry, status, estimatedValue, currency, deadlineAt, sourceUrl, fetchedAt, changeStatus. ai.matchScore (0–100) is present only when AI scoring produced a score.

# 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": [
        "software development",
        "artificial intelligence"
    ],
    "cpvCodes": [
        "72000000"
    ],
    "naicsCodes": [
        "541511"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("rational_opaque/public-tender-rfp-radar").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": [
        "software development",
        "artificial intelligence",
    ],
    "cpvCodes": ["72000000"],
    "naicsCodes": ["541511"],
}

# Run the Actor and wait for it to finish
run = client.actor("rational_opaque/public-tender-rfp-radar").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": [
    "software development",
    "artificial intelligence"
  ],
  "cpvCodes": [
    "72000000"
  ],
  "naicsCodes": [
    "541511"
  ]
}' |
apify call rational_opaque/public-tender-rfp-radar --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,rational_opaque/public-tender-rfp-radar"
        }
    }
}
```

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/ofBmMGme9ITbydEr5/builds/flNnmXzraZNrVDNDy/openapi.json
