
# Salvare una bozza di modello e-mail

`PUT /v1/email-templates/{family}/{locale}` · permesso `email-templates:write` · piano Startup e superiori

Salva il contenuto come nuova versione bozza. La versione pubblicata non cambia finché non [pubblichi](publish.md) la bozza.

`If-Match` è obbligatorio e contiene la versione più recente che hai letto (il `ETag` di [ottieni](get.md) o [elenca le versioni](list-versions.md)). Per uno slot che non ha ancora versioni, invia `If-Match: "0"`; `*` non corrisponde a uno slot vuoto. Una mancata corrispondenza restituisce `412`.

Prima del salvataggio, il contenuto passa gli stessi controlli di un invio reale:

- Deve essere renderizzabile nella sandbox Liquid con dati di esempio.
- L'HTML deve essere bilanciato.
- Il codice o il link della famiglia (vedi `requires` in [elenco](list.md)) deve comparire sia nell'HTML sia nel corpo di testo semplice.
- I link possono puntare solo agli host della piattaforma.
- Si applicano i limiti di dimensione.

Uno slot conserva al massimo 50 versioni oltre a quella pubblicata; le bozze più vecchie vengono eliminate.

## Parametri di percorso

| Parametro | Descrizione |
|---|---|
| `family` | Famiglia di e-mail, per esempio `verify_email` o `email_otp` (vedi [Elencare i modelli e-mail](list.md)). |
| `locale` | Tag della lingua, per esempio `en` o `de`. |

## Richiesta

| Campo | Tipo | Obbligatorio | Descrizione |
|---|---|---|---|
| `subject` | string | sì | Liquid, testo semplice, da 1 a 200 caratteri, senza interruzioni di riga. |
| `html` | string | sì | Frammento HTML Liquid, al massimo 256 KiB. La piattaforma aggiunge il layout. |
| `text_body` | string | sì | Corpo di testo semplice Liquid, al massimo 64 KiB. |
| `from_name` | string | no | Nome visualizzato del mittente, al massimo 64 caratteri, senza interruzioni di riga. Vuoto o assente: si usa il nome dell'applicazione o dell'ambiente. |

## Risposta

`200 OK` con la nuova bozza e `ETag` impostato sulla sua versione.

```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
}
```

## Errori

| HTTP | code | Quando |
|---|---|---|
| 400 | `unknown_field` | Il corpo contiene un campo sconosciuto o non è un oggetto JSON. |
| 404 | `not_found` | La famiglia o la lingua è sconosciuta, oppure la versione non esiste. |
| 403 | `plan_feature_unavailable` | Il piano dell'ambiente non include i modelli e-mail personalizzati (Startup e superiori; `required_plan` indica quale). |
| 412 | `precondition_failed` | `If-Match` non è la versione più recente (qualcuno ha salvato nel frattempo), oppure è `*` su uno slot vuoto. |
| 413 | `payload_too_large` | Il corpo supera i 2 MiB. |
| 428 | `precondition_required` | `If-Match` manca. |
| 422 | `validation_failed` | Il contenuto non supera la validazione; `errors[]` indica ogni campo (`/subject`, `/html`, `/text_body`, `/from_name`, `/family`) e la sua regola. |
| 422 | `template_forbidden_construct` | Il modello usa un costrutto Liquid fuori dalla sandbox (per esempio `{% include %}`); `errors[]` indica il campo. |
| 401 | `unauthenticated` | La credenziale è mancante, non valida o revocata. |
| 403 | `insufficient_permissions` | La credenziale non ha il permesso richiesto. |
| 429 | `rate_limited` | È stato superato il limite di frequenza; riprova dopo il periodo indicato in `Retry-After`. |
| 503 | `service_unavailable` | Una dipendenza è temporaneamente non disponibile; riprova dopo il periodo indicato in `Retry-After`. |

Le regole di validazione in `errors[]` includono `required`, `too_long`, `invalid`, `unbalanced_html`, `missing_code`, `missing_link`, `missing_code_or_link`, `template_render_failed`, `template_too_large` e `family_not_available`.

## Esempio

```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`
