# French Public Tender Monitor - BOAMP Alerts (`lowlanddata/france-public-tender-monitor`) Actor

Soyez alerté dès qu'un nouveau marché public français correspondant à votre activité est publié au BOAMP. Filtrez par mots-clés, départements et type de marché ; uniquement les avis jamais vus. API officielle, données organisationnelles, sans contacts personnels.

- **URL**: https://apify.com/lowlanddata/france-public-tender-monitor.md
- **Developed by:** [Lowland Data](https://apify.com/lowlanddata) (community)
- **Categories:** Lead generation, Automation, Agents
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.60 / 1,000 baseline notices

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 a software tools running on the Apify platform, for all kinds of web data extraction and automation use cases.
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.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js/docs.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python/docs.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/integrations/mcp.md).

If your project is in a different language, use 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 Public Tender Monitor — BOAMP Alerts

Watches BOAMP (Bulletin officiel des annonces des marchés publics — France's
official public-procurement bulletin) for new tender notices matching your
profile: French keywords, departments, market type. It alerts the moment a
matching notice is published, and it remembers what it has already told you — so
an alert always means a genuinely new tender, never a re-scrape of yesterday's
list.

It reads BOAMP's official open-data API (the reuse channel France publishes for
exactly this), and the output is GDPR-clean by construction: buyer organization,
subject, deadline, department — never the notice's contact persons. Safe to store,
share with your bid team, or import into a CRM.

This is the **French national** leg of public procurement — the below-EU-threshold
tenders that don't appear on TED. Its EU-wide sibling, the
[EU Tender Monitor](https://apify.com/lowlanddata/eu-tender-monitor), watches TED.
Run both for full French + European coverage.

### Quick start (30 seconds, no account keys needed)

1. Run the actor with the prefilled input (keyword "informatique", last 3 days) —
   it finishes in a few seconds and shows a baseline of recent notices.
2. Replace the demo profile with your own: your French keywords, the departments
   you serve, your market type.
3. Add a **daily schedule** (Actor page → Schedule). From then on, runs are quiet
   until a matching tender is actually published.

### Who uses this

- **A regional IT services company** monitors `keywords: ["informatique",
"logiciel"]`, `departments: ["69", "01", "38"]` (its region) daily — every new
  public IT tender near it lands with the `deadline` and the `boamp.fr` link the
  day it publishes.
- **A construction SME** watches `marketTypes: ["travaux"]` in its departments —
  only public works it can actually bid on.
- **A supplier** runs `keywords` for its product category nationwide to find every
  public buyer newly in the market.
- **A bid consultancy** monitors several client profiles on one schedule, each a
  separate keyword/department set.
- **A market analyst** tracks tender volumes per department and market type as a
  public-spending indicator — the baseline plus daily deltas is a clean series.

### What you get

One JSON item per **event**: a baseline snapshot per notice on the first run, then
only new matching notices. A new-tender alert looks like:

```json
{
  "noticeId": "26-71206",
  "objet": "Marché d'acquisition et de livraison de véhicules pour la commune",
  "buyerName": "Commune de Saint-Benoît",
  "publishedDate": "2026-07-19",
  "deadline": "2026-08-18",
  "departments": ["974"],
  "descriptors": ["Véhicules (acquisition)"],
  "descriptorCodes": ["475"],
  "marketType": "Fournitures",
  "family": "Marchés européens",
  "noticeType": "Avis de marché",
  "url": "https://www.boamp.fr/pages/avis/?q=idweb:26-71206",
  "isBaseline": false,
  "isUpdate": false
}
````

Field honesty notes:

- Everything is **in French** — `objet` and descriptors are as BOAMP publishes
  them. Keyword matching runs on the French subject; use French terms.
- `deadline` is the response deadline where the notice carries one (contract
  notices); award notices carry none.
- `noticeType` distinguishes a contract notice (`Avis de marché`) from an award
  (`Avis d'attribution`) and other natures — filter downstream if you only want
  one.
- `winnerName` appears on award notices — the winning organization, no contact
  data.
- Corrections (`rectificatifs`) publish on BOAMP as their own new notice, so they
  arrive as a new alert rather than a modification of the original.

### How much does tender monitoring cost?

Pay per outcome — checking costs nothing; you pay when the monitor tells you
something new:

- **New matching notice (the alert): $0.02**.
- Baseline item (first run only): $0.002.
- Actor start: $0.005. Everything included - no separate platform-usage charges,
  and higher Apify plans get automatic unit-price discounts.

Cost feel: a focused profile (a keyword or two, a few departments) sees a handful
of new notices per working day → roughly **$2–8/month** for complete coverage,
with the one-time baseline (say 100 notices) costing about $0.20. A run with zero
new matches costs $0.005 all-in. Dedicated tender-alert services charge
€30–200/month.

#### Why an alert costs more than a scraped row

The store's headline ("from $2.00 / 1,000 baseline results") is what a trial
costs: a 100-notice baseline ≈ $0.20. Apify displays every event per 1,000, so the
alert reads "$20.00 / 1,000" next to raw scrapers at $1–3 per 1,000 rows — but
that is a different thing:

- A **raw scraper** sells rows: to monitor with rows you re-download the BOAMP feed
  every day and diff it yourself.
- **This monitor** sells the transition: it remembers state in your account and
  charges $0.02 exactly when a notice you have not seen matches your profile.

### Not technical? Let your AI assistant set it up

Paste this prompt with a line about your business (in French or English):

```text
Set up the Apify actor lowlanddata/france-public-tender-monitor to watch French
public tenders for me. Build the input JSON from my business description:
- keywords: 3-8 FRENCH words a tender subject would contain (e.g. ["informatique",
  "logiciel"] for IT; BOAMP is a French bulletin so French terms match)
- departments: French department codes I serve (e.g. ["75","69","974"])
- marketTypes: ["services"], ["travaux"] (works) or ["fournitures"] (supplies) if
  relevant
Leave alertOn, emitBaseline and maxItems at their defaults. Run it once and show
me the baseline as a table (objet, buyer, department, deadline, url). Then create
a daily schedule and set up a notification so I get an email when a run produces
items.
```

***

### Coverage — measured, not promised

- **Source:** BOAMP's official opendatasoft open-data API, keyless. Covers French
  public-procurement notices — over 1,000 published per working day.
- **French national scope by design** — the below-EU-threshold tenders TED does
  not carry. For EU-wide above-threshold tenders, run the EU Tender Monitor
  alongside.
- **French only.** BOAMP publishes in French; keyword matching is on the French
  `objet`. This monitor does not translate — that is stated, not hidden.
- Server-side filters (date window, departments, market types, keyword search) run
  in the API query.
- A profile broader than several thousand notices per run is truncated honestly
  (the run status says so) — narrow it.

### How the monitor thinks

- **First run = baseline.** It fetches your profile's matches from the last
  `lookbackDays` (default 7), pushes them flagged `isBaseline: true` at the low
  baseline price, and memorizes them. `emitBaseline: false` seeds silently.
- **After that, only new notices.** Each run continues from the previous run (one
  day of overlap; the memory absorbs duplicates) and pushes only notices it has
  never alerted.
- **Editing the profile starts a fresh baseline** — matching-relevant inputs are
  the profile's identity, so a changed profile can never flood you with alerts
  computed against another profile's memory.
- **Memory** lives in a named key-value store (`stateStoreName`, default
  `france-tender-monitor-state`) in your account. Run several profiles on separate
  schedules against the same store — they never interfere. `resetState: true`
  wipes the current profile's memory.
- Re-running after a crash or overlap re-alerts at most the last few unsaved items
  — state is checkpointed during the run.

### Input reference

| Field            | Type    | Default                         | Notes                                                   |
| ---------------- | ------- | ------------------------------- | ------------------------------------------------------- |
| `keywords`       | array   | `[]`                            | French terms, matched on the notice subject. OR within. |
| `departments`    | array   | `[]`                            | French department codes (`75`, `69`, `974`, `2A`).      |
| `marketTypes`    | array   | `[]`                            | `fournitures`, `services`, `travaux`.                   |
| `lookbackDays`   | integer | `7`                             | Baseline reach on the first run (max 30).               |
| `alertOn`        | string  | `"new"`                         | `"new-and-updated"` adds état-change alerts.            |
| `emitBaseline`   | boolean | `true`                          | `false` = silent seeding.                               |
| `resetState`     | boolean | `false`                         | One-shot: wipe this profile's memory.                   |
| `maxItems`       | integer | `500`                           | Overflow alerts on the next run, never lost.            |
| `stateStoreName` | string  | `"france-tender-monitor-state"` | Only change to fully isolate instances.                 |

\* At least one of `keywords`, `departments` or `marketTypes` is required.

### Scheduling and API use

Run it daily and pair the schedule with a Monitoring alert on "dataset items > 0"
to get an email exactly when a tender matched.

```bash
curl -X POST \
  "https://api.apify.com/v2/acts/lowlanddata~france-public-tender-monitor/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{"keywords": ["informatique"], "departments": ["75"]}'
```

```js
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('lowlanddata/france-public-tender-monitor').call({
  keywords: ['informatique', 'logiciel'],
  departments: ['69', '01'],
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items); // only new notices since the last run
```

```python
from apify_client import ApifyClient

client = ApifyClient(os.environ["APIFY_TOKEN"])
run = client.actor("lowlanddata/france-public-tender-monitor").call(run_input={
    "keywords": ["travaux"],
    "marketTypes": ["travaux"],
})
items = client.dataset(run["defaultDatasetId"]).list_items().items
```

Daily runs finish in well under a minute, comfortably inside the 300s sync-call
wall.

### Use it with AI agents (MCP)

Claude, Cursor and other MCP-capable agents can run this monitor as a tool through
Apify's hosted MCP server: the agent builds the profile from a plain-language
brief, runs it, and reads the notices back — no glue code.

Claude Code:

```bash
claude mcp add apify --transport http "https://mcp.apify.com?actors=lowlanddata/france-public-tender-monitor"
```

Cursor or Claude Desktop (add a custom connector / MCP server with this URL):

```text
https://mcp.apify.com?actors=lowlanddata/france-public-tender-monitor
```

Sign in with your Apify account when prompted — runs are billed to it. Setup
details per client: [Apify MCP docs](https://docs.apify.com/platform/integrations/mcp),
or start from this actor's own MCP page:
[apify.com/lowlanddata/france-public-tender-monitor/api/mcp](https://apify.com/lowlanddata/france-public-tender-monitor/api/mcp).

Prompts that work once connected:

- "Surveille les marchés publics informatiques dans le Rhône et montre-moi ceux
  d'aujourd'hui."
- "Watch French public works tenders in Paris and alert me daily."
- "Quels marchés de services ont été publiés cette semaine en Île-de-France ?"

### Is it legal to monitor French public tenders?

Yes — French public-procurement notices are published for exactly this purpose,
and BOAMP provides an official open-data API for their reuse. No login walls, no
anti-bot bypass — if the API is unreachable, the run reports it rather than
fighting it. And the output is safe by construction: contact persons are never
requested from the API (see below).

Source: BOAMP / DILA, reused under France's open-data licence.

### Compliance: safe to store, safe to CRM-import

BOAMP notices do contain personal data — the buyer's contact person, with a name,
email and phone, inside the notice's detailed data blob. This actor's guarantee is
structural: it requests only the organization-level fields from the API (subject,
buyer name, department, dates, descriptors, winner organization) and **never
fetches the contact blob at all** — the personal data never crosses the wire. An
automated test proves that even a response carrying such a blob cannot reach the
output. One honest limit: `objet` is text the buyer wrote — on rare occasions a
name appears in free text. Everything structured is guaranteed clean.

### FAQ

**Why did my second run return nothing?** Because nothing new matched — that is
the product working. The first run is the baseline; afterwards you only pay for
notices you have not seen.

**Does the output contain the buyer's contact person?** No — by design. The API
request never asks for the contact fields. You get the buying organization and the
official notice link; contacts are on the notice itself if you need them for a bid.

**Why French keywords?** BOAMP is a French national bulletin — the notice subject
is in French, so French keywords match. For English/multilingual EU-wide tenders,
use the EU Tender Monitor (TED).

**How is this different from the EU Tender Monitor?** BOAMP covers French national
tenders (including below the EU thresholds); TED covers EU-wide above-threshold
tenders. Run both for complete coverage.

**What about a correction to a tender?** French corrections publish as their own
new BOAMP notice, so you get them as a new alert with the same subject.

### Troubleshooting

- **"The profile matches all of BOAMP"** — add at least one of `keywords`,
  `departments` or `marketTypes`.
- **"Coverage truncated by the per-run request budget"** — the window matched more
  than several thousand notices; narrow the profile or lower `lookbackDays`.
- **"Monitor state record … is not readable"** — the state was written by a newer
  version; run once with `resetState: true` to start a fresh baseline.

Something else off? Open an issue on the actor's Issues tab — reports are read and
answered.

# Actor input Schema

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

Alert on notices whose subject (objet) contains ANY of these words. BOAMP is a French bulletin - use French terms, e.g. \["informatique", "logiciel"]. Leave empty and filter by department or market type instead. At least one of keywords, departments or marketTypes is required.

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

French department codes to limit the search to, e.g. \["75"] (Paris), \["69"] (Rhône), \["974"] (Réunion), \["2A"] (Corse-du-Sud). Empty = all of France.

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

Only these kinds of procurement. Empty = all.

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

How many days of already-published notices the FIRST run of a profile loads as its baseline. Later runs automatically continue from the previous run with one day of overlap - re-alerting a seen notice is impossible.

## `alertOn` (type: `string`):

"new" alerts once per notice. "new-and-updated" also alerts when a seen notice's état changes (marked isUpdate: true). Note: French corrections usually publish as a separate new notice.

## `emitBaseline` (type: `boolean`):

On the very first run of a profile, push the currently matching notices (flagged isBaseline: true, charged at the lower baseline price). Turn off to seed silently and only ever receive new alerts.

## `resetState` (type: `boolean`):

Discard this profile's memory of already-seen notices and start over with a fresh baseline run. One-shot switch: turn it back off afterwards.

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

Upper bound on items pushed per run (baseline or alerts). Matches beyond the cap are not lost: they alert on the next run.

## `stateStoreName` (type: `string`):

Named key-value store holding the monitor's seen-notice memory. Only change this to run fully isolated monitor instances.

## Actor input object example

```json
{
  "keywords": [
    "informatique"
  ],
  "lookbackDays": 3,
  "alertOn": "new",
  "emitBaseline": true,
  "resetState": false,
  "maxItems": 10,
  "stateStoreName": "france-tender-monitor-state"
}
```

# Actor output Schema

## `notices` (type: `string`):

French public-procurement notices matching your profile, one JSON object per notice. On the first run: the recent baseline; afterwards: only new matches.

# 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": [
        "informatique"
    ],
    "lookbackDays": 3,
    "maxItems": 10
};

// Run the Actor and wait for it to finish
const run = await client.actor("lowlanddata/france-public-tender-monitor").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": ["informatique"],
    "lookbackDays": 3,
    "maxItems": 10,
}

# Run the Actor and wait for it to finish
run = client.actor("lowlanddata/france-public-tender-monitor").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": [
    "informatique"
  ],
  "lookbackDays": 3,
  "maxItems": 10
}' |
apify call lowlanddata/france-public-tender-monitor --silent --output-dataset

```

## MCP server setup

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

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "French Public Tender Monitor - BOAMP Alerts",
        "description": "Soyez alerté dès qu'un nouveau marché public français correspondant à votre activité est publié au BOAMP. Filtrez par mots-clés, départements et type de marché ; uniquement les avis jamais vus. API officielle, données organisationnelles, sans contacts personnels.",
        "version": "0.1",
        "x-build-id": "QSYDcxW73qmXBVDOD"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/lowlanddata~france-public-tender-monitor/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-lowlanddata-france-public-tender-monitor",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/lowlanddata~france-public-tender-monitor/runs": {
            "post": {
                "operationId": "runs-sync-lowlanddata-france-public-tender-monitor",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/lowlanddata~france-public-tender-monitor/run-sync": {
            "post": {
                "operationId": "run-sync-lowlanddata-france-public-tender-monitor",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "properties": {
                    "keywords": {
                        "title": "Keywords (French)",
                        "type": "array",
                        "description": "Alert on notices whose subject (objet) contains ANY of these words. BOAMP is a French bulletin - use French terms, e.g. [\"informatique\", \"logiciel\"]. Leave empty and filter by department or market type instead. At least one of keywords, departments or marketTypes is required.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "departments": {
                        "title": "Departments",
                        "type": "array",
                        "description": "French department codes to limit the search to, e.g. [\"75\"] (Paris), [\"69\"] (Rhône), [\"974\"] (Réunion), [\"2A\"] (Corse-du-Sud). Empty = all of France.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "marketTypes": {
                        "title": "Market types",
                        "type": "array",
                        "description": "Only these kinds of procurement. Empty = all.",
                        "items": {
                            "type": "string",
                            "enum": [
                                "fournitures",
                                "services",
                                "travaux"
                            ],
                            "enumTitles": [
                                "Supplies (Fournitures)",
                                "Services",
                                "Works (Travaux)"
                            ]
                        }
                    },
                    "lookbackDays": {
                        "title": "Baseline lookback (days)",
                        "minimum": 1,
                        "maximum": 30,
                        "type": "integer",
                        "description": "How many days of already-published notices the FIRST run of a profile loads as its baseline. Later runs automatically continue from the previous run with one day of overlap - re-alerting a seen notice is impossible.",
                        "default": 7
                    },
                    "alertOn": {
                        "title": "Alert on",
                        "enum": [
                            "new",
                            "new-and-updated"
                        ],
                        "type": "string",
                        "description": "\"new\" alerts once per notice. \"new-and-updated\" also alerts when a seen notice's état changes (marked isUpdate: true). Note: French corrections usually publish as a separate new notice.",
                        "default": "new"
                    },
                    "emitBaseline": {
                        "title": "Emit baseline on first run",
                        "type": "boolean",
                        "description": "On the very first run of a profile, push the currently matching notices (flagged isBaseline: true, charged at the lower baseline price). Turn off to seed silently and only ever receive new alerts.",
                        "default": true
                    },
                    "resetState": {
                        "title": "Reset monitor state",
                        "type": "boolean",
                        "description": "Discard this profile's memory of already-seen notices and start over with a fresh baseline run. One-shot switch: turn it back off afterwards.",
                        "default": false
                    },
                    "maxItems": {
                        "title": "Max items per run",
                        "minimum": 1,
                        "maximum": 10000,
                        "type": "integer",
                        "description": "Upper bound on items pushed per run (baseline or alerts). Matches beyond the cap are not lost: they alert on the next run.",
                        "default": 500
                    },
                    "stateStoreName": {
                        "title": "State store name",
                        "type": "string",
                        "description": "Named key-value store holding the monitor's seen-notice memory. Only change this to run fully isolated monitor instances.",
                        "default": "france-tender-monitor-state"
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
