> ## Documentation Index
> Fetch the complete documentation index at: https://docs.switchbord.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Endpoint dei template

> Endpoint REST per la gestione dei template WhatsApp — elenco, creazione, aggiornamento, eliminazione, invio e seeding dello starter pack.

Switchbord esporta un piccolo insieme di endpoint autenticati sotto `/api/templates` nell'app control-plane (`apps/app`) per gestire la libreria di template WhatsApp del workspace. Tutte le route richiedono un operatore autenticato con **accesso alle impostazioni** (`owner`, `admin` o `developer`); la route di seed richiede inoltre `owner` o `admin`.

Le richieste sono limitate al workspace attivo del chiamante — non è possibile vedere o modificare i template di un altro workspace. Gli errori di autenticazione restituiscono `401 unauthenticated` o `403 forbidden`.

## Riepilogo

| Metodo | Percorso                           | Scopo                                       | Ruolo richiesto           |
| ------ | ---------------------------------- | ------------------------------------------- | ------------------------- |
| GET    | `/api/templates`                   | Elenca tutti i template nel workspace       | accesso alle impostazioni |
| POST   | `/api/templates`                   | Crea un template in bozza                   | accesso alle impostazioni |
| GET    | `/api/templates/{id}`              | Recupera un template                        | accesso alle impostazioni |
| PUT    | `/api/templates/{id}`              | Aggiorna un template in bozza               | accesso alle impostazioni |
| DELETE | `/api/templates/{id}`              | Elimina una bozza (solo stato `draft`)      | accesso alle impostazioni |
| POST   | `/api/templates/{id}/submit`       | Invia una bozza a Meta per l'approvazione   | accesso alle impostazioni |
| POST   | `/api/templates/seed-starter-pack` | Esegue il seed dello starter pack GB Viaggi | owner o admin             |

***

## GET /api/templates

Elenca ogni template per il workspace attivo, ordinato per data di aggiornamento più recente.

**Risposta 200**

```json theme={null}
{
  "templates": [
    {
      "id": "b3d2b8f1-...",
      "name": "booking_confirmed",
      "language": "it",
      "category": "UTILITY",
      "status": "approved",
      "parameterFormat": "POSITIONAL",
      "components": [ ... ],
      "variables": ["var1", "var2"],
      "preview": "Prenotazione confermata per var1 a var2.",
      "metaTemplateId": "123456789",
      "rejectionReason": null,
      "updatedAt": "2026-04-22T10:15:00Z"
    }
  ]
}
```

**Errori** — `401 unauthenticated`, `403 forbidden`, `500 internal_error`.

***

## POST /api/templates

Crea una nuova bozza di template. Il template viene memorizzato con `status = "draft"` e **non** viene inviato a Meta. Usa `POST /api/templates/{id}/submit` dopo che la bozza è pronta.

**Corpo della richiesta**

```json theme={null}
{
  "name": "winback_30d",
  "language": "it",
  "category": "MARKETING",
  "parameterFormat": "POSITIONAL",
  "components": [
    { "type": "BODY",
      "text": "Ciao {{1}}, è passato un po' dall'ultima volta...",
      "example": { "body_text": [["Marco"]] } }
  ]
}
```

Campi:

* `name` (stringa, obbligatorio) — i caratteri minuscoli e non corrispondenti vengono ridotti a `_`. Vedi [name-regex](/it/whatsapp/template-rules#name-regex).
* `language` (stringa, default `"en_US"`) — codice locale Meta, ad es. `"it"`, `"en_US"`, `"pt_BR"`.
* `category` (`"MARKETING" | "UTILITY" | "AUTHENTICATION"`, default `"UTILITY"`).
* `parameterFormat` (`"POSITIONAL" | "NAMED"`, default `"POSITIONAL"`).
* `components` (array) — la struttura dei componenti secondo lo schema di Meta.

**Risposta 200**

```json theme={null}
{ "template": { "id": "...", "status": "draft", ... } }
```

**Errori** — `400 create_failed` con `message` che descrive l'errore del DB o di validazione, oltre agli errori di autenticazione.

***

## GET /api/templates/{id}

Recupera un singolo template per id. Restituisce `404 not_found` se l'id non esiste nel workspace del chiamante.

**Risposta 200** — stessa struttura di una voce dell'elenco.

***

## PUT /api/templates/{id}

Aggiorna uno o più campi di un template in bozza. I campi inviati vengono applicati come patch; i campi non inviati rimangono inalterati.

**Corpo della richiesta** (tutti i campi opzionali)

```json theme={null}
{
  "name": "winback_30d_v2",
  "language": "it",
  "category": "MARKETING",
  "parameterFormat": "POSITIONAL",
  "components": [ ... ]
}
```

**Risposta 200**

```json theme={null}
{ "template": { ... } }
```

**Errori** — `400 update_failed`, errori di autenticazione.

***

## DELETE /api/templates/{id}

Elimina un template in bozza. **Solo i template con `status = "draft"`** possono essere eliminati — una volta inviati, i template vengono conservati per l'audit. Un template non in bozza restituisce `409 conflict`.

**Risposta 200**

```json theme={null}
{ "ok": true }
```

**Errori** — `404 not_found`, `409 conflict` con `"Only draft templates can be deleted"`, errori di autenticazione.

***

## POST /api/templates/{id}/submit

Invia un template in bozza all'endpoint `POST /{waba_id}/message_templates` di Meta. Switchbord esegue prima l'intero validatore lato client (le stesse regole documentate in [Regole dei template](/it/whatsapp/template-rules)); se un controllo fallisce, non viene effettuata alcuna chiamata a Meta e viene restituito un `400 validation_failed` con l'array dei problemi riscontrati.

In caso di successo, la riga del template viene aggiornata con `meta_template_id`, `status = "pending_approval"` e `rejection_reason = null`.

In caso di rifiuto da parte di Meta (HTTP 4xx con un corpo `error`), la riga viene aggiornata con `status = "rejected"` e `rejection_reason` impostato sul messaggio leggibile di Meta, e viene restituito al chiamante un `400 meta_submit_failed` con il payload di errore completo di Meta.

**Risposta 200**

```json theme={null}
{ "template": { "id": "...", "status": "pending_approval", "metaTemplateId": "123456789" } }
```

**Errori**

* `400 validation_failed` — il validatore lato client ha rifiutato la bozza. `issues` è l'array di problemi Zod.
* `400 meta_submit_failed` — Meta ha restituito un errore. `meta` è l'oggetto `error` grezzo di Meta (code, subcode, `error_user_msg`, `error_data.details`).
* `400 no_waba` — nessun WhatsApp Business Account configurato per il workspace.
* `400 no_access_token` — nessun token di accesso Meta nel vault del workspace.
* `404 not_found`, errori di autenticazione.

***

## POST /api/templates/seed-starter-pack

Seeder one-shot riservato agli admin che invia lo starter pack GB Viaggi (8 `UTILITY` + 5 `MARKETING`, italiano + inglese dove applicabile) a Meta e inserisce/aggiorna le righe corrispondenti nella tabella locale `templates`. È sicuro rieseguirlo — la chiave di upsert è `(workspace_id, name, locale)`.

Ruolo richiesto: **owner** o **admin**.

**Corpo della richiesta** — vuoto.

**Risposta 200**

```json theme={null}
{
  "total": 13,
  "submitted": 11,
  "errored": 2,
  "results": [
    {
      "name": "booking_confirmed",
      "language": "it",
      "category": "UTILITY",
      "status": "submitted",
      "metaTemplateId": "987654321"
    },
    {
      "name": "flash_sale",
      "language": "it",
      "category": "MARKETING",
      "status": "error",
      "error": "Variable parameters in the body text cannot be next to each other."
    }
  ]
}
```

`status` per ogni voce:

* `submitted` — accettato da Meta, riga memorizzata come `pending_approval`.
* `error` — errore di Meta o del DB, riga memorizzata come `rejected` con il messaggio di Meta.
* `skipped` — riservato; attualmente non viene emesso.

**Errori**

* `400 no_waba` — nessun WhatsApp Business Account configurato.
* `400 no_access_token` — segreto del vault `meta-access-token` mancante.
* `500 internal_error` — errore non gestito.
* `401 unauthenticated`, `403 forbidden` — il chiamante non possiede il ruolo owner/admin.

***

## Endpoint interni correlati

Esistono due route interne, non pubbliche, in `apps/api` per i flussi di sincronizzazione machine-to-machine:

* `POST /internal/templates` — upsert del template dal worker verso l'API dopo un evento webhook.
* `POST /internal/templates/sync` — ri-sincronizzazione completa della libreria da Meta verso Switchbord.

Queste non sono esposte pubblicamente e non dovrebbero essere chiamate dal frontend. Vedi [Specifica API interna](/it/api-reference/internal-spec) per l'elenco autorevole.

## OpenAPI

La struttura leggibile dalla macchina per questi endpoint verrà generata in `apps/docs/api-reference/openapi.json` da `pnpm openapi:generate`. Esegui il generatore dopo aver modificato una route per mantenere la specifica sincronizzata.
