
# Créer ou remplacer une politique d'organisation

`PUT /v1/organizations/{org_id}/policies/{policy_kind}` · autorisation `organizations:write`

Remplace l'ensemble de l'objet de paramètres d'un type de politique. Une politique d'organisation ne peut être que plus stricte que le paramètre de l'environnement. La restriction liée au forfait est appliquée par le serveur : les types `session` et `ip_allowlist`, ainsi que la liste d'autorisation des AAGUID, nécessitent Enterprise (accessible dans les environnements de développement). Le contenu des paramètres est écrit dans le journal d'audit de gestion ; l'événement `organization.updated` ne le contient pas.

## Requête

| Champ | Type | Obligatoire | Description |
|---|---|---|---|
| `org_id` | path | oui | Identifiant de l'organisation (`org_…`). |
| `policy_kind` | path | oui | Type de politique : `authentication_methods`, `mfa`, `phishing_resistant`, `sso_enforcement`, `session` ou `ip_allowlist`. Toute autre valeur renvoie `404`. |
| `If-Match` | header | non | Obligatoire lorsque la politique existe (`ETag` de la dernière lecture) ; à omettre pour créer la politique. `*` correspond à une politique existante. |
| `settings` | object | oui | L'objet de paramètres du type. Champs par type : `authentication_methods` : `allowed_connection_ids` (`conn_…`), `allow_passkey`, `allow_password` ; `mfa` : `required_for` (`none`, `admins`, `all`), `allowed_factors` (`totp`, `webauthn`, `sms`, `email`), `enrollment_grace_days` (0-30) ; `phishing_resistant` : `required_for`, `aaguid_allowlist` (500 maximum) ; `sso_enforcement` : `mode` (`off`, `org_context`, `verified_domains`), `connection_ids` (`conn_…`), `bypass_user_ids` (`usr_…`, 2 maximum) ; `session` : `idle_minutes`, `absolute_minutes`, `refresh_idle_days`, `refresh_absolute_days` ; `ip_allowlist` : `cidrs` (100 maximum), `applies_to` (`admins`, `all`). |

Corps de la requête :

```json
{
  "settings": {
    "required_for": "all",
    "allowed_factors": [
      "totp",
      "webauthn"
    ],
    "enrollment_grace_days": 7
  }
}
```

## Réponse

`201 Created` lorsque la politique a été créée, `200 OK` lorsqu'elle a été remplacée ; le corps contient la politique et la réponse porte son nouvel `ETag`.

```json
{
  "organization_id": "org_01j9xk3m7q8r2s4t6v8w0y2z4a",
  "policy_kind": "mfa",
  "schema_version": 1,
  "settings": {
    "required_for": "all",
    "allowed_factors": [
      "totp",
      "webauthn"
    ],
    "enrollment_grace_days": 7
  },
  "updated_at": "2026-10-12T09:30:00.123456Z",
  "version": 1
}
```

## Erreurs

| HTTP | code | Cas |
|---|---|---|
| 400 | `unknown_field` | Le corps contient un champ absent du schéma ou en lecture seule. |
| 403 | `plan_feature_unavailable` | Le type ou la liste d'autorisation des AAGUID nécessite un forfait supérieur ; le problème contient `feature` et `required_plan`. |
| 404 | `not_found` | L'organisation n'existe pas ou le type est inconnu. |
| 409 | `domain_not_verified` | `sso_enforcement` avec `mode` `verified_domains` nécessite un domaine vérifié sur l'organisation. |
| 409 | `connection_test_required` | Activer `sso_enforcement` (depuis `off` ou en l'absence de politique) nécessite une connexion de test réussie avec la configuration actuelle d'au moins une des `connection_ids`, au cours des 24 dernières heures. Lancez un test de connexion (`POST /v1/connections/{connection_id}:test`) puis réessayez. |
| 409 | `organization_pending_deletion` | L'organisation attend une suppression en libre-service ; annulez d'abord la suppression. |
| 412 | `precondition_failed` | `If-Match` ne correspond pas à la version actuelle, a été envoyé alors qu'aucune politique de ce type n'existe, ou une autre requête a créé la politique pendant que celle-ci était en cours de création ; relisez la politique. |
| 422 | `validation_failed` | Un champ de paramètres est inconnu ou invalide ; `errors[]` pointe vers `/settings/…`. |
| 422 | `policy_weaker_than_parent` | Le paramètre est moins strict que celui de l'environnement ; `errors[]` pointe vers le champ concerné. |
| 422 | `at_least_one_method` | `authentication_methods` ne laisse aucune méthode de connexion. |
| 428 | `precondition_required` | `If-Match` est absent alors que la politique existe. |
| 401 | `unauthenticated` | L'identifiant est absent, invalide ou révoqué. |
| 403 | `insufficient_permissions` | L'identifiant ne dispose pas de l'autorisation requise. |
| 429 | `rate_limited` | La limite de débit a été dépassée ; réessayez après le délai indiqué par `Retry-After`. |
| 503 | `service_unavailable` | Une dépendance est temporairement indisponible ; réessayez après le délai indiqué par `Retry-After`. |

## Exemple

```bash
curl -X PUT https://api.eu.keenauth.com/v1/organizations/org_01j9xk3m7q8r2s4t6v8w0y2z4a/policies/mfa \
  -H "Authorization: Bearer $KEENAUTH_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{"settings":{"required_for":"all","allowed_factors":["totp","webauthn"]}}'
```
