
# Remplacer les correspondances d'attributs d'une connexion

`PUT /v1/connections/{connection_id}/attribute-mappings` · autorisation `connections:write`

Remplace la liste complète des correspondances d'attributs d'une connexion d'entreprise. L'ordre des règles n'a pas d'importance ; la réponse est classée par cible. `If-Match` est obligatoire : sans lui, la requête échoue avec `428` ; si la liste a changé depuis votre lecture (ou si la valeur ne correspond pas), la requête échoue avec `412` et rien n'est écrit. Envoyer la même liste n'écrit rien. La modification s'applique dès la connexion suivante et n'invalide pas le dernier test de connexion réussi. L'écriture est auditée sous `connection.attribute_mappings_replaced` (cibles ajoutées, supprimées et modifiées) ; les valeurs d'attributs issues des connexions ne sont jamais écrites dans le journal d'audit.

## Requête

| Champ | Type | Obligatoire | Description |
|---|---|---|---|
| `connection_id` | chemin | oui | ID de la connexion d'entreprise (`conn_…`). |
| `If-Match` | en-tête | oui | L'`ETag` de la dernière lecture. Absent : `428` ; périmé : `412`. |
| `attribute_mappings` | tableau | oui | La nouvelle liste complète, 28 règles au maximum. |
| `attribute_mappings[].target` | chaîne | oui | `email` (obligatoire dans toute liste), `given_name`, `family_name`, `name`, `locale`, `zoneinfo`, `phone`, `groups` ou `user_metadata.<key>` (clé `[a-z0-9_]{1,40}` ; les noms de revendications OIDC enregistrés et le préfixe `idp_` sont interdits ; 20 clés au maximum). Une règle par cible. Une correspondance ne peut pas écrire `app_metadata`. |
| `attribute_mappings[].source_name` | chaîne | oui | 1 à 512 octets, sans caractère de contrôle ni caractère bidirectionnel, sans espace en début ou en fin. |
| `attribute_mappings[].source_name_format` | chaîne \| null | non | `NameFormat` SAML (URI absolue). Un même nom source ne peut être lu qu'avec un seul format. |
| `attribute_mappings[].overwrite` | chaîne | oui | `always`, `if_empty` ou `never`. |
| `attribute_mappings[].profile` | chaîne | non | Nom du profil prédéfini ; `generic` si omis. |

## Réponse

`200 OK` avec la liste enregistrée (voir [Obtenir les correspondances d'attributs](get.md)) et le nouvel `ETag`.

## Erreurs

| HTTP | code | Cas |
|---|---|---|
| 404 | `not_found` | La connexion n'existe pas dans cet environnement ou n'est pas une connexion d'entreprise. |
| 409 | `conflict` | Le protocole de la connexion n'a pas de correspondances d'attributs (LDAP). |
| 412 | `precondition_failed` | `If-Match` ne correspond pas à la version actuelle, ou la liste a été modifiée entre-temps. |
| 422 | `validation_failed` | Une règle ne respecte pas les règles ci-dessus. Chaque règle non conforme est un élément `errors[]` pointant vers `/attribute_mappings/<index>/<field>`, ou vers `/attribute_mappings` pour les règles de liste (`email_required`, `too_many_metadata_keys`). |
| 428 | `precondition_required` | L'en-tête `If-Match` est absent. |
| 400 | `unknown_field` | Le corps de la requête contient un champ inconnu. |
| 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 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 -X PUT "https://api.eu.keenauth.com/v1/connections/conn_01j9xp6q0r1s5t7v9w1x3y5z7b/attribute-mappings" \
  -H "Authorization: Bearer $KEENAUTH_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -H 'If-Match: "6f1c…"' \
  -d '{"attribute_mappings":[{"target":"email","source_name":"email","overwrite":"always"},{"target":"user_metadata.department","source_name":"department","overwrite":"if_empty"}]}'
```

```bash
keenauth connections attribute-mappings put conn_01j9xp6q0r1s5t7v9w1x3y5z7b --data @mappings.json --if-match '"6f1c…"'
```
