Membres
Provisionner l'espace de travail d'un client ne s'arrête pas aux données : son équipe doit pouvoir y entrer. L'API Membres couvre cette étape : vous invitez chaque collaborateur par son adresse e-mail, suivez l'acceptation de son invitation, ajustez son rôle et retirez un accès, sans passage par l'interface Scribee. Chaque membre porte un rôle (member, manager ou owner) et un statut (invited, pending_activation ou activated), lisibles sur chaque réponse.
Ce que fait l'API
- Reconnaît l'adresse e-mail : une adresse inconnue déclenche la création d'un compte et l'envoi d'une invitation ; une adresse déjà connue rattache le compte existant et lui envoie l'e-mail qui correspond à son statut. Un seul appel couvre les deux cas.
- Envoie un lien d'invitation valable 7 jours. Chaque renvoi génère un nouveau lien et invalide le précédent.
- Refuse de rétrograder le dernier
ownerde l'espace de travail, et refuse tout retrait d'un membreowner. - Renvoie le statut de chaque membre dans chaque réponse, sans appel supplémentaire.
Les scopes exigés
Les lectures de cette page exigent read : un token dont les scopes l'omettent reçoit 403 sur la liste comme sur le détail. Les écritures - ajout, changement de rôle, renvoi d'invitation - exigent write, et le retrait accepte destroy ou write. Un token qui ne porte que read reçoit 403 sur ces appels.
Demandez donc read write pour tout ce qui n'est pas une simple lecture : c'est la combinaison courante, et read est vérifié sur chaque lecture (Authentification).
Les rôles
| Rôle | Ce qu'il permet |
|---|---|
member | Utilise l'espace de travail au quotidien, sans gestion de l'équipe. |
manager | Tout ce que permet member, plus la gestion de l'équipe : inviter, changer les rôles, retirer des membres. |
owner | Tout ce que permet manager, plus la gestion des autres propriétaires. Chaque espace de travail en conserve au moins un. |
Par l'API, les trois rôles s'attribuent à la création d'un membre. Ensuite, la modification de rôle n'accepte que member et manager : attribuer owner à un membre existant répond 403, cette promotion se fait depuis l'interface Scribee. Rétrograder un owner existant reste possible par l'API tant qu'il n'est pas le dernier de l'espace de travail (étape 4).
Un membre créé par l'API a toujours accès à l'ensemble de l'espace de travail : aucun paramètre de restriction par entreprise n'est exposé. Cette restriction se configure depuis l'interface Scribee, et l'API liste ces membres comme les autres, avec les mêmes champs.
Conséquence à connaître avant tout retrait : supprimer un membre restreint à certaines entreprises (étape 5) détruit aussi ses accès par entreprise, définitivement. Le réinviter par l'API lui rend l'espace de travail entier. Après un aller-retour de ce type, reconfigurez la restriction depuis l'interface Scribee.
Le statut d'un membre
| Statut | Ce qu'il signifie exactement |
|---|---|
invited | Un jeton d'invitation est actif et n'a pas encore été accepté. |
pending_activation | L'invitation est acceptée ; la création du compte n'est pas terminée. |
activated | Ni invited ni pending_activation. C'est la valeur par défaut. |
activated est calculé par élimination, pas depuis un indicateur d'activité. La désactivation d'un compte par Scribee ne change donc jamais le statut renvoyé : le membre garde celui que l'élimination calcule - un compte déjà activé reste activated, un compte encore invité reste invited - et l'API n'expose aucun champ de désactivation. Si un membre ne parvient pas à se connecter, la désactivation est une cause possible ; elle se vérifie depuis l'interface Scribee.
Un compte déjà actif ajouté à un nouvel espace de travail apparaît directement activated.
Étape 1 : lister les membres
Cet appel est une lecture : exécutez-le tel quel, il ne modifie rien et n'envoie rien vers l'extérieur. Le scope read suffit.
curl https://app.scribee.tech/api/v1/workspaces/YOUR_WORKSPACE_ID/members \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
Réponse 200 :
{
"data": [
{
"id": 12,
"role": "owner",
"joined_at": "2025-11-04T09:12:00+01:00",
"status": "activated",
"user": {
"id": 7,
"email": "direction@client.example",
"first_name": "Marie",
"last_name": "Leroy",
"full_name": "Marie Leroy"
}
},
{
"id": 87,
"role": "member",
"joined_at": "2026-07-31T11:15:00+02:00",
"status": "invited",
"user": {
"id": 231,
"email": "camille.dupont@client.example",
"first_name": "Camille",
"last_name": "Dupont",
"full_name": "Camille Dupont"
}
}
],
"meta": { "current_page": 1, "per_page": 20, "total_pages": 1, "total_count": 2 }
}
Chaque membre porte toujours ces cinq champs - id, role, joined_at, status, user - sur toutes les réponses de cette page. Il n'y a ni filtrage de champs ni paramètre include sur cette ressource.
Le tri par défaut est sort_by=role&sort_order=desc. role est trié comme une chaîne de caractères, pas comme un niveau de privilège : en desc l'ordre obtenu est owner, member, manager ; en asc il est manager, member, owner. À rôle égal, les membres sont classés par date d'ajout croissante. sort_by accepte role, created_at et updated_at ; sort_order accepte asc et desc. Une valeur inconnue de l'un ou l'autre ne provoque pas d'erreur : le tri retombe sur le défaut. La pagination suit les conventions communes (Conventions de l'API).
Un membre seul se lit sur GET /api/v1/members/{id} - notez le chemin sans workspace_id. Cette route cherche l'identifiant dans tous les espaces de travail rattachés à votre application, et la réponse ne contient aucun identifiant d'espace de travail. Si vous en gérez plusieurs, tenez vous-même la correspondance entre l'id d'un membre et son workspace (Votre premier appel, référence API).
Étape 2 : ajouter un membre
Cet appel crée l'accès du membre et envoie un e-mail réel à l'adresse indiquée - il n'y a pas de sandbox. Une adresse inconnue reçoit une invitation à créer son compte Scribee ; une adresse déjà connue ne donne lieu à aucune création de compte, et l'e-mail qu'elle reçoit dépend de son statut. Un compte resté invited, qui n'a donc jamais accepté son invitation, reçoit l'e-mail d'invitation et son lien d'activation : son lien précédent reste valable tant qu'il n'a pas expiré, sinon un nouveau lien de 7 jours est émis. Un compte pending_activation ou activated reçoit la notification de son nouvel accès. Pour une répétition, invitez une adresse que vous contrôlez, puis retirez le membre (étape 5) : le retrait supprime l'accès, pas l'e-mail déjà parti. Le scope read write est requis.
Si l'adresse invitée appartient à un domaine couvert par une configuration SAML active de l'espace de travail, le membre est ajouté directement et aucun e-mail n'est envoyé : il se connecte avec son identité d'entreprise habituelle. Ce parcours dépend du domaine de l'adresse invitée, pas de l'espace de travail dans son ensemble.
curl -X POST https://app.scribee.tech/api/v1/workspaces/YOUR_WORKSPACE_ID/members \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"member": {
"email": "camille.dupont@client.example",
"first_name": "Camille",
"last_name": "Dupont",
"role": "member"
}
}'
Réponse 201 :
{
"data": {
"id": 87,
"role": "member",
"joined_at": "2026-07-31T11:15:00+02:00",
"status": "invited",
"user": {
"id": 231,
"email": "camille.dupont@client.example",
"first_name": "Camille",
"last_name": "Dupont",
"full_name": "Camille Dupont"
}
}
}
L'objet member est obligatoire : une requête qui ne le contient pas répond 400, avec l'enveloppe JSON habituelle dont la clé error vaut bad_request. email est obligatoire. role est optionnel et vaut member à défaut ; il accepte member, manager et owner à la création.
first_name et last_name sont optionnels et ne sont pris en compte que pour une adresse inconnue. Sur une adresse déjà connue de Scribee, l'identité du compte existant l'emporte : les valeurs que vous envoyez sont ignorées et la réponse 201 renvoie les noms stockés. Aucun endpoint de l'API ne modifie le nom ni l'adresse e-mail d'un utilisateur.
Un compte désactivé est refusé
Inviter une adresse dont le compte Scribee a été désactivé répond 422, sur le parcours SAML comme sur le parcours ordinaire : aucun accès n'est créé et aucun e-mail n'est envoyé (voir Erreurs). La désactivation bloquant l'authentification, l'accès aurait de toute façon été inutilisable.
Faites réactiver le compte depuis l'interface Scribee, puis rejouez l'appel. Ce contrôle ne porte que sur l'ajout : un compte désactivé après coup reste membre, et la désactivation ne change pas le statut que l'API renvoie pour lui (voir Le statut d'un membre).
Étape 3 : renvoyer une invitation
Cet appel envoie un nouvel e-mail d'invitation réel au membre. Il s'applique aux statuts invited et pending_activation ; un membre activated répond 422 (voir Erreurs). Un nouveau lien valable 7 jours est généré et le lien précédent cesse de fonctionner. Le scope read write est requis.
Sur un membre pending_activation, le renvoi réinitialise l'invitation : l'acceptation est effacée et la réponse renvoie le statut invited. Le membre reprend tout le parcours depuis le nouveau lien - choix d'un mot de passe, puis activation du compte, qui exige l'authentification à deux facteurs - et un mot de passe qu'il avait déjà choisi ne lui donne plus accès à Scribee.
curl -X POST https://app.scribee.tech/api/v1/members/87/resend_invitation \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
Réponse 200, abrégée aux trois champs utiles ici ; le corps réel porte les cinq champs de l'étape 1 :
{
"data": {
"id": 87,
"role": "member",
"status": "invited"
}
}
Étape 4 : changer le rôle d'un membre
Cet appel modifie le rôle du membre, avec effet immédiat sur ses droits dans l'espace de travail. Il n'envoie aucun e-mail. Le scope read write est requis.
PATCH n'est pas une mise à jour partielle : member.role est obligatoire. L'omettre ne laisse pas le rôle inchangé, cela répond 422.
curl -X PATCH https://app.scribee.tech/api/v1/members/87 \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "member": { "role": "manager" } }'
Réponse 200 :
{
"data": {
"id": 87,
"role": "manager",
"joined_at": "2026-07-31T11:15:00+02:00",
"status": "invited",
"user": {
"id": 231,
"email": "camille.dupont@client.example",
"first_name": "Camille",
"last_name": "Dupont",
"full_name": "Camille Dupont"
}
}
}
role accepte member et manager. Attribuer owner à un membre existant répond 403 : le rôle de propriétaire s'attribue à la création (étape 2) ou depuis l'interface Scribee. Rétrograder un propriétaire fonctionne tant que l'espace de travail en conserve un autre ; rétrograder le dernier répond 422 (voir Erreurs). Toutes les erreurs de validation de cet appel arrivent sous details.base, jamais sous details.role. Référence : modifier le rôle d'un membre.
Étape 5 : retirer un membre
Cet appel retire immédiatement l'accès du membre à l'espace de travail. Le compte utilisateur n'est pas supprimé : réinviter la même adresse (étape 2) recrée un accès avec le compte existant. Le scope write ou destroy est requis (voir Les scopes exigés).
Un membre owner ne se retire pas par l'API : la réponse est 403, quel que soit le nombre de propriétaires de l'espace de travail. Si le membre était restreint à certaines entreprises, le retrait détruit aussi ces accès par entreprise (voir Les rôles).
curl -X DELETE https://app.scribee.tech/api/v1/members/87 \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
Réponse 204, sans corps. Référence : retirer un membre.
Ce qui se passe ensuite
- Le membre invité reçoit l'e-mail, accepte l'invitation (
pending_activation), puis termine la création de son compte (activated). Suivez la progression avec leGETde l'étape 1. - La gestion des membres ne touche que l'accès à l'espace de travail : rien ne part vers le PPF (Portail Public de Facturation) ni vers le réseau Peppol, et les données de facturation ne sont pas modifiées.
- Passé 7 jours sans acceptation, le lien d'invitation expire ; le membre reste
invitedet l'étape 3 génère un nouveau lien.
Erreurs et cas limites
422 : details.email porte toute erreur d'ajout
Sur POST, details.email réunit tous les messages du refus, quel que soit le champ réellement en cause. Une adresse déjà membre de l'espace de travail :
{
"error": "unprocessable_entity",
"code": "validation_failed",
"message": "La validation a échoué",
"details": {
"email": ["L'utilisateur est déjà membre de cet espace de travail"]
}
}
Quand le refus vient de la validation d'un champ, ce champ apparaît en plus sous sa propre clé. Un role invalide :
{
"error": "unprocessable_entity",
"code": "validation_failed",
"message": "La validation a échoué",
"details": {
"email": ["Role n'est pas inclus(e) dans la liste"],
"role": ["n'est pas inclus(e) dans la liste"]
}
}
Les refus qui ne visent aucun champ - adresse déjà membre, compte désactivé - n'apparaissent que sous email. Traitez donc details.email comme la liste complète des messages, et les autres clés, quand elles sont présentes, comme le champ en cause : sur cet endpoint l'absence d'une clé de champ ne signifie pas que ce champ est valide. C'est une exception partielle à la règle décrite dans Conventions de l'API, qui associe chaque champ fautif à ses erreurs.
Sur une adresse déjà membre, retrouvez le membre existant avec le GET de l'étape 1 ; s'il n'a pas accepté son invitation, renvoyez-la (étape 3).
422 : le compte de l'invité est désactivé
L'ajout d'une adresse dont le compte Scribee a été désactivé (voir étape 2) :
{
"error": "unprocessable_entity",
"code": "validation_failed",
"message": "La validation a échoué",
"details": {
"email": ["Cet utilisateur est désactivé. Réactivez le compte avant de lui accorder l'accès."]
}
}
Rien n'est créé et aucun e-mail ne part. Faites réactiver le compte depuis l'interface Scribee, puis rejouez le même appel.
422 : le compte est déjà activé
Le renvoi d'invitation sur un membre activated :
{
"error": "unprocessable_entity",
"code": "operation_failed",
"message": "L'utilisateur a déjà activé son compte"
}
Cette réponse ne porte pas de details, et ce message unique couvre tous les refus de l'étape 3. Il n'y a rien à renvoyer : le membre a terminé la création de son compte.
422 : role manquant ou invalide sur le changement de rôle
Sur PATCH, les erreurs sont regroupées sous details.base. Un role invalide :
{
"error": "unprocessable_entity",
"code": "validation_failed",
"message": "La validation a échoué",
"details": {
"base": ["Role n'est pas inclus(e) dans la liste"]
}
}
Omettre member.role produit la même forme, avec un message supplémentaire signalant le champ vide.
422 : dernier propriétaire
Rétrograder le seul owner de l'espace de travail :
{
"error": "unprocessable_entity",
"code": "validation_failed",
"message": "La validation a échoué",
"details": {
"base": ["Role Impossible de changer le rôle : le tenant doit avoir au moins un propriétaire"]
}
}
Dans ce message, tenant désigne l'espace de travail. Nommez d'abord un autre propriétaire depuis l'interface Scribee, puis rejouez l'appel. Basez vos traitements sur le statut HTTP et les clés error et code, jamais sur le texte du message (Conventions de l'API).
403 : le rôle owner est protégé
Attribuer owner à un membre existant (étape 4) ou retirer un membre owner (étape 5) répond 403, y compris avec les bons scopes. Ces opérations se font depuis l'interface Scribee.
Ces deux 403 portent l'enveloppe habituelle des refus, avec la clé error à forbidden, mais leur message est propre à chaque refus : celui de l'étape 4 explique que le rôle owner ne s'attribue pas à un membre existant et rappelle que la rétrogradation d'un propriétaire reste possible, celui de l'étape 5 explique qu'un membre owner ne se retire pas par l'API. Les deux textes diffèrent l'un de l'autre et du message générique des autres 403 de cette page ; comme ailleurs, basez vos traitements sur le statut HTTP et la clé error, jamais sur le texte du message.
403 : scope insuffisant
Une écriture (ajout, changement de rôle, renvoi d'invitation) avec un token sans write, ou un retrait avec un token sans destroy ni write (voir Les scopes exigés) :
{
"error": "forbidden",
"message": "Vous n'êtes pas autorisé à effectuer cette action"
}
Redemandez un token avec les scopes voulus (Authentification).
403 : espace de travail ou adresse IP refusés
Sur les deux routes imbriquées de cette page - GET et POST /api/v1/workspaces/{workspace_id}/members - l'espace de travail est résolu avant l'action, et deux refus renvoient 403. L'espace de travail n'est pas rattaché à votre application :
{
"error": "forbidden",
"message": "L'application n'a pas accès à cet espace de travail"
}
L'espace de travail a une liste d'IP autorisées qui ne couvre pas votre adresse source :
{
"error": "forbidden",
"message": "Cette adresse IP n'est pas autorisée pour cet espace de travail"
}
Un workspace_id qui ne correspond à aucun espace de travail reçoit le premier refus ci-dessus, mot pour mot : rien ne distingue un espace de travail inexistant d'un espace de travail que votre application n'a pas le droit d'atteindre, si bien que la réponse ne vous dit jamais si l'espace de travail existe. Les accès workspace et IP sont configurés par Scribee : adressez-vous à votre contact.
404 Not Found
Sur les quatre routes plates - GET, PATCH, DELETE /api/v1/members/{id} et POST /api/v1/members/{id}/resend_invitation - le membre est cherché uniquement dans les espaces de travail rattachés à votre application dont la liste d'IP autorise votre adresse source. Tout ce qui sort de ce périmètre est indistinctement introuvable :
{
"error": "not_found",
"message": "La ressource demandée est introuvable"
}
Une adresse IP hors liste produit donc 404 ici, là où les routes imbriquées produisent 403. Si un identifiant connu répond soudain 404, vérifiez votre adresse IP source avant l'identifiant (Votre premier appel).
Pages liées
- Votre premier appel - identifier vos workspaces et leurs identifiants
- Catégories - l'autre ressource de configuration de l'espace de travail
- Référence API : lister les membres
- Référence API : ajouter un membre
- Référence API : renvoyer une invitation