
# Ajouter un utilisateur à une organisation

`POST /v1/organizations/{org_id}/memberships` · autorisation `organizations:write`

Ajoute directement un utilisateur existant à l'organisation (source `admin_api`, statut `active`). Sans `role_ids`, le rôle de membre par défaut de l'organisation est attribué ; chaque rôle doit être un rôle de l'environnement ou un rôle de cette organisation. La réponse contient un `ETag` ; l'écriture est journalisée sous `organization_membership.created`. `Idempotency-Key` est facultatif.

## Requête

| Champ | Type | Obligatoire | Description |
|---|---|---|---|
| `org_id` | chemin | oui | Identifiant de l'organisation (`org_…`). |
| `user_id` | string | oui | Identifiant de l'utilisateur (`usr_…`). |
| `role_ids` | string[] | non | Identifiants de rôles (`rol_…`), 50 au maximum. |
| `expires_at` | string | non | Date et heure RFC 3339 future de fin de l'appartenance. |

## Réponse

`201 Created` avec l'appartenance.

```json
{
  "id": "mem_01j9xn5p9s0t4v6w8x0y2z4a6c",
  "organization_id": "org_01j9xk3m7q8r2s4t6v8w0y2z4a",
  "user_id": "usr_01j9xh2k6p7q1r3s5t7v9w1x3y",
  "status": "active",
  "source": "admin_api",
  "reason": null,
  "roles": [
    {
      "role_id": "rol_01j9xr7s1t2w6x8y0z2a4b6c8e",
      "source": "admin_api",
      "assigned_at": "2026-10-12T09:31:00.123456Z"
    }
  ],
  "expires_at": null,
  "created_at": "2026-10-12T09:31:00.123456Z",
  "activated_at": "2026-10-12T09:31:00.123456Z",
  "suspended_at": null,
  "removed_at": null,
  "updated_at": "2026-10-12T09:31:00.123456Z",
  "version": 1
}
```

## Erreurs

| HTTP | code | Quand |
|---|---|---|
| 404 | `not_found` | L'organisation ou l'utilisateur n'existe pas dans cet environnement. |
| 403 | `role_not_assignable` | Un rôle n'est ni un rôle de l'environnement ni un rôle de cette organisation. |
| 403 | `user_not_active` | L'utilisateur n'est pas actif. |
| 409 | `membership_already_exists` | L'utilisateur est déjà membre de l'organisation. |
| 409 | `organization_disabled` | L'organisation est désactivée. |
| 409 | `organization_membership_limit_reached` | La limite de membres de l'organisation est atteinte. |
| 409 | `membership_limit_reached` | La limite d'appartenances de l'utilisateur est atteinte. |
| 422 | `anonymous_user_not_allowed` | L'utilisateur est anonyme. |
| 422 | `validation_failed` | Un champ est absent ou invalide. |
| 401 | `unauthenticated` | L'identifiant est absent, invalide ou révoqué. |
| 403 | `insufficient_permissions` | L'identifiant ne dispose pas de l'autorisation requise. L'attribution d'un rôle privilégié (`is_privileged`) requiert aussi `roles:write` ; sans cette autorisation, rien n'est écrit et `required_permissions` liste les deux autorisations. |
| 429 | `rate_limited` | La limite de débit a été dépassée ; réessayez après la durée indiquée par `Retry-After`. |
| 503 | `service_unavailable` | Une dépendance est temporairement indisponible ; réessayez après la durée indiquée par `Retry-After`. |

## Exemple

```bash
curl -i -X POST "https://api.eu.keenauth.com/v1/organizations/org_01j9xk3m7q8r2s4t6v8w0y2z4a/memberships" \
  -H "Authorization: Bearer $KEENAUTH_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{"user_id":"usr_01j9xh2k6p7q1r3s5t7v9w1x3y","role_ids":["rol_01j9xr7s1t2w6x8y0z2a4b6c8e"]}'
```

## Données personnelles

Cet endpoint traite des données personnelles : appartenances aux organisations et invitations. [Données personnelles dans les API KeenAuth](/docs/policies/personal-data) décrit ce qui est stocké, la durée de conservation et la manière dont elles sont supprimées. N'envoyez de données personnelles sensibles (santé, données biométriques, religion, opinions politiques, orientation sexuelle) dans aucun champ.
