# France BOAMP Procurement Notices - eForms, Per Notice (`nexgensignal/fr-boamp-procurement-notice-records`) Actor

France BOAMP procurement notices (DILA eForms XML) as clean per-notice records - publication number, date, buyer, project title, procedure, contract nature and CPV, by month. Contacts/free-text dropped. Licence Ouverte 2.0. $0.05 per record.

- **URL**: https://apify.com/nexgensignal/fr-boamp-procurement-notice-records.md
- **Developed by:** [NexGen Signal](https://apify.com/nexgensignal) (community)
- **Categories:** Business, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $33.50 / 1,000 boamp notice records

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?

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

## France BOAMP Procurement Notices - eForms, Per Notice

France's official public-procurement notices - **BOAMP** eForms - as clean, per-notice records, for the month
you choose. Publication number, notice id, date, subtype, procedure, contract nature, CPV code, project title
and buyer organisation. **Contact persons, emails, phones and free-text are dropped.**

### What one record represents

The source is **BOAMP** (Bulletin officiel des annonces de marches publics), published by DILA as daily eForms
XML on `echanges.dila.gouv.fr`. Each record is **one notice**: its BOAMP publication number, eForms notice id,
issue date, notice type and subtype, procurement procedure, contract nature (works/supplies/services), the main
CPV classification code, the project title and the buyer organisation.

### Coverage and volume

For month **2026/08** the archive holds **7,596** notices across its daily directories - measured live at build
time.

**Sol's Wave-4 index put this door at 7,596 EXACT for Aug-2026; measured live at build time the month holds
7,596 notices - matching the index.**

Each month is one partition: set the **Month** input (`YYYY/MM`) to pull that month. The Actor lists the month's
daily directories, reads each notice's eForms XML, and delivers a record per notice, stopping as soon as your
**Maximum records** cap is met.

### Licence and attribution

BOAMP is published under the **Licence Ouverte 2.0** (Etalab / data.gouv.fr). The full notice travels on every
record:

> BOAMP (DILA), France. Published under the Licence Ouverte 2.0 (Etalab / data.gouv.fr fr-lo): free to reproduce, redistribute and adapt, including for commercial use, provided the source and date are acknowledged.

### Person-data policy

eForms notices carry contact blocks with a contact person, email and phone, and a free-text description. This
Actor extracts **only** the structured notice fields listed above; the contact blocks (`cac:Contact`,
`cbc:Telephone`, `cbc:ElectronicMail`) and the free-text `cbc:Description` are **never extracted**. A per-record
assertion rejects any contact/description/person field, and a value-level guard rejects any field that contains
an email address (verified with a planted-field test). The buyer is delivered as an **organisation** name. No
natural-person data is processed.

### Interpretation caveat

One record per BOAMP procurement notice (eForms XML) for the selected month: publication number, notice id, issue date, notice subtype, procedure, contract nature, main CPV code, project title and buyer organisation. Contact person/email/phone blocks and the free-text description are never extracted or delivered.

Values are reproduced verbatim from the eForms XML; the Actor never rewrites a field. The CPV code is the main
classification; the procedure and contract-nature codes are the eForms code values.

### Provenance and compliance

Every run reads the door host's `robots.txt` at runtime; the gate result (URL, status, byte length and, where a
policy is served, its SHA-256) is written to the run's `RUN_RECEIPT`. Where the host serves no robots.txt, the
gate records that fact (flagged) and proceeds on the licence, which expressly grants re-use. The endpoint is
keyless. The Actor never bypasses a block or fetches through a mirror.

### Data quality and freshness

Boolean columns are delivered as real booleans and numeric columns as real numbers. Delivery is keyed on a
stable id, so the dataset is safe to diff, deduplicate or upsert. Every run re-reads the live door, so the data
is as fresh as the source publishes, and each record's `observed_at` stamp dates the snapshot. The run's
`RUN_RECEIPT` records the source URL and how many records were delivered and charged, and confirms
`charge_equals_delivered`.

### Billing and delivery

Pricing is per record: you are billed only for records the Actor actually delivers, with the charge raised
after each record is pushed (push-then-charge), so a failed or empty run costs nothing. The **Maximum records**
cap bounds every run, so you control spend precisely - sample cheaply, then raise it. Because delivery is keyed
on a stable id, re-running and upserting keeps a downstream table current without re-paying for rows you already
hold; only new and changed records add cost, and every receipt reconciles delivered against charged.

### Schema, typing and joins

Every record is a flat object with a fixed, typed schema: strings stay strings, numbers are parsed to real
numbers, and booleans to real booleans, so the data loads into a warehouse or a dataframe without a cleaning
pass. The `record_id` is a stable composite key, which means the dataset is safe to diff between runs, to
deduplicate, and to upsert into a table you maintain over time. Because the identifiers the source uses are
preserved verbatim, the dataset joins cleanly onto other sources keyed on the same identifier, and a scheduled
run keeps the downstream copy current with no manual reconciliation - the new and changed rows simply upsert
over the old ones, and the `observed_at` stamp on every record tells you when each was last seen live.

### Inputs

- **Month** (`month`, required) - the month to pull, as `YYYY/MM`. Prefilled with `2026/08`.
- **Maximum records** (`maxRecords`) - hard cap on notices delivered and billed within the month.

### Output

Records land in the Actor's default dataset and export as JSON, CSV, Excel or via the Apify API. A tabular
overview surfaces publication number, issue date, buyer, project title, procedure, contract nature and CPV.

### Fields in detail

The record leads with `publication_number`, `notice_id`, `issue_date`, `notice_type`, `notice_subtype`,
`procedure`, `contract_nature`, `cpv_code`, `project_title`, `buyer_name` and `version`. The provenance block
closes every record.

### Typical uses

French bid teams use this cell to track BOAMP notices daily - who is buying what, under which procedure and CPV

- as a flat, queryable table without parsing eForms UBL themselves. Because the CPV, procedure and buyer are
  first-class fields, a filter gives every services tender in a CPV family this month without cleaning. To build a
  history, run once per month and concatenate. A scheduled monthly run keeps a downstream tender feed current.

### Parsing eForms without the pain

eForms is the EU's standard procurement-notice format, published as deeply nested UBL XML - powerful but
awkward to work with. This cell does the parsing for you, pulling the notice-level fields most teams query -
publication number, dates, procedure, contract nature, CPV and buyer - into a flat record, and deliberately
leaving the contact blocks and free-text untouched. You get a clean row per notice without writing a single
XPath, and without any of the personal contact data the raw XML carries.

### Why the monthly partition

BOAMP publishes notices as daily XML directories, and the month is the natural pull unit: one month gives the
complete set (about 7,596 for 2026/08) across its daily folders. Making the month a required input keeps each
run bounded and reproducible; the archive spans years, so to build a longer history you run once per month and
concatenate. The publication number and notice id key each record, so the dataset is safe to diff and upsert
run to run.

### Reading the fields

`contract_nature` separates works, supplies and services; `procedure` names the procurement procedure;
`cpv_code` is the main Common Procurement Vocabulary classification, the standard way to filter procurement by
subject; and `buyer_name` is the contracting authority. A filter on CPV family and contract nature gives, for
example, every services tender in a sector this month, and because the buyer is a clean organisation name,
aggregation by authority needs no cleaning. The project title is the notice's own subject line, reproduced
verbatim.

### Sibling Actors

It sits beside the fleet-2 EU TED tender monitor (~25% overlap) and the fleet's Netherlands TenderNed and Germany OCDS procurement cells. It shares its XML-directory engineering with the fleet's other records Actors.

# Actor input Schema

## `month` (type: `string`):

Which month of daily BOAMP notices to pull (YYYY/MM). One month is one partition; 2026/08 holds ~7,596 notices across its daily directories. The archive spans years.

## `maxRecords` (type: `integer`):

Maximum notices delivered and billed within the month. You are billed only for records delivered.

## Actor input object example

```json
{
  "month": "2026/08",
  "maxRecords": 500
}
```

# Actor output Schema

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

The delivered France BOAMP procurement notice record.

# 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 = {
    "month": "2026/08",
    "maxRecords": 500
};

// Run the Actor and wait for it to finish
const run = await client.actor("nexgensignal/fr-boamp-procurement-notice-records").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 = {
    "month": "2026/08",
    "maxRecords": 500,
}

# Run the Actor and wait for it to finish
run = client.actor("nexgensignal/fr-boamp-procurement-notice-records").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 '{
  "month": "2026/08",
  "maxRecords": 500
}' |
apify call nexgensignal/fr-boamp-procurement-notice-records --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,nexgensignal/fr-boamp-procurement-notice-records"
        }
    }
}
```

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/ZFIycTi5mgOhtTqVH/builds/HBA3pEPaXf8VJi5PJ/openapi.json
