# BOAMP France : appels d’offres / tenders (`wavy_millpond/boamp-appels-offres-france`) Actor

FR : Avis BOAMP officiels, mots-clés stricts et filtres d’activité. Démo fictive par défaut. EN: Official French tenders, strict phrases and activity filters. Synthetic demo by default.

- **URL**: https://apify.com/wavy_millpond/boamp-appels-offres-france.md
- **Developed by:** [Westbrook](https://apify.com/wavy_millpond) (community)
- **Categories:** Business, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$2.00 / 1,000 résultat réels

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

## BOAMP France — appels d’offres / public tenders

**FR.** Recherchez les avis d’appel d’offres français dans l’[API officielle BOAMP / DILA](https://www.boamp.fr/pages/donnees-ouvertes-et-api/), avec mots-clés, expression stricte facultative, départements de publication, activité et échéances ouvertes. **Le mode par défaut est une démo fictive sans collecte.** Vérifiez toujours l’avis officiel avant de répondre à un marché.

**EN.** Search French public tender notices through the official BOAMP / DILA API using keywords, optional strict phrases, publication departments, activity and open deadlines. **Default mode is a synthetic demo without collection.** Read the official notice before submitting a tender.

### Entrées prêtes à utiliser / Ready-to-use inputs

Démo fictive, sans réseau ni événement `result` / Synthetic demo, no network or `result` event:

```json
{ "mode": "demo" }
```

Recherche réelle avec mots entiers / Live search with whole words ([examples/INPUT.live.json](examples/INPUT.live.json)):

```json
{
  "mode": "live",
  "query": "traiteur",
  "strictQuery": true,
  "marketTypes": ["SERVICES"],
  "descriptorCodes": [],
  "departments": [],
  "daysBack": 7,
  "maxItems": 10,
  "onlyOpen": true
}
```

Filtre d’activité officiel, sans mot-clé / Official activity filter, no keyword ([examples/INPUT.activity.json](examples/INPUT.activity.json)):

```json
{
  "mode": "live",
  "query": "",
  "marketTypes": ["SERVICES"],
  "descriptorCodes": ["274"],
  "departments": ["75", "92"],
  "daysBack": 7,
  "maxItems": 10,
  "onlyOpen": true
}
```

| Entrée / Input | Comportement / Behavior |
| --- | --- |
| `query` | FR : objet de l’avis, 150 caractères maximum ; vide = tous les objets. EN: notice title, maximum 150 characters; empty = all titles. |
| `strictQuery` | FR : facultatif, `false` par défaut pour conserver l’ancienne recherche ODSQL approximative/par préfixe. `true` applique localement une expression de mots entiers contigus. EN: optional, defaults to `false` for existing ODSQL fuzzy/prefix behavior. `true` applies a local contiguous whole-token phrase filter. |
| `marketTypes` | FR : `TRAVAUX`, `FOURNITURES`, `SERVICES`, casse indifférente. EN: official works/supplies/services codes, case insensitive. |
| `descriptorCodes` | FR : codes `descripteur_code` BOAMP, chaînes de 1 à 6 chiffres ; ex. `274` = Prestations de services, `33` = Bâtiment. **Ce ne sont pas des CPV.** EN: official BOAMP descriptor codes, strings of 1–6 digits; **these are not CPV codes.** |
| `departments` | FR : jusqu’à 20 codes (`75`, `2A`, `974`) ; département de publication, pas une garantie du lieu de prestation. EN: up to 20 publication department codes; not proof of work location. |
| `daysBack` | FR : 1–90 jours, aujourd’hui inclus, en UTC. EN: 1–90 days including today, UTC. |
| `maxItems` | FR : 1–1 000 avis uniques émis ; démo = une seule ligne. EN: 1–1,000 unique emitted notices; demo = one row. |
| `onlyOpen` | FR : `true` par défaut ; échéance connue strictement après le début de recherche, échéances inconnues exclues. EN: defaults to `true`; known deadline strictly after search start, unknown deadlines excluded. |

**FR.** Les listes d’activité vides ne restreignent pas la recherche. Les valeurs d’une liste sont combinées par OU ; les différents filtres par ET. Un code descripteur absent de la source ne renvoie aucun avis. Les attributions sont exclues. En démo, les filtres sont ignorés après validation et une seule ligne clairement fictive est produite.

**EN.** Empty activity lists are unrestricted. Values within each list use OR; different filters use AND. A descriptor code absent from the source returns no notices. Award notices are excluded. Demo validates inputs, ignores filters and emits one clearly synthetic row.

### Expression stricte / Strict phrase matching

**FR.** `traiteur` correspond à « TRAITEUR pour réception », mais pas à « traitement » ou « traiteurs ». Les mots doivent rester contigus et dans le même ordre. La casse et les accents sont ignorés ; `œ` équivaut à `oe`, `æ` à `ae`. Apostrophes, tirets et ponctuation séparent les mots : `maitrise d oeuvre` correspond à « Maîtrise d’œuvre » et « Maîtrise-d-oeuvre ». Les suffixes `+`/`#` font partie du mot : `C++`, `C#` et `C` restent distincts. Une entrée non vide sans lettre ni chiffre est refusée. Il n’y a ni syntaxe booléenne ni expression régulière.

**EN.** `traiteur` matches “TRAITEUR pour réception”, but excludes “traitement” and “traiteurs”. Tokens must be contiguous and ordered. Case and accents are folded; `œ` equals `oe`, `æ` equals `ae`. Apostrophes, hyphens and punctuation separate tokens: `maitrise d oeuvre` matches “Maîtrise d’œuvre” and “Maîtrise-d-oeuvre”. `+`/`#` suffixes remain part of a token: `C++`, `C#` and `C` differ. Nonempty queries without letters or digits are rejected. No Boolean or regular-expression syntax.

**FR.** En mode strict, la recherche textuelle ODSQL est conservée pour limiter les candidats et le coût réseau. Le filtre strict est ensuite appliqué à ces candidats : la sémantique textuelle de la source peut donc limiter le rappel, notamment pour certaines ponctuations ou ligatures. L’Actor parcourt les candidats par date décroissante et rejette les objets non conformes **avant stockage et facturation**. Une recherche stricte large peut atteindre les limites de scan avant de trouver tous les avis souhaités.

**EN.** Strict mode retains the upstream ODSQL text search to bound candidates and network cost. Strict matching then applies to those candidates: source text semantics can limit recall, particularly for some punctuation or ligatures. The Actor scans candidates, newest first, and rejects nonmatching titles **before storage and charging**. A broad strict search can reach scan limits before finding every desired notice.

### Résultats et bilan / Results and summary

**FR.** Chaque ligne contient l’identifiant, l’objet, le nom officiel de l’acheteur, les dates, les départements, les types de marché, la procédure, le statut et le lien officiel. Les champs absents sont nuls ou des listes vides ; les dates et fuseaux sont conservés. `source`, `sourceApiUrl`, `fetchedAt`, `isDemo` et `attribution` assurent la traçabilité. `fetchedAt` indique le début de recherche. Aucun contact e-mail/téléphone, JSON source brut ou texte intégral n’est exporté. Des noms propres peuvent déjà figurer dans l’objet ou le nom d’acheteur publiés par la source. Aucun champ ni filtre CPV n’est annoncé.

**EN.** Rows contain ID, title, official buyer name, dates, departments, market types, procedure, status and official URL. Missing fields are null or empty lists; source dates/timezones are preserved. `source`, `sourceApiUrl`, `fetchedAt`, `isDemo` and `attribution` provide provenance. `fetchedAt` is the search start. No email/phone contacts, raw source JSON or full text are exported. Published titles/buyer names may already contain proper names. No CPV field or filter is advertised.

**FR.** Téléchargez le dataset en JSON, CSV, HTML ou Excel. `SUMMARY` contient `emitted` (lignes écrites), `filtered` (objets rejetés par le filtre strict), `duplicates`, `scanned` (lignes de pages téléchargées, y compris une éventuelle fin de page non examinée après le plafond), `requests`, `httpAttempts` (reprises incluses), `exhausted` et `truncated`. `totalReported` concerne les filtres appliqués par la source, avant le filtre strict local. `truncated: true` signifie que tous les avis correspondants n’ont pas été examinés. Une erreur ou un arrêt conserve le bilan partiel.

**EN.** Export the dataset as JSON, CSV, HTML or Excel. `SUMMARY` includes `emitted` (written rows), `filtered` (titles rejected by strict matching), `duplicates`, `scanned` (downloaded page rows, including an unexamined page tail after the result cap), `requests`, `httpAttempts` (including retries), `exhausted` and `truncated`. `totalReported` is the source-filter count before local strict matching. `truncated: true` means not all candidate notices were examined. Failures/interruption preserve a partial summary.

### Limites et coût / Limits and pricing

**FR.** Maximum 1 000 résultats, 100 pages, 100 lignes par page et 10 000 lignes sources par run. Une requête active, une seconde minimum entre pages ; trois tentatives maximum sur erreur réseau/429/5xx, attente plafonnée à 30 s, délai de 20 s par tentative, réponse plafonnée à 2 Mio. Redirections et autres hôtes refusés. La source peut changer pendant la pagination : ordre stable et dédoublonnage dans le run ne garantissent pas une photographie transactionnelle. Les runs successifs peuvent renvoyer les mêmes avis ; pas de notification automatique, de rapprochement des rectificatifs ou de mode « nouveaux uniquement ».

**EN.** Maximum 1,000 results, 100 pages, 100 rows/page and 10,000 source rows/run. One active request, at least one second between pages; at most three attempts for network/429/5xx failures, retry wait capped at 30 s, 20 s timeout/attempt, 2 MiB response cap. Redirects/other hosts are rejected. Source data may change during pagination; ordering and within-run deduplication do not guarantee a transactional snapshot. Consecutive runs can return the same notices; no automatic notifications, linked-correction reconciliation or “new only” mode.

**FR.** Une reprise/résurrection avec dataset déjà rempli échoue avant collecte (`EXISTING_DATASET`) pour éviter doublons et refacturation. Consultez les données et le bilan partiels avant de démarrer un nouveau run ; aucun curseur persistant n’est disponible.

**EN.** Resume/resurrection with a populated dataset fails before collection (`EXISTING_DATASET`) to prevent duplicate output/charging. Review partial data/summary before starting a new run; no persistent cursor is provided.

**FR.** Tarif prévu : **0,002 USD par résultat réel, soit 2 USD/1 000**, événement PPE `result` uniquement. Consultez Pricing sur Apify pour le tarif actif. Aucune charge `result` pour une ligne filtrée, un doublon ou la démo. Le plafond est réduit avant collecte selon le budget PPE disponible. Les ressources cloud peuvent consommer du crédit, même en démo. Le lot historique de 101 avis du 28 octobre 2026 coûtait environ 0,00068 USD avant monétisation ; ce n’est ni un coût garanti ni une preuve de demande payante.

**EN.** Intended price: **USD 0.002 per real result, USD 2/1,000**, PPE `result` event only. Check Apify Pricing for active terms. Rejected rows, duplicates and demo trigger no `result` charge. The result cap is reduced before collection according to available PPE budget. Cloud resources can consume credit even in demo. The historical 101-notice batch on 28 October 2026 cost about USD 0.00068 before monetization; this is neither a guaranteed cost nor evidence of paying demand.

### API, MCP et n8n / API, MCP and n8n

**FR.** [Actor public et documentation MCP](https://apify.com/wavy_millpond/boamp-appels-offres-france). Ajoutez ce serveur MCP distant dans votre client, authentification via le gestionnaire sécurisé du client. L’outil de l’Actor accepte le même JSON que l’entrée ci-dessus. Utilisez explicitement `mode: "live"` pour des données réelles.

**EN.** [Public Actor and MCP documentation](https://apify.com/wavy_millpond/boamp-appels-offres-france). Add this remote MCP server in your client and use its secure authentication settings. The Actor tool accepts the same input JSON shown above. Explicitly use `mode: "live"` for real data.

```json
{
  "mcpServers": {
    "boamp": {
      "url": "https://mcp.apify.com/?tools=wavy_millpond%2Fboamp-appels-offres-france"
    }
  }
}
```

**FR.** API directe, jeton fourni par variable d’environnement sécurisée / **EN.** Direct API, token supplied through a secure environment variable:

```bash
curl --fail --request POST \
  'https://api.apify.com/v2/acts/wavy_millpond~boamp-appels-offres-france/run-sync-get-dataset-items' \
  --header "Authorization: Bearer ${APIFY_TOKEN}" \
  --header 'Content-Type: application/json' \
  --data '{"mode":"live","query":"traiteur","strictQuery":true,"marketTypes":["SERVICES"],"daysBack":7,"maxItems":10,"onlyOpen":true}'
```

**FR.** Dans n8n, créez un nœud **HTTP Request** : méthode `POST`, URL ci-dessous, authentification **Header Auth** via les credentials (`Authorization: Bearer …`), corps **JSON** = exemple réel ci-dessus. La réponse est le tableau des résultats. Pour les runs pouvant dépasser le délai synchrone de l’API, utilisez l’endpoint asynchrone `/runs`, puis récupérez le dataset à la fin du run.

**EN.** In n8n, create an **HTTP Request** node: method `POST`, URL below, **Header Auth** stored in credentials (`Authorization: Bearer …`), **JSON** body = live example above. The response is the result array. For runs that can exceed the API synchronous timeout, use asynchronous `/runs`, then fetch the dataset once the run finishes.

```text
https://api.apify.com/v2/acts/wavy_millpond~boamp-appels-offres-france/run-sync-get-dataset-items
```

### Source vérifiée / Verified source

**FR.** Le 29 octobre 2026, des GET limités sur les [métadonnées officielles](https://boamp-datadila.opendatasoft.com/api/explore/v2.1/catalog/datasets/boamp) et les [enregistrements officiels](https://boamp-datadila.opendatasoft.com/api/explore/v2.1/catalog/datasets/boamp/records?select=descripteur_code%2Cdescripteur_libelle%2Ctype_marche\&where=nature%3D%22APPEL_OFFRE%22\&limit=2) ont confirmé `descripteur_code` multivalué (séparateur déclaré virgule), `descripteur_libelle` (point-virgule) et `type_marche` (virgule), renvoyés comme tableaux dans les enregistrements. Les exemples observés incluaient `33`/Bâtiment, `274`/Prestations de services et les trois types de marché. Une requête réelle avec `type_marche IN ("SERVICES") AND descripteur_code IN ("274", "33")` a renvoyé des tableaux conformes. Cette vérification limitée ne garantit ni la couverture des classifications ni la disponibilité future. Les descripteurs ne sont jamais renommés CPV ; le JSON `donnees` n’est pas lu.

**EN.** Limited GET checks on 29 October 2026 against the official metadata and records confirmed multivalued `descripteur_code` (declared comma separator), `descripteur_libelle` (semicolon) and `type_marche` (comma), returned as record arrays. Observed samples included `33`/Bâtiment, `274`/Prestations de services and all three market types. A live query using `type_marche IN ("SERVICES") AND descripteur_code IN ("274", "33")` returned matching arrays. This limited check guarantees neither classification coverage nor future availability. Descriptors are never renamed CPV; `donnees` JSON is not read.

**FR.** Les données DILA sont réutilisables sous conditions d’attribution et de prise en compte des corrections. Chaque avis réel conserve sa provenance. Respectez les conditions de réutilisation applicables et les demandes de mise à jour. Cet Actor n’est pas affilié à la DILA.

**EN.** DILA reuse terms require attribution and attention to corrections. Each live notice retains provenance. Follow applicable reuse terms and update requests. This Actor is not affiliated with DILA.

### Vérifications locales / Local verification

**FR.** Depuis la racine : `npm test`. Depuis ce dossier : `npm ci`, puis `npm test`. Les tests utilisent des données synthétiques et ne collectent rien. Pour la démo SDK, préparez `storage/key_value_stores/default/INPUT.json` avec `{"mode":"demo"}`, puis `apify validate-schema` et `apify run`. Ne mettez aucun jeton dans les fichiers du dépôt.

**EN.** From repository root: `npm test`. From this folder: `npm ci`, then `npm test`. Tests use synthetic data without collection. For an SDK demo, set `storage/key_value_stores/default/INPUT.json` to `{"mode":"demo"}`, then run `apify validate-schema` and `apify run`. Keep tokens out of repository files. `node_modules`, `storage` and `.env` are excluded from Git and Docker context.

# Actor input Schema

## `mode` (type: `string`):

Démo : données fictives sans collecte. Réel : appel de l’API publique BOAMP. / EN: Demo: synthetic data without collection. Live: official public BOAMP API.

## `query` (type: `string`):

FR : Objet de l’avis. Vide : tous les objets. Par défaut : recherche ODSQL approximative/par préfixe. Avec strictQuery : expression de mots entiers contigus, sans distinction de casse/accents, ponctuation séparatrice, suffixes +/# littéraux. Ignoré en démo. / EN: Search notice title. Empty means all titles. Default: ODSQL fuzzy/prefix search. With strictQuery: adjacent whole-token phrase, case/accent insensitive; punctuation separates tokens, +/# word suffixes stay literal. Ignored in demo.

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

Codes comme 75, 2A ou 974. Liste vide : France entière. Ce filtre vise le département de publication, pas nécessairement le lieu de prestation. Ignoré en démo. / EN: Publication department codes, e.g. 75, 2A, 974; not necessarily the work location. Empty: all France. Ignored in demo.

## `daysBack` (type: `integer`):

Fenêtre de publication incluant aujourd’hui, calculée en UTC. Ignorée en démo. / EN: Publication window including today, in UTC. Ignored in demo.

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

Plafond de résultats uniques pour cette exécution. La démo produit un seul résultat. / EN: Maximum unique emitted results per run. Demo emits one synthetic row.

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

Conserver les avis dont la date limite de réponse connue est postérieure au début de la recherche. Les avis sans échéance connue sont exclus. Ignoré en démo. / EN: Keep known response deadlines later than the search start. Unknown deadlines excluded. Ignored in demo.

## `strictQuery` (type: `boolean`):

FR : false conserve la recherche historique. true filtre localement l’objet par expression contiguë : traiteur exclut traitement et traiteurs. Accents ignorés, œ=oe, æ=ae ; apostrophes et tirets séparent les mots. C++ et C# restent distincts de C. Une requête non vide doit contenir un mot. Pas de syntaxe booléenne/regex. Scan borné, voir README. Ignoré en démo. / EN: false preserves legacy search. true matches a contiguous whole-token phrase in the title locally; traiteur excludes traitement/traiteurs. Accents folded, œ=oe, æ=ae; apostrophes/hyphens separate tokens. C++/C# differ from C. Nonempty query needs a word. No Boolean/regex syntax. Bounded scan; see README. Ignored in demo.

## `marketTypes` (type: `array`):

FR : Valeurs officielles type_marche : TRAVAUX, FOURNITURES, SERVICES. OU dans la liste ; ET avec les autres filtres. Vide : aucun filtre. Ignoré en démo. / EN: Official type_marche values: TRAVAUX (works), FOURNITURES (supplies), SERVICES. OR within list, AND with other filters. Empty: no restriction. Ignored in demo.

## `descriptorCodes` (type: `array`):

FR : Codes officiels descripteur_code (chaînes de 1 à 6 chiffres), ex. 274 = Prestations de services, 33 = Bâtiment. Ce ne sont pas des codes CPV. OU dans la liste ; ET avec les autres filtres. Vide : aucun filtre. Code inconnu : aucun résultat. Ignoré en démo. / EN: Official descripteur_code strings (1–6 digits), e.g. 274 = Prestations de services, 33 = Bâtiment. These are not CPV codes. OR within list, AND with other filters. Empty: unrestricted. Unknown code: no results. Ignored in demo.

## Actor input object example

```json
{
  "mode": "demo",
  "query": "",
  "departments": [],
  "daysBack": 7,
  "maxItems": 10,
  "onlyOpen": true,
  "strictQuery": false,
  "marketTypes": [],
  "descriptorCodes": []
}
```

# Actor output Schema

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

Lignes de résultat, avec isDemo pour identifier toute donnée fictive. / EN: Result rows; isDemo identifies synthetic data.

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

Plafonds, pages, tentatives HTTP, troncature et statut de l’exécution. / EN: Limits, pages, filtered rows, HTTP attempts, truncation and run status.

# 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 = {};

// Run the Actor and wait for it to finish
const run = await client.actor("wavy_millpond/boamp-appels-offres-france").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 = {}

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

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,wavy_millpond/boamp-appels-offres-france"
        }
    }
}
```

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/yMJenzSiKwxwGHFNs/builds/53arbIORwsNZPswuL/openapi.json
