Français
Membres et invitations
Les routes sont relatives à <PUBLIC_BASE_URL> ; les corps de requête et de réponse sont en JSON sauf mention contraire. L’authentification, les portées, la pagination et le format des erreurs sont décrits dans les guides de l’API REST.
GET /api/v1/admin/members
Lister les membres
Tous les membres de l’instance, avec statut, rôle et compteurs.
Accès — Session de membre ou clé d’API portant admin:read (rôle administrateur requis).
Réponses
200 — Les membres.
| Champ | Type | Requis |
|---|---|---|
members | object[] | oui |
Schéma JSON
json
{
"type": "object",
"properties": {
"members": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
"email": { "type": "string" },
"name": { "type": "string" },
"role": { "type": "string", "enum": [ "member", "admin" ] },
"status": { "type": "string", "enum": [ "active", "suspended" ] },
"mailboxCount": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 },
"publishedWorkflowCount": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 },
"createdAt": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
}
},
"required": [
"id",
"email",
"name",
"role",
"status",
"mailboxCount",
"publishedWorkflowCount",
"createdAt"
],
"additionalProperties": false
}
}
},
"required": [ "members" ],
"additionalProperties": false
}401 — Aucune session ni clé d’API valide (auth.unauthenticated).
403 — Refusé : rôle insuffisant (auth.forbidden), portée manquante (api_key.scope_missing, details.required la nomme) ou route fermée aux clés (api_key.session_required).
429 — La clé d’API dépasse son débit (api_key.rate_limited) ; Retry-After dit quand réessayer.
PATCH /api/v1/admin/members/{id}
Changer le rôle d’un membre
L’instance garde au moins un administrateur actif : rétrograder le dernier est refusé. Journalisé dans l’audit.
Accès — Session de membre ou clé d’API portant admin:write (rôle administrateur requis).
Paramètres
| Nom | Où | Type | Requis |
|---|---|---|---|
id | chemin | string | oui |
Corps de la requête (application/json)
| Champ | Type | Requis |
|---|---|---|
role | "member" | "admin" | oui |
Schéma JSON
json
{
"type": "object",
"properties": { "role": { "type": "string", "enum": [ "member", "admin" ] } },
"required": [ "role" ]
}Réponses
200 — Le membre.
| Champ | Type | Requis |
|---|---|---|
member | object | oui |
Schéma JSON
json
{
"type": "object",
"properties": {
"member": {
"type": "object",
"properties": {
"id": {
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
"email": { "type": "string" },
"name": { "type": "string" },
"role": { "type": "string", "enum": [ "member", "admin" ] },
"status": { "type": "string", "enum": [ "active", "suspended" ] },
"mailboxCount": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 },
"publishedWorkflowCount": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 },
"createdAt": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
}
},
"required": [
"id",
"email",
"name",
"role",
"status",
"mailboxCount",
"publishedWorkflowCount",
"createdAt"
],
"additionalProperties": false
}
},
"required": [ "member" ],
"additionalProperties": false
}400 — La requête ne respecte pas son schéma.
401 — Aucune session ni clé d’API valide (auth.unauthenticated).
403 — Refusé : rôle insuffisant (auth.forbidden), portée manquante (api_key.scope_missing, details.required la nomme) ou route fermée aux clés (api_key.session_required).
429 — La clé d’API dépasse son débit (api_key.rate_limited) ; Retry-After dit quand réessayer.
Codes d’erreur — request.bad_request, governance.not_found, governance.last_admin. Les codes communs (request.bad_request, auth.unauthenticated, api_key.scope_missing, api_key.rate_limited…) s’appliquent à toutes les routes ; voir Erreurs.
POST /api/v1/admin/members/{id}/deactivate
Désactiver un membre
Révoque les sessions, déconnecte les boîtes et dépublie les workflows ; la réponse dit ce qui a réellement été coupé. Un administrateur ne se désactive pas lui-même ni le dernier administrateur actif.
Accès — Session de membre ou clé d’API portant admin:write (rôle administrateur requis).
Paramètres
| Nom | Où | Type | Requis |
|---|---|---|---|
id | chemin | string | oui |
Réponses
200 — Le membre et les effets.
| Champ | Type | Requis |
|---|---|---|
member | object | oui |
effects | object | oui |
Schéma JSON
json
{
"type": "object",
"properties": {
"member": {
"type": "object",
"properties": {
"id": {
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
"email": { "type": "string" },
"name": { "type": "string" },
"role": { "type": "string", "enum": [ "member", "admin" ] },
"status": { "type": "string", "enum": [ "active", "suspended" ] },
"mailboxCount": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 },
"publishedWorkflowCount": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 },
"createdAt": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
}
},
"required": [
"id",
"email",
"name",
"role",
"status",
"mailboxCount",
"publishedWorkflowCount",
"createdAt"
],
"additionalProperties": false
},
"effects": {
"type": "object",
"properties": {
"sessionsRevoked": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 },
"mailboxesPaused": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 },
"workflowsUnpublished": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }
},
"required": [ "sessionsRevoked", "mailboxesPaused", "workflowsUnpublished" ],
"additionalProperties": false
}
},
"required": [ "member", "effects" ],
"additionalProperties": false
}401 — Aucune session ni clé d’API valide (auth.unauthenticated).
403 — Refusé : rôle insuffisant (auth.forbidden), portée manquante (api_key.scope_missing, details.required la nomme) ou route fermée aux clés (api_key.session_required).
429 — La clé d’API dépasse son débit (api_key.rate_limited) ; Retry-After dit quand réessayer.
Codes d’erreur — governance.not_found, governance.self_target, governance.last_admin. Les codes communs (request.bad_request, auth.unauthenticated, api_key.scope_missing, api_key.rate_limited…) s’appliquent à toutes les routes ; voir Erreurs.
POST /api/v1/admin/members/{id}/reactivate
Réactiver un membre
Le compte redevient utilisable, et rien d’autre : les boîtes restent déconnectées et les workflows dépubliés.
Accès — Session de membre ou clé d’API portant admin:write (rôle administrateur requis).
Paramètres
| Nom | Où | Type | Requis |
|---|---|---|---|
id | chemin | string | oui |
Réponses
200 — Le membre.
| Champ | Type | Requis |
|---|---|---|
member | object | oui |
Même schéma que PATCH /api/v1/admin/members/{id}.
401 — Aucune session ni clé d’API valide (auth.unauthenticated).
403 — Refusé : rôle insuffisant (auth.forbidden), portée manquante (api_key.scope_missing, details.required la nomme) ou route fermée aux clés (api_key.session_required).
429 — La clé d’API dépasse son débit (api_key.rate_limited) ; Retry-After dit quand réessayer.
Codes d’erreur — governance.not_found. Les codes communs (request.bad_request, auth.unauthenticated, api_key.scope_missing, api_key.rate_limited…) s’appliquent à toutes les routes ; voir Erreurs.
GET /api/v1/admin/members/invitations
Lister les invitations en attente
Accès — Session de membre ou clé d’API portant admin:read (rôle administrateur requis).
Réponses
200 — Les invitations.
| Champ | Type | Requis |
|---|---|---|
invitations | object[] | oui |
Schéma JSON
json
{
"type": "object",
"properties": {
"invitations": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
"email": { "type": "string" },
"role": { "type": "string", "enum": [ "member", "admin" ] },
"expiresAt": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
},
"createdAt": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
},
"invitedBy": {
"anyOf": [
{
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
{ "type": "null" }
]
},
"expired": { "type": "boolean" }
},
"required": [
"id",
"email",
"role",
"expiresAt",
"createdAt",
"invitedBy",
"expired"
],
"additionalProperties": false
}
}
},
"required": [ "invitations" ],
"additionalProperties": false
}401 — Aucune session ni clé d’API valide (auth.unauthenticated).
403 — Refusé : rôle insuffisant (auth.forbidden), portée manquante (api_key.scope_missing, details.required la nomme) ou route fermée aux clés (api_key.session_required).
429 — La clé d’API dépasse son débit (api_key.rate_limited) ; Retry-After dit quand réessayer.
POST /api/v1/admin/members/invitations
Inviter un membre
Crée l’invitation et rend le lien d’acceptation : le seul endroit où un jeton en clair sort de l’instance. L’invitation n’est pas envoyée par email ; l’administrateur transmet le lien. Refusée si un membre ou une invitation en attente existe déjà pour l’adresse.
Accès — Session de membre ou clé d’API portant admin:write (rôle administrateur requis).
Corps de la requête (application/json)
| Champ | Type | Requis |
|---|---|---|
email | string | oui |
role | "member" | "admin" | non |
Schéma JSON
json
{
"type": "object",
"properties": {
"email": { "type": "string" },
"role": { "default": "member", "type": "string", "enum": [ "member", "admin" ] }
},
"required": [ "email" ]
}Réponses
201 — L’invitation et son lien.
| Champ | Type | Requis |
|---|---|---|
invitation | object | oui |
acceptUrl | string (uri) | oui |
token | string | oui |
Schéma JSON
json
{
"type": "object",
"properties": {
"invitation": {
"type": "object",
"properties": {
"id": {
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
"email": { "type": "string" },
"role": { "type": "string", "enum": [ "member", "admin" ] },
"expiresAt": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
},
"createdAt": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
},
"invitedBy": {
"anyOf": [
{
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
{ "type": "null" }
]
},
"expired": { "type": "boolean" }
},
"required": [
"id",
"email",
"role",
"expiresAt",
"createdAt",
"invitedBy",
"expired"
],
"additionalProperties": false
},
"acceptUrl": { "type": "string", "format": "uri" },
"token": { "type": "string", "minLength": 1 }
},
"required": [ "invitation", "acceptUrl", "token" ],
"additionalProperties": false
}400 — La requête ne respecte pas son schéma.
401 — Aucune session ni clé d’API valide (auth.unauthenticated).
403 — Refusé : rôle insuffisant (auth.forbidden), portée manquante (api_key.scope_missing, details.required la nomme) ou route fermée aux clés (api_key.session_required).
429 — La clé d’API dépasse son débit (api_key.rate_limited) ; Retry-After dit quand réessayer.
Cette opération accepte un en-tête Idempotency-Key : rejouer la même requête avec la même clé rend la réponse d’origine au lieu d’agir deux fois. Voir Idempotence.
Codes d’erreur — request.bad_request, governance.member_exists, governance.invitation_exists. Les codes communs (request.bad_request, auth.unauthenticated, api_key.scope_missing, api_key.rate_limited…) s’appliquent à toutes les routes ; voir Erreurs.
Exemple de requête
json
{ "email": "bob@example.test", "role": "member" }Exemple de réponse (201)
json
{
"invitation": {
"id": "0192f1c2-3b4d-7e8f-9a0b-1c2d3e4f5a6b",
"email": "bob@example.test",
"role": "member",
"invitedBy": "0192f1c2-0000-7000-8000-000000000001",
"createdAt": "2026-10-04T09:00:00.000Z",
"expiresAt": "2026-10-11T09:00:00.000Z",
"status": "pending"
},
"acceptUrl": "https://mail.example.test/invite/Qm9uam91cl9jZXN0X3VuX2V4ZW1wbGU",
"token": "Qm9uam91cl9jZXN0X3VuX2V4ZW1wbGU"
}DELETE /api/v1/admin/members/invitations/{id}
Révoquer une invitation
Une invitation déjà consommée ou inconnue est un 404 et ne laisse aucune trace ; une révocation est journalisée dans l’audit.
Accès — Session de membre ou clé d’API portant admin:write (rôle administrateur requis).
Paramètres
| Nom | Où | Type | Requis |
|---|---|---|---|
id | chemin | string | oui |
Réponses
204 — Révoquée.
401 — Aucune session ni clé d’API valide (auth.unauthenticated).
403 — Refusé : rôle insuffisant (auth.forbidden), portée manquante (api_key.scope_missing, details.required la nomme) ou route fermée aux clés (api_key.session_required).
429 — La clé d’API dépasse son débit (api_key.rate_limited) ; Retry-After dit quand réessayer.
Codes d’erreur — governance.not_found. Les codes communs (request.bad_request, auth.unauthenticated, api_key.scope_missing, api_key.rate_limited…) s’appliquent à toutes les routes ; voir Erreurs.