# France BOAMP Tenders Scraper: Appels d'Offres to Excel (`tenderfeed/france-boamp-tenders`) Actor

French public tenders and awards from BOAMP, the official bulletin (DILA open data API). Filter by keyword, CPV, department, notice type, value, deadline. English schema, GDPR-safe defaults.

- **URL**: https://apify.com/tenderfeed/france-boamp-tenders.md
- **Developed by:** [TenderFeed](https://apify.com/tenderfeed) (community)
- **Categories:** Lead generation, Automation
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 results

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

## France BOAMP Public Tenders Scraper (appels d'offres) by TenderFeed

Search **French public tenders and contract awards** from the **BOAMP** (Bulletin officiel des annonces des marchés publics), the official French government bulletin where State bodies, local authorities, hospitals and public companies publish their *appels d'offres*. Filter by **keyword, CPV code, department, notice type, contract type, buyer, value (EUR) and deadline**. Clean, English-labelled JSON, CSV or Excel.

Built by **TenderFeed** ([apify.com/tenderfeed](https://apify.com/tenderfeed)) on the official BOAMP open data API published by DILA (Direction de l'information légale et administrative) under the French **Licence Ouverte / Etalab** open licence. No API key, no login. BOAMP publishes around **600 notices per working day**, including the below-EU-threshold notices (MAPA, 90 k€+) that never reach TED.

### What can you do with it?

- **Daily French bid alerts** for your sector and regions (e.g. IT services in Île-de-France).
- **Lead generation**: buyer organisation, city and department in every row; contact name, email and phone on request (`includeBuyerContacts`).
- **Win/loss and competitor analysis**: `ATTRIBUTION` notices with winners (`awardees`) and awarded amounts.
- **Market sizing** of French public spending by CPV, department or buyer.
- **AI agents**: use it as an **MCP tool** (Apify MCP server) to answer *"Which French hospitals are tendering for cleaning services this week?"*

### Input example

```json
{
  "keywords": ["informatique", "logiciel"],
  "noticeTypes": ["APPEL_OFFRE", "ATTRIBUTION"],
  "contractTypes": ["SERVICES"],
  "departments": ["75", "92", "93", "94"],
  "cpvCodes": ["72"],
  "publishedFrom": "7 days",
  "onlyOpen": true,
  "maxResults": 0
}
```

- `keywords` use BOAMP's own full-text search over the whole notice, so French terms work best (`informatique`, `nettoyage`, `travaux`).
- `noticeTypes`: `APPEL_OFFRE` (calls for tenders, default), `ATTRIBUTION` (awards), `RECTIFICATIF`, `PRE-INFORMATION`, `MODIFICATION`, `ANNULATION`, `EX_ANTE_VOLONTAIRE`, `QUALIFICATION`.
- `departments`: French department codes (`75`, `69`, `2A`, `971`...).

### Output example

Real row from a live run (2026-10-29, default input, description shortened):

```json
{
  "source": "boamp",
  "sourceId": "26-105605",
  "url": "https://www.boamp.fr/pages/avis/?q=idweb:26-105605",
  "title": "ASSISTANCE A MAITRISE D’OUVRAGE POUR LE SUIVI DES ENJEUX ENVIRONNEMENTAUX ET DE DEVELOPPEMENT DURABLE (AMO DD) DANS LE CADRE DE LA CONSTRUCTION DU CENTRE PENITENTIAIRE DE NIMES (30)",
  "noticeType": "Avis de marché",
  "status": "active",
  "procedureType": "Procédure Ouverte",
  "contractType": "services",
  "buyerName": "AGENCE PUBLIQUE POUR L'IMMOBILIER DE LA JUSTICE (APIJ)",
  "buyerCountry": "FR",
  "buyerCity": "LE KREMLIN-BICETRE",
  "cpvCodes": ["71313000"],
  "otherClassificationCodes": ["FR-DEP:13", "FR-DEP:30", "FR-DEP:34", "FR-DEP:75", "FR-DEP:84", "FR-DEP:94"],
  "publishedAt": "2026-10-29",
  "deadlineAt": "2026-11-30T12:00:00+01:00",
  "submissionUrl": "https://www.marches-publics.gouv.fr/?page=Entreprise.EntrepriseAdvancedSearch&AllCons&id=3094532&orgAcronyme=d3f",
  "boampFamily": "Marchés entre 90 k€ et seuils européens",
  "boampDescriptors": ["Assistance à maîtrise d'ouvrage", "Bâtiment"]
}
```

Same schema as the other TenderFeed Actors (EU TED, UK, SAM.gov, Switzerland, Poland, World Bank...), so tenders from every country merge into one table. Deadlines are converted to explicit Paris time offsets.

### Buyer contacts and GDPR (`includeBuyerContacts`)

By default (`includeBuyerContacts: false`) the Actor returns **organisation-level data only**: buyer name, city, country, notice, documents and submission links. Contact person names, email addresses and phone numbers are removed from the output and from the optional `raw` payload, and email addresses inside description text are masked as `[email removed]`.

Set `includeBuyerContacts: true` to keep them exactly as published. Only do this if you have a lawful basis under the GDPR (for example legitimate interest for B2G sales) and honour objection and erasure requests. In a live test (36 notices matching "informatique", 2026-10-29) contacts-on returned an email on 27/36 rows, a contact name on 33/36 and a phone on 29/36; contacts-off returned 0 of each while keeping `buyerName` on 36/36.

### Daily alerts ("only new" monitoring mode)

Turn on `onlyNew`, give the search a `monitoringId` (e.g. `"fr-it-daily"`) and schedule the Actor daily. Each run returns, and charges for, only notices you have not received before. Pair it with an Apify integration (Slack, email, Google Sheets, Zapier, Make) for a ready-made French tender alert.

### Sample output (real run)

One row from a run on 6 November 2026 (core columns only; every row also has description, status, procedureType, documentsUrl and more). Contact values are masked here. Since schema 1.2 every row also carries the cross-source columns `country`, `deadline`, `valueAmount`, `valueCurrency` and `cpvOrNaics` next to the original ones (`buyerCountry`, `deadlineAt`, `estimatedValue`, `currency`, `cpvCodes`/`naicsCodes`), which are unchanged.

```json
{
  "title": "MARCHE RELATIF A LA MISSION D''ELABORATION DU PLAN STRATEGIQUE DU PATRIMOINE DE ROUEN HABITAT, LA CREATION DES FICHES D'IDENTITE DES IMME...",
  "source": "boamp",
  "country": "FR",
  "noticeType": "Avis de marché",
  "publishedAt": "2026-11-06",
  "deadline": "2026-12-01T16:00:00+01:00",
  "buyerName": "ROUEN HABITAT",
  "valueAmount": null,
  "valueCurrency": null,
  "cpvOrNaics": "71241000",
  "setAside": null,
  "url": "https://www.boamp.fr/pages/avis/?q=idweb:26-108078",
  "buyerContactName": null,
  "buyerContactEmail": null,
  "buyerContactPhone": null
}
```

### Limits and notes

- **Data source:** BOAMP open data (DILA, via Opendatasoft).
- **Access:** No login or API key.
- **Delays and gaps:** BOAMP open data is refreshed from the official bulletin; notices can appear in the dataset after they are visible on boamp.fr. Estimated value is often not published.
- **Contacts:** No buyer contact persons are extracted.
- Fields the portal does not publish stay `null`; nothing is guessed or filled in.

### Pricing

**Pay per result: $2.00 per 1,000 notices** ($0.002 per row) plus Apify's small run-start fee. A daily alert with 20 new notices costs about **$1.20 a month**.

### Notes and limits

- Text fields (title, description, procedure) are published in French; field names and the schema are English.
- `estimatedValue` is filled only when the buyer publishes an estimate (about 30% of calls for tenders).
- BOAMP's API pages up to 10,000 notices per day and query; for bigger pulls narrow by notice type or department.

### More TenderFeed sources

Same output schema across all sources, so you can merge results in one sheet or CRM:

- [EU TED tenders](https://apify.com/tenderfeed/ted-eu-tenders)
- [SAM.gov federal contract opportunities](https://apify.com/tenderfeed/sam-gov-opportunities)
- [Grants.gov US federal grants](https://apify.com/tenderfeed/grants-gov-us)
- [USAspending federal contract awards](https://apify.com/tenderfeed/usaspending-contract-awards)
- [UK Find a Tender + Contracts Finder](https://apify.com/tenderfeed/uk-tenders)
- [Switzerland SIMAP tenders](https://apify.com/tenderfeed/switzerland-simap-tenders)
- [World Bank procurement notices & awards](https://apify.com/tenderfeed/world-bank-procurement)
- [Poland BZP e-Zamówienia tenders](https://apify.com/tenderfeed/poland-bzp-tenders)
- [Ukraine Prozorro tenders](https://apify.com/tenderfeed/ukraine-prozorro-tenders)
- [AusTender Australian government contracts](https://apify.com/tenderfeed/australia-austender-contracts)
- [EU Funding & Tenders Portal grants and calls](https://apify.com/tenderfeed/eu-funding-tenders-portal)
- [CanadaBuys tenders and awards](https://apify.com/tenderfeed/canada-canadabuys-tenders)
- [Germany public tenders (Ausschreibungen)](https://apify.com/tenderfeed/germany-public-tenders)
- [NYC City Record bids & awards](https://apify.com/tenderfeed/nyc-city-record-procurement)
- [Brazil PNCP licitações](https://apify.com/tenderfeed/brazil-pncp-tenders)
- [Colombia SECOP II licitaciones](https://apify.com/tenderfeed/colombia-secop-tenders)
- [Netherlands TenderNed aanbestedingen](https://apify.com/tenderfeed/netherlands-tenderned-tenders)

### FAQ

**Is this legal?** Yes. BOAMP data is French government open data released by DILA under the Licence Ouverte (Etalab). Personal contact details are excluded unless you set `includeBuyerContacts: true`; if you do, handle them in line with the GDPR.

**Does it include above-EU-threshold tenders?** Yes, BOAMP republishes French notices sent to TED (eForms) as well as national MAPA notices. Use the TenderFeed EU TED Actor for the other EU countries.

# Actor input Schema

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

French words to look for (BOAMP full-text search over the whole notice), e.g. \["informatique", "logiciel"]. Each keyword is searched as an exact phrase. Empty = all notices.

## `keywordMode` (type: `string`):

Match ANY or ALL keywords.

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

APPEL_OFFRE = calls for tenders (open opportunities), ATTRIBUTION = contract awards, RECTIFICATIF = corrections, PRE-INFORMATION = prior information, MODIFICATION = contract modifications, ANNULATION = cancellations, EX_ANTE_VOLONTAIRE = voluntary ex-ante transparency, QUALIFICATION = qualification systems.

## `contractTypes` (type: `array`):

Empty = all.

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

CPV codes or prefixes; 72000000 or 72 = all IT services, 45 = construction works.

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

Department codes of the notice, e.g. \["75", "92", "69", "2A", "971"].

## `buyer` (type: `string`):

e.g. "Ville de Paris" or "CHU".

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

YYYY-MM-DD or relative ("7 days"). Default: last 3 days.

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

YYYY-MM-DD. Default: today.

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

Keep only notices with a submission deadline today or later.

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

Estimated contract value (excl. VAT) when the buyer publishes it.

## `maxValue` (type: `integer`):

Estimated contract value (excl. VAT) when the buyer publishes it.

## `includeUnknownValue` (type: `boolean`):

Keep notices that publish no value when a value filter is set.

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

0 = no limit. Default 50. BOAMP publishes ~600 notices per working day.

## `includeBuyerContacts` (type: `boolean`):

Include named contact persons, emails and phone numbers published in the notices (buyerContactName/Email/Phone). Off by default for GDPR data minimisation: you then get organization-level info only (buyer name, city, country, notice and document links). Turn on only if you have a lawful basis (e.g. legitimate interest for B2G bid contact) to process this personal data.

## `onlyNew` (type: `boolean`):

Remember what earlier runs delivered and return (and charge for) only notices you have not received yet. Ideal for scheduled daily alerts.

## `monitoringId` (type: `string`):

Name of the watch-list memory used by 'Only new'. Use a different ID per saved search/schedule.

## `includeRawData` (type: `boolean`):

Adds the full BOAMP record under `raw` (bigger output). Personal contact keys are removed unless contacts are on.

## Actor input object example

```json
{
  "keywordMode": "any",
  "noticeTypes": [
    "APPEL_OFFRE"
  ],
  "onlyOpen": false,
  "includeUnknownValue": true,
  "maxResults": 20,
  "includeBuyerContacts": false,
  "onlyNew": false,
  "includeRawData": false
}
```

# Actor output Schema

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

All normalized records from the default dataset, opened in the Overview view.

# 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 = {
    "maxResults": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("tenderfeed/france-boamp-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 = { "maxResults": 20 }

# Run the Actor and wait for it to finish
run = client.actor("tenderfeed/france-boamp-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 '{
  "maxResults": 20
}' |
apify call tenderfeed/france-boamp-tenders --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,tenderfeed/france-boamp-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/3uBorxotXqHll2LA2/builds/LvJFoMeWKKW4nulKN/openapi.json
