API Scoutee : documentation développeur
Les appels d’offres, adaptés à votre secteur. Sources officielles, filtres par mots-clés et CPV, alertes quotidiennes sur Scoutee.
Mis à jour le 13 septembre 2026
Retrouvez les appels d’offres adaptés à votre secteur depuis votre script de veille, votre CRM ou votre tableau de bord. Scoutee réunit les sources officielles dans une seule recherche. Affinez les résultats avec vos mots-clés, votre budget et les filtres CPV optionnels pour les marchés européens, puis consultez les avis complets.
Vos codes CPV, trouvés pour vous. Connectez-vous gratuitement : notre IA croise votre activité avec notre base de connaissances pour identifier automatiquement les codes adaptés à votre entreprise. Renseignez un nom ou identifiant d'entreprise, un site web ou une description d'activité dans le service gratuit de recherche de CPV par l'IA, vérifiez les suggestions, puis utilisez-les dans l'API ou le MCP connecté à votre espace.
Base URL : https://scoutee.org/api
Les réponses sont en JSON (application/json), en UTF-8, sauf le téléchargement facultatif du catalogue en CSV. Les dates sont au format ISO 8601 (2026-09-05T14:30:00Z).
Alertes email quotidiennes
Créez un compte et enregistrez votre recherche sur Scoutee. Son alerte email quotidienne s’active automatiquement dès que des critères sont définis et qu’une place est disponible ; vous pouvez la désactiver. Votre compte gratuit inclut 1 recherche(s) avec alerte active, tous espaces confondus, uniquement lorsqu’un nouvel appel d’offres correspond, dans la limite de 20 résultats par recherche. L’email présente 3 appels d’offres en aperçu ; ouvrir la recherche conserve l’allocation gratuite de 20 recherches par heure et de 1 page(s) de 20 résultats. Les offres payantes permettent d’activer des alertes pour plusieurs recherches.
Si vous demandez à votre assistant de vous prévenir par email, il peut vous guider vers l’inscription puis votre recherche enregistrée sur Scoutee. La gestion des alertes nécessite votre session Scoutee ; les outils MCP et les endpoints REST de recherche avec OAuth ne créent pas d’abonnement et ne programment pas d’email. GET /api/public/plans publie les droits email_alerts de chaque offre, avec les quotas de recherche.
Le CPV pour les marchés européens
Le Common Procurement Vocabulary (CPV) est le standard commun des marchés publics dans toute l'Union européenne. Ce filtre optionnel permet de trouver des avis par activité. Son application dépend du pays du marché, pas de la langue de l'interface ; le CPV ne remplace pas les nomenclatures américaines ou canadiennes.
La recherche authentifiée accepte jusqu'à 50 valeurs cpv, avec ou sans leur chiffre de contrôle vérifié. Chaque code sélectionné inclut ses descendants officiels. Les codes CPV et les keyword se combinent avec OU ; le pays, le budget et les autres filtres restent applicables. Les cpv_codes publiés par l'acheteur restent distincts des cpv_inferred_codes suggérés par Scoutee, utilisés pour la recherche uniquement en l'absence de CPV publié reconnu.
curl -s -G "https://scoutee.org/api/tenders" \
-H "Authorization: Bearer $SCOUTEE_ACCESS_TOKEN" \
--data-urlencode "cpv=90911200-8" \
--data-urlencode "country=France"
API publique du catalogue CPV
Ces points d'entrée en lecture ne nécessitent ni compte ni identifiant. Ils consultent le catalogue ; pour des suggestions personnalisées, utilisez la recherche par l'IA après connexion.
| Point d'entrée | Utilisation |
|---|---|
GET /public/classifications/cpv |
Chercher un code ou libellé avec q, résoudre des valeurs code répétées ou parcourir les enfants d'un code parent. |
GET /public/classifications/cpv/catalogue |
Télécharger le catalogue complet en format=json (par défaut) ou format=csv. |
Précisez locale=fr, en ou une autre langue de libellés prise en charge. La recherche exacte code est prioritaire sur parent, puis sur q. q accepte au plus 100 caractères et renvoie jusqu'à 50 résultats ; la recherche exacte accepte jusqu'à 50 codes. Les valeurs code inconnues ou invalides sont omises de items. Un parent inconnu renvoie 422, une nomenclature non prise en charge 404.
La réponse contient system, items, total_codes et catalogue. Chaque élément comprend code, display_code, label, parent, retired et replaced_by. total_codes indique la taille du catalogue complet. Les métadonnées du catalogue comprennent la version de l'instantané, la nomenclature_version officielle, le sha256 et la provenance. Conservez la version avec les libellés pour identifier les anciens codes. Le téléchargement JSON inclut ces métadonnées ; le CSV contient les lignes de codes.
curl -s "https://scoutee.org/api/public/classifications/cpv?q=90911200-8&locale=fr"
curl -s "https://scoutee.org/api/public/classifications/cpv/catalogue?locale=fr&format=csv"
Vous pouvez aussi parcourir le catalogue sur Scoutee.
Clés API
Une clé appartient à un espace de travail, pas à une personne : elle survit au départ de celui qui l'a créée, et les administrateurs de l'espace de travail peuvent la révoquer à tout moment.
Une clé n'est créée et n'est utilisable que si l'espace de travail est sur une offre payante — Pro ou Team (une ancienne offre payante conserve respectivement les limites de Pro et de Team). Si l'espace de travail repasse sur l'offre gratuite, les clés existantes restent listées mais les appels répondent 403.
Pour créer une clé, ouvrez votre espace de travail depuis le menu en haut, sélectionnez son onglet API, puis cliquez sur « Créer une clé ». La valeur complète n'est affichée qu'une fois, à la création. Scoutee n'en conserve que l'empreinte SHA-256 et ne peut donc pas vous la redonner ; en cas de perte, révoquez la clé et créez-en une nouvelle.
Format d'une clé : sct_ suivi de 40 caractères hexadécimaux. Les 12 premiers caractères (le préfixe, par exemple sct_1a2b3c4d) sont affichés dans la liste des clés pour vous permettre de les reconnaître.
Un espace de travail peut avoir 10 clés actives au maximum. Au-delà, la création répond 409 : révoquez une clé avant d'en créer une autre.
Authentification
Connectez un espace par OAuth sur toutes les offres, y compris Gratuit, avec la portée tenders.read. Envoyez le jeton dans Authorization: Bearer $SCOUTEE_ACCESS_TOKEN. La découverte OAuth est disponible sur https://scoutee.org/.well-known/oauth-authorization-server. L'offre et l'appartenance à l'espace choisi sont contrôlées à chaque appel. Révoquer la connexion coupe l'accès immédiatement.
Pour les scripts, une clé d'espace sur une offre payante fonctionne dans X-API-Key: $SCOUTEE_API_KEY. Ces deux identifiants permettent uniquement la recherche et la lecture des marchés. Ils ne donnent pas accès à la facturation, à la mémoire d'entreprise ni au lancement d'analyses. Conservez-les dans le gestionnaire de secrets du client.
Quotas
Chaque recherche authentifiée consomme une unité. Lire un avis ne consomme pas de recherche. OAuth partage un quota par espace ; chaque clé API possède son quota. REST et MCP partagent le quota d'un même identifiant.
| Offre | Recherches/h | Rafale/min | Résultats/page | Page max. | OAuth | Clé API |
|---|---|---|---|---|---|---|
| free | 20 | 20 | 20 | 1 | Oui | Non |
| pro | 100 | 10 | 50 | 20 | Oui | Oui |
| team | 300 | 30 | 100 | 50 | Oui | Oui |
Standard reprend les limites de Pro ; Premium celles de Team. Ces limites régulent le trafic par processus API et sont distinctes des crédits d'analyse. Les réponses portent X-Quota-Plan, X-Quota-Limit et X-Quota-Remaining. MCP renvoie quota_plan, quota_limit et quota_remaining. Respectez Retry-After sur HTTP 429. La taille et la profondeur des pages sont plafonnées : tous les avis trouvés ne sont pas nécessairement accessibles.
GET /tenders
Recherche paginée. Par défaut : appels d'offres ouverts uniquement, du plus récent au plus ancien. Un appel d'offres publié sur plusieurs portails n'apparaît qu'une fois : une seule ligne par appel d'offres, celle de son portail national plutôt que celle de TED, et les copies des autres portails sont citées dans also_on (jamais masquées : chacune garde sa propre fiche dans GET /tenders/{id}). total compte les appels d'offres, pas les copies.
Paramètres
Tous facultatifs, passés en query string.
| Paramètre | Type | Défaut | Description |
|---|---|---|---|
workspace_id |
entier | aucun | Ignoré avec une clé API : la clé est déjà liée à un espace de travail. |
page |
entier, minimum 1 | 1 |
Page demandée. Ramenée à 500 au-delà. |
page_size |
entier, 1 à 500 | 50 |
Résultats par page. Ramené à 200 au-delà. |
q |
chaîne, 200 caractères au plus | aucun | Recherche libre dans le titre, l'acheteur et la description. Chaque mot doit correspondre au début d'un mot de l'appel d'offres (nettoy trouve nettoyage) ; une sous-chaîne au milieu d'un mot ne correspond pas. Insensible à la casse et aux accents. |
keyword |
chaîne, répétable | aucun | Mots-clés. Correspondance sur mots entiers (pluriel toléré), insensible à la casse et aux accents, dans le titre, l'acheteur ou la description, plus les traductions du mot-clé sur les sources de la langue concernée ; avec un country sélectionné, seules les traductions dans les langues de ce pays et en anglais sont cherchées. Plusieurs keyword élargissent la recherche (au moins l'un d'eux). |
cpv |
chaîne, répétable | aucun | Codes CPV optionnels : huit chiffres, avec chiffre de contrôle facultatif vérifié. Inclut les descendants du catalogue officiel. Plusieurs codes et les mots-clés se combinent avec OU ; les autres filtres restent applicables. Uniquement les sources des pays utilisant le CPV. Maximum 50 codes ; code inconnu ou invalide : 422. |
exclude_term |
entier, répétable | aucun | Identifiants de termes (traductions ou variantes d'un mot-clé) à retirer de la recherche. |
country |
chaîne, répétable | aucun | Pays du portail, par leur nom anglais (France, Germany, United States, Canada ; Europe pour TED). Plusieurs country sont cumulatifs. L'objet by_country d'une réponse liste les valeurs exactes en usage. |
sector |
chaîne de deux chiffres, répétable | aucun | Secteurs, c'est-à-dire divisions CPV 2008 : les deux premiers chiffres d'un code CPV (45 travaux de construction, 72 services informatiques, 85 santé et action sociale). Un appel d'offres correspond dès qu'il appartient à l'un des secteurs demandés. Jamais appliqué sans demande explicite : sans sector, tous les secteurs sont cherchés. Une valeur hors des 45 divisions renvoie 422 avec le code invalid_sector. L'objet by_sector d'une réponse liste les divisions en usage. |
min_value |
nombre | aucun | Montant estimé minimum, dans la devise de l'appel d'offres. |
max_value |
nombre | aucun | Montant estimé maximum. |
sort |
newest, oldest ou deadline |
newest |
Tri : publication décroissante, publication croissante, ou date limite croissante. |
include_closed |
booléen | false |
Inclure les appels d'offres clôturés. |
seen_after |
date-heure ISO 8601 | aucun | Ne garder que les appels d'offres vus pour la première fois après cet instant. Utile pour une veille incrémentale. |
| seen_before | ISO 8601 | none | Conserver les avis collectés au plus tard à cet instant. Garder cette valeur fixe pendant la pagination d’une fenêtre de veille. |
Réponse
200 OK, objet TenderPage :
| Champ | Type | Description |
|---|---|---|
items |
tableau de Tender |
Les appels d'offres de la page. |
total |
entier | Nombre total d'appels d'offres correspondant aux critères. |
page |
entier | Page réellement renvoyée. |
page_size |
entier | Taille de page réellement appliquée. |
pages |
entier | Nombre de pages accessibles, plafonné par l'offre. |
by_country |
objet, code pays vers entier | Nombre d'appels d'offres par pays du portail, tous les autres filtres appliqués mais sans le filtre country. Sert à construire une facette. |
by_sector |
objet, division à deux chiffres vers entier | Nombre d'appels d'offres par secteur, tous les autres filtres appliqués — country compris — mais sans le filtre sector. Sert à construire une facette. Un appel d'offres portant plusieurs secteurs est compté une fois par secteur : la somme ne vaut donc pas total. |
Un objet Tender :
| Champ | Type | Description |
|---|---|---|
id |
entier | Identifiant Scoutee de l'appel d'offres. |
source_id |
entier | Identifiant du portail d'origine. |
source_name |
chaîne, nullable | Nom du portail. |
source_country |
chaîne, nullable | Pays du portail, deux lettres. |
external_id |
chaîne | Identifiant de l'appel d'offres chez le portail. |
title |
chaîne | Intitulé de la consultation. |
buyer |
chaîne, nullable | Acheteur public. |
description |
chaîne, nullable | Objet du marché, tel que publié. |
url |
chaîne | Page de l'appel d'offres sur le portail d'origine. |
location |
chaîne, nullable | Lieu d'exécution. |
procedure |
chaîne, nullable | Type de procédure, tel que publié. |
cpv_codes |
tableau de chaînes | Codes CPV rattachés à l'appel d'offres. |
cpv_inferred_codes |
tableau de chaînes | Suggestions CPV de Scoutee, distinctes des codes publiés par l’acheteur. Utilisées pour la recherche uniquement en l’absence de CPV publié reconnu. |
sectors |
tableau de chaînes de deux chiffres | Secteurs (divisions CPV) de l'appel d'offres : les divisions de ses codes CPV quand il en a, sinon l'unique division attribuée par notre classement automatique. Vide si ni l'un ni l'autre. |
estimated_value |
nombre, nullable | Montant estimé. |
currency |
chaîne, nullable | Devise du montant. |
published_at |
date-heure, nullable | Date de publication. |
deadline_at |
date-heure, nullable | Date limite de remise des offres. |
first_seen_at |
date-heure | Première collecte par Scoutee. |
last_seen_at |
date-heure | Dernière collecte. |
closed_at |
date-heure, nullable | Clôture constatée. null si l'appel d'offres est ouvert. |
favorite |
booléen | true quand l'appel d'offres est un favori de l'espace de travail. Les favoris appartiennent à l'espace de travail et sont partagés par ses membres ; avec une clé API, l'espace de travail de la clé. |
also_on |
tableau de AlsoOn |
Les copies du même appel d'offres sur d'autres portails, portails nationaux d'abord. Une copie sur le portail de la ligne elle-même (un autre lot sous le même titre) n'en fait jamais partie. |
Un objet AlsoOn : source_id (entier), source_name (chaîne), source_country (chaîne, nullable), url (chaîne), tender_id (entier, nullable : la fiche de ce portail), deadline_at (date-heure, nullable : la date limite de ce portail, qui peut différer de celle de la ligne).
Exemple
curl -s -G "https://scoutee.org/api/tenders" \
-H "X-API-Key: $SCOUTEE_API_KEY" \
--data-urlencode "keyword=voirie" \
--data-urlencode "keyword=signalisation" \
--data-urlencode "country=France" \
--data-urlencode "sort=deadline" \
--data-urlencode "page_size=50"
{
"items": [
{
"id": 918233,
"source_id": 12,
"source_name": "PLACE",
"source_country": "FR",
"external_id": "25-114287",
"title": "Travaux de voirie et de signalisation horizontale",
"buyer": "Communauté de communes du Val de Loire",
"description": "Marché à bons de commande pour la réfection de voirie...",
"url": "https://www.marches-publics.gouv.fr/?page=Entreprise.EntrepriseAdvancedSearch&id=25-114287",
"location": "Loiret",
"procedure": "Procédure adaptée",
"cpv_codes": ["45233220", "45233221"],
"sectors": ["45"],
"estimated_value": 420000.0,
"currency": "EUR",
"published_at": "2026-09-01T08:00:00Z",
"deadline_at": "2026-10-03T12:00:00Z",
"first_seen_at": "2026-09-01T09:12:44Z",
"last_seen_at": "2026-09-05T06:03:11Z",
"closed_at": null,
"favorite": false,
"also_on": []
}
],
"total": 137,
"page": 1,
"page_size": 50,
"pages": 3,
"by_country": { "France": 137, "Belgium": 12 },
"by_sector": { "45": 96, "71": 28, "50": 13 }
}
En Python, avec requests :
import os
import requests
BASE = "https://scoutee.org/api"
HEADERS = {"X-API-Key": os.environ["SCOUTEE_API_KEY"]}
response = requests.get(
f"{BASE}/tenders",
headers=HEADERS,
params={
"keyword": ["voirie", "signalisation"],
"country": ["France"],
"sort": "deadline",
"page_size": 50,
},
timeout=30,
)
response.raise_for_status()
page = response.json()
print(page["total"], "appels d'offres", "|", response.headers["X-Quota-Remaining"], "recherches restantes")
for tender in page["items"]:
print(tender["id"], tender["deadline_at"], tender["title"])
Parcourir toutes les pages :
def iter_tenders(**params):
"""Toutes les pages d'une recherche, dans l'ordre demandé."""
page = 1
while True:
response = requests.get(
f"{BASE}/tenders",
headers=HEADERS,
params={**params, "page": page, "page_size": 200},
timeout=30,
)
response.raise_for_status()
body = response.json()
yield from body["items"]
if page >= body["pages"]:
return
page += 1
Pour une veille incrémentale, gardez la date du dernier passage et repassez-la en seen_after : seuls les appels d'offres découverts depuis reviennent.
GET /tenders/{id}
Un appel d'offres, enrichi comme un résultat de recherche. Ne consomme pas de quota.
curl -s "https://scoutee.org/api/tenders/918233" \
-H "X-API-Key: $SCOUTEE_API_KEY"
La réponse est un objet Tender, identique à ceux de items. Si l'identifiant demandé désigne la copie d'un appel d'offres publié sur plusieurs portails, c'est la copie de référence qui est renvoyée. Un identifiant inconnu répond 404.
Serveur MCP
Les deux mêmes opérations sont exposées sous forme de serveur MCP à l'adresse https://scoutee.org/api/mcp, avec le même jeton OAuth ou la même clé, les mêmes paramètres et les mêmes quotas : Claude Code, Cursor, VS Code, Windsurf ou tout client du protocole peut ainsi chercher des appels d'offres pour vous. Installation, outils et exemples sont sur la page du serveur MCP.
Erreurs
Le corps d'une erreur est toujours {"detail": "..."}, et le message est toujours en anglais, quelle que soit la langue de votre intégration : l'anglais est la langue de travail de l'API. Chaque erreur qu'un utilisateur peut rencontrer porte aussi un code stable dans l'en-tête de réponse X-Error-Code : votre intégration s'appuie sur ce code et rédige son propre message, plutôt que de comparer le texte.
| Code | X-Error-Code |
Cas | detail |
|---|---|---|---|
| 401 | — | Aucun identifiant sur une route d'appels d'offres (le catalogue est public) | Login required |
| 401 | invalid_api_key |
Clé inconnue ou révoquée | Invalid API key |
| 402 | plan_required |
Création ou révocation d'une clé sur un espace de travail sans offre payante | This feature requires a paid plan |
| 403 | api_key_disabled |
L'espace de travail de la clé n'est pas sur une offre payante (il l'a quittée, ou n'en a jamais eu) | API key disabled: this workspace is not on a paid plan |
| 403 | api_key_scope |
Route protégée hors recherche et détail d'appels d'offres | This key only grants access to the tender search |
| 404 | — | Identifiant d'appel d'offres inconnu | Tender not found |
| 429 | quota_exceeded |
Quota horaire épuisé | You have reached the limit of 100 searches per hour of your plan. Try again in 12 min. |
| 429 | search_burst |
Trop de requêtes en une minute | Too many searches at once, try again in a minute |
Une réponse quota_exceeded répète ses nombres dans X-Error-Limit (recherches par heure) et X-Error-Minutes (l'attente) : le message peut ainsi être reconstruit dans n'importe quelle langue.
Les réponses 429 portent un en-tête Retry-After, en secondes. Respectez-le plutôt que de réessayer immédiatement :
import time
def search(**params):
"""Une recherche, avec attente si le quota par minute est atteint."""
for _ in range(3):
response = requests.get(f"{BASE}/tenders", headers=HEADERS, params=params, timeout=30)
if response.status_code != 429:
response.raise_for_status()
return response.json()
time.sleep(int(response.headers.get("Retry-After", "60")))
raise RuntimeError("quota toujours épuisé après trois tentatives")
Les codes 402 et 403 ne se corrigent pas en réessayant : vérifiez l'offre de l'espace de travail, ou créez une nouvelle clé si la vôtre a été révoquée.
En MCP, les mêmes échecs reviennent sous forme d'erreurs d'outil portant les mêmes messages, et non de codes HTTP.