
# Enregistrer un brouillon de modèle d'e-mail

`PUT /v1/email-templates/{family}/{locale}` · autorisation `email-templates:write` · plan Startup et supérieurs

Enregistre le contenu comme nouvelle version brouillon. La version publiée ne change pas tant que vous n'[avez pas publié](publish.md) le brouillon.

`If-Match` est obligatoire et contient la version la plus récente que vous avez lue (l'`ETag` de [obtenir](get.md) ou de [lister les versions](list-versions.md)). Pour un emplacement qui n'a pas encore de version, envoyez `If-Match: "0"` ; `*` ne correspond pas à un emplacement vide. Une non-correspondance renvoie `412`.

Avant l'enregistrement, le contenu passe les mêmes contrôles qu'un envoi réel :

- Il doit s'afficher dans le bac à sable Liquid avec des données d'exemple.
- Le HTML doit être équilibré.
- Le code ou le lien de la famille (voir `requires` dans [la liste](list.md)) doit apparaître à la fois dans le HTML et dans le corps en texte brut.
- Les liens ne peuvent pointer que vers les hôtes de la plateforme.
- Les limites de taille s'appliquent.

Un emplacement conserve au plus 50 versions en plus de la version publiée ; les anciens brouillons sont supprimés.

## Paramètres de chemin

| Paramètre | Description |
|---|---|
| `family` | Famille d'e-mails, par exemple `verify_email` ou `email_otp` (voir [Lister les modèles d'e-mail](list.md)). |
| `locale` | Étiquette de langue, par exemple `en` ou `de`. |

## Requête

| Champ | Type | Obligatoire | Description |
|---|---|---|---|
| `subject` | string | oui | Liquid, texte brut, 1 à 200 caractères, sans saut de ligne. |
| `html` | string | oui | Fragment HTML Liquid, 256 Kio au maximum. La plateforme ajoute la mise en page. |
| `text_body` | string | oui | Corps en texte brut Liquid, 64 Kio au maximum. |
| `from_name` | string | non | Nom d'affichage de l'expéditeur, 64 caractères au maximum, sans saut de ligne. Vide ou absent : le nom de l'application ou de l'environnement est utilisé. |

## Réponse

`200 OK` avec le nouveau brouillon et `ETag` défini sur sa version.

```json
{
  "family": "verify_email",
  "locale": "en",
  "version": 3,
  "status": "draft",
  "subject": "Confirm your email for {{ application.name }}",
  "html": "<p>Hi,</p><p><a href=\"{{ link }}\">Confirm your email</a></p>",
  "text_body": "Confirm your email: {{ link }}",
  "from_name": null,
  "source_version": null,
  "created_at": "2026-10-19T09:00:00Z",
  "published_at": null,
  "latest_version": 3,
  "published_version": 2
}
```

## Erreurs

| HTTP | code | Quand |
|---|---|---|
| 400 | `unknown_field` | Le corps contient un champ inconnu ou n'est pas un objet JSON. |
| 404 | `not_found` | La famille ou la langue est inconnue, ou la version n'existe pas. |
| 403 | `plan_feature_unavailable` | Le plan de l'environnement n'inclut pas les modèles d'e-mail personnalisés (Startup et supérieurs ; `required_plan` indique lequel). |
| 412 | `precondition_failed` | `If-Match` n'est pas la version la plus récente (quelqu'un a enregistré entre-temps), ou vaut `*` sur un emplacement vide. |
| 413 | `payload_too_large` | Le corps dépasse 2 MiB. |
| 428 | `precondition_required` | `If-Match` est absent. |
| 422 | `validation_failed` | Le contenu ne passe pas la validation ; `errors[]` nomme chaque champ (`/subject`, `/html`, `/text_body`, `/from_name`, `/family`) et sa règle. |
| 422 | `template_forbidden_construct` | Le modèle utilise une construction Liquid hors du bac à sable (par exemple `{% include %}`) ; `errors[]` nomme le champ. |
| 401 | `unauthenticated` | L'identifiant est absent, invalide ou révoqué. |
| 403 | `insufficient_permissions` | L'identifiant n'a pas 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`. |

Les règles de validation présentes dans `errors[]` incluent `required`, `too_long`, `invalid`, `unbalanced_html`, `missing_code`, `missing_link`, `missing_code_or_link`, `template_render_failed`, `template_too_large` et `family_not_available`.

## Exemple

```bash
curl -X PUT https://api.eu.keenauth.com/v1/email-templates/verify_email/en \
  -H "Authorization: Bearer $KEENAUTH_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -H 'If-Match: "2"' \
  -d '{"subject":"Confirm your email for {{ application.name }}","html":"<p><a href=\"{{ link }}\">Confirm your email</a></p>","text_body":"Confirm your email: {{ link }}"}'
```

CLI : `keenauth email-templates put verify_email en --if-match '"2"' --data @template.json`
