
# API d'équipe

Votre équipe se compose de toutes les personnes travaillant dans votre compte en dehors de vous — administrateurs, agents et lecteurs en lecture seule — ainsi que des invitations que vous avez envoyées et des départements dans lesquels vous les organisez. L'API d'équipe est la version programmatique de **Paramètres → Équipe** : ajoutez et supprimez des personnes, définissez ce que chacune d'entre elles peut voir et faire, envoyez et relancez des invitations, et gérez les départements.

Tous les points de terminaison ci-dessous sont relatifs à l'URL de base `https://api.youraiconnector.com/v1`. Pour la version tableau de bord de tout ce qui figure sur cette page, consultez [Gestion d'équipe](../settings/team-management.md).

---

## Authentification : ces points de terminaison nécessitent une personne connectée

**C'est la seule partie de l'API qu'une clé API ne peut pas utiliser.** Chaque point de terminaison `/team`, à l'exception de ceux relatifs aux [départements](#departments), doit être appelé avec un **jeton d'ID Firebase** provenant d'une session connectée :

```
Authorization: Bearer <Firebase ID token>
```

Envoyez une clé API à la place et la requête sera rejetée avec une erreur `401` :

```json
{
  "success": false,
  "error_code": 401,
  "error": "This endpoint requires a Firebase ID token (Authorization: Bearer <token>)."
}
```

La raison est que ces points de terminaison décident de ce qu'il faut faire en fonction de **qui est connecté** : votre rôle, la limite de ce que vous êtes autorisé à accorder à quelqu'un d'autre, et si vous travaillez actuellement dans un autre compte. Une clé API est une intégration, pas une personne, il n'y a donc personne à qui ces règles peuvent s'appliquer.

En pratique, cela signifie que l'API d'équipe est destinée à une application propriétaire avec un utilisateur <span data-t="appName">Your AI Connector</span> connecté (voir [Authentification → Jeton d'ID Firebase](authentication.md#4-firebase-id-token-first-party-only)). Une intégration serveur à serveur ne peut pas gérer les membres de l'équipe — il n'y a aucun moyen de générer l'un de ces jetons depuis l'extérieur de l'application.

> **L'exception :** les quatre points de terminaison [département](#departments) sont des points de terminaison d'API ordinaires. Ils acceptent votre clé API exactement comme le reste de l'API, ainsi qu'une session connectée.

Chaque réponse sur cette page suit l'enveloppe habituelle : `success: true` plus les champs du point de terminaison au niveau supérieur, ou `success: false` avec `error` et `error_code` en cas de problème.

---

## Rôles et autorisations

Chaque membre de l'équipe a un **rôle**, qui définit son accès par défaut dans 12 zones de l'application. Vous pouvez ensuite remplacer les paramètres de zones individuelles.

| Rôle | Valeur | Résumé |
|---|---|---|
| Admin | `admin` | Tout sauf les actions liées à la facturation du propriétaire. |
| Éditeur | `editor` | Peut créer et modifier des éléments. Affiché en tant qu'**Agent** dans l'application. |
| Lecteur | `viewer` | Lecture seule. |

Chaque zone est définie sur l'un des quatre niveaux : `none` (masqué), `view` (lecture seule), `edit` (créer et modifier), `full` (incluant la suppression).

| Zone | Admin | Éditeur | Lecteur |
|---|---|---|---|
| `campaigns` | complet | modifier | voir |
| `contacts` | complet | modifier | voir |
| `messages` | complet | modifier | voir |
| `appointments` | complet | modifier | voir |
| `settings` | modifier | voir | aucun |
| `billing` | modifier | aucun | aucun |
| `team_management` | modifier | aucun | aucun |
| `analytics` | complet | voir | voir |
| `phone_numbers` | modifier | aucun | aucun |
| `integrations` | modifier | aucun | aucun |
| `faqs` | complet | modifier | voir |
| `daily_summaries` | complet | voir | voir |

Pour déroger aux valeurs par défaut du rôle, envoyez `permission_overrides` — un tableau d'objets `{ "area": ..., "level": ... }`. Chaque entrée remplace la valeur par défaut du rôle pour cette zone spécifique ; tout ce que vous ne listez pas conserve la valeur par défaut du rôle.

```json
"permission_overrides": [
  { "area": "analytics", "level": "full" },
  { "area": "billing", "level": "none" }
]
```

**Qui peut appeler ces points de terminaison**

- Le **propriétaire du compte** peut toujours tout faire.
- Un membre de l'équipe a besoin de `team_management` au niveau `view` pour lire la liste des membres et la liste des invitations, et au niveau `edit` pour ajouter, modifier, suspendre, supprimer, inviter, annuler ou renvoyer. Les administrateurs ont `edit` par défaut ; les éditeurs et les lecteurs ont `none`, donc par défaut, seuls les administrateurs peuvent gérer l'équipe.
- **Personne ne peut accorder un accès supérieur au sien.** Si vous essayez de donner à quelqu'un un niveau que vous ne possédez pas vous-même — ou de modifier, suspendre ou supprimer quelqu'un dont l'accès est déjà plus étendu que le vôtre — la requête est refusée avec `403` et un message nommant la zone.

---

## L'objet membre de l'équipe

`GET /team/members` renvoie un de ces objets par membre :

| Champ | Type | Description |
|---|---|---|
| `member_uid` | string | L'identifiant utilisateur du membre. Il s'agit du `{memberUid}` dans les chemins ci-dessous. |
| `account_owner_uid` | string | Le compte dont il est membre. |
| `member_email` | string | Son adresse e-mail. |
| `member_display_name` | string | Le nom qui lui est attribué dans l'application. |
| `role` | string | `admin`, `editor` ou `viewer`. |
| `permission_overrides` | array | Ses exceptions par zone. `[]` lorsqu'il suit uniquement les valeurs par défaut du rôle. |
| `status` | string | `active` ou `suspended`. |
| `auto_assign_enabled` | boolean \| null | Si les nouveaux contacts peuvent lui être automatiquement attribués. `null` signifie jamais modifié, ce qui se comporte comme `true`. |
| `created_by` | string | Qui l'a ajouté. |
| `created_at` | string \| null | Horodatage ISO 8601. |
| `updated_at` | string \| null | Horodatage ISO 8601. |

Les membres supprimés ne sont pas renvoyés — la liste ne contient que les membres actifs et suspendus.

> **Les limites de visibilité sont en écriture seule ici.** `contact_scope`, `contact_scope_axes` et `sub_account_access` (voir [Limiter ce qu'un membre peut voir](#limiting-what-a-member-can-see)) peuvent être définis lors de la création, de la mise à jour et de l'invitation, mais ce point de terminaison ne les renvoie pas.

---

## Lister les membres de l'équipe

`GET /team/members`

Renvoie la liste des membres ainsi que le nombre de sièges de votre forfait, afin que vous puissiez afficher « 3 sièges sur 5 » et savoir quand une invitation est sur le point d'être refusée.

**cURL**

```bash
curl "https://api.youraiconnector.com/v1/team/members" \
  -H "Authorization: Bearer FIREBASE_ID_TOKEN"
```

**JavaScript**

```javascript
const res = await fetch("https://api.youraiconnector.com/v1/team/members", {
  headers: { Authorization: `Bearer ${idToken}` },
});
const { members, seat_limit, seats_used } = await res.json();
```

**Python**

```python
import requests

res = requests.get(
    "https://api.youraiconnector.com/v1/team/members",
    headers={"Authorization": f"Bearer {id_token}"},
)
data = res.json()
```

**Réponse**

```json
{
  "success": true,
  "members": [
    {
      "account_owner_uid": "owner_uid_123",
      "member_uid": "uid_alice",
      "member_email": "alice@example.com",
      "member_display_name": "Alice Chen",
      "role": "admin",
      "permission_overrides": [],
      "status": "active",
      "auto_assign_enabled": true,
      "created_by": "owner_uid_123",
      "created_at": "2026-05-01T10:00:00.000Z",
      "updated_at": "2026-06-02T09:15:00.000Z"
    }
  ],
  "seat_limit": 5,
  "seats_used": 3
}
```

`seat_limit` est `null` lorsque votre forfait n'a pas de limite de sièges. `seats_used` ne compte que les membres **actifs** — suspendre ou supprimer quelqu'un libère immédiatement son siège.

---

## Ajouter un membre de l'équipe directement

`POST /team/members`

Ajoute quelqu'un à votre équipe immédiatement, sans invitation.

> **Ceci n'envoie aucun e-mail.** Personne n'est informé de son ajout, et s'ils ne possèdent pas déjà un identifiant <span data-t="appName">Your AI Connector</span>, le compte créé pour eux n'a **aucun mot de passe**, ils ne peuvent donc pas se connecter avant de l'avoir réinitialisé. Utilisez [Envoyer une invitation](#send-an-invitation) sauf si vous avez votre propre moyen d'en informer la personne et de lui permettre de se connecter.

**Champs de la requête**

| Champ | Requis | Description |
|---|---|---|
| `email` | Oui | L'adresse e-mail du membre de l'équipe. |
| `display_name` | Oui | Le nom affiché pour lui dans l'application. |
| `role` | Oui | `admin`, `editor` ou `viewer`. |
| `permission_overrides` | Non | Exceptions par zone aux paramètres par défaut du rôle. |
| `contact_scope` | Non | `all` ou `assigned` — voir [Limiter ce qu'un membre peut voir](#limiting-what-a-member-can-see). |
| `contact_scope_unassigned` | Non | Avec `assigned`, permettez-lui également de voir les contacts qui n'appartiennent encore à personne. |
| `contact_scope_axes` | Non | Limitez-le à des agents, canaux ou départements nommés. |
| `sub_account_access` | Non | Agences uniquement — quels sous-comptes clients ils peuvent ouvrir. |

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/team/members" \
  -H "Authorization: Bearer FIREBASE_ID_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "email": "sam@example.com",
    "display_name": "Sam Rivera",
    "role": "editor"
  }'
```

**JavaScript**

```javascript
const res = await fetch("https://api.youraiconnector.com/v1/team/members", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${idToken}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    email: "sam@example.com",
    display_name: "Sam Rivera",
    role: "editor",
  }),
});
const { member_uid } = await res.json();
```

**Réponse** — `201 Created`

```json
{
  "success": true,
  "team_member_id": "owner_uid_123_uid_sam",
  "member_uid": "uid_sam",
  "message": "Team member created successfully."
}
```

| Statut | Quand |
|---|---|
| `400` | `email`, `display_name` ou `role` est manquant, le rôle n'est pas l'un des trois, ou vous avez essayé de vous ajouter vous-même. |
| `403` | Vous n'avez pas la permission de gérer l'équipe, ou vous avez essayé d'accorder un accès supérieur au vôtre. |
| `409` | Cette personne est déjà un membre actif de votre équipe. |
| `429` | Les places de votre forfait d'équipe sont pleines. |

Ajouter quelqu'un qui a été précédemment **suspendu ou supprimé** le rétablit au lieu d'échouer.

---

## Mettre à jour un membre de l'équipe

`PATCH /team/members/{memberUid}`

Modifie le rôle, les permissions, la visibilité, l'accès client d'un membre, ou sa participation à l'attribution automatique des contacts. Envoyez uniquement les champs que vous souhaitez modifier ; tout ce que vous omettez conserve sa valeur actuelle.

**Champs de la requête**

| Champ | Description |
|---|---|
| `role` | `admin`, `editor` ou `viewer`. |
| `permission_overrides` | Remplace toute sa liste de dérogations. Envoyez `[]` pour le remettre aux paramètres par défaut du rôle. |
| `status` | Seul `active` est accepté, pour réactiver un membre suspendu. Pour suspendre quelqu'un, utilisez le [point de terminaison de suspension](#suspend-a-team-member). |
| `auto_assign_enabled` | `true` ou `false`. |
| `contact_scope` | `all` ou `assigned`. |
| `contact_scope_unassigned` | `true` ou `false`. |
| `contact_scope_axes` | Voir [Limiter ce qu'un membre peut voir](#limiting-what-a-member-can-see). |
| `sub_account_access` | Agences uniquement. |

> **Ceci est le seul point de terminaison où `null` signifie « effacer ».** Envoyer `"contact_scope": null`, `"contact_scope_axes": null` ou `"sub_account_access": null` supprime complètement cette limite et permet au membre de tout voir à nouveau. Lors de la création et de l'invitation, `null` signifie simplement « non fourni ».

**cURL**

```bash
curl -X PATCH "https://api.youraiconnector.com/v1/team/members/uid_sam" \
  -H "Authorization: Bearer FIREBASE_ID_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "role": "admin",
    "permission_overrides": [{ "area": "billing", "level": "none" }]
  }'
```

**Réponse**

```json
{
  "success": true,
  "message": "Team member updated successfully."
}
```

| Statut | Quand |
|---|---|
| `400` | Une valeur `status` ou `auto_assign_enabled` invalide, ou vous avez essayé de réactiver un membre qui a été supprimé (les membres supprimés doivent être réinvités). |
| `403` | Vous n'avez pas la permission, ou le changement éditerait ou créerait un accès plus large que le vôtre. |
| `404` | Aucun membre d'équipe de ce type. |

---

## Suspendre un membre de l'équipe

`POST /team/members/{memberUid}/suspend`

Suspend quelqu'un : il conserve sa place dans l'équipe mais perd l'accès. Utilisez ceci au lieu de la suppression lorsque la pause est temporaire — ramenez-le avec `PATCH /team/members/{memberUid}` et `{"status": "active"}`.

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/team/members/uid_sam/suspend" \
  -H "Authorization: Bearer FIREBASE_ID_TOKEN"
```

**Réponse**

```json
{
  "success": true,
  "message": "Team member suspended successfully."
}
```

Un membre suspendu **libère sa place**, vous pouvez donc inviter quelqu'un d'autre à sa place. Son accès prend fin lors du prochain rafraîchissement de son jeton de session actuel, ce qui peut prendre jusqu'à une heure — supprimez-le plutôt si vous avez besoin que ce soit immédiat.

| Statut | Quand |
|---|---|
| `400` | Vous avez essayé de suspendre le propriétaire du compte, ou un membre déjà suspendu ou supprimé. |
| `403` | Son accès est plus large que le vôtre. |
| `404` | Aucun membre d'équipe de ce type. |

---

## Supprimer un membre de l'équipe

`DELETE /team/members/{memberUid}`

Supprime une personne de votre équipe et libère sa licence. Elle est déconnectée et perd l'accès à votre compte ; ses propres identifiants restent inchangés.

**cURL**

```bash
curl -X DELETE "https://api.youraiconnector.com/v1/team/members/uid_sam" \
  -H "Authorization: Bearer FIREBASE_ID_TOKEN"
```

**Réponse**

```json
{
  "success": true,
  "message": "Team member removed successfully."
}
```

La suppression est définitive de votre côté : un membre supprimé **ne peut pas être réactivé** via le point de terminaison de mise à jour — invitez-le à nouveau si vous changez d'avis. Son adresse e-mail est également retirée de la liste de notification de votre compte.

| Statut | Quand |
|---|---|
| `400` | Vous avez tenté de supprimer le propriétaire du compte. |
| `403` | Son accès est plus étendu que le vôtre. |
| `404` | Ce membre de l'équipe n'existe pas. |

---

## Limiter ce qu'un membre peut voir

Trois champs optionnels, acceptés lors de l'ajout ([add](#add-a-team-member-directly)), de la mise à jour ([update](#update-a-team-member)) et de l'invitation ([invite](#send-an-invitation)), déterminent quelle partie du compte une personne peut voir. Ils se cumulent : un membre limité par plusieurs critères est restreint par l'ensemble de ceux-ci.

**`contact_scope`** — `all` (par défaut : tous les contacts et conversations) ou `assigned` (uniquement ceux qui leur sont assignés). Avec `assigned`, ajoutez `"contact_scope_unassigned": true` pour leur permettre également de voir les contacts qui n'appartiennent encore à personne.

**`contact_scope_axes`** — les limite aux agents, canaux ou départements nommés :

| Champ | Type | Description |
|---|---|---|
| `agents` | string[] | IDs des agents. Ils ne voient que les discussions routées vers l'un de ces agents. Max 200. |
| `channels` | string[] | Noms des canaux — `whatsapp`, `whatsapp_web`, `sms`, `instagram`, `instagram_private`, `messenger`, `facebook`, `chat_widget`, `telegram`, `line`, `viber`, `tiktok`, `imessage`, `email`, `linkedin`, `skool`, `custom`, `custom_channel`. Max 200. |
| `departments` | string[] | IDs des départements (voir [Départements](#departments)). Ils ne voient que les prospects classés dans ces départements. Max 200. |
| `include_unrouted` | boolean | Avec `agents` activé, affiche également les discussions qu'aucun agent ne gère. Désactivé par défaut. Ignoré lorsque `agents` est vide. |
| `include_undepartmented` | boolean | Avec `departments` activé, affiche également les discussions qui ne sont dans aucun département. Désactivé par défaut. Ignoré lorsque `departments` est vide. |

Les IDs des agents et des départements ne sont pas vérifiés lors de l'enregistrement — un ID inexistant ne correspond simplement à rien, ce qui se traduit par une boîte de réception vide plutôt que par une erreur. Les noms des canaux **sont** vérifiés : un nom non reconnu est rejeté avec `400`.


Aucun de ces trois éléments ne peut être défini pour le propriétaire du compte — cette requête est refusée avec `400`.

---

## Lister les invitations

`GET /team/invites`

Les invitations que vous avez envoyées, de la plus récente à la plus ancienne, afin que vous puissiez voir qui n'a pas encore accepté.

**Paramètres de requête**

| Paramètre | Requis | Description |
|---|---|---|
| `status` | Non | Ne renvoie que les invitations dans cet état — `pending`, `accepted`, `declined`, `cancelled` ou `expired`. |

**cURL**

```bash
curl "https://api.youraiconnector.com/v1/team/invites?status=pending" \
  -H "Authorization: Bearer FIREBASE_ID_TOKEN"
```

**Réponse**

```json
{
  "success": true,
  "invites": [
    {
      "id": "inv_abc123",
      "account_owner_uid": "owner_uid_123",
      "account_owner_display_name": "Acme Ltd",
      "invitee_email": "sam@example.com",
      "invitee_uid": null,
      "role": "editor",
      "permission_overrides": [],
      "status": "pending",
      "created_by": "owner_uid_123",
      "created_at": "2026-06-10T12:00:00.000Z",
      "expires_at": "2026-06-17T12:00:00.000Z",
      "responded_at": null
    }
  ]
}
```

Le jeton d'invitation n'est jamais renvoyé — il n'existe que dans l'e-mail qui a été envoyé.

---

## Envoyer une invitation

`POST /team/invites`

Envoie par e-mail une invitation à rejoindre votre équipe. C'est la méthode habituelle pour ajouter un coéquipier : il clique sur le lien, se connecte avec ses propres identifiants et accepte. S'il ne possède pas encore de compte <span data-t="appName">Your AI Connector</span>, un compte est créé pour lui et l'e-mail le guide pour définir un mot de passe.

**Champs de la requête**

| Champ | Requis | Description |
|---|---|---|
| `email` | Oui | Adresse où envoyer l'invitation. |
| `role` | Oui | `admin`, `editor` ou `viewer`. |
| `permission_overrides` | Non | Exceptions par zone, appliquées dès qu'ils acceptent. |
| `contact_scope` | Non | Appliqué lorsqu'ils acceptent. |
| `contact_scope_unassigned` | Non | Appliqué lorsqu'ils acceptent. |
| `contact_scope_axes` | Non | Appliqué lorsqu'ils acceptent. |
| `sub_account_access` | Non | Agences uniquement. Appliqué lorsqu'ils acceptent. |

Configurer les autorisations à l'avance signifie que vous n'avez pas à modifier le membre par la suite — tout est copié sur son adhésion lorsqu'il accepte.

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/team/invites" \
  -H "Authorization: Bearer FIREBASE_ID_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "email": "sam@example.com", "role": "editor" }'
```

**JavaScript**

```javascript
const res = await fetch("https://api.youraiconnector.com/v1/team/invites", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${idToken}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ email: "sam@example.com", role: "editor" }),
});
const { invite_id } = await res.json();
```

**Réponse** — `201 Created`

```json
{
  "success": true,
  "invite_id": "inv_abc123",
  "message": "Team invite sent successfully."
}
```

**Points à prévoir**

- **Les invitations expirent après 7 jours.** Une invitation expirée peut être renvoyée, ce qui déclenche une nouvelle période de 7 jours.
- **Les invitations en attente occupent une place.** Contrairement à l'ajout direct d'un membre, la vérification des places ici compte les membres actifs *plus* les invitations en attente. Ainsi, un compte dont toutes les places sont occupées sera refusé avant l'envoi de l'e-mail.
- **20 invitations par jour**, comptées par compte, incluant les envois et les renvois.

| Statut | Quand |
|---|---|
| `400` | `email` est manquant ou le rôle est invalide. |
| `403` | Vous n'avez pas la permission de gérer l'équipe, ou vous avez tenté d'accorder un accès supérieur au vôtre. |
| `409` | Une invitation en attente pour cet e-mail existe déjà, ou cette personne est déjà dans votre équipe. |
| `429` | Les places d'équipe de votre forfait sont pleines, ou vous avez atteint la limite de 20 invitations par jour. Le message `error` indique lequel. |

---

## Annuler une invitation

`DELETE /team/invites/{inviteId}`

Annule une invitation avant qu'elle ne soit acceptée. Le lien dans l'e-mail cesse de fonctionner.

**cURL**

```bash
curl -X DELETE "https://api.youraiconnector.com/v1/team/invites/inv_abc123" \
  -H "Authorization: Bearer FIREBASE_ID_TOKEN"
```

**Réponse**

```json
{
  "success": true,
  "message": "Team invite cancelled."
}
```

Les invitations `pending` et `expired` peuvent être annulées. Une invitation déjà acceptée, refusée ou annulée renvoie `400` ; une invitation qui n'est pas la vôtre renvoie `403` ; un identifiant inconnu renvoie `404`.

---

## Renvoyer une invitation

`POST /team/invites/{inviteId}/resend`

Renvoie l'e-mail d'invitation — utile s'il a été manqué ou s'il est arrivé dans les courriers indésirables. Fonctionne pour les invitations `pending` et `expired`, et réinitialise la date d'expiration à 7 jours à partir de maintenant.

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/team/invites/inv_abc123/resend" \
  -H "Authorization: Bearer FIREBASE_ID_TOKEN"
```

**Réponse**

```json
{
  "success": true,
  "message": "Team invite resent successfully."
}
```

Le nouvel e-mail contient un nouveau lien, et **l'ancien lien continue également de fonctionner**, de sorte qu'une personne qui retrouverait le premier e-mail plus tard ne soit pas bloquée. Le renvoi est comptabilisé dans la même limite de 20 par jour que l'envoi initial, et la réactivation d'une invitation *expirée* vérifie à nouveau vos sièges — un forfait complet sera refusé avec `429`.

---

## Accepter une invitation

`POST /team/invites/accept`

Accepte une invitation avec le jeton provenant de l'e-mail d'invitation, ajoutant la personne connectée à l'équipe de ce compte.

> **Il s'agit d'un acte lié à votre propre identité.** Connectez-vous en tant que vous-même — l'action est délibérément refusée avec `403` si vous travaillez au sein du compte de quelqu'un d'autre.

**Champs de la requête**

| Champ | Requis | Description |
|---|---|---|
| `invite_token` | Oui | Le jeton provenant du lien de l'e-mail d'invitation. |

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/team/invites/accept" \
  -H "Authorization: Bearer FIREBASE_ID_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "invite_token": "1f4c…" }'
```

**Réponse**

```json
{
  "success": true,
  "team_member_id": "owner_uid_123_uid_sam",
  "account_owner_uid": "owner_uid_123",
  "message": "Team invite accepted successfully."
}
```

| Statut | Quand |
|---|---|
| `400` | `invite_token` est manquant, ou l'invitation est destinée à votre propre compte. |
| `403` | La session est active dans un autre compte, ou l'invitation a été envoyée à une adresse e-mail différente de celle avec laquelle vous êtes connecté. |
| `404` | L'invitation n'existe pas ou a déjà été utilisée. |
| `429` | Les sièges du compte ont été remplis entre l'invitation et votre acceptation. |
| `504` | L'invitation a expiré. Demandez à l'expéditeur de la renvoyer. |

---

## Refuser une invitation

`POST /team/invites/decline`

Refuse une invitation avec le jeton provenant de l'e-mail. Tout comme pour l'acceptation, il s'agit d'un acte lié à votre propre identité et l'action est refusée si vous travaillez au sein d'un autre compte.

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/team/invites/decline" \
  -H "Authorization: Bearer FIREBASE_ID_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "invite_token": "1f4c…" }'
```

**Réponse**

```json
{
  "success": true,
  "message": "Team invite declined."
}
```

---

## Départements

Un **département** est un groupe nommé au sein de votre équipe — Ventes, Support client, RH. Il permet d'attribuer une équipe responsable à un prospect, de prendre en charge de nouvelles conversations de manière autonome et peut être utilisé pour limiter ce qu'un membre peut voir.

> **Ces quatre points de terminaison nécessitent une clé API.** Contrairement au reste de cette page, ils s'authentifient comme tout autre point de terminaison de l'API (voir [Authentification](authentication.md)). Une session connectée fonctionne également : la lecture nécessite `contacts` sur `view`, et la création, la modification ou la suppression nécessite `team_management` sur `edit`.

**L'objet département**

| Champ | Type | Description |
|---|---|---|
| `id` | string | L'ID du département. Utilisez-le dans `contact_scope_axes.departments` et dans les chemins ci-dessous. |
| `name` | string | Le nom de l'équipe. Jusqu'à 60 caractères, unique sur le compte. |
| `color` | string \| null | Couleur d'accentuation au format `#rrggbb`, ou `null`. |
| `member_uids` | string[] | Les membres de l'équipe dans ce département. Peut inclure le propriétaire du compte. |
| `auto_assign_enabled` | boolean | Indique si un prospect classé dans ce département est également transmis à l'un de ses membres. `false` signifie que le département travaille à partir d'une file d'attente partagée. |
| `routing_agents` | string[] | Les nouvelles conversations gérées par ces agents IA sont automatiquement classées dans ce département. Vide signifie aucune règle d'agent. |
| `routing_channels` | string[] | Les nouvelles conversations sur ces canaux sont automatiquement classées ici. Vide signifie aucune règle de canal. |
| `created_by` | string \| null | Qui l'a créé. |

Lorsque `routing_agents` et `routing_channels` sont tous deux définis, une conversation doit correspondre aux **deux** pour être classée ici — c'est ainsi que vous pouvez attribuer à une équipe "l'agent de support, mais uniquement sur WhatsApp".

Un compte peut avoir jusqu'à **50** départements.

### Lister les départements

`GET /team/departments`

```bash
curl "https://api.youraiconnector.com/v1/team/departments?apiKey=YOUR_API_KEY"
```

**Réponse**

```json
{
  "success": true,
  "departments": [
    {
      "id": "dep_abc123",
      "name": "Sales",
      "color": "#2f6fed",
      "member_uids": ["uid_alice", "uid_bob"],
      "auto_assign_enabled": true,
      "routing_agents": [],
      "routing_channels": ["whatsapp"],
      "created_by": "owner_uid_123"
    }
  ]
}
```

### Créer un département

`POST /team/departments`

**Champs de la requête**

| Champ | Requis | Description |
|---|---|---|
| `name` | Oui | Jusqu'à 60 caractères. Ne doit pas correspondre à un département existant. |
| `color` | Non | Hexadécimal `#rrggbb`, ou `null`. |
| `member_uids` | Non | Qui en fait partie. Chaque UID doit être le propriétaire du compte ou un membre de l'équipe **actif**. |
| `auto_assign_enabled` | Non | Par défaut à `true`. |
| `routing_agents` | Non | ID des agents dont les nouveaux chats arrivent ici. |
| `routing_channels` | Non | Noms des canaux dont les nouveaux chats arrivent ici — même vocabulaire que `contact_scope_axes.channels`. |

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/team/departments?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Sales",
    "color": "#2f6fed",
    "member_uids": ["uid_alice", "uid_bob"],
    "routing_channels": ["whatsapp"]
  }'
```

**JavaScript**

```javascript
const res = await fetch("https://api.youraiconnector.com/v1/team/departments", {
  method: "POST",
  headers: {
    "X-API-Key": "YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    name: "Sales",
    color: "#2f6fed",
    member_uids: ["uid_alice", "uid_bob"],
    routing_channels: ["whatsapp"],
  }),
});
const { department } = await res.json();
```

**Python**

```python
import requests

res = requests.post(
    "https://api.youraiconnector.com/v1/team/departments",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={
        "name": "Sales",
        "color": "#2f6fed",
        "member_uids": ["uid_alice", "uid_bob"],
        "routing_channels": ["whatsapp"],
    },
)
department = res.json()["department"]
```

**Réponse** — `201 Created`

```json
{
  "success": true,
  "department": {
    "id": "dep_abc123",
    "name": "Sales",
    "color": "#2f6fed",
    "member_uids": ["uid_alice", "uid_bob"],
    "auto_assign_enabled": true,
    "routing_agents": [],
    "routing_channels": ["whatsapp"],
    "created_by": "owner_uid_123"
  }
}
```

| Statut | Quand |
|---|---|
| `400` | `name` est manquant ou trop long, `color` n'est pas `#rrggbb`, un nom de canal n'est pas reconnu, un UID listé n'est pas un membre actif de cette équipe, ou vous avez déjà 50 départements. |
| `409` | Un département portant ce nom existe déjà. |

### Mettre à jour un département

`PATCH /team/departments/{departmentId}`

Modifie un département. Seuls les champs que vous envoyez sont modifiés.

```bash
curl -X PATCH "https://api.youraiconnector.com/v1/team/departments/dep_abc123?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "member_uids": ["uid_alice"], "auto_assign_enabled": false }'
```

**Réponse**

```json
{
  "success": true,
  "department": {
    "id": "dep_abc123",
    "name": "Sales",
    "color": "#2f6fed",
    "member_uids": ["uid_alice"],
    "auto_assign_enabled": false,
    "routing_agents": [],
    "routing_channels": ["whatsapp"],
    "created_by": "owner_uid_123"
  }
}
```

L'envoi d'aucun champ reconnu renvoie `400` ; un département inconnu renvoie `404` ; un nom qui entre en conflit avec un autre département renvoie `409`.

### Supprimer un département

`DELETE /team/departments/{departmentId}`

```bash
curl -X DELETE "https://api.youraiconnector.com/v1/team/departments/dep_abc123?apiKey=YOUR_API_KEY"
```

**Réponse**

```json
{
  "success": true,
  "deleted": "dep_abc123"
}
```

> **La suppression d'un département auquel quelqu'un est limité est refusée.** La réponse `400` nomme les membres dont la visibilité est restreinte à celui-ci, afin que vous puissiez d'abord modifier leur périmètre. C'est intentionnel : supprimer silencieusement leur limite leur donnerait accès à toute votre base de clients sans aucune trace de ce qui s'est passé.

Les contacts classés sous un département supprimé ne sont pas réécrits — ils cessent simplement d'afficher un département, et la prochaine fois que vous les classerez, cela sera pris en compte.

---

## Vérifiez vos propres autorisations

`GET /team/permissions`

Renvoie ce que la personne connectée est autorisée à faire dans le compte sur lequel elle travaille actuellement. Utilisez-le pour masquer les boutons qu'un membre ne peut pas utiliser, plutôt que de le laisser découvrir la limite par une erreur.

**cURL**

```bash
curl "https://api.youraiconnector.com/v1/team/permissions" \
  -H "Authorization: Bearer FIREBASE_ID_TOKEN"
```

**Réponse — le propriétaire du compte**

```json
{
  "success": true,
  "role": "owner",
  "is_team_mode": false,
  "permissions": {
    "campaigns": "full",
    "contacts": "full",
    "messages": "full",
    "appointments": "full",
    "settings": "full",
    "billing": "full",
    "team_management": "full",
    "analytics": "full",
    "phone_numbers": "full",
    "integrations": "full",
    "faqs": "full",
    "daily_summaries": "full"
  }
}
```

**Réponse — un membre de l'équipe travaillant dans un compte**

```json
{
  "success": true,
  "role": "editor",
  "is_team_mode": true,
  "permissions": { "campaigns": "edit", "billing": "none", "…": "…" },
  "member": {
    "uid": "uid_sam",
    "email": "sam@example.com",
    "display_name": "Sam Rivera",
    "account_owner_uid": "owner_uid_123"
  }
}
```

`role` est `owner` lorsque la personne connectée est le propriétaire du compte ; sinon, il s'agit de son rôle dans l'équipe. `member` n'est présent qu'en mode équipe, et contient `contact_scope`, `contact_scope_unassigned` et `contact_scope_axes` lorsque son adhésion les inclut.

---

## Jetons de session

Cinq points de terminaison génèrent un jeton de connexion à usage unique pour basculer entre les comptes. Ils répondent tous de la même manière :

```json
{
  "success": true,
  "customToken": "eyJhbGciOi…"
}
```

Le jeton est échangé contre une session avec le SDK client Firebase. **Ce n'est pas une clé API et ne peut pas être envoyé comme telle**, c'est pourquoi ces points de terminaison ne sont utiles qu'au sein d'une application propriétaire.

| Point de terminaison | Ce qu'il fait | Corps |
|---|---|---|
| `POST /team/tokens/team-member` | Permet à un membre de l'équipe de commencer à travailler dans un compte auquel il appartient. | `account_owner_uid` (requis) |
| `POST /team/tokens/return-from-team` | Le ramène à son propre compte. | — |
| `POST /team/tokens/assist` | Permet au personnel <span data-t="appName">Your AI Connector</span> d'ouvrir le compte d'un client pour apporter de l'aide. Personnel uniquement. | `customerUid` |
| `POST /team/tokens/return-to-admin` | Met fin à une session d'assistance et ramène le personnel à son propre compte. | — |
| `POST /team/tokens/agency-assist` | Permet à une agence d'ouvrir l'un de ses sous-comptes clients — ou, appelé sans argument, de revenir au compte de l'agence. | `subAccountUid` (optionnel) |

Chaque requête échoue avec `403` lorsque la session n'y est pas autorisée : non-membre de ce compte, non-membre du personnel, ce sous-compte n'appartient pas à votre agence ou ne vous a pas été accordé, ou la session n'est pas actuellement dans le mode requis par le point de terminaison.

---

## Attribuer un rôle de plateforme

`POST /team/users/{targetUid}/role`

Définit le rôle **plateforme** d'un utilisateur — `User`, `Dev`, `Support` ou `Agency`. Il ne s'agit pas de l'appartenance à une équipe : c'est le type de compte <span data-t="appName">Your AI Connector</span> dont dispose une personne.

Ce point de terminaison est réservé au personnel <span data-t="appName">Your AI Connector</span>, et le dernier `Dev` restant ne peut pas être rétrogradé. Listé par souci d'exhaustivité ; il ne fait pas partie de la gestion de votre propre équipe.

```json
{
  "success": true,
  "targetUid": "uid_sam",
  "role": "Agency",
  "claimUpdated": true
}
```

| Statut | Quand |
|---|---|
| `400` | `role` est manquant ou ne fait pas partie des quatre rôles, ou cela supprimerait le dernier `Dev`. |
| `403` | Vous n'êtes pas membre du personnel, ou la session fonctionne au sein d'un autre compte. |
| `404` | Utilisateur inexistant. |

---

## Erreurs de l'API d'équipe

Les points de terminaison d'équipe renvoient l'enveloppe d'erreur standard, toujours avec `error_code` en plus du statut HTTP :

```json
{
  "success": false,
  "error_code": 403,
  "error": "Cannot grant \"full\" access to \"billing\" — exceeds your own permissions."
}
```

| Statut | Quand cela se produit sur un point de terminaison d'équipe |
|---|---|
| `400` | Un champ requis est manquant ou invalide, ou l'action n'est pas autorisée dans cet état (réactivation d'un membre supprimé, suspension du propriétaire, suppression d'un département auquel quelqu'un est limité). |
| `401` | Vous avez envoyé une clé API à un point de terminaison qui nécessite une personne connectée — voir [Authentification](#authentication-these-endpoints-need-a-signed-in-person). |
| `403` | Vous n'avez pas l'autorisation `team_management`, le changement dépasse votre propre accès, ou l'action est refusée lors d'une opération au sein d'un autre compte. |
| `404` | Membre, invitation, département ou utilisateur inexistant. |
| `409` | Déjà membre de l'équipe, une invitation en attente existe déjà, ou un département portant ce nom existe. |
| `429` | Les places de l'équipe sont pleines, la limite de 20 invitations par jour est atteinte, ou vous avez atteint la limite de débit de l'API. |
| `504` | L'invitation que vous avez essayé d'accepter a expiré. |

Les codes partagés que chaque point de terminaison peut renvoyer — `429` (limite de débit) et `500` — sont listés avec des conseils de nouvelle tentative dans [Erreurs et pagination](errors-and-pagination.md).

---

## Connexe

- [Gestion d'équipe](../settings/team-management.md) — les mêmes fonctionnalités dans le tableau de bord, avec des captures d'écran.
- [Authentification](authentication.md) — comment envoyer un jeton d'identification Firebase au lieu d'une clé API.
- [API Contacts](contacts.md) — les contacts auxquels les limites de visibilité d'un membre s'appliquent.

