{
  "openapi": "3.0.1",
  "info": {
    "title": "France Tenders Monitor: BOAMP, TED & Marchés Publics",
    "description": "French public tenders and public procurement notices (marchés publics, appels d'offres) from BOAMP and TED in one deduplicated list, incl. MAPA. Tenders scored to your CPV codes, keywords and départements, with deadlines and match reasons. Daily tender alerts (veille).",
    "version": "0.1",
    "x-build-id": "QAfaw0AXKlwn2t1qr"
  },
  "servers": [
    {
      "url": "https://api.apify.com/v2"
    }
  ],
  "paths": {
    "/acts/lindenwerk~france-tender-matcher/run-sync-get-dataset-items": {
      "post": {
        "operationId": "run-sync-get-dataset-items-lindenwerk-france-tender-matcher",
        "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/lindenwerk~france-tender-matcher/runs": {
      "post": {
        "operationId": "runs-sync-lindenwerk-france-tender-matcher",
        "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/lindenwerk~france-tender-matcher/run-sync": {
      "post": {
        "operationId": "run-sync-lindenwerk-france-tender-matcher",
        "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": {
          "mode": {
            "title": "Mode",
            "enum": [
              "monitor",
              "backfill",
              "awards"
            ],
            "type": "string",
            "description": "monitor = only notices not returned by a previous run with the same stateKey (schedule it daily; this is the default when the field is omitted, e.g. in API calls). backfill = every notice published in dateFrom..dateTo (max 31 days; without dates: the last 7 days). awards = contract award notices only (who won what, at what price) in dateFrom..dateTo. The form opens with backfill so a first try shows the last 7 days right away; switch to monitor before you schedule it.",
            "default": "monitor"
          },
          "profileName": {
            "title": "Profile name",
            "type": "string",
            "description": "Free label for this search profile, copied to every output row. Also the default stateKey in monitor mode, so different profiles keep separate \"already seen\" lists. Example: \"nettoyage-idf\"."
          },
          "cpvCodes": {
            "title": "CPV codes (prefix match)",
            "type": "array",
            "description": "CPV classification codes or prefixes. A prefix matches every code that starts with it: \"72\" = IT services, \"48\" = software, \"45\" = construction works, \"909\" = cleaning, \"7971\" = guarding / security services (gardiennage, not IT), \"4873\" = security software packages, \"72212730\" = security software development (for IT security, combine these with keywords), \"7132\" = engineering design. A main-CPV match gives the strongest score. Check digits like \"-8\" are ignored. Note: small MAPA notices (< 90 k EUR) usually carry no CPV, so add keywords too.",
            "items": {
              "type": "string"
            }
          },
          "keywords": {
            "title": "Keywords (French)",
            "type": "array",
            "description": "Words matched in the title and BOAMP descriptors (full weight) and in the description (half weight). Case- and accent-insensitive (\"electricite\" = \"électricité\"). Keywords with 4+ letters also match inside longer words (\"nettoyage\" matches \"nettoyages\"); shorter ones (BTP, VRD) only as whole words. Wrap a keyword in double quotes to force whole-word matching. Notices are in French, so use French terms. Keywords raise relevanceScore, so they interact with minScore: a CPV-only match scores 50, so a high minScore (60+) with only a few keywords can return nothing. Add more keyword variants or lower minScore.",
            "items": {
              "type": "string"
            }
          },
          "excludeKeywords": {
            "title": "Exclude keywords",
            "type": "array",
            "description": "Notices whose title, descriptors or description contain any of these words are dropped (never charged). Same matching rules as keywords. Example: [\"fourniture de papier\", \"restauration\"].",
            "items": {
              "type": "string"
            }
          },
          "departments": {
            "title": "Départements",
            "type": "array",
            "description": "Keep only notices whose buyer or place of performance is in one of these French départements. Codes like \"75\", \"69\", \"06\", \"2A\", \"971\" (leading zero optional). Works for every BOAMP notice; TED-only notices are mapped from the buyer postal code.",
            "items": {
              "type": "string"
            }
          },
          "regions": {
            "title": "Regions (NUTS or name)",
            "type": "array",
            "description": "Keep only notices located in these regions. Accepts NUTS prefixes (\"FR1\" Île-de-France, \"FRK\" Auvergne-Rhône-Alpes, \"FRK2\" Rhône-Alpes, \"FRL04\") or region names/abbreviations (\"Bretagne\", \"Île-de-France\", \"IDF\", \"PACA\", \"AURA\", \"Occitanie\"). National and MAPA notices often carry no NUTS code; for them the région is derived from the département, so use region-level prefixes (FR1, FRK ...) or the departments filter for fine-grained filtering.",
            "items": {
              "type": "string"
            }
          },
          "marketLevels": {
            "title": "Market levels",
            "type": "array",
            "description": "Keep only these market levels. Empty = all. SMEs often want [\"national\", \"mapa\"] (smaller contracts, less competition).",
            "items": {
              "type": "string",
              "enum": [
                "eu",
                "national",
                "mapa",
                "other"
              ],
              "enumTitles": [
                "eu: above EU thresholds (BOAMP \"JOUE\" + TED)",
                "national: 90 k EUR to EU thresholds (BOAMP \"FNS\")",
                "mapa: adapted procedures below 90 k EUR (BOAMP \"MAPA\")",
                "other: concessions (DSP) and miscellaneous"
              ]
            }
          },
          "contractTypes": {
            "title": "Contract types",
            "type": "array",
            "description": "Keep only these contract natures. Empty = all.",
            "items": {
              "type": "string",
              "enum": [
                "works",
                "services",
                "supplies"
              ],
              "enumTitles": [
                "works (travaux)",
                "services",
                "supplies (fournitures)"
              ]
            }
          },
          "minValue": {
            "title": "Minimum value (EUR)",
            "minimum": 0,
            "type": "integer",
            "description": "Drop notices whose published estimated value (awards mode: awarded value) is below this amount. Notices without a published value are kept and say so in matchReasons."
          },
          "maxValue": {
            "title": "Maximum value (EUR)",
            "minimum": 0,
            "type": "integer",
            "description": "Drop notices whose published estimated value (awards mode: awarded value) is above this amount."
          },
          "onlyOpen": {
            "title": "Only open tenders",
            "type": "boolean",
            "description": "Drop tenders whose response deadline (date limite de réponse) has already passed. Tenders without a published deadline are kept.",
            "default": true
          },
          "minDaysUntilDeadline": {
            "title": "Minimum days until deadline",
            "minimum": 0,
            "maximum": 366,
            "type": "integer",
            "description": "Optional. Keep only notices whose deadline is at least this many days after the run (daysUntilDeadline >= value), e.g. 5 to skip tenders you cannot prepare in time. Days are counted from the run date to the response deadline (the participation-request deadline when no response deadline is published), the same number as the daysUntilDeadline output field. Empty = no filter (default). When set, notices without a published deadline are excluded. Filtered notices are never charged."
          },
          "maxDaysUntilDeadline": {
            "title": "Maximum days until deadline",
            "minimum": 0,
            "maximum": 366,
            "type": "integer",
            "description": "Optional. Keep only notices whose deadline is at most this many days after the run (daysUntilDeadline <= value), e.g. 21 = due within three weeks. Days are counted from the run date to the response deadline (the participation-request deadline when no response deadline is published), the same number as the daysUntilDeadline output field. Empty = no filter (default). When set, notices without a published deadline are excluded. Filtered notices are never charged."
          },
          "minScore": {
            "title": "Minimum relevance score",
            "minimum": 0,
            "maximum": 100,
            "type": "integer",
            "description": "Only notices with relevanceScore >= minScore are returned (and charged as scored-match). Guide for a CPV + keyword profile: CPV match only = 50, one title keyword only = 46, CPV + one title keyword = 73, CPV + two keywords = 85+. Keywords raise the score: with few keywords a high minScore can return nothing. Ignored for an unscored feed.",
            "default": 40
          },
          "competitorNames": {
            "title": "Competitor names (awards)",
            "type": "array",
            "description": "Only return award notices won by an organisation whose name contains one of these strings (case- and accent-insensitive), e.g. [\"Eiffage\", \"Atos\"]. Use with mode = awards.",
            "items": {
              "type": "string"
            }
          },
          "lookbackDays": {
            "title": "Lookback days (monitor)",
            "minimum": 1,
            "maximum": 14,
            "type": "integer",
            "description": "Monitor mode: how many publication days back to look on each run (plus today). 1 = yesterday and today. Larger values are safe: already delivered notices are skipped and not charged.",
            "default": 1
          },
          "dateFrom": {
            "title": "Date from (backfill / awards)",
            "type": "string",
            "description": "First publication day (YYYY-MM-DD) for backfill and awards mode. Default: dateTo minus 6 days. Ranges longer than 31 days are capped to the last 31 days."
          },
          "dateTo": {
            "title": "Date to (backfill / awards)",
            "type": "string",
            "description": "Last publication day (YYYY-MM-DD), inclusive. Default: today."
          },
          "sources": {
            "title": "Sources",
            "type": "array",
            "description": "boamp = Bulletin officiel des annonces des marchés publics (European, national and MAPA notices). ted = Tenders Electronic Daily, French buyers only (adds EU-level notices published through other French platforms). Use both for full coverage; cross-posted notices are merged.",
            "items": {
              "type": "string",
              "enum": [
                "boamp",
                "ted"
              ],
              "enumTitles": [
                "BOAMP (all French levels incl. below EU thresholds)",
                "TED (French buyers, EU level)"
              ]
            },
            "default": [
              "boamp",
              "ted"
            ]
          },
          "noticeTypes": {
            "title": "Notice types",
            "type": "array",
            "description": "Which notice types to return. Default: tender (monitor/backfill); awards mode forces award.",
            "items": {
              "type": "string",
              "enum": [
                "tender",
                "award",
                "planning",
                "modification",
                "change",
                "other"
              ],
              "enumTitles": [
                "tender (avis de marché)",
                "award (résultat / attribution)",
                "planning (pré-information)",
                "modification",
                "change (rectificatif / annulation)",
                "other"
              ]
            }
          },
          "maxResults": {
            "title": "Max results",
            "minimum": 0,
            "type": "integer",
            "description": "Maximum number of rows to return (and charge) in this run, best matches first. 0 = no limit. Default 200; the form prefills 25 for a cheap first try, so raise it (or set 0) for full results. The run also stops when your maximum total charge for the run is reached.",
            "default": 200
          },
          "sortBy": {
            "title": "Sort by",
            "enum": [
              "relevance",
              "deadline",
              "publicationDate"
            ],
            "type": "string",
            "description": "Order of the output rows.",
            "default": "relevance"
          },
          "includeDescription": {
            "title": "Include description",
            "type": "boolean",
            "description": "Include a shortened notice description in each row (personal contact details are removed).",
            "default": true
          },
          "descriptionMaxLength": {
            "title": "Description max length",
            "minimum": 0,
            "type": "integer",
            "description": "Maximum number of characters of the description per row.",
            "default": 500
          },
          "includeFunctionalContacts": {
            "title": "Include functional buyer contacts",
            "type": "boolean",
            "description": "Include the buyer's functional contact (e.g. marchespublics@ville.fr, \"Service de la commande publique\"). Personal names, personal e-mail addresses (prenom.nom@...) and phone numbers are never output.",
            "default": true
          },
          "stateKey": {
            "title": "State key (monitor)",
            "type": "string",
            "description": "Name of the \"already seen\" list kept in the named key-value store \"fr-tender-matcher-state\". Default: the profile name. Use a different key per profile or schedule."
          },
          "resetState": {
            "title": "Reset monitor state",
            "type": "boolean",
            "description": "Forget all notices seen by earlier runs with this stateKey before running (monitor mode).",
            "default": false
          },
          "firstRunBackfillDays": {
            "title": "First-run backfill days (monitor mode)",
            "minimum": 0,
            "maximum": 14,
            "type": "integer",
            "description": "Monitor mode: if a run without saved state (the very first run for this stateKey, or after Reset monitor state) finds nothing new in its lookback window, for example because it starts on a weekend or holiday, it looks back this many days once instead, so you see the current open tenders. Later runs are normal monitor runs. 0 = off.",
            "default": 7
          }
        }
      },
      "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
                  },
                  "PROXY_UNBLOCKER_UNITS": {
                    "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
                  },
                  "PROXY_UNBLOCKER_UNITS": {
                    "type": "integer",
                    "example": 0
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}