---
title: "L’API Partenaire Talkspirit"
description: "L’API Partenaire est un contrat REST versionné destiné à des partenaires d’intégration nommés. Elle s’authentifie à l’aide d’une clé API qu’un administrateur de votre organisation crée, et elle n’est pas ouverte à une inscription en libre-service."
category: integrations
section: api-and-webhooks
type: Reference
lastUpdated: 2026-09-30
locale: fr
canonical: https://support.talkspirit.com/fr/integrations/partner-api
---

# L’API Partenaire Talkspirit


## L’API Partenaire Talkspirit

Talkspirit expose une API REST sous un préfixe `/v1` pour qu’une intégration puisse lire les membres d’une organisation, sa structure, ses réunions, ses projets, ses objectifs et ses accords de fonctionnement, et écrire à quelques endroits précis, sans que personne n’intervienne dans l’interface Talkspirit. Chaque réponse est en JSON, et la plupart des échecs sont un document de problème RFC 7807 portant un `code` stable et exploitable par une machine. La limitation de débit et les dépassements de délai font exception : leurs corps ont une forme qui leur est propre.

C’est une API **partenaire**, pas une API publique. L’ensemble des ressources est délibérément restreint, l’accès est provisionné par intégration nommée, et il n’existe aucun portail développeur où vous pourriez vous inscrire ou générer vous-même une clé. Pour connecter un service de stockage cloud ou une autre intégration intégrée, aucun travail d’API n’est nécessaire : consultez [Comment ajouter ou supprimer une intégration ?](../integrations/enable-a-cloud-file-picker).

## Ce qui doit être en place pour qu’un appel aboutisse

Deux conditions, toutes deux détenues par l’organisation Talkspirit avec laquelle vous vous intégrez :

1. **Le module API est activé sur cette organisation.** C’est un module optionnel, désactivé par défaut. Sans lui, chaque requête est rejetée avec un `401`, même si la clé est valide. Si le module est désactivé plus tard, les clés déjà émises cessent de fonctionner, après un court délai de propagation.
2. **Vous disposez d’une clé API pour cette organisation.** Un administrateur de l’organisation la crée dans l’Administration, sous Sécurité, sur la page **API**. Le support Talkspirit ne distribue pas de clés, et vous ne pouvez pas en créer depuis le côté partenaire.

Demandez à l’administrateur qui détient l’organisation d’organiser les deux. La procédure figure dans [Gérer les jetons API en tant qu’administrateur](../integrations/manage-api-tokens-as-an-admin).

## Où se trouve la documentation de référence ?

L’API se documente elle-même. Le service publie, sous le même hôte que celui qui sert l’API :

- `/v1/docs`, une référence interactive rendue avec Scalar. Elle lit `/v1/openapi.json`, liste chaque opération avec ses schémas et permet d’envoyer des requêtes de test depuis la page.
- `/v1/openapi.json`, le document OpenAPI exploitable par une machine, pour générer un client.

Les deux sont consultables sans identifiant. `/v1/redoc` était auparavant une page de lecture distincte et répond désormais `301` vers `/v1/docs` : il y a donc une seule page de référence, et non deux.

Le contrat est généré depuis le service en fonctionnement et vérifié en intégration continue : il ne peut donc pas dériver de ce que l’API sert réellement. Considérez-le comme l’autorité : cet article explique la forme, la référence explique chaque champ. Il porte son propre numéro de version, distinct du chemin `/v1` : cet article a été vérifié sur la version **0.65.0**.

## Comment fonctionne l’authentification

Transmettez votre clé comme jeton bearer sur chaque requête :

```http
Authorization: Bearer <votre clé API>
```

La clé est une chaîne opaque commençant par `ts_partner_`. Talkspirit n’en stocke qu’une empreinte : la valeur complète n’est affichée qu’une fois, à la création, et ne peut pas être récupérée ensuite. Une clé perdue est remplacée, jamais retrouvée. Ne la confondez pas avec une clé MCP, qui commence par `tsk_`, que chaque membre crée dans son propre espace de compte, et qui authentifie le point de terminaison MCP distinct plutôt que cette API.

En coulisses, le service vérifie votre clé, puis l’échange contre un jeton de courte durée appartenant à un utilisateur technique dédié à votre intégration. Votre intégration voit donc exactement ce que cet utilisateur technique est autorisé à voir : les cercles, les rôles et les tableaux qui lui ont été donnés dans l’organisation, et, pour une tâche qui n’appartient à aucun projet, seulement les tâches que cet utilisateur peut voir dans le produit. Une portée sur la clé n’élargit jamais cela.

Traitez la clé comme un mot de passe. Gardez-la hors du code source, et demandez à l’administrateur de la révoquer et de la réémettre si elle est exposée. La révocation prend effet immédiatement, avec une fenêtre de tolérance d’environ cinq minutes pour un jeton déjà échangé.

## Ce que l’API expose

Quarante-huit opérations sous `/v1`, plus `GET /healthz`. Neuf d’entre elles écrivent ; toutes les autres lisent.

| Ressource | Points de terminaison en lecture | Portée |
| --- | --- | --- |
| Utilisateurs | `GET /v1/users`, `GET /v1/users/{user_id}`, `GET /v1/users/{user_id}/memberships` | `users:read` |
| Toutes les appartenances de l’organisation | `GET /v1/memberships` | `users:read` |
| Cercles | `GET /v1/circles`, `GET /v1/circles/{circle_id}`, `GET /v1/circles/{circle_id}/members` | `circles:read` |
| Rôles | `GET /v1/roles`, `GET /v1/roles/{role_id}`, `GET /v1/roles/{role_id}/members` | `roles:read` |
| Modèles de rôle | `GET /v1/role-templates`, `GET /v1/role-templates/{role_template_id}` | `roles:read` |
| Définitions de champs personnalisés | `GET /v1/custom-fields` | `roles:read`, `circles:read` ou `users:read`, selon l’`entity_type` demandé |
| Réunions | `GET /v1/meetings`, `GET /v1/meetings/{meeting_id}` | `meetings:read` |
| Projets | `GET /v1/projects`, `GET /v1/projects/{project_id}`, `GET /v1/projects/{project_id}/comments` | `projects:read` |
| Sections | `GET /v1/sections`, `GET /v1/sections/{section_id}` | `projects:read` |
| Libellés | `GET /v1/labels`, `GET /v1/labels/{label_id}` | `projects:read` |
| Tâches | `GET /v1/tasks`, `GET /v1/tasks/{task_id}`, `GET /v1/tasks/{task_id}/comments` | `tasks:read` |
| Objectifs | `GET /v1/goals`, `GET /v1/goals/{goal_id}`, `GET /v1/goals/{goal_id}/key-results`, `GET /v1/goals/{goal_id}/comments` | `goals:read` |
| Périodes | `GET /v1/time-periods`, `GET /v1/time-periods/{time_period_id}` | `goals:read` |
| Accords de fonctionnement | `GET /v1/documents`, `GET /v1/documents/{document_id}`, `GET /v1/documents/{document_id}/content`, `GET /v1/documents/{document_id}/comments` | `documents:read` |
| Tensions | `GET /v1/tensions`, `GET /v1/tensions/{tension_id}` | `tensions:read` |
| Journal d’activité | `GET /v1/audit-logs` | `audit_log:read` |
| Votre propre identité | `GET /v1/whoami` | aucune |

Deux regroupements méritent l’attention, car ils ne suivent pas le nom du chemin : les sections et les libellés se lisent avec `projects:read`, et les périodes avec `goals:read`.

Le texte d’un accord de fonctionnement est une sous-ressource à part entière, `GET /v1/documents/{document_id}/content` : lister les documents ne transporte donc jamais une page de textes complets. Elle sert la version que le compte de la clé voit dans le produit, c’est-à-dire la version publiée, ou le dernier brouillon si rien n’a encore été publié. Un accord de fonctionnement qui existe mais ne contient aucun texte répond `200` avec un texte vide plutôt que `404`.

`GET /v1/memberships` renvoie toutes les appartenances de l’organisation, une page par appel : une synchronisation complète de la structure coûte donc autant d’appels que de pages, et non un appel par membre. Chaque ligne est exactement une ligne de `GET /v1/users/{user_id}/memberships`, avec le `user_id` du membre. Passez `?updated_since=` pour ne recevoir que les appartenances ajoutées ou modifiées depuis un instant donné ; un tel parcours ne peut pas voir une appartenance qui a été supprimée : réconciliez donc de temps en temps avec un parcours complet.

`GET /v1/audit-logs` est le journal d’activité de l’organisation, du plus récent au plus ancien : connexions (réussies et refusées), publications, commentaires, et accès aux groupes et sorties de groupes. Comme il couvre tous les membres, le compte derrière la clé doit être un administrateur de l’organisation, en plus de la portée `audit_log:read` que la clé doit porter. Passez `?occurred_after=` pour ne lire que ce qui s’est passé depuis un instant donné.

Plusieurs listes acceptent aussi des filtres, par exemple les rôles que détient un membre, les cercles dont un membre fait partie, les rôles créés à partir d’un modèle de rôle, ou les tensions mises à l’ordre du jour d’une réunion. La documentation de référence liste tous les filtres qu’accepte un point de terminaison.

### Des champs qui méritent une explication

Plusieurs champs portent plus de sens que leur nom ne le laisse croire.

- **`last_activity_at`, sur un membre.** `GET /v1/users`, `GET /v1/users/{user_id}` et la réponse de `PATCH /v1/users/{user_id}` publient la dernière activité enregistrée du membre. C’est un signal d’activité, pas une connexion : il est enregistré quand un membre authentifié utilise le produit, et rafraîchi environ une fois par heure plutôt qu’à chaque requête. Lisez-le donc comme « actif récemment » et jamais comme un événement d’authentification. Il vaut `null` quand aucune activité n’a jamais été enregistrée, et pour un membre anonymisé. Les appels que vous faites avec votre propre clé enregistrent l’activité de l’utilisateur technique derrière la clé, jamais celle des membres qu’elle lit ou modifie.
- **`assigned_at` et `updated_at`, sur une affectation.** Chaque ligne de `GET /v1/roles/{role_id}/members`, `GET /v1/circles/{circle_id}/members` et `GET /v1/users/{user_id}/memberships`, et chaque ligne de membre renvoyée par `GET /v1/roles` et `GET /v1/roles/{role_id}` avec `?include=members`, porte les deux. `assigned_at` est le moment où l’affectation a commencé : pour une organisation migrée depuis Holaspirit, la date que l’affectation avait là-bas, et non la date de la migration. Les lignes dont la source ne portait pas cette date retombent sur l’instant de leur exécution d’import, ce qui permet de les reconnaître : elles partagent toutes une même valeur. `updated_at` est le moment où la ligne a été écrite pour la dernière fois : son intitulé, ses indicateurs de décideur et d’administrateur, un départ ou un retour. Il ne bouge pas quand une allocation change, ce n’est donc pas un flux des changements d’affectation, et aucun des deux champs n’est un historique d’affectation.
- **`options`, sur une définition de champ personnalisé de membre.** `GET /v1/custom-fields?entity_type=user` publie le catalogue complet des options de chaque champ à sélection simple et à sélection multiple, là où il ne publiait rien : toutes les options configurées, y compris celles qu’aucun membre ne porte encore, sous forme de paires `{value, label}`. `value` est l’identifiant d’option que `PATCH /v1/users/{user_id}/custom-fields` accepte ; `label` est ce à quoi la valeur d’un membre correspond le plus souvent. Faites donc correspondre la valeur d’un membre d’abord sur `label`, puis sur `value` si cela échoue, et attendez-vous à ce que deux options d’un même champ puissent partager un intitulé. Les options arrivent triées par intitulé, jusqu’à 5 000 par champ, et `options_truncated`, sur la même définition, indique si ce plafond a été atteint. Un champ à sélection sans aucune option configurée renvoie une liste vide ; `null` signifie toujours que le type du champ n’a pas de liste d’options. Les valeurs servies par `GET /v1/users?include=custom_fields` sont inchangées.

- **`source_template_id`, sur un rôle.** Le modèle de rôle à partir duquel le rôle a été créé, l’identifiant que renvoie `GET /v1/role-templates`, ou `null` quand le rôle a été créé sans modèle. Un modèle de rôle est une définition de rôle réutilisable, par exemple « Secrétaire ». Une copie invitée d’un rôle vaut `null` : son `source_role_id` mène au rôle qui porte le modèle. Si votre organisation a été migrée depuis Holaspirit, les identifiants de modèle ont changé avec la migration : relisez-les depuis `GET /v1/role-templates`.
- **Les champs personnels d’un membre.** `email`, `phone`, `last_activity_at` et les valeurs des champs personnalisés parviennent à votre clé comme ils parviennent à l’utilisateur technique dans le produit. Un administrateur les lit tous. Un membre les lit tous, sauf un e-mail que son propriétaire a choisi de masquer. Un invité qui ne partage aucun groupe actif avec ce membre n’en lit aucun. Un champ retenu vaut `null`. L’utilisateur technique derrière une clé n’est généralement pas un administrateur : attendez-vous donc à ce que `email` soit `null` pour les membres qui l’ont masqué.
- **`priority`, sur une tension.** Elle peut valoir `NONE`, ce qui signifie que personne n’en a défini, et c’est ce qu’enregistre désormais une tension créée sans priorité. Traitez une valeur que vous ne reconnaissez pas comme une valeur future plutôt que comme une erreur.

**Changer le type d’un champ à sélection déplace ses valeurs d’un emplacement à l’autre.** Un champ qu’un administrateur fait passer de sélection simple à sélection multiple cesse d’être lu dans `value`, une valeur unique, et commence à être lu dans `values`, une liste ; une écriture doit utiliser le même emplacement. Envoyer le mauvais est refusé par un `422 INVALID_CUSTOM_FIELD_VALUE` dont le message nomme l’emplacement à utiliser ; il n’y a jamais de conversion silencieuse.

### Les neuf écritures

| Opération | Portée | Ce qu’il faut savoir |
| --- | --- | --- |
| `POST /v1/tasks` | `tasks:write` | Crée une tâche à chaque appel : ne relancez donc pas la requête à l’aveugle. |
| `POST /v1/tensions` | `tensions:write` | Crée une tension. Une `priority` omise enregistre `NONE`. |
| `PATCH /v1/tensions/{tension_id}` | `tensions:write` | Modifie une tension. |
| `PATCH /v1/tensions/{tension_id}/status` | `tensions:write` | Fait avancer une tension dans ses statuts. |
| `DELETE /v1/tensions/{tension_id}` | `tensions:delete` | **Une suppression définitive, sans retour arrière.** Voir ci-dessous. |
| `PATCH /v1/users/{user_id}` | `users:write` | Modifie un membre. |
| `PATCH /v1/users/{user_id}/custom-fields` | `users:write` | Renseigne les valeurs des champs personnalisés d’un membre. |
| `PATCH /v1/circles/{circle_id}/custom-fields` | `circles:write` | Renseigne les valeurs des champs personnalisés d’un cercle. |
| `PATCH /v1/roles/{role_id}/custom-fields` | `roles:write` | Renseigne les valeurs des champs personnalisés d’un rôle. |

**Supprimer une tension est irréversible.** La tension et ses liens disparaissent, et aucune lecture ne les renvoie ensuite. L’opération est protégée par sa propre portée `tensions:delete`, que `tensions:write` n’accorde délibérément pas : la capacité doit donc être donnée explicitement plutôt qu’héritée. Une tension n’est par ailleurs supprimable que par son créateur : une clé peut supprimer les tensions créées par son propre utilisateur technique, et rien d’autre.

## Les portées

Un administrateur choisit les portées à la création de la clé. Seize sont définies :

- Sans conditionnement : `users:read`, `users:write`, `audit_log:read`
- Module Structure : `roles:read`, `roles:write`, `circles:read`, `circles:write`, `tensions:read`, `tensions:write`, `tensions:delete`, `documents:read`
- Module Objectifs : `goals:read`
- Module Projets : `projects:read`, `tasks:read`, `tasks:write`
- Module Réunions : `meetings:read`

Elles n’apparaissent pas toutes en même temps. Une portée n’est proposée que si le module dont elle lit les données est actif sur l’organisation : `tasks:read` est donc absente si Projets est désactivé, et tout le bloc Structure est absent si Structure est désactivé. Demandez à l’administrateur quels modules l’organisation utilise avant de concevoir votre intégration autour d’une portée.

`audit_log:read` lit le journal d’activité, `GET /v1/audit-logs`. Elle ne suffit pas à elle seule : le compte derrière la clé doit aussi être un administrateur de l’organisation, sinon la route répond `403 FORBIDDEN_UPSTREAM`.

## Votre première requête

`GET /v1/whoami` ne demande aucune portée et fait aussi office de vérification d’identifiant. Elle renvoie le nom du partenaire sous lequel votre clé a été émise, l’organisation à laquelle elle appartient, les portées qu’elle porte, `user_id`, le membre sous lequel agit votre clé, et `created_by_user_id`, l’administrateur qui a créé la clé (`null` pour une clé plus ancienne ou créée par un opérateur Talkspirit). Quand un appel est refusé ou renvoie moins que prévu, `user_id` est le compte à examiner.

```
curl -H "Authorization: Bearer <votre clé API>" \
     https://partner-api.talkspirit.com/v1/whoami
```

Un `200` signifie que la clé elle-même est valide, et vous indique ce qu’elle porte. Il ne prouve pas que l’organisation accepte encore le compte qui se trouve derrière : `whoami` ne vérifie que la clé et n’appelle jamais Talkspirit, elle continue donc de répondre `200` alors que chaque point de terminaison exigeant une portée répond `403`. Tout le reste figure dans le tableau des erreurs ci-dessous.

## Conventions à respecter

- **Versionnement.** Tout se trouve sous `/v1`. Un changement cassant est livré sous un nouveau préfixe au lieu de modifier celui-ci.
- **Pagination.** Les points de terminaison de liste acceptent `?cursor=` et `?limit=`, et répondent avec un tableau `data` et un objet `pagination` portant `next_cursor` et `has_more`. Le `limit` par défaut est de 50 partout. Le maximum est de 199, avec deux exceptions : 100 sur `GET /v1/users` et 50 sur `GET /v1/meetings`. Le curseur est opaque : renvoyez-le tel quel. Il n’existe aucun paramètre `page`, `skip` ou `offset`, sous quelque orthographe que ce soit.
- **Expansion des champs.** Les réponses portent un ensemble minimal de champs. Demandez-en davantage avec `?include=`, une liste séparée par des virgules documentée sur chaque point de terminaison. Un champ que vous n’avez pas demandé est absent de la réponse plutôt que `null` : une liste absente signifie donc « non demandée » et `[]` signifie « demandée, et il n’y en a aucune ».
- **De serveur à serveur uniquement.** Les requêtes cross-origin depuis un navigateur ne sont pas prises en charge.
- **Nouvelles tentatives.** Chaque `GET` peut être relancé sans risque. Les écritures ne sont pas idempotentes : `POST /v1/tasks` et `POST /v1/tensions` créent un enregistrement à chaque appel, dédupliquez donc de votre côté plutôt que de relancer à l’aveugle.

## Ce que signifient les erreurs

| Statut et code | Ce qui s’est passé |
| --- | --- |
| `401 AUTHENTICATION_REQUIRED` | Aucun en-tête `Authorization` sur la requête. |
| `401 AUTHENTICATION_INVALID` | La clé est inconnue ou révoquée, ou l’organisation n’a pas accès à l’API. Le message permet de distinguer les deux. |
| `403 FORBIDDEN_SCOPE` | La clé est valide mais la portée exigée par ce point de terminaison ne lui a pas été accordée. |
| `403 FORBIDDEN_UPSTREAM` | La clé a la portée, mais le compte qui se trouve derrière ne peut pas apporter cette modification à un membre, ou n’est pas administrateur pour le journal d’activité. C’est à un administrateur de l’accorder. |
| `403 FORBIDDEN_SIGN_IN_DISABLED`, `FORBIDDEN_MODULE_DISABLED`, `FORBIDDEN_ACCOUNT_SUSPENDED`, `FORBIDDEN_ACCOUNT_UNKNOWN` ou `FORBIDDEN_ACCESS_DENIED` | La portée est bien là, mais l’organisation refuse le compte qui se trouve derrière la clé : sa méthode de connexion a été désactivée, le module que lit ce point de terminaison est désactivé, le compte est suspendu, il n’existe plus dans l’organisation, ou il n’a pas le droit de voir ce que vous demandez. Aiguillez votre code sur le `code` reçu. |
| `400 INVALID_CURSOR` ou `INVALID_INCLUDE` | Le jeton de pagination est mal formé ou au-delà de son plafond, ou un jeton `include` n’est pas accepté par ce point de terminaison. |
| `409 ACTIVITY_LOG_DISABLED` | L’organisation n’a jamais activé son journal d’activité. C’est un administrateur qui change ce réglage : relancer ne sert à rien. |
| `429 RATE_LIMIT_EXCEEDED` ou `UPSTREAM_RATE_LIMITED` | Trop de requêtes pour cette clé, ou Talkspirit limite lui-même les requêtes derrière l’API. Attendez le nombre de secondes indiqué dans l’en-tête `Retry-After`. |
| `502 UPSTREAM_ERROR` ou `UPSTREAM_AUTH_ERROR` | Un service dont dépend ce point de terminaison est en échec ou a répondu de façon inattendue. Rien n’a changé : relancez avec un délai croissant. |
| `504` | La requête a dépassé la limite de temps du serveur et a été abandonnée. Nul ne sait si une écriture a pris effet : ne la relancez que si la répéter est sans risque. |

Un refus de l’organisation, les cinq codes `403` du tableau, est définitif : ni une nouvelle tentative ni une nouvelle clé ne le lèvent, c’est à un administrateur de l’organisation d’agir. Jusqu’à la version 0.49.0 du contrat, ces refus et la limitation de débit de Talkspirit arrivaient tous deux sous la forme d’un `502`, qui se lit comme un incident passager. Une intégration écrite pour cet ancien comportement relance indéfiniment un refus et ignore `Retry-After` en cas de limitation : vérifiez la vôtre à l’aune du tableau ci-dessus.

Les corps d’erreur n’indiquent jamais si une clé existe ni si c’est la portée qui a échoué : n’essayez donc pas d’en déduire un état.

## Et ensuite ?

- [Gérer les jetons API en tant qu’administrateur](../integrations/manage-api-tokens-as-an-admin)
- [Comment ajouter ou supprimer une intégration ?](../integrations/enable-a-cloud-file-picker)
