# Connecteurs

Comment les connecteurs et les connexions donnent aux agents un accès limité aux outils externes.

Canonical page: https://beeuni.ai/docs/fr/connect/connectors

Un connecteur relie un projet à un outil ou service externe. L’agent
l’appelle comme un outil. Beeuni relaie chaque appel, de sorte que le bac à sable ne détient jamais
l’identifiant du connecteur.

Vous déclarez la plupart des connecteurs dans `beeuni.yaml`. Consultez la
[référence du manifeste](/docs/fr/project/manifest) pour connaître tous les champs. Beeuni déclare
les connecteurs de canal et d’ordinateur lorsque vous connectez une plateforme de discussion ou une
machine.

<a id="browse-and-add-a-connector"></a>

## Parcourir et ajouter un connecteur

Ouvrez **Connectors** pour parcourir le catalogue géré. Sa liste par défaut contient
des boîtes à outils de fournisseurs gérés, connectables avec une authentification gérée par le fournisseur ou une
configuration d’authentification personnalisée activée. Une connexion existante dans votre
projet n’est pas nécessaire. Une boîte à outils qui nécessite une configuration OAuth personnalisée
non vérifiée reste masquée jusqu’à ce que cette configuration puisse être vérifiée.

Pour les sources directes, activez **Connectors API Discover** dans les indicateurs de fonctionnalité
du projet, puis sélectionnez **API / MCP** sur la même page. L’activation de cet indicateur ne
remplace pas la valeur par défaut gérée. Le catalogue direct regroupe les surfaces OpenAPI, MCP,
GraphQL, Postman et autres API publiées. Sélectionnez une carte, choisissez une
surface publiée et remplissez son formulaire de connexion. Les surfaces fournissant uniquement de la documentation ouvrent
la documentation du fournisseur ; elles ne sont pas présentées comme un modèle prêt à connecter.
Utilisez **Add → Manual** pour une API brute ou un schéma absent du catalogue.
La découverte directe fonctionne également sans fournisseur géré configuré.

<a id="connectors-connections-and-accounts"></a>

## Connecteurs, connexions et comptes

Un connecteur est le paquet d’accès destiné à l’agent : une capacité déclarée (quelles
actions, et comment atteindre le service). Ce n’est pas un rôle et il ne détient aucune
permission Beeuni : un agent n’atteint un connecteur que lorsque l’autorisation de son manifeste répertorie
le slug et que la décision du rôle autorise l’appel. Consultez
[Un vocabulaire, deux liaisons](/docs/fr/accounts#one-vocabulary-two-bindings). Un
connecteur contient :

- un slug unique au projet
- un nom d’affichage
- une application fournisseur
- des politiques de connecteur

Une connexion est un **compte** — une identité autorisée — pour le
connecteur : un identifiant, une autorisation OAuth ou une clé API. Un connecteur peut contenir
plusieurs comptes côte à côte. Chaque compte utilise les politiques du connecteur.
Le `owner_type` de chaque compte détermine qui peut exécuter un appel en son nom :

- `project` — un compte **partagé**. Accessible à toute personne à qui le connecteur est
  accordé, qu’il s’agisse d’un humain ou d’un compte de service (agent, déclencheur).
- `member` — un compte **privé**, appartenant à un membre du projet
  (`owner_id`). Accessible uniquement à ce membre, et uniquement dans une session **privée**.
  Un compte de service (un agent ou un déclencheur agissant sans surveillance) ne peut jamais
  exécuter d’appel en tant que compte privé d’un membre.

Plusieurs connecteurs peuvent faire référence à la même application fournisseur. Utilisez des connecteurs
séparés lorsqu’une application nécessite des politiques différentes.

<a id="add-an-account"></a>

### Ajouter un compte

Ouvrez le connecteur dans **Customize → Connectors**. L’onglet **Accounts** répertorie
tous les comptes que vous pouvez utiliser ou gérer dans une seule liste. Chaque carte indique qui peut utiliser
le compte : **Only you**, **Everyone in project**, ou les groupes et personnes avec lesquels il
est partagé.

Sélectionnez **Add account**, nommez le compte et choisissez **Who can use it** :

- **Only you** — un compte privé. Tout membre peut en ajouter un.
- **Everyone in the project** — un compte partagé.
- **Specific people or groups** — un compte partagé, limité aux personnes,
  groupes et agents que vous sélectionnez.

Les deux choix partagés nécessitent `project.connector.connections.manage`. Pour
**Specific people or groups**, Beeuni écrit les autorisations avant que vous n’autorisiez
le compte, afin que le compte ne détienne jamais d’identifiant lorsqu’il est ouvert à tout le
projet. Le nom d’un compte doit être nouveau : un nom déjà utilisé par un compte du même propriétaire est
refusé.

Lorsqu’un agent a besoin d’un compte, il publie une carte **Connect** dans la discussion. La
carte ouvre la même boîte de dialogue, avec le nom suggéré par l’agent déjà renseigné et le public
demandé présélectionné. Beeuni crée un nouveau compte, ne réautorise jamais un compte
existant et indique à l’agent le nom du nouveau compte afin qu’il puisse exécuter des appels en
utilisant ce compte.

<a id="choose-who-can-use-a-shared-account"></a>

### Choisir qui peut utiliser un compte partagé

Un compte partagé est utilisable par tous les membres du projet jusqu’à ce que vous le restreigniez.
Sélectionnez **Share** sur la carte du compte. La boîte de dialogue est la même boîte de dialogue
**Grant access** que celle utilisée pour les agents. Elle répertorie les personnes qui peuvent utiliser
le compte actuellement, et vous pouvez ajouter :

- **Everyone in the project** — la valeur par défaut.
- **Groups** — chaque membre de chaque groupe.
- **People** — un membre à la fois. Sélectionnez uniquement vous-même pour limiter le compte à vous.
- **Agents** — chaque session de cet agent, y compris les déclencheurs et les sessions
  partagées. Toute personne pouvant exécuter l’agent peut utiliser le compte par son intermédiaire.

Rien ne change tant que vous n’avez pas sélectionné **Save**. La suppression du dernier groupe ou de la
dernière personne rend à nouveau le compte utilisable par tous ; la boîte de dialogue indique le résultat avant
l’enregistrement.

Un compte restreint suit les règles des comptes privés, avec son public à la place du propriétaire :

- Une personne du public peut l’utiliser, et uniquement dans une session privée.
- Un agent du public peut l’utiliser dans chacune de ses sessions.
- Tout autre agent, ainsi que le déclencheur de tout autre agent, ne l’utilise jamais.
- Une session qui le lie ne peut pas être partagée, sauf si le compte est partagé avec
  l’agent propre à cette session.
- Seule une personne peut modifier les personnes autorisées à utiliser un compte. Une session d’agent reçoit `403`.

Une personne extérieure au public ne voit pas le compte. Une personne qui gère les connexions
du projet le voit néanmoins, marqué **Not shared with you**, afin de pouvoir modifier les personnes autorisées
à l’utiliser.

<a id="share-your-own-private-account"></a>

### Partager votre propre compte privé

Votre compte **Only you** possède également un bouton **Share**. Le partage le transforme
en compte partagé pour les personnes et groupes que vous sélectionnez (vous le conservez tant que vous ne
vous retirez pas), ou pour tous les membres du projet. Il devient alors un compte partagé : les personnes
qui gèrent les connexions du projet peuvent également le gérer.

- Le partage nécessite `project.connector.connections.manage`, le même droit que
  l’ajout d’un compte partagé. Sans ce droit, le bouton est désactivé et en indique la raison.
- Beeuni écrit d’abord les autorisations et transforme le compte en compte partagé en une seule mise à jour,
  de sorte qu’il ne soit jamais ouvert à tout le projet entre les deux opérations.
- Un compte partagé portant le même nom sur le connecteur le bloque (`409`) : renommez-en
  un d’abord.

```text
POST /projects/{projectId}/connections/{connectionId}/share
     {"principals": [{"principal_type": "group", "principal_id": "<group-id>"}]}
```

Une liste `principals` vide le partage avec tout le monde. Depuis la CLI :
`beeuni connectors connections share <connection-id> --group <group-id>`
(également `--user <email|id>`, répétable, ou `--everyone`).

Chaque entrée de public est une affectation d’objet `connection` dans le magasin des autorisations :

```text
POST   /accounts/{accountId}/iam/assignments
       {"principal_type": "group", "principal_id": "<group-id>",
        "role_key": "agent-user", "scope_type": "project", "scope_id": "<project-id>",
        "object_type": "connection", "object_id": "<connection-id>"}
DELETE /accounts/{accountId}/iam/assignments/{assignmentId}
```

Depuis la CLI, les mêmes écritures sont :

```bash
beeuni access grant --group <group-id> --connection <connection-id>
beeuni access grant --everyone --connection <connection-id>
beeuni access revoke <assignment-id>
beeuni connectors connections ls   # the WHO CAN USE column
```

- `principal_type` est `user`, `group` ou `project` (tout le monde dans le projet ;
  `principal_id` est l’identifiant du projet).
- L’octroi ou la révocation d’une autorisation nécessite `project.connector.connections.manage`.
- Seul un compte partagé peut être restreint au moyen de ces autorisations. Un compte privé,
  ou un identifiant qui n’est pas une connexion dans ce projet, renvoie `404` ; partagez votre
  propre compte privé avec la route `share` ci-dessus à la place.
- `GET /projects/{projectId}/connections` renvoie les autorisations de chaque compte partagé
  dans `shared_with`, ainsi que `usable: false` sur un compte que l’appelant voit uniquement pour
  le gérer. Le sélecteur de session ne propose que les comptes utilisables.

<a id="which-identity-an-account-acts-as"></a>

### Quelle identité un compte utilise

Le `label` d’un compte est un nom choisi avant l’autorisation. Il n’indique pas quelle connexion a été utilisée. `connected_as`, lui, le fait : l’adresse e-mail, la connexion ou le nom d’affichage que le fournisseur communique pour le compte autorisé.

- Beeuni le récupère à la finalisation d’une autorisation gérée : d’abord le nom d’affichage du compte connecté, puis l’outil « qui suis-je » du toolkit (Gmail, Google Calendar, Google Drive, Linear, GitHub, Slack, Notion, Outlook, Microsoft Teams, HubSpot, Jira, Asana, Figma, Airtable, Salesforce, Trello, Dropbox, Calendly). Google Docs et Google Sheets ne proposent pas cet outil ; leur `connected_as` reste donc `null`.
- Si un compte porte encore un libellé par défaut (`Private connection`, `Project connection` ou le nom du connecteur), il est renommé avec cette identité. Un libellé choisi par quelqu’un n’est jamais remplacé.
- La page de connexion affiche « Connected as … » dès que le compte est ajouté : un compte partagé autorisé avec une connexion personnelle est donc immédiatement identifiable.
- `connected_as` apparaît sur chaque connexion (`GET /projects/{projectId}/connections`), dans la liste des comptes, dans `beeuni connectors accounts <slug>` et `beeuni connectors connections ls` (la colonne `CONNECTED AS`), ainsi que sur les lignes de compte dans **Customize → Connectors**.

<a id="rename-an-account"></a>

### Renommer un compte

Renommez un compte sans l’autoriser à nouveau :

```text
PUT /projects/{projectId}/connections/{connectionId}/label   {"label": "Support inbox"}
beeuni connectors connections rename <connection-id> Support inbox
```

Dans le tableau de bord, ouvrez le connecteur, puis sélectionnez **⋯ → Rename** sur la ligne du compte. Seul le libellé change. Le compte autorisé, son propriétaire, son indicateur par défaut et l’état du fournisseur restent inchangés. La même condition que pour la déconnexion s’applique : votre propre compte privé ou `project.connector.connections.manage` pour un compte partagé.

Le renommage est refusé avec `400` pour `me`, `project` ou un libellé au format UUID, car `--account` les résout avant les libellés. Il est refusé avec `409` si un autre compte du même propriétaire porte déjà ce libellé, sans distinction entre majuscules et minuscules.

<a id="connect-a-different-account"></a>

### Connecter un autre compte

Un lien de connexion pour un emplacement qui contient déjà un compte actif ne l’autorise pas à nouveau. Le fournisseur réutilise le compte et la page de connexion affiche **Already connected**. Pour utiliser une autre connexion, ajoutez un nouveau compte au connecteur, définissez-le comme compte par défaut, puis déconnectez l’ancien.

Un appel qui ne précise aucun compte utilise d’abord le compte privé par défaut de l’appelant, puis le compte partagé par défaut du projet. Chaque résultat d’appel indique le compte utilisé (`account: { connection_id, label, owner_type }`), afin que la transcription montre toujours l’identité utilisée par un appel d’outil. Avec `GET /connectors/projects/{projectId}/connectors/{slug}/accounts`, répertoriez les comptes auxquels un connecteur peut faire appel, en plaçant le compte par défaut en premier.

> **Warning**
> `authorization_strategy` (`project` | `user`) était un MODE au niveau du connecteur qui rendait les comptes appartenant au projet et ceux appartenant aux membres mutuellement exclusifs. Un connecteur de stratégie `user` ne pouvait proposer aucun compte partagé et n’avait donc aucun parcours de connexion utilisable par un compte de service. Ce mode est obsolète : le manifeste et `PUT .../authorization-strategy` l’acceptent toujours et répondent sans erreur, mais il n’est plus utilisé. `owner_type` sur chaque connexion constitue désormais l’ensemble des règles d’accès.

<a id="providers"></a>

## Fournisseurs

Un connecteur utilise un type de fournisseur :

- **composio** — OAuth géré pour les applications SaaS prises en charge
- **pipedream** — OAuth géré hérité, conservé uniquement pour revenir à la version précédente
- **openapi**, **postman**, **graphql**, **http** — connecteurs API directs
- **mcp** — serveur MCP distant via HTTP ou SSE
- **channel** — connexion à une plateforme de messagerie
- **computer** — la machine connectée de chaque membre constitue un compte

Consultez [Slack et les canaux](/docs/fr/connect/slack) et [Ordinateurs](/docs/fr/connect/computers) pour les parcours de fournisseur gérés.

<a id="apps-that-need-your-own-oauth-app"></a>

### Disponibilité des applications

Le catalogue des connecteurs affiche les applications disponibles à la connexion. Certaines nécessitent une configuration d’authentification supplémentaire et peuvent ne pas apparaître avant sa finalisation.

## Authentification et politiques

Une connexion s’authentifie à l’aide de :

- OAuth géré, une installation de canal ou une autorisation OAuth2 native
- une clé API ou un jeton saisi dans le tableau de bord

Beeuni chiffre les données de connexion et les résout côté serveur pour chaque appel d’outil. L’agent demande une action. Beeuni ajoute l’identifiant d’accès, vérifie l’autorisation de l’agent et la politique de connexion au connecteur, appelle l’API externe et renvoie le résultat.

Les politiques des connecteurs s’appliquent au connecteur. Une connexion ne peut pas les remplacer. Les garde-fous du projet s’appliquent en complément des politiques de connexion au connecteur.

Par défaut, une action de connecteur non couverte par une règle s’exécute sans approbation. Définissez `policy.default_mode: risk` pour exiger une approbation pour les actions d’écriture et destructrices non couvertes par une règle. Définissez `sensitive: true` pour faire de `require_approval` la règle par défaut du connecteur pour les actions non couvertes, y compris les lectures. Les règles explicites du projet ou de la connexion au connecteur s’appliquent toujours en premier.

<a id="approve-one-governed-call"></a>

### Approuver un appel soumis à des règles

`require_approval` crée une décision pour un seul appel de connecteur. Le connecteur renvoie `202 pending_approval` avec `approval_url`, `approval_summary` et `execution_id`. Il ne garde pas une requête HTTP ouverte.

Partagez `approval_url` avec un membre de l’équipe. L’URL identifie la requête, mais ne confère aucun droit. La page exige une connexion à un compte Beeuni. Beeuni vérifie ensuite que ce compte peut accéder au projet et approuver des actions.

La page d’approbation affiche les paramètres masqués que le connecteur recevra. L’appelant peut ajouter `approval_context` (CLI : `--reason`) pour décrire l’effet de l’action. Utilisez-le lorsque les paramètres ne sont que des références : `gmail.send_draft` reçoit un identifiant de brouillon ; l’agent indique donc le destinataire, l’objet et le corps du message. La page présente ce texte comme une description de l’agent, et non comme une information vérifiée. Les paramètres restent les éléments probants. Beeuni n’envoie jamais `approval_context` au fournisseur.

Approuvez ou refusez l’appel une seule fois. Vous pouvez ajouter un message facultatif à la décision. Ce message est renvoyé à l’agent avec la décision : un refus peut donc lui indiquer quoi faire à la place.

Chaque appel en attente apparaît également dans **Review → Needs you** pour le projet. Ouvrez **Review** dans la barre latérale ; le compteur indique le nombre d’éléments qui vous attendent. Un appel s’ouvre dans la même vue d’approbation que celle de son lien d’approbation, afin que vous puissiez voir le connecteur, les paramètres et la description de l’agent avant de prendre votre décision.

Lorsque l’appel provient d’une session Slack ou Teams, Beeuni publie une carte d’approbation dans le fil correspondant. La carte affiche la description de l’agent, les paramètres et **Approve** / **Deny**. Dans Slack, **Reply…** ouvre une zone de saisie pour envoyer un message à l’agent ; dans Teams, la zone de saisie est intégrée à la carte. Seul un chef de projet ou la personne qui a démarré la session peut prendre une décision. Une décision prise n’importe où (dans le fil, dans Beeuni ou sur la page d’approbation) remplace les boutons de la carte par le résultat, et l’agent continue dans le même fil. Beeuni renvoie la décision à la session au moyen d’un rappel durable. Une approbation ne s’applique qu’à la requête dont l’empreinte est exacte. Toute modification du destinataire, de l’objet, du corps du message, du canal, de l’URL ou d’un autre paramètre nécessite une nouvelle décision.

Ouvrez le panneau **Audit** de la session pour consulter la même vue des paramètres. Les entrées historiques restent en lecture seule. Il n’existe pas d’option d’approbation pour toute la session. Utilisez une règle `always_run` explicite uniquement lorsqu’une action du connecteur doit s’exécuter sans surveillance.

<a id="connect-with-oauth"></a>

## Se connecter avec OAuth

### Ouvrir la page Connectors du projet
Ouvrez le projet. Sélectionnez **Connectors**, puis l’application.

### Sélectionner le périmètre du compte
Sélectionnez **Project** pour un compte partagé, accessible à toute personne à qui le connecteur est accordé. Sélectionnez **User** pour un compte privé, qui vous appartient et auquel vous seul avez accès, uniquement dans une session privée.

### Terminer l’autorisation
Terminez le flux OAuth. Beeuni enregistre le compte connecté comme une connexion.

<a id="connect-an-mcp-server-that-uses-oauth-21"></a>

## Connecter un serveur MCP qui utilise OAuth 2.1

Beeuni implémente la spécification d’autorisation MCP. Ouvrez le connecteur, sélectionnez **Add credential**, puis l’onglet **OAuth 2.0**. Beeuni interroge le serveur et lit ses métadonnées :

1. La requête sans authentification renvoie `401` avec
   `WWW-Authenticate: Bearer resource_metadata="…"`.
2. Beeuni lit les métadonnées de la ressource protégée (RFC 9728) à cette URL ou à
   `/.well-known/oauth-protected-resource`.
3. Beeuni lit les métadonnées du serveur d’autorisation (RFC 8414 ou découverte OpenID Connect) du premier serveur d’autorisation indiqué par la ressource.

Lorsque ce serveur annonce `registration_endpoint`, Beeuni s’enregistre comme client OAuth (RFC 7591) et affiche un seul bouton : **Connect &lt;server&gt;**. Vous n’avez pas à créer d’application ni à copier d’identifiant ou de secret client. Beeuni exécute ensuite le flux Authorization Code avec PKCE (S256) et lie le jeton au serveur à l’aide du paramètre `resource` (RFC 8707).

Enregistrez cet URI de redirection si le serveur doit le connaître à l’avance :

```text
https://api.beeuni.ai/v1/connectors/oauth2/callback
```

Lorsque le serveur publie des points de terminaison, mais aucun `registration_endpoint`, Beeuni préremplit l’URL d’autorisation, l’URL du jeton et les portées. Saisissez l’identifiant client d’une application que vous créez auprès de ce fournisseur. Si le serveur ne publie aucune métadonnée, renseignez tous les champs.

Beeuni conserve la session MCP : il exécute `initialize` et
`notifications/initialized` à la demande, puis envoie `Mcp-Session-Id` lors des appels ultérieurs. Un serveur qui répond sans session ne reçoit jamais la négociation initiale.

Beeuni lie chaque connexion au serveur d’autorisation qui l’a émise. Lorsque le rappel contient un paramètre `iss` (RFC 9207), Beeuni le rejette s’il ne correspond pas à l’émetteur enregistré — un code émis par un autre serveur est refusé avant son échange.

<a id="authorize-from-the-cli"></a>

### Autoriser depuis la CLI

Le tableau de bord est une façon d’exécuter ce flux, mais pas la seule. Déclarez le connecteur dans `beeuni.yaml`, puis autorisez-le depuis un terminal ou une session d’agent :

```yaml
connectors:
  - slug: read-ai
    name: Read AI
    provider: mcp
    url: 'https://api.read.ai/mcp'
    auth:
      type: bearer
```

```text
beeuni connectors authorize read-ai --json
```

La commande crée la connexion, exécute la chaîne de découverte, enregistre Beeuni comme client si le serveur prend en charge RFC 7591, puis renvoie l’URL à approuver :

```json
{
  "connection_id": "7b1a16b2-...",
  "registered": true,
  "scopes": ["openid", "offline_access", "mcp:execute", "meeting:read"],
  "authorization_url": "https://authn.read.ai/oauth2/auth?response_type=code&...",
  "expires_at": "2026-08-19T14:48:26.345Z"
}
```

Un agent renvoie `authorization_url` à la personne avec laquelle il travaille. Après son approbation, l’agent confirme :

```text
beeuni connectors authorize read-ai --status
```

La commande se termine avec un code différent de zéro tant que l’état est `error`. Utilisez `--scope` pour limiter les éléments demandés. Utilisez `--client-id` et `--client-secret` pour un serveur qui ne prend pas en charge l’enregistrement dynamique des clients.

Beeuni récupère à nouveau le catalogue d’outils du connecteur dès que l’autorisation est terminée : le connecteur quitte donc l’état `error` sans synchronisation manuelle.

<a id="connect-a-direct-api-with-oauth2"></a>

## Connecter une API directe avec OAuth2

Les connecteurs directs prennent en charge :

- les informations d’identification du client
- le flux Authorization Code avec PKCE
- l’autorisation par appareil
- l’enregistrement dynamique des clients (RFC 7591)

Pour les informations d’identification du client, saisissez l’URL du jeton, l’identifiant client, les portées et le secret client. Vous pouvez utiliser l’authentification du point de terminaison du jeton `client_secret_basic`, `client_secret_post`,
`client_secret_jwt` ou `private_key_jwt`.

Pour le flux Authorization Code, saisissez l’URL d’autorisation et l’URL du jeton. Pour l’autorisation par appareil, saisissez l’URL d’autorisation par appareil et l’URL du jeton. Une URL de découverte RFC 8414 peut fournir ces points de terminaison.

Beeuni chiffre la configuration OAuth2 et les jetons. Il renouvelle les jetons d’accès avant leur expiration et enregistre chaque jeton d’actualisation renouvelé. La révocation de la connexion bloque le prochain appel au connecteur.

Pour Microsoft Graph, utilisez :

```text
https://login.microsoftonline.com/{tenant_id}/oauth2/v2.0/token
https://graph.microsoft.com/.default
```

Pour les appels directs à l’API REST SharePoint, utilisez la portée de ressource SharePoint :

```text
https://{tenant}.sharepoint.com/.default
```

<a id="connect-with-an-api-key"></a>

## Se connecter avec une clé API

### Déclarer le connecteur
```yaml
connectors:
- slug: stripe-read
name: Stripe read access
provider: openapi
spec: 'https://raw.githubusercontent.com/stripe/openapi/master/openapi/spec3.json'
auth:
type: bearer
policies:
- match: 'get_*'
action: always_run
- match: '*'
action: block
```

Le manifeste accepte toujours une clé `authorization_strategy` pour assurer la rétrocompatibilité. Beeuni l’ignore : définissez le propriétaire (partagé ou privé) pour chaque connexion lorsque vous ajoutez ses identifiants.

### Fusionner la demande de modification
Beeuni lit le manifeste depuis la branche par défaut. Le connecteur devient actif une fois la demande de modification fusionnée.

### Ajouter la connexion
Ouvrez le connecteur et définissez ses identifiants. Beeuni enregistre la valeur sous forme chiffrée. Il ne l’écrit pas dans le manifeste.

<a id="grant-an-agent-access"></a>

## Accorder l’accès à un agent

Ajoutez le nom court du connecteur au champ `connectors` de l’agent :

```yaml
agents:
  release-bot:
    connectors: [stripe-read]
```

Omettez `connectors`, et l’agent reçoit `none`. Fusionnez la modification pour qu’elle prenne effet.

`connectors_required` est obsolète. Le manifeste l’accepte toujours, mais rien ne le lit : la création d’une session n’est jamais refusée parce qu’un connecteur ne dispose pas de compte utilisable. En pratique, le refus de création d’une session pour un connecteur manquant était impossible à résoudre : un connecteur réservé aux comptes privés ne disposait d’aucun compte partagé à proposer, si bien que l’appelant ne pouvait rien faire pour remédier au refus. Le contrôle s’effectue désormais au moment de l’**appel** du connecteur : un agent auquel `stripe-read` est accordé peut commencer son tour immédiatement, et seul un appel nécessitant réellement le connecteur est refusé (voir [Lorsqu’un appel est refusé](#when-a-call-is-denied)) — avec une solution proposée.

<a id="select-an-account"></a>

## Sélectionner un compte

Deux moyens indépendants de choisir le compte utilisé pour un appel : en fixer un pour toute la session ou en indiquer un pour un seul appel.

<a id="pin-a-session-wide-default"></a>

### Définir une valeur par défaut pour toute la session

Une session peut remplacer le compte par défaut du connecteur pour tous ses appels :

```json
{
  "connector_bindings": {
    "stripe-read": {
      "connection_id": "00000000-0000-4000-8000-000000000000"
    }
  }
}
```

La clé de liaison est le nom court du connecteur. La valeur est un compte (une connexion) auquel l’appelant de cette session est autorisé à accéder.

Utilisez `GET /projects/{projectId}/sessions/{sessionId}/scope` pour consulter la liaison effective. Utilisez `PUT` sur le même chemin pour la remplacer. Le remplacement s’applique au prochain appel d’outil sans redémarrer la session.

<a id="name-an-account-on-one-call"></a>

### Indiquer un compte pour un seul appel

Listez les comptes qui peuvent être utilisés pour appeler un connecteur — le compte par défaut en premier — avec :

```text
GET /connectors/projects/{projectId}/connectors/{slug}/accounts
```

```json
{
  "connector": "stripe-read",
  "accounts": [
    { "connection_id": "...", "label": "Shared workspace", "owner_type": "project", "is_default": true, "connected_as": "billing@example.com" },
    { "connection_id": "...", "label": "My Stripe", "owner_type": "member", "is_default": false, "connected_as": null }
  ]
}
```

Indiquez ensuite un compte dans l’appel, par son ID de connexion ou son libellé (sans distinction de casse), ou avec les deux mots de sélection `me` (votre propre compte privé par défaut) et `project` (le compte partagé par défaut du projet) :

```text
beeuni connectors call stripe-read get_balance '{}' --account me
beeuni connectors call stripe-read get_balance '{}' --account "Shared workspace"
```

Un appel qui ne précise aucun compte utilise d’abord le compte privé par défaut de l’appelant, puis le compte partagé par défaut du projet — comme avant qu’un connecteur puisse avoir plusieurs comptes. Un compte nommé introuvable est **refusé** ; il n’est jamais remplacé silencieusement par un autre (voir [Quand un appel est refusé](#when-a-call-is-denied)). Le résultat de chaque appel réussi indique le compte utilisé : `account: { connection_id, label,
owner_type }`.

<a id="use-a-connector-in-a-session"></a>

## Utiliser un connecteur dans une session

Dans une session, utilisez la CLI Connector :

```text
beeuni connectors ls
beeuni connectors accounts stripe-read
beeuni connectors call stripe-read <action> '<json-args>' [--account <id|label|me|project>]
```

`connectors` répertorie les connecteurs disponibles. `accounts` répertorie les comptes que cet appelant peut utiliser `stripe-read` — par défaut d’abord, puis les comptes partagés avant les comptes privés dans chaque groupe. `call` exécute une action avec le `--account` indiqué ou, s’il est omis, applique la même résolution par défaut qu’avant qu’un connecteur puisse avoir plusieurs comptes.

<a id="large-results"></a>

### Résultats volumineux

Un appel de liste ou de recherche peut renvoyer plus de données qu’un modèle ne peut en lire : la sortie d’un outil dépassant environ 50 KB est tronquée. Enregistrez le résultat dans un fichier et traitez-le avec du code :

```text
beeuni connectors call linear graphql.issues '{"first":250}' --out /workspace/output/issues.json
# → { "ok": true, "account": …, "saved_to": "/workspace/output/issues.json",
#     "bytes": 93037, "shape": { "issues": { "nodes": "array(250) of {id,title,…}",
#     "pageInfo": { "hasNextPage": true, "endCursor": "…" } } } }
jq '.data.issues.nodes[] | {id, title}' /workspace/output/issues.json
```

`--out` écrit le résultat JSON complet en créant les répertoires parents. La sortie standard contient l’enveloppe de l’appel sans `data`, ainsi que `saved_to`, `bytes` et `shape` : la structure de `data` (clés, longueurs des tableaux et chaque `pageInfo`). Le code de sortie reste inchangé.

<a id="attach-files"></a>

### Joindre des fichiers

Un appel ne contient jamais les octets d’un fichier dans ses arguments. Préparez le fichier, puis ajoutez sa référence aux arguments. La passerelle lit les octets côté serveur et les insère dans la requête.

```text
beeuni connectors call microsoft-graph.sendmail @mail.json \
  --attach /workspace/artifacts/report.pdf
```

`--attach` prépare le fichier et ajoute une référence au tableau des pièces jointes de l’action. Ce tableau se trouve dans le schéma d’entrée de l’action : `attachments` pour le canal Email, `body.message.attachments` pour Microsoft Graph `sendMail`. Utilisez `--attach-path body.message.attachments` pour le nommer si le schéma est inhabituel.
Les arguments JSON volumineux doivent être placés dans un fichier (`@mail.json`) ou transmis via l’entrée standard (`-`).

Pour ajouter vous-même un fichier, préparez-le d’abord :

```text
beeuni connectors upload /workspace/artifacts/report.pdf --connector microsoft-graph
# → { "attachment_id": "…", "ref": { "$beeuni_attachment": "…" }, … }
```

Placez `ref` n’importe où dans les arguments. La passerelle le remplace selon sa position :

| Position de `ref` | Remplacé par |
| --- | --- |
| Un élément d’un tableau de pièces jointes dont les éléments sont des objets | L’élément de pièce jointe du fournisseur. Le schéma de l’élément détermine sa forme : Microsoft Graph `fileAttachment` (`name` + `contentBytes` ou `@odata.type`), Postmark (`Name` + `Content`), Mailjet (`Filename` + `Base64Content`), SendGrid et Resend (`filename` + `content`), Brevo (`name` + `content`). Toute autre forme d’élément est refusée avec `attachment_item_shape_unknown`. |
| Un champ de chaîne, par exemple `contentBytes` ou un fichier GitHub `content` | La chaîne base64 du fichier. |
| `attachments[]` du canal Email | Une URL de téléchargement signée pour le fournisseur Email. |

Règles :

- Les fichiers doivent provenir de `/workspace/output`, `/workspace/artifacts`,
  `/workspace/reports` ou `/workspace/deliverables`. Les liens symboliques et physiques sont refusés. Copiez d’abord le fichier à cet emplacement.
- Un appel peut contenir jusqu’à 20 fichiers et 25 MiB au total. L’API en amont peut imposer une limite inférieure : Microsoft Graph indique qu’une requête `sendMail` ne peut joindre qu’un fichier de 3 MB au maximum.
- Un fichier préparé est privé à la session qui l’a préparé, ne peut être utilisé qu’une fois et est supprimé après 24 heures. Un appel échoué le libère pour une nouvelle tentative.
- Le journal d’audit, l’aperçu d’approbation et le modèle ne voient que la référence, jamais les octets. Si une erreur en amont renvoie le fichier, sa chaîne base64 est supprimée.
- Les connecteurs gérés n’acceptent pas les fichiers préparés (`connector_attachments_unsupported`).

Le serveur MCP propose le même processus : `call` prend `attachment_files` (et un `attachment_path` facultatif), et `upload_attachment` renvoie un `ref`. L’équivalent dans le SDK est `connectors.uploadAttachment(bytes, { filename, contentType,
connector })`, which returns `ref`.

<a id="call-results"></a>

### Résultats des appels

`POST /connectors/projects/{projectId}/call` renvoie un objet JSON. Ces champs sont identiques pour chaque interface (OpenAPI, HTTP, MCP, GraphQL, `composio`,
`pipedream`, ordinateurs) :

| Champ | Pour | Valeur |
| --- | --- | --- |
| `data` | 200 | La réponse brute en amont, inchangée. |
| `output` | 200 | La charge utile sans l’enveloppe de l’interface : `composio` `data.result`, MCP `result.structuredContent ?? result.content`, GraphQL `data.data`. Absent lorsqu’il est égal à `data` (appels OpenAPI, HTTP, Postman, canal, `pipedream` et ordinateur), afin que le corps ne contienne la charge utile qu’une seule fois : lisez `output ?? data`. Le SDK le renseigne. |
| `binding` | 200, 500, 429, 503 | L’interface qui a exécuté l’appel : `openapi`, `http`, `mcp`, `graphql`, `composio`, `pipedream`, `pipedream_proxy`, `postman`, `tunnel`. `null` en cas d’erreur avant la résolution de l’action. |
| `upstream_status` | 200, 500, 429, 503 | Le statut HTTP en amont. `null` lorsqu’aucune réponse en amont n’a été reçue (expiration du délai, requête refusée, ordinateur). `composio` et `pipedream` signalent un échec du fournisseur dans une réponse 200 ; Beeuni définit donc `502` dans ce cas (`400` pour une requête Linear rejetée, `429` pour une limite de débit). |
| `upstream_error` | 200 | Présent lorsque le système en amont signale un échec dans une réponse 2xx : un résultat d’outil MCP avec `isError: true` ou une erreur JSON-RPC, ou GraphQL `errors` sans données. L’appel est tout de même considéré comme exécuté : `ok` reste `true`. |
| `retry_after_seconds` | 429, 503 | La valeur `Retry-After` du système en amont, en secondes, s’il en a fourni une. La réponse contient également l’en-tête `Retry-After`. |

Statut HTTP d’un appel échoué :

- Une erreur `429` en amont renvoie `429`. Une erreur `503` en amont renvoie `503`. Attendez `retry_after_seconds` (ou appliquez un délai exponentiel), puis réessayez.
- Les autres erreurs en amont renvoient `500`, avec leur cause dans `reason`.

- Une réponse en amont de plus de 64 MiB renvoie `500` avec `reason: "upstream_response_too_large: …"`. Beeuni arrête la lecture à la limite. Demandez une page ou un filtre plus petit.
- Un système en amont qui ne répond pas avant l’échéance renvoie `500` avec `reason: "upstream_timeout: …"`. L’échéance est de 60 secondes par défaut. Définissez un délai d’expiration client supérieur, afin que la passerelle réponde toujours en premier.

Un appel de connecteur n’est pas idempotent. Beeuni ne déduplique pas les appels répétés. Après `upstream_timeout` ou l’interruption côté client, l’appel a peut-être été exécuté en amont : vérifiez son effet avant de répéter une écriture (un e-mail envoyé, un enregistrement créé).

<a id="typed-calls-from-code"></a>

### Appels typés depuis le code

`beeuni connectors types` génère un fichier de déclaration TypeScript pour chaque action que vous pouvez appeler. Chaque action obtient le type de ses arguments à partir de son schéma d’entrée et le type de son résultat à partir de son schéma de sortie. Le type du résultat décrit le champ `output` de l’appel.

```sh
beeuni connectors types --out src/beeuni-connectors.d.ts
beeuni connectors types --connector linear,github --out src/beeuni-connectors.d.ts
```

Incluez le fichier dans votre `tsconfig.json`. Puis effectuez l’appel via `callAction` :

```ts
import { createBeeuni } from '@beeuni/sdk';

const connectors = createBeeuni({ backendUrl, getToken }).project(projectId).connectors;
const result = await connectors.callAction('linear', 'list_issues', { team: 'CORE' });
if (result.ok) console.log(result.output?.issues.length);
```

Le handle du connecteur lit le même fichier, et `run` renvoie directement la sortie typée ou lève une erreur typée (voir Connecteurs depuis le code) :

```ts
const issues = await createBeeuni({ backendUrl, getToken })
  .project(projectId)
  .connector('linear')
  .run('list_issues', { team: 'CORE' });
```

`callAction(slug, action, args, options)` envoie la même requête que `call('<slug>.<action>', args, options)` et renvoie le même résultat. Seuls les types diffèrent : un argument manquant ou inconnu provoque une erreur de compilation, et `output` utilise le type généré. Une action absente du fichier accepte n’importe quel objet et renvoie `output: unknown`.

- Les connecteurs OpenAPI, HTTP, MCP et GraphQL publient un schéma de sortie lorsque leur source en déclare un. Le résultat GraphQL est typé comme un objet.
- Les connecteurs gérés ne publient aucun schéma de sortie. Leur résultat est `unknown`. La CLI les nomme après avoir écrit le fichier.
- Chaque entrée `$defs` devient un type nommé (`BeeuniConnectorDef<n>_<name>`), afin qu’un schéma récursif reste fini. Un schéma qui ne peut pas être compilé (une union qui se contient elle-même) ou dont les types dépassent 256 Ko pour une action devient `unknown`.
- Relancez la commande après avoir ajouté un connecteur ou lorsqu’il synchronise une nouvelle version.
- Le catalogue ne renvoie les schémas de sortie que sur demande :
  `GET /connectors/projects/{projectId}/catalog?include_output_schemas=true`
  ajoute `outputSchema` à chaque action (`null` lorsqu’aucun schéma n’est enregistré).

<a id="when-a-call-is-denied"></a>

### Lorsqu’un appel est refusé

Un appel refusé renvoie `{ ok: false, status: "denied", reason, hint }`. `reason` est un code stable ; `hint` indique la marche à suivre.

| `reason` | HTTP | Signification | Également dans le corps |
| --- | --- | --- | --- |
| `connector_not_assigned` | 403 | La subvention `connectors:` de l’agent en cours dans `beeuni.yaml` n’inclut pas ce connecteur. | `agent`, `granted` (la liste ou `"all"`), `manifest_revision` et `manifest_commit` (le manifeste dont provient la subvention). |
| `connector_not_connected` | 403 | Aucun compte utilisable pour cet appel. Soit le connecteur n’a aucun compte pour cet appelant (aucun identifiant enregistré, ou l’application n’a jamais été autorisée — `beeuni connectors ls` l’indique comme `needs_auth`), soit `--account` en a nommé un qui n’a pas pu être résolu. | `connect_url` — un lien hébergé pour autoriser un compte, lorsque l’appelant peut en créer un — lorsqu’aucun compte n’est connecté. `requested_account` et `available_accounts` — le nom qui n’a pas pu être résolu et les noms qui l’ont été — lorsque `--account` en a nommé un. |
| `connector_disabled` | 403 | Le connecteur est déclaré mais désactivé. | — |
| `connector_not_found` | 404 | Aucun connecteur portant ce slug n’est déclaré dans le projet. | — |
| `action_not_found` | 404 | Le connecteur ne possède pas cette action. | — |

`connect_url` est l’unique solution pour un connecteur non connecté : une session n’est jamais refusée à l’avance pour cette raison (voir [Accorder à un agent l’accès](#grant-an-agent-access)), le refus lui-même contient donc la solution. L’agent affiche le lien tel quel ; la transcription Web le rend sous forme de bouton Connect en un clic. Par défaut, le lien autorise un compte privé pour la personne qui l’ouvre — connecter un compte partagé est un choix explicite (`beeuni connectors connect stripe-read --owner project`, soumis à `project.connector.write`).

Le connecteur de canal qui a créé une session (Slack, Teams, e-mail) peut toujours être appelé depuis cette session, quelles que soient les subventions de l’agent, afin que l’agent puisse toujours répondre dans le fil depuis lequel il a été sollicité.

La subvention d’une session suit `beeuni.yaml` : une modification de `connectors:` de l’agent en cours (y compris `beeuni connectors add --apply`) s’applique au prochain appel. La subvention enregistre le blob de manifeste et le commit dont elle provient ; une lecture qui la remplacerait à partir du même blob est confirmée par une seconde lecture préalable, et une lecture provenant d’un commit plus ancien ne la remplace jamais.

Slack et Microsoft Teams se connectent depuis le tableau de bord comme les applications OAuth. La connexion de Slack écrit pour vous un connecteur `channel` dans `beeuni.yaml`. Voir [Slack et canaux](/docs/fr/connect/slack).
