API Prosperian
API HTTP publique de Prosperian. Elle permet de piloter le flux outbound de bout en bout — sourcer des prospects → créer une séquence → y attacher une liste → l'activer — depuis n'importe quel client HTTP.
- Base URL :
https://app.prosperian.co - Format : JSON (requêtes et réponses). Toutes les routes sont en
POST. - Spec machine-lisible :
openapi.yaml(OpenAPI 3.1, importable dans Postman / Swagger / pour générer un client). - MCP : la même surface est exposée comme serveur MCP — voir Utilisation via MCP. Deux façons de s'y authentifier : une clé API, ou un connecteur OAuth 2.1 branché depuis claude.ai — voir Connecteur claude.ai (OAuth 2.1).
Sommaire
- Authentification
- Obtenir une clé API
- Endpoints
- Enrichissement
- Gestion des erreurs
- Rate limiting
- Utilisation via MCP
Authentification
Chaque requête doit porter votre clé API dans le header X-API-Key :
X-API-Key: psk_live_xxxxxxxxxxxxxxxxxxxxxxxx
Une clé est scopée à une seule organisation. Elle ne peut accéder qu'aux ressources de
cette organisation : toute tentative d'accès à une autre organisation renvoie 403.
| Cas | Réponse |
|---|---|
Header X-API-Key absent ou clé invalide / révoquée | 401 { "error": "Clé API invalide" } |
| Clé valide mais organisation ciblée ≠ organisation de la clé | 403 { "error": "Clé API non autorisée pour cette organisation" } |
Le serveur MCP accepte une seconde famille de credentials. Un connecteur branché depuis claude.ai présente un jeton d'accès OAuth (
pmo_at_…) au lieu d'une clé API. Ce jeton ne vaut que sur/api/mcp: les endpoints HTTP décrits ci-dessous restent enX-API-Key. Voir Connecteur claude.ai (OAuth 2.1).
Obtenir une clé API
- Dans l'application : Paramètres → API et développeurs.
- Créez une clé. Le secret complet (
psk_live_…) n'est affiché qu'une seule fois à la création — copiez-le et stockez-le en lieu sûr. L'app n'en conserve qu'un hash et les 4 derniers caractères (pour l'affichage). - Pour révoquer une clé, supprimez-la depuis la même page. La révocation est immédiate.
Les endpoints de gestion des clés (
/api/api-keys) sont réservés à l'interface (auth par session) et ne font pas partie de l'API publique.
Endpoints
POST /api/sourcing/prospects
Lance une recherche de prospects à partir d'une description en langage naturel et de filtres optionnels. La recherche s'exécute en asynchrone ; les prospects trouvés alimentent une liste.
Paramètres (corps JSON)
| Champ | Type | Requis | Description |
|---|---|---|---|
criteria.description | string | ✅ | Description en langage naturel des prospects recherchés |
criteria.industry | string | — | Filtre secteur |
criteria.companySize | string | — | Filtre taille d'entreprise |
criteria.location | string | — | Filtre localisation |
criteria.revenue | string | — | Filtre chiffre d'affaires |
criteria.technologies | string | — | Filtre technologies |
criteria.keywords | string | — | Mots-clés additionnels |
listName | string | — | Nom de la liste créée (auto-généré si absent) |
userContext.organizationId | string | — | Si fourni, doit correspondre à l'org de la clé |
Exemple
curl -X POST https://app.prosperian.co/api/sourcing/prospects \
-H "X-API-Key: psk_live_xxx" \
-H "Content-Type: application/json" \
-d '{
"criteria": {
"description": "Fondateurs de fintech à Londres",
"industry": "Financial Services",
"location": "London, United Kingdom"
},
"listName": "Fintech London"
}'
Réponse 200
{
"success": true,
"message": "Recherche de prospects lancée avec succès pour la liste \"Fintech London\"",
"webhookResponse": {},
"criteria": "Fondateurs de fintech à Londres",
"listName": "Fintech London"
}
400 si criteria.description est absent.
POST /api/copilot/create-campaign
Crée une séquence outbound (campagne) avec une suite d'étapes ordonnées. La séquence est créée
au statut draft — utilisez update-status pour l'activer.
Paramètres (corps JSON)
| Champ | Type | Requis | Description |
|---|---|---|---|
name | string | ✅ | Nom de la campagne |
sequence | array | — | Étapes ordonnées (voir ci-dessous) |
sequence[].type | string | ✅ | Type d'étape : mail_send, linkedin_message, logic_wait, … |
sequence[].subject | string | — | Objet (pour les étapes email) |
sequence[].message | string | — | Corps du message |
sequence[].delay | number | — | Délai en jours (pour les étapes d'attente) |
description | string | — | Description de la campagne |
organization_id | string | — | Doit correspondre à l'org de la clé si fourni |
Exemple
curl -X POST https://app.prosperian.co/api/copilot/create-campaign \
-H "X-API-Key: psk_live_xxx" \
-H "Content-Type: application/json" \
-d '{
"name": "Cold email fintech",
"sequence": [
{ "type": "mail_send", "subject": "Quick question", "message": "Bonjour {{first_name}}, ..." },
{ "type": "logic_wait", "delay": 3 },
{ "type": "mail_send", "subject": "Re: Quick question", "message": "Petite relance ..." }
]
}'
Réponse 200
{
"success": true,
"campaignId": "a1b2c3d4-0000-0000-0000-000000000000",
"stepsCount": 3,
"outreachSynced": true,
"message": "Campagne créée"
}
POST /api/sequences/attach-prospects
Attache tous les prospects d'une liste à une séquence : déduplique, crée les prospects manquants, génère les tâches d'outreach et synchronise vers le système d'envoi. Les prospects présents dans la blacklist de l'organisation sont ignorés.
Opération potentiellement longue (jusqu'à 300 s pour de grandes listes).
Paramètres (corps JSON)
| Champ | Type | Requis | Description |
|---|---|---|---|
sequence_id | string | ✅ | UUID de la séquence cible |
prospect_list_id | string | ✅ | UUID de la liste de prospects à attacher |
Exemple
curl -X POST https://app.prosperian.co/api/sequences/attach-prospects \
-H "X-API-Key: psk_live_xxx" \
-H "Content-Type: application/json" \
-d '{
"sequence_id": "a1b2c3d4-0000-0000-0000-000000000000",
"prospect_list_id": "e5f6a7b8-0000-0000-0000-000000000000"
}'
Réponse 200
{
"success": true,
"added": 87,
"tasksCreated": 174,
"attachedInThisCall": 87,
"totalInSequence": 87,
"blacklisted": 3,
"enrolled_skipped": 0,
"locked_skipped": 0,
"outreach": { "native": true, "provider": "unipile", "enrolled": 87 },
"motif_enrolement": {
"kind": "filtre",
"resolus": 90,
"enroles": 87,
"liste_tronquee": false,
"ventilation": { "liste_noire": 0, "deja_demarche": 2, "canal_absent": 1, "doublon": 0 }
},
"ai_import": { "ran": false, "keys": [], "generated": 0, "skipped_existing": 0 }
}
Champs additionnels possibles : blacklist_skips[] ({ id, label, reason }), prospect_errors[],
message.
⚠️
totalInSequenceest déprécié — utilisezattachedInThisCall. Les deux portent la même valeur (le volume rattaché par CET appel), maistotalInSequenceporte l'ancienne sémantique « total de la séquence », qui est fausse : ce total est recalculé séparément, depuis les enrôlements réels.
⚠️
outreachn'est présent que sur le chemin natif. Ce bloc était documenté ici avec un champpushedque le code n'émet jamais — la forme réelle est{ native, provider, enrolled }, oùenrolledest identique àmotif_enrolement.enroles.
Lire motif_enrolement — POURQUOI ce nombre de leads, et pas un autre
Les cinq portes de sortie en 200 le portent : subset vide, liste vide ou introuvable, tout
blacklisté, tout déjà en campagne, tout sous verrou 90 j, plus le chemin nominal. Le champ est
une union discriminée par kind ; la liste des 11 valeurs et leur sens exact vivent dans
openapi.yaml (schéma MotifEnrolement).
⚠️ Absent ≠ zéro. Un client qui ne trouve pas ce champ doit dire qu'il ne sait pas, jamais afficher une ventilation à zéro : la réponse peut venir d'un déploiement antérieur.
⚠️ enroles = INSÉRÉ, mesuré. L'écriture est synchrone : le nombre est celui que la base a
réellement enregistré, pas celui qu'on a proposé. Un fait accompli, pas une intention.
⚠️ Un reliquat peut rester en vol. Sur une grosse liste, l'écriture s'arrête avant la limite
de durée de l'appel et le reste est repris ensuite : non_tentes compte ces lignes, et
non_tentes - non_confies seront enrôlées d'elles-mêmes en quelques minutes. non_confies est le
sous-ensemble que personne ne reprendra tout seul.
⚠️ non_confies a DEUX causes, et arret_pause est le discriminant. Soit le reliquat a été
REFUSÉ à la reprise — il faut alors relancer. Soit la séquence a été MISE EN PAUSE pendant
l'écriture, et rien n'a alors été proposé du tout : non_confies vaut TOUT non_tentes, aucun
refus n'a eu lieu, et le geste attendu est de réactiver la séquence. Lire arret_pause pour les
distinguer ; la spécification OpenAPI porte le détail du champ.
⚠️ Ces nombres ne s'additionnent pas. resolus est ce que le FILTRE a vu : il n'inclut
aucune des trois exclusions amont (blacklisted, enrolled_skipped, locked_skipped), retirées
avant. L'égalité exacte porte trois termes, pas un :
somme(ventilation) + exclus_pool + non_tentes = resolus - enroles — une ligne tombe dans un seul
compartiment, et deux causes vivent HORS ventilation parce qu'elles ne sont pas des verdicts sur
le prospect (aucun expéditeur sain ; écriture arrêtée avant la fin). ventilation compte
désormais cinq compartiments (deja_enrole s'y est ajouté).
⚠️ Une exception : quand deja_enroles_illisible vaut true, l'égalité devient un
minorant — la lecture des déjà-enrôlés ayant échoué, ces lignes sont écartées par la
contrainte d'unicité sans tomber dans aucun terme. Sur ce chemin,
ventilation.liste_noire vaut toujours 0 : l'exclusion est faite en amont et rapportée par
blacklisted.
Réponse 502 — les leads ont bien été rattachés, mais l'ordre d'enrôlement n'a pas pu
être transmis au moteur d'envoi : personne ne recevra rien. motif_enrolement.kind vaut
envoi_impossible. added, count et tasksCreated restent renseignés (le rattachement, lui,
a eu lieu). Rejouable tel quel : la création de tâches est dédupliquée, relancer ne double
aucune ligne.
Réponse 503 — la liste noire n'a pas pu être lue. Aucun lead n'a été rattaché et aucune
tâche créée : continuer sans elle risquerait de recontacter des personnes qui ont demandé à ne
plus l'être. motif_enrolement.kind vaut liste_noire_illisible. Réessayez.
POST /api/sequences/update-status
Passe une séquence en active (démarre les envois) ou en paused (les arrête), et synchronise
l'état vers le système d'outreach.
Pré-requis pour l'activation : un abonnement outreach actif et au moins un profil expéditeur configuré pour l'organisation. À défaut, l'endpoint renvoie une erreur.
Opération potentiellement longue (jusqu'à 300 s) : l'activation lit la liste cible en paginant (jusqu'à 20 000 lignes), charge la liste noire paginée, puis émet les ordres d'enrôlement par lots.
Paramètres (corps JSON)
| Champ | Type | Requis | Description |
|---|---|---|---|
sequence_id | string | ✅ | UUID de la séquence |
status | string | ✅ | active ou paused |
Exemple
curl -X POST https://app.prosperian.co/api/sequences/update-status \
-H "X-API-Key: psk_live_xxx" \
-H "Content-Type: application/json" \
-d '{
"sequence_id": "a1b2c3d4-0000-0000-0000-000000000000",
"status": "active"
}'
Réponse 200
{
"ok": true,
"status": "active",
"provider": "unipile",
"native": true,
"enroll_items": 87,
"motif_enrolement": {
"kind": "filtre",
"resolus": 90,
"enroles": 87,
"liste_tronquee": false,
"ventilation": { "liste_noire": 1, "deja_demarche": 1, "canal_absent": 1, "doublon": 0 }
}
}
Champs additionnels possibles : post_engager_ingestion.
⚠️ Cet exemple documentait
getsales_syncedetresynced_flow_uuid— deux champs que le code n'émet plus, les colonnes correspondantes ayant été supprimées.
enroll_items est le nombre de lignes réellement insérées en base par cet appel ; il vaut 0
sur toute sortie dont le motif_enrolement.kind n'est pas filtre. Même réserve de lecture que
pour attach-prospects : absent ≠ zéro. Contrairement au chemin d'attachement, ventilation.liste_noire peut ici être non nul —
l'activation filtre la liste noire elle-même.
Réponse 500 (panne d'enrôlement) — trois motifs : envoi_impossible, lecture_impossible,
liste_noire_illisible. La séquence est rendue à son statut d'avant et les enrôlements
réveillés par l'appel sont rendormis : rien n'a été activé, rien n'a été envoyé. L'appel est
atomique du point de vue du client et se rejoue tel quel. Le corps porte ok: false,
status (le statut restauré, pas active), enroll_items: 0 et motif_enrolement.
⚠️ Une activation qui n'enrôle personne pour une raison normale (brouillon sans canal, liste
vide, tout filtré) reste un 200 : y rendre un 5xx déclencherait des tempêtes de reprise sur le
geste le plus courant du produit. Lisez motif_enrolement, pas seulement le code HTTP.
Enrichissement
Enrichit des contacts ou des listes en email et/ou téléphone. Consomme des crédits de
l'organisation (email ≈ 1, téléphone ≈ 10 par contact résolu) ; une réponse 402 est renvoyée si
le solde est insuffisant. Pour une clé API, organizationId est optionnel (déduit de la clé).
Modèle asynchrone : certaines résolutions ne sont pas immédiates. Une réponse avec
pending: true (ou des compteurs from…API) signifie qu'une partie est en cours côté fournisseur.
Récupérez les résultats avec les endpoints de réconciliation (sync-pending-item,
sync-pending-list, pull-list-item).
| Endpoint | Rôle |
|---|---|
POST /api/enrichment/manual | Créer + enrichir un nouveau contact (nom + société) |
POST /api/enrichment/single | Enrichir un prospect existant (prospectId) |
POST /api/enrichment/prospect-list-item | Enrichir une ligne de liste précise (itemId) |
POST /api/enrichment/pronto | Enrichir tous les prospects d'une liste existante |
POST /api/enrichment/csv | Créer une liste depuis des prospects fournis (≤ 1000) et l'enrichir |
GET /api/enrichment/list-coverage | Couverture LinkedIn/domaine d'une liste |
POST /api/enrichment/sync-pending-item | Réconcilier une ligne en attente |
POST /api/enrichment/sync-pending-list | Réconcilier les lignes en attente d'une liste |
POST /api/enrichment/pull-list-item | Forcer le polling Pronto d'une ligne |
Enrichir un contact — POST /api/enrichment/manual
| Champ | Type | Requis | Description |
|---|---|---|---|
first_name | string | ✅ | Prénom |
last_name | string | ✅ | Nom |
enrichmentTypes | object | ✅ | { email?: boolean, phone?: boolean } — au moins un true |
company_name | string | — | Société |
company_domain | string | — | Domaine (ex. stripe.com) — améliore le taux de match |
linkedin_url | string | — | URL LinkedIn |
organizationId | string | — | Optionnel avec une clé API |
curl -X POST https://app.prosperian.co/api/enrichment/manual \
-H "X-API-Key: psk_live_xxx" \
-H "Content-Type: application/json" \
-d '{
"first_name": "Jane",
"last_name": "Doe",
"company_domain": "stripe.com",
"enrichmentTypes": { "email": true }
}'
{
"success": true,
"source": "pronto",
"data": { "email": "jane@stripe.com" },
"itemId": "…",
"listId": "…",
"pending": false,
"creditsDeducted": 1,
"message": "Données enrichies immédiatement."
}
Enrichir une liste — POST /api/enrichment/pronto
| Champ | Type | Requis | Description |
|---|---|---|---|
prospectListId | string | ✅ | Liste à enrichir |
enrichmentTypes | object | ✅ | { email?: boolean, phone?: boolean } |
organizationId | string | — | Optionnel avec une clé API |
curl -X POST https://app.prosperian.co/api/enrichment/pronto \
-H "X-API-Key: psk_live_xxx" \
-H "Content-Type: application/json" \
-d '{ "prospectListId": "…", "enrichmentTypes": { "email": true, "phone": false } }'
{
"success": true,
"message": "Enrichissement terminé pour 120 prospects",
"creditsDeducted": 110,
"results": {
"total": 120,
"success": 110,
"errors": 10,
"fromDatabase": 30,
"fromAirscaleAPI": 80
}
}
Les autres endpoints (
single,prospect-list-item,csv,list-coverage,sync-pending-*,pull-list-item) suivent les mêmes conventions d'auth et de crédits. Voiropenapi.yamlpour les schémas request/response complets.
Gestion des erreurs
Les erreurs renvoient un statut HTTP 4xx/5xx et un corps JSON :
{ "error": "Message lisible", "details": "Détail technique optionnel" }
| Code | Signification |
|---|---|
400 | Requête invalide (champ requis manquant, statut non supporté) |
401 | Clé API absente, invalide ou révoquée |
402 | Crédits d'enrichissement insuffisants ({ error, required, available }) |
403 | Clé non autorisée pour l'organisation ciblée |
404 | Ressource introuvable (prospect, item ou liste) |
409 | Conflit. Trois émetteurs sur update-status, discriminés par code — c'est lui qui décide s'il faut réessayer, jamais le statut HTTP : activation_deja_en_cours (une autre activation tourne ; le verrou est pris avant toute écriture ⇒ réessayer est sûr), organisation_en_migration (gel temporaire ⇒ réessayer plus tard), no_healthy_sending_account (aucune boîte connectée ⇒ ne pas réessayer, un humain doit en connecter une). Sur les routes d'enrichissement : enrichissement déjà en cours pour l'organisation |
500 | Erreur interne (le champ details précise la cause quand disponible). Sur update-status, recouvre aussi la panne d'enrôlement : la séquence est rendue à son statut d'avant, l'appel se rejoue tel quel |
502 | attach-prospects : leads rattachés, mais l'ordre d'enrôlement n'a pas pu être transmis au moteur d'envoi. Rejouable (création de tâches dédupliquée) |
503 | attach-prospects : la liste noire n'a pas pu être lue — rien n'a été rattaché, plutôt que de risquer de recontacter des personnes qui l'ont refusé. Réessayez |
⚠️ Un
200ne veut pas dire « des leads sont partis ». Sur les deux endpoints d'enrôlement, une sortie à zéro pour une raison normale (brouillon sans canal, liste vide, tout blacklisté, tout déjà en campagne) reste un200— c'estmotif_enrolementqui porte le pourquoi. Les5xxsont réservés aux pannes techniques, celles qui méritent une reprise.
Rate limiting
Restez raisonnable sur le volume et la fréquence des appels, en particulier pour
attach-prospects (opération lourde). Un usage manifestement abusif peut être restreint
sans préavis.
Les endpoints OAuth sont limités. Au-delà du débit autorisé, ils rendent 429 ;
patientez avant de réessayer.
Utilisation via MCP
La même surface est exposée comme serveur MCP hébergé (Streamable HTTP) sur /api/mcp
— implémentation dans le code source,
outils dans le code source — pour piloter Prosperian
depuis Claude Code (ou tout client MCP) sans écrire de requêtes HTTP :
find_leads → create_campaign → attach_prospects → start_sequence
| Outil MCP | Endpoint |
|---|---|
find_leads | POST /api/sourcing/prospects |
create_campaign | POST /api/copilot/create-campaign |
attach_prospects | POST /api/sequences/attach-prospects |
start_sequence | POST /api/sequences/update-status |
enrich_contact | POST /api/enrichment/manual |
enrich_list | POST /api/enrichment/pronto |
⚠️ attach_prospects, enrich_contact, enrich_list et start_sequence (branche
« activer ») ne s'exécutent PAS au premier appel. Ils passent par proposeOrExecute
(le code source) : le premier appel
crée une demande de validation en attente et n'exécute rien. Il faut
un second appel portant un approval_action_id approuvé par un humain pour que
executeApprovedAction fasse le travail — en appelant les fonctions internes, pas l'endpoint
HTTP listé ci-dessus. La colonne « Endpoint » indique donc la surface équivalente, pas ce que
l'outil déclenche. Seule exception : start_sequence avec status: 'paused' appelle
directement POST /api/sequences/update-status.
Outils de lecture (stats) — pour que l'agent suive ses résultats :
| Outil MCP | Endpoint | Renvoie |
|---|---|---|
get_campaign_stats | POST /api/copilot/stats/campaign | funnel + buckets d'une séquence (live) |
list_campaigns | POST /api/copilot/stats/list | campagnes + compteurs (cache rollup) — découverte des sequence_id |
get_org_stats | POST /api/copilot/stats/org | crédits restants + totaux (prospects, listes, campagnes, RDV) |
get_activity_report | POST /api/copilot/stats/report | activité par rep/séquence/liste (tâches, appels, RDV, issues) |
get_objections | POST /api/copilot/stats/objections | matrice objections catégorie × canal |
get_response_heatmap | POST /api/copilot/stats/heatmap | meilleurs créneaux de réponse par canal |
Dépréciation —
get_activity_report. Chaque entrée deperUserporte désormaisdisplayName(string | null) etrelation(agency|member|left|unknown).userNamereste servi comme alias et vaut la chaîne vide quand l'auteur n'est pas nommable ; il sera retiré à la prochaine version majeure.relationdit comment l'auteur se rattache au compte :member= membre actuel,left= son compte d'origine est celui-ci mais il opère ailleurs,agency= opérateur de l'agence qui gère le compte,unknown= non rattachable (les compteurs restent justes, le nom est tu). Ne jamais afficherdisplayNamenul tel quel.
Les outils de lecture sont accessibles à toute clé API valide (modèle per-org, plein accès).
Installation avec une clé API (Claude Code, ou tout autre client MCP) :
claude mcp add --transport http prosperian \
https://app.prosperian.co/api/mcp \
-H "x-api-key: psk_live_xxx"
⚠️ Le CLI npm @prosperian/mcp n'a jamais été publié : l'endpoint hébergé ci-dessus
est la seule installation valide.
L'authentification accepte Authorization: Bearer comme x-api-key, avec la clé API per-org.
Connecteur claude.ai (OAuth 2.1)
claude.ai ne sait pas coller une clé API dans un header : pour ajouter un serveur MCP, il exige un serveur d'autorisation OAuth. Prosperian en sert un. On ajoute donc Prosperian comme connecteur personnalisé (claude.ai → Settings → Connectors → Add custom connector) avec la seule URL du serveur MCP :
https://app.prosperian.co/api/mcp
Le reste est automatique. Claude suit la chaîne 401 → métadonnées de ressource protégée (RFC 9728) → métadonnées du serveur d'autorisation (RFC 8414) → enregistrement dynamique du client (RFC 7591) → écran de consentement → jetons. Un seul maillon manquant produit
« Couldn't reach the MCP server », sans autre explication.
| Endpoint | Rôle |
|---|---|
GET /.well-known/oauth-protected-resource/api/mcp | RFC 9728 — décrit la ressource et pointe le serveur d'autorisation. La forme nue /.well-known/oauth-protected-resource est servie en alias |
GET /.well-known/oauth-authorization-server | RFC 8414 — métadonnées du serveur d'autorisation |
POST /api/oauth/register | RFC 7591 — enregistrement dynamique du client (non authentifié par nature, limité en débit) |
GET /oauth/authorize | écran de consentement, en session applicative |
POST /api/oauth/token | échange du code d'autorisation, puis rafraîchissement |
Ce qu'il faut savoir avant de brancher :
- Le consentement est réservé aux administrateurs de l'organisation. Un membre non administrateur voit l'écran refuser, avec le motif écrit.
- Le connecteur est lié à l'organisation affichée sur l'écran de consentement, pas à l'organisation « active » au moment du clic : basculer de client dans un autre onglet pendant que l'écran est ouvert ne détourne pas le jeton.
- PKCE
S256est obligatoire. Le client est public (aucun secret) et seuls lesredirect_urisurclaude.ai/claude.com, ou en boucle locale (http://127.0.0.1,http://localhost, port ignoré — RFC 8252 §7.3), sont enregistrables. Un hôte hors de cette liste est refusé en400nommant l'URI, jamais en silence. - Durées de vie : code d'autorisation 60 s, jeton d'accès 1 h, jeton de rafraîchissement 60 j. Le rafraîchissement tourne à chaque usage : un jeton rejoué est refusé, et un rejeu caractérisé révoque toute la chaîne — c'est la détection de vol de la BCP OAuth 2.1. En cas de doute sur un connecteur, révoquez-le depuis l'application.
- Le périmètre est celui d'une clé API. Le scope annoncé (
mcp) désigne l'accès au serveur MCP, pas un sous-ensemble d'outils : un connecteur peut tout ce que peut une clé API de l'organisation. Les outils d'écriture restent derrière le flux d'approbation décrit plus haut. - L'accès est revérifié à chaque appel, pas seulement au consentement : désactiver la personne, ou couper son lien d'agence, lui retire l'accès sans avoir à révoquer son jeton.
Révoquer un connecteur : Paramètres → API et développeurs, carte « Connecteurs MCP ». Elle liste qui a branché quoi, quand, et la date du dernier appel. Révoquer coupe le grant et ses jetons, immédiatement. Chacun peut révoquer le sien ; un administrateur peut révoquer n'importe lequel. Les clés API ne sont pas affectées.