# Veille Marchés Publics 🇫🇷🇪🇺 : BOAMP + TED, Alertes & IA (`tagadanar/french-public-tenders`) Actor

Tous les appels d'offres BOAMP (France) et TED (UE) réunis dans un seul actor, avec filtres mots-clés, codes CPV, département et deadline. Le mode veille ne facture que les nouveaux marchés, avec alertes Slack/webhook et scoring IA de pertinence en option. Données officielles, dédupliquées.

- **URL**: https://apify.com/tagadanar/french-public-tenders.md
- **Developed by:** [Tagada Data](https://apify.com/tagadanar) (community)
- **Categories:** Lead generation, Automation, AI
- **Stats:** 2 total users, 0 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.80 / 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/platform/actors/running/actors-in-store#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

## French & EU Public Tenders Monitor (BOAMP + TED)

**Track public procurement opportunities across France and the EU from one call, and let AI tell you which ones are worth bidding on.** Query **BOAMP** (the French official procurement journal, *Bulletin officiel des annonces des marchés publics*) and **TED** (*Tenders Electronic Daily*, the EU-wide procurement journal) with keyword, CPV, department and deadline filters, then get one clean, unified, structured record per tender.

Built for **bid/tender monitoring, sales & business development to the public sector, market intelligence, and AI agents** (works via API and MCP out of the box).

### Why this actor

- ✅ **Two official sources, one schema.** BOAMP (France) and TED (EU) results come back normalized to identical fields, deduplicated, and filtered by deadline.
- ✅ **True monitor mode:** it remembers what it already reported, so scheduled runs return (and charge for) **new tenders only**.
- ✅ **Slack and webhook alerts.** New tenders land in your Slack channel or any endpoint the moment a run finds them.
- ✅ **AI relevance scoring**, optional and off by default (bring your own Anthropic API key for now; a built-in option is planned). Describe your company once and every tender gets a **0-100 relevance score**, a one-line reason, and a **bid / consider / skip** recommendation.
- ✅ **Official open data** from DILA (BOAMP) and the EU Publications Office (TED). No scraping, no stale caches.
- ✅ **Real filtering** on keywords, French department codes, CPV codes, publication window, and "only tenders still open for bids".

### The 5-minute tender radar

1. Set your `keywords` / `cpvCodes` / `departments`.
2. Turn on **`monitorMode`** and paste a **Slack webhook URL**.
3. (Optional) Describe your business in **`companyProfile`**, add your **`anthropicApiKey`** and set `alertMinScore: 60`.
4. Create an Apify **Schedule** (daily).

Every morning, your Slack channel gets only the **new** tenders relevant to **your** business, scored and sorted. Nothing you've already seen, nothing off-topic.

### Use cases

- **Never miss a relevant tender.** Get every new public contract matching your keywords or CPV codes the day it's published.
- **Stop reading irrelevant tenders**: the AI score does that reading for you and tells you which ones actually fit.
- **Public-sector sales.** Build a live pipeline of buyers and deadlines across your segment and region.
- **Market intelligence**, plain and simple: who's buying what, where, and by when.
- **AI agents.** Plug into Claude / Cursor via MCP and ask *"any open IT tenders in Île-de-France closing this month?"*

### Input

```json
{
    "keywords": ["logiciel", "cybersécurité", "infogérance"],
    "sources": ["boamp", "ted"],
    "departments": ["75", "69", "13"],
    "cpvCodes": ["72000000"],
    "publishedWithinDays": 7,
    "onlyOpen": true,
    "monitorMode": true,
    "monitorName": "cyber-idf",
    "webhookUrl": "https://hooks.slack.com/services/XXX/YYY/ZZZ",
    "companyProfile": "ESN de 15 personnes à Paris : audit cybersécurité, pentest, développement sécurisé, RGPD. Clients secteur public et santé.",
    "alertMinScore": 60
}
```

- `keywords`: matched in the tender object or title (OR logic). Leave it empty and every tender in your other filters comes through.
- `sources`: `boamp`, `ted`, or both.
- `departments`: French department codes, used as a BOAMP filter.
- `cpvCodes`: Common Procurement Vocabulary codes, used as a TED filter.
- `onlyOpen`: drops tenders whose response deadline has already passed.
- `monitorMode`: only returns tenders not seen in previous runs (tracked per `monitorName`).
- `webhookUrl`: a Slack incoming webhook for a digest message, or any URL for a JSON payload.
- `companyProfile`: enables AI scoring. A few sentences is enough, in French or English.
- `alertMinScore`: alerts only include tenders scoring at least this value.

### Output (one record per tender)

```json
{
    "source": "TED",
    "id": "378060-2026",
    "title": "France, Services de maintenance des systèmes...",
    "buyer": "GRENOBLE ALPES METROPOLE",
    "publicationDate": "2026-06-03",
    "deadline": "2026-07-20",
    "marketType": "Services",
    "cpvCodes": ["72250000"],
    "location": "NUTS FRK24",
    "country": "FR",
    "url": "https://ted.europa.eu/fr/notice/-/detail/378060-2026",
    "relevanceScore": 82,
    "relevanceReason": "Maintenance de systèmes IT pour une métropole : cœur de métier, région couverte.",
    "recommendation": "bid",
    "source_ref": "api.ted.europa.eu (TED / EU Publications Office)",
    "retrievedAt": "2026-07-03T09:12:00.000Z"
}
```

BOAMP records share the exact same shape (`source: "BOAMP"`, `location: "FR dept 75"`, `url` to boamp.fr). The `relevance*` fields appear when `companyProfile` is set; results are then sorted best-first.

### Companion actors (French open-data suite)

- [**French Company KYC / KYB**](https://apify.com/tagadanar/french-company-kyc): enrich any SIREN/SIRET/company name with INSEE SIRENE + BODACC data and qualify the buyers and bidders behind a tender.
- [**French Real Estate Sales (DVF)**](https://apify.com/tagadanar/french-real-estate-dvf): official recorded property sale prices straight from the land registry.

### Pricing

Pay per event, no subscription:

| Event | When |
|---|---|
| Actor start | Once per run |
| Tender found | Per tender returned (in monitor mode: **new tenders only**) |
| Tender scored | Per tender AI-scored (only when `companyProfile` is set). *Billable event goes live July 18, 2026; scoring is free until then.* |

### FAQ

**Where does the data come from?** Official open data only: `boamp-datadila.opendatasoft.com` (BOAMP / DILA) and `api.ted.europa.eu` (TED / EU Publications Office). Fetched live at run time.

**How does monitor mode work?** The actor keeps a per-`monitorName` memory of every tender id it already returned (kept 120 days). Scheduled runs output only what's new, so you're not charged twice for the same tender.

**How does AI scoring work?** Each tender's key facts (title, buyer, type, CPV, location, deadline) are rated against your `companyProfile` by a fast Claude model, called with **your own Anthropic API key** (`anthropicApiKey` input; get one at console.anthropic.com). You get a 0-100 score, a one-sentence reason, and bid/consider/skip. Token cost on your key is tiny (~$1 per 1,000 tenders), and your key is used for the calls only, never stored.

**How fresh is it?** Both registries publish continuously; the actor returns what's live at run time. Schedule it daily for a monitoring feed.

**Can I filter by amount / procedure type?** Keywords, department, CPV, deadline and window are supported today. More structured filters are on the roadmap, so open an issue with what you need.

**Does it deduplicate?** Yes, within a run (by source + notice id), and across runs in monitor mode.

**Does it work with AI agents?** Yes, exposed via REST API and **MCP**, callable as a tool from Claude, Cursor & co.

***

### Something missing?

If you need an extra field, another source, or a different output, open an issue on this Actor and describe it. I read every request and small additions usually ship within days. More French company and tender Actors are on [my profile](https://apify.com/tagadanar).

*Keywords: appels d'offres, marchés publics, BOAMP, TED, public tenders France, EU procurement, tender monitoring, tender alerts, veille marchés publics, CPV, appel d'offre API, government contracts, AI tender scoring, bid/no-bid.*

# Actor input Schema

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

Free-text terms to match in the tender object/title (matched with OR). Leave empty to get all recent tenders in your other filters. E.g. <code>logiciel</code>, <code>cybersécurité</code>, <code>infogérance</code>.

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

Which registries to query.

## `departments` (type: `array`):

Filter BOAMP tenders by French department code(s), e.g. <code>75</code>, <code>69</code>, <code>2A</code>. Empty = all of France.

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

Common Procurement Vocabulary codes to filter TED results, e.g. <code>72000000</code> (IT services). Empty = all categories.

## `publishedWithinDays` (type: `integer`):

Only return tenders published in this window.

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

Exclude tenders whose response deadline has already passed (based on the published deadline, when available).

## `maxResultsPerSource` (type: `integer`):

Cap the number of tenders returned from each registry.

## `monitorMode` (type: `boolean`):

Remember which tenders were already returned in previous runs and only output (and charge for) new ones. Perfect with an Apify Schedule: run daily, get only what's new.

## `monitorName` (type: `string`):

Memory bucket for monitor mode. Use a different name per saved search (e.g. <code>cyber-paris</code>, <code>btp-sud</code>) so each keeps its own history.

## `webhookUrl` (type: `string`):

POST new tenders to this URL after each run. Slack incoming-webhook URLs (<code>hooks.slack.com</code>) get a formatted digest message; any other URL gets a JSON payload. Leave empty to disable.

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

Optional — leave empty to get normal results (no API key needed, nothing extra billed). If filled: describe what your company sells and to whom (a few sentences, French or English); each tender then gets <code>relevanceScore</code> (0–100), <code>relevanceReason</code> and a <code>bid/consider/skip</code> recommendation, sorted by score. Requires your Anthropic API key below.

## `anthropicApiKey` (type: `string`):

Leave empty unless you filled in the company profile above. Get one at <code>console.anthropic.com</code>. Used only to score tenders against your profile; never stored. If empty, scoring is simply skipped.

## `maxTendersToScore` (type: `integer`):

Cap on AI-scored tenders per run (each scored tender is a paid event).

## `alertMinScore` (type: `integer`):

Webhook/Slack alerts only include tenders with a relevance score at or above this value (unscored tenders always alert). 0 = alert on everything.

## Actor input object example

```json
{
  "keywords": [
    "logiciel",
    "développement"
  ],
  "sources": [
    "boamp",
    "ted"
  ],
  "departments": [],
  "cpvCodes": [],
  "publishedWithinDays": 7,
  "onlyOpen": true,
  "maxResultsPerSource": 100,
  "monitorMode": false,
  "monitorName": "default",
  "maxTendersToScore": 50,
  "alertMinScore": 0
}
```

# Actor output Schema

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

All matched tender notices (one item per tender) in the default dataset.

# 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": [
        "logiciel",
        "développement"
    ],
    "departments": [],
    "cpvCodes": []
};

// Run the Actor and wait for it to finish
const run = await client.actor("tagadanar/french-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 = {
    "keywords": [
        "logiciel",
        "développement",
    ],
    "departments": [],
    "cpvCodes": [],
}

# Run the Actor and wait for it to finish
run = client.actor("tagadanar/french-public-tenders").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).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": [
    "logiciel",
    "développement"
  ],
  "departments": [],
  "cpvCodes": []
}' |
apify call tagadanar/french-public-tenders --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=tagadanar/french-public-tenders",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/acts/kBKekwWbddKSLCRJ9/builds/gIYUVe2pnKffUAmcv/openapi.json
