
# API dei modelli WhatsApp

I modelli di messaggio WhatsApp sono messaggi predefiniti approvati per l'invio al di fuori della normale finestra di conversazione di 24 ore, come ad esempio un messaggio di benvenuto, un promemoria per un appuntamento o un sollecito di riattivazione. Questa API ti consente di elencare, creare, modificare, inviare, verificare, eliminare e spedire modelli a livello programmatico.

Tutti i percorsi seguenti sono relativi all'URL di base dell'API:

```
https://api.youraiconnector.com/v1
```

Ogni richiesta deve essere autenticata. Consulta [Autenticazione](authentication.md) per i quattro metodi accettati. Gli esempi in questa pagina utilizzano l'intestazione `X-API-Key` (e una forma di parametro di query per cURL).

::: note
**Nota:** I modelli si basano sul canale WhatsApp Business API, pertanto questa parte dell'API richiede sia l'accesso all'API che un piano che includa i canali WhatsApp. Senza di essi, le richieste vengono rifiutate con un `403`.
:::


---

## Utilizzo dei sotto-account (agenzie)


---

## Stati di approvazione

Poiché i messaggi inviati al di fuori di una conversazione aperta devono essere prima revisionati da WhatsApp, ogni modello ha uno `status` di approvazione:

| Stato | Significato |
|---|---|
| `draft` | Creato o salvato ma non ancora inviato per la revisione. È ancora possibile modificarlo. |
| `received` | Inviato e accettato nella coda di revisione. |
| `pending` | In fase di revisione. |
| `approved` | Autorizzato all'invio. |
| `rejected` | Respinto. Il campo `rejection_reason` spiega il motivo; correggilo e invialo di nuovo. |

Solo i modelli `draft` e `rejected` possono essere modificati o (ri)inviati. Una volta che un modello è `approved`, viene bloccato: creane uno nuovo se hai bisogno di apportare modifiche.

> **Approvazione automatica:** Alcuni canali non richiedono una fase di revisione esterna. I modelli creati o inviati per una campagna su tali canali vengono archiviati immediatamente come `approved`, senza un ID contenuto (`sid`).

---

## Template su account connessi a Meta

Questi endpoint funzionano allo stesso modo indipendentemente dalla connessione WhatsApp utilizzata dal tuo account, ma ciò che accade dietro le quinte differisce:

- Su una **connessione WhatsApp gestita**, i template vengono registrati presso il provider di messaggistica e `sid` è l'ID contenuto del provider (`HXXXXXXXX…`).
- Su un account il cui numero è eseguito sul **proprio WhatsApp Business Account** (una delle due opzioni di connessione Meta), i template vengono creati e revisionati **in quel WhatsApp Business Account** e `sid` è l'ID template di Meta — una stringa numerica come `"3394843740694756"`. `status` utilizza ancora i valori nella tabella sopra, e `rejection_reason` riporta ancora la spiegazione di Meta.

Esistono due endpoint aggiuntivi per questo: uno per chiedere su quale connessione ti trovi e uno per riconciliare il tuo elenco di template con il tuo WhatsApp Business Account. I template già esistenti nel WhatsApp Business Account vengono importati nella tua libreria tramite la sincronizzazione, quindi una `GET /whatsapp-templates` successiva li elenca come qualsiasi altro template.

### Controlla su quale connessione vengono eseguiti i template

`GET /whatsapp-templates/provider`

| Campo | Descrizione |
|---|---|
| `provider` | `twilio` quando i template sono registrati presso il provider di messaggistica gestito, `meta` quando risiedono nel tuo WhatsApp Business Account. |
| `lane` | Quale connessione Meta è in uso — `meta_cloud_api` (la tua app Meta) o `meta_embedded` (connessa tramite la nostra app Meta). `null` su una connessione gestita. |
| `waba_id` | Il WhatsApp Business Account in cui vengono creati i template, o `null`. |
| `templates_enabled` | `false` quando la connessione Meta non è ancora completata (nessun WhatsApp Business Account o token di accesso memorizzato). La creazione o l'invio di template fallirà con un `400` finché non lo sarà. |

**cURL**

```bash
curl "https://api.youraiconnector.com/v1/whatsapp-templates/provider?apiKey=YOUR_API_KEY"
```

**JavaScript**

```javascript
const res = await fetch("https://api.youraiconnector.com/v1/whatsapp-templates/provider", {
  headers: { "X-API-Key": "YOUR_API_KEY" },
});
const data = await res.json();
```

**Python**

```python
import requests

res = requests.get(
    "https://api.youraiconnector.com/v1/whatsapp-templates/provider",
    headers={"X-API-Key": "YOUR_API_KEY"},
)
data = res.json()
```

**Risposta**

```json
{
  "success": true,
  "provider": "meta",
  "lane": "meta_cloud_api",
  "waba_id": "2357661648036355",
  "templates_enabled": true
}
```

### Sincronizza i template da Meta

Aggiorna lo stato di approvazione di ogni template che risiede nel tuo WhatsApp Business Account e importa qualsiasi template che esiste lì ma non è ancora nella tua libreria. È sicuro chiamarlo tutte le volte che vuoi. Su una connessione gestita non c'è nulla da sincronizzare, quindi la chiamata non esegue alcuna azione e riporta semplicemente quanti template hai.

`POST /whatsapp-templates/meta-sync`

| Campo | Descrizione |
|---|---|
| `imported` | Template trovati nel WhatsApp Business Account che sono stati aggiunti alla tua libreria tramite questa chiamata. |
| `updated` | Template esistenti il cui stato o dettagli sono cambiati. |
| `total` | Template presenti nella tua libreria dopo la sincronizzazione. |

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/whatsapp-templates/meta-sync?apiKey=YOUR_API_KEY"
```

**JavaScript**

```javascript
const res = await fetch("https://api.youraiconnector.com/v1/whatsapp-templates/meta-sync", {
  method: "POST",
  headers: { "X-API-Key": "YOUR_API_KEY" },
});
const data = await res.json();
```

**Python**

```python
import requests

res = requests.post(
    "https://api.youraiconnector.com/v1/whatsapp-templates/meta-sync",
    headers={"X-API-Key": "YOUR_API_KEY"},
)
data = res.json()
```

**Risposta**

```json
{
  "success": true,
  "provider": "meta",
  "imported": 2,
  "updated": 5,
  "total": 12
}
```

### Comunicare direttamente con Meta (avanzato)

Se hai bisogno di qualcosa che gli endpoint sopra non espongono — intestazioni, piè di pagina, pulsanti o un template creato interamente a mano — `/v1/meta-templates` inoltra la tua richiesta direttamente all'API dei template di Meta, senza memorizzare nulla nella tua libreria di template. Funziona solo su account il cui numero è eseguito sul proprio WhatsApp Business Account; su una connessione gestita, ogni chiamata restituisce `400` chiedendoti di collegare prima un'app Meta.

| Endpoint | Cosa fa |
|---|---|
| `GET /meta-templates` | Elenca i template sul tuo WhatsApp Business Account con il loro stato più recente. Aggiungi `?name=` per filtrare su un nome template esatto. Restituisce `{ "success": true, "templates": [...] }`. |
| `POST /meta-templates` | Crea un template e lo invia per la revisione di Meta in un unico passaggio. Richiede `name`, `language` e `body` (o un array `components` completo invece di `body`). Opzionale: `variables` (array di stringhe), `category` (`MARKETING`, `UTILITY` o `AUTHENTICATION`), `header`, `footer`, `buttons`. Restituisce `201` con `{ "success": true, "template": {...} }`. |
| `DELETE /meta-templates/{name}` | Elimina il template tramite il suo nome Meta — **ogni sua lingua**. Aggiungi `?hsm_id=` con l'ID template di Meta per rimuovere una singola lingua. Restituisce `{ "success": true, "name": "..." }`. |

Un template rifiutato da Meta restituisce `400` con la spiegazione di Meta in `error`.

---

## Elenca modelli

Restituisce tutti i modelli presenti nel tuo account, con un riepilogo leggero per ciascuno.

`GET /whatsapp-templates`

**cURL**

```bash
curl "https://api.youraiconnector.com/v1/whatsapp-templates?apiKey=YOUR_API_KEY"
```

**JavaScript**

```javascript
const res = await fetch("https://api.youraiconnector.com/v1/whatsapp-templates", {
  headers: { "X-API-Key": "YOUR_API_KEY" },
});
const data = await res.json();
```

**Python**

```python
import requests

res = requests.get(
    "https://api.youraiconnector.com/v1/whatsapp-templates",
    headers={"X-API-Key": "YOUR_API_KEY"},
)
data = res.json()
```

**Risposta**

```json
{
  "success": true,
  "data": [
    {
      "id": "template_abc123",
      "name": "welcome_message",
      "status": "approved",
      "language": "en",
      "body": "Hi {{first_name}}, thanks for reaching out!"
    },
    {
      "id": "template_def456",
      "name": "appointment_reminder",
      "status": "pending",
      "language": "en",
      "body": "Hi {{first_name}}, this is a reminder about your appointment."
    }
  ]
}
```

---

## Ottieni un modello

Restituisce i dettagli completi di un singolo modello, incluse le sue variabili, lo stato e i timestamp.

`GET /whatsapp-templates/{templateId}`

**cURL**

```bash
curl "https://api.youraiconnector.com/v1/whatsapp-templates/template_abc123" \
  -H "X-API-Key: YOUR_API_KEY"
```

**JavaScript**

```javascript
const res = await fetch(
  "https://api.youraiconnector.com/v1/whatsapp-templates/template_abc123",
  { headers: { "X-API-Key": "YOUR_API_KEY" } }
);
const data = await res.json();
```

**Python**

```python
import requests

res = requests.get(
    "https://api.youraiconnector.com/v1/whatsapp-templates/template_abc123",
    headers={"X-API-Key": "YOUR_API_KEY"},
)
data = res.json()
```

**Risposta**

```json
{
  "success": true,
  "template": {
    "id": "template_abc123",
    "name": "welcome_message",
    "body": "Hi {{first_name}}, thanks for reaching out!",
    "language": "en",
    "variables": ["first_name"],
    "status": "approved",
    "sid": "HXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
    "type": "general",
    "category": "marketing",
    "rejection_reason": null,
    "campaign_id": "campaign123",
    "date_created": "2026-06-01T10:00:00.000Z",
    "date_updated": "2026-06-02T08:30:00.000Z",
    "submitted_at": "2026-06-01T10:05:00.000Z",
    "approved_at": "2026-06-02T08:30:00.000Z"
  }
}
```

Un modello che non esiste nel tuo account restituisce `404` con `{ "success": false, "error": "Template not found" }`.

---

## Crea un modello

Crea un modello per il messaggio di apertura di una campagna e lo invia per l'approvazione in un unico passaggio.

`POST /whatsapp-templates`

| Campo | Obbligatorio | Descrizione |
|---|---|---|
| `campaign_id` | Sì | La campagna a cui appartiene il modello. |
| `name` | Sì | Un nome per il modello. |
| `language` | Sì | Codice lingua, ad esempio `en`, `es`, `de`, `pt_BR`, `zh_CN`. |
| `body` | Sì | Il testo del messaggio, fino a 1024 caratteri. |
| `variables` | No | Elenco ordinato dei nomi delle variabili utilizzate nel corpo del testo. |

I segnaposto delle variabili possono essere scritti come `{{first_name}}`, `{first_name}` o `[first_name]`: vengono tutti normalizzati nella forma a doppia parentesi graffa.

Il risultato dipende dai canali della campagna:

- **Campagna WhatsApp Business API:** il contenuto viene inviato per la revisione di WhatsApp. La risposta contiene `campaign_status` (`received` o `pending`) e un `template_sid`.
- **Un canale senza una fase di revisione esterna:** il modello viene salvato e approvato automaticamente (`campaign_status: "approved"`, `template_sid: null`).
- **Nessun canale WhatsApp nella campagna:** non viene creato nulla e `campaign_status` è `not_applicable`.

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/whatsapp-templates?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "campaign_id": "campaign123",
    "name": "welcome_message",
    "language": "en",
    "body": "Hi {{first_name}}, thanks for reaching out!",
    "variables": ["first_name"]
  }'
```

**JavaScript**

```javascript
const res = await fetch("https://api.youraiconnector.com/v1/whatsapp-templates", {
  method: "POST",
  headers: {
    "X-API-Key": "YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    campaign_id: "campaign123",
    name: "welcome_message",
    language: "en",
    body: "Hi {{first_name}}, thanks for reaching out!",
    variables: ["first_name"],
  }),
});
const data = await res.json();
```

**Python**

```python
import requests

res = requests.post(
    "https://api.youraiconnector.com/v1/whatsapp-templates",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={
        "campaign_id": "campaign123",
        "name": "welcome_message",
        "language": "en",
        "body": "Hi {{first_name}}, thanks for reaching out!",
        "variables": ["first_name"],
    },
)
data = res.json()
```

**Risposta** (inviato per la revisione)

```json
{
  "success": true,
  "campaign_status": "pending",
  "template_sid": "HXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
}
```

---

## Creare un modello autonomo

Crea un modello nella tua libreria di modelli senza collegarlo al messaggio di apertura di una campagna. Questo è il passaggio di creazione del ciclo di vita che il resto di questa pagina segue: crealo qui, modificalo, invialo per la revisione, controllane lo stato ed eliminalo quando non ti serve più.

`POST /whatsapp-templates/docs`

| Campo | Obbligatorio | Descrizione |
|---|---|---|
| `name` | Sì | Un nome per il modello. |
| `language` | Sì | Codice lingua, ad esempio `en`, `es`, `de`, `pt_BR`, `zh_CN`. |
| `body` | Sì | Il testo del messaggio, fino a 1024 caratteri. |
| `variables` | No | Elenco ordinato dei nomi delle variabili utilizzati nel corpo. |
| `status` | No | `draft` (predefinito) lo archivia senza inviarlo; `submitted` lo mette subito in coda per la revisione di WhatsApp. |
| `type` | No | `general` (predefinito) o `smart_followup`. |
| `category` | No | `marketing`, `utility`, `authentication` o `authentication-international`. |
| `campaign_id` | No | Collega il modello a una delle tue campagne. |

> **Modelli di autenticazione (codice monouso).** WhatsApp non accetta modelli di autenticazione a testo libero: il corpo del messaggio è preimpostato da WhatsApp e il modello deve contenere un pulsante "copia codice". Quando crei un modello con `category: "authentication"`, lo inviamo in quel formato fisso per te. Il tuo `body` viene mantenuto come anteprima mostrata nell'app, ma il testo che il tuo contatto riceve è la formulazione propria di WhatsApp (il codice, un promemoria di sicurezza e una nota di scadenza di 10 minuti). Dichiara esattamente una variabile, ad esempio `["code"]`, e passa il codice quando invii (vedi il campo `variables` su [Invia un modello a un contatto](#send-a-template-to-a-contact)). Il codice deve essere più breve di 15 caratteri.

> **Quale creazione dovrei usare?** Usa questa quando vuoi un modello che puoi modificare e inviare tu stesso. Usa `POST /whatsapp-templates` (sopra) quando vuoi impostare il messaggio di apertura di una campagna: quella richiede `campaign_id` e scrive direttamente nella campagna.

Un modello creato come `submitted` viene inviato per la revisione di WhatsApp in background, quindi controlla l'endpoint di stato per il risultato invece di aspettartelo nella risposta.

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/whatsapp-templates/docs?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "welcome_message",
    "language": "en",
    "body": "Hi {{first_name}}, thanks for reaching out!",
    "variables": ["first_name"],
    "status": "draft",
    "category": "marketing"
  }'
```

**JavaScript**

```javascript
const res = await fetch("https://api.youraiconnector.com/v1/whatsapp-templates/docs", {
  method: "POST",
  headers: {
    "X-API-Key": "YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    name: "welcome_message",
    language: "en",
    body: "Hi {{first_name}}, thanks for reaching out!",
    variables: ["first_name"],
    status: "draft",
    category: "marketing",
  }),
});
const data = await res.json();
```

**Python**

```python
import requests

res = requests.post(
    "https://api.youraiconnector.com/v1/whatsapp-templates/docs",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={
        "name": "welcome_message",
        "language": "en",
        "body": "Hi {{first_name}}, thanks for reaching out!",
        "variables": ["first_name"],
        "status": "draft",
        "category": "marketing",
    },
)
data = res.json()
```

**Risposta**

```json
{
  "success": true,
  "template_id": "template_abc123",
  "status": "draft"
}
```

Un `name`, `language` o `body` mancante, una lingua non supportata, un `status` diverso da `draft` o `submitted`, un `type` o `category` sconosciuto, o un corpo superiore a 1024 caratteri restituisce `400` con una `error` esplicativa. Un `campaign_id` che non è una delle tue campagne restituisce `404`.

---

## Aggiorna un modello

Modifica un modello che non è ancora stato approvato. È possibile modificare solo i modelli con stato `draft` o `rejected`. Fornisci una qualsiasi combinazione di `name`, `body`, `language` e `variables`: verranno modificati solo i campi inviati.

`PUT /whatsapp-templates/{templateId}`

> La modifica **non** invia nuovamente il modello per la revisione. Utilizzare l'endpoint di invio in seguito.

**cURL**

```bash
curl -X PUT "https://api.youraiconnector.com/v1/whatsapp-templates/template_abc123" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "body": "Hi {{first_name}}, here is an update for you.",
    "variables": ["first_name"]
  }'
```

**JavaScript**

```javascript
const res = await fetch(
  "https://api.youraiconnector.com/v1/whatsapp-templates/template_abc123",
  {
    method: "PUT",
    headers: {
      "X-API-Key": "YOUR_API_KEY",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      body: "Hi {{first_name}}, here is an update for you.",
      variables: ["first_name"],
    }),
  }
);
const data = await res.json();
```

**Python**

```python
import requests

res = requests.put(
    "https://api.youraiconnector.com/v1/whatsapp-templates/template_abc123",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={
        "body": "Hi {{first_name}}, here is an update for you.",
        "variables": ["first_name"],
    },
)
data = res.json()
```

**Risposta**

```json
{
  "success": true,
  "template_id": "template_abc123"
}
```

Il tentativo di modificare un modello che è già `approved` (o comunque non modificabile), l'invio di campi vuoti o l'invio di un valore non valido restituisce `400` con un `error` esplicativo.

---

## Inviare un modello per l'approvazione

Invia un modello `draft` o `rejected` per la revisione. I modelli su un canale che non richiede una revisione esterna vengono approvati immediatamente; tutti gli altri vengono inviati a WhatsApp e il `status` restituito (solitamente `received` o `pending`) viene memorizzato nel modello.

`POST /whatsapp-templates/{templateId}/submit`

> I **modelli di follow-up** devono dichiarare e utilizzare le variabili richieste prima di poter essere inviati: un segnaposto per il nome e un segnaposto per il contesto personale per i follow-up intelligenti.

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/whatsapp-templates/template_abc123/submit" \
  -H "X-API-Key: YOUR_API_KEY"
```

**JavaScript**

```javascript
const res = await fetch(
  "https://api.youraiconnector.com/v1/whatsapp-templates/template_abc123/submit",
  { method: "POST", headers: { "X-API-Key": "YOUR_API_KEY" } }
);
const data = await res.json();
```

**Python**

```python
import requests

res = requests.post(
    "https://api.youraiconnector.com/v1/whatsapp-templates/template_abc123/submit",
    headers={"X-API-Key": "YOUR_API_KEY"},
)
data = res.json()
```

**Risposta**

```json
{
  "success": true,
  "template_id": "template_abc123",
  "status": "pending",
  "sid": "HXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
}
```

---

## Controllare lo stato di approvazione

Un endpoint leggero per il polling dello stato attuale di un modello. Lo stato viene letto dal record memorizzato, che viene aggiornato periodicamente in background, quindi un'approvazione o un rifiuto molto recenti potrebbero richiedere un breve lasso di tempo prima di apparire.

`GET /whatsapp-templates/{templateId}/status`

**cURL**

```bash
curl "https://api.youraiconnector.com/v1/whatsapp-templates/template_abc123/status" \
  -H "X-API-Key: YOUR_API_KEY"
```

**JavaScript**

```javascript
const res = await fetch(
  "https://api.youraiconnector.com/v1/whatsapp-templates/template_abc123/status",
  { headers: { "X-API-Key": "YOUR_API_KEY" } }
);
const data = await res.json();
```

**Python**

```python
import requests

res = requests.get(
    "https://api.youraiconnector.com/v1/whatsapp-templates/template_abc123/status",
    headers={"X-API-Key": "YOUR_API_KEY"},
)
data = res.json()
```

**Risposta**

```json
{
  "success": true,
  "template_id": "template_abc123",
  "name": "welcome_message",
  "status": "approved",
  "sid": "HXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
  "rejection_reason": null,
  "date_updated": "2026-06-02T08:30:00.000Z"
}
```

---

## Eliminare un modello

Rimuove il record del modello dal tuo account.

`DELETE /whatsapp-templates/{templateId}`

::: warning
**Importante:** Su una connessione gestita viene rimosso solo il record archiviato: il contenuto che WhatsApp ha già approvato potrebbe rimanere registrato presso il provider di messaggistica. Su un account che utilizza il proprio WhatsApp Business Account, il modello viene eliminato anche da quell'account. In ogni caso, se una campagna utilizza ancora questo modello, reindirizza la campagna su un altro modello **prima** di eliminarlo, altrimenti gli invii che si basano su di esso falliranno.
:::


**cURL**

```bash
curl -X DELETE "https://api.youraiconnector.com/v1/whatsapp-templates/template_abc123" \
  -H "X-API-Key: YOUR_API_KEY"
```

**JavaScript**

```javascript
const res = await fetch(
  "https://api.youraiconnector.com/v1/whatsapp-templates/template_abc123",
  { method: "DELETE", headers: { "X-API-Key": "YOUR_API_KEY" } }
);
const data = await res.json();
```

**Python**

```python
import requests

res = requests.delete(
    "https://api.youraiconnector.com/v1/whatsapp-templates/template_abc123",
    headers={"X-API-Key": "YOUR_API_KEY"},
)
data = res.json()
```

**Risposta**

```json
{
  "success": true,
  "template_id": "template_abc123",
  "note": "The template record was removed from your account. Content already approved by WhatsApp may remain registered with the messaging provider."
}
```

---

## Inviare un modello a un contatto

Invia un modello approvato a un contatto, anche quando non c'è una conversazione aperta: questo riapre la sessione di chat. Puoi indirizzare il contatto tramite `contactId` o tramite `phoneNumber` e scegliere il modello tramite `whatsappTemplateId` o tramite `templateName`.

`POST /whatsapp-templates/send`

| Campo | Obbligatorio | Descrizione |
|---|---|---|
| `contactId` | Uno di questi due | L'ID del contatto. |
| `phoneNumber` | Uno di questi due | Il numero di telefono del contatto (con prefisso internazionale, senza spazi). Cercato o creato se necessario. |
| `whatsappTemplateId` | Uno di questi due | L'ID del modello. |
| `templateName` | Uno di questi due | Il nome del modello, come mostrato nell'app. |
| `firstName` | No | Utilizzato per compilare un contatto appena creato. |
| `lastName` | No | Utilizzato per compilare un contatto appena creato. |
| `email` | No | Utilizzato per compilare un contatto appena creato. |
| `variables` | No | Valori espliciti per le variabili del modello, indicati per nome variabile, ad esempio `{ "code": "482913" }`. Un valore fornito qui prevale sui campi del contatto per quella variabile; le variabili che ometti vengono comunque compilate dal contatto come descritto di seguito. È così che passi un codice monouso a un modello di autenticazione. |

Il corpo del modello supporta la sostituzione avanzata delle variabili:

- **Variabili di base:** `{{first_name}}`, `{{email}}`, `{{company}}`
- **Valori predefiniti:** `{{first_name|there}}` mostra `there` se il campo è vuoto
- **Trasformazioni:** `{{company|uppercase}}`, `{{name|lowercase}}`, `{{name|capitalize}}`
- **Combinate:** `{{company|Your Company|uppercase}}`

> **Crediti:** L'invio di un modello consuma crediti. Il costo esatto dipende dal paese del destinatario e dalla categoria del modello.

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/whatsapp-templates/send?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "contactId": "contact123",
    "whatsappTemplateId": "template_abc123"
  }'
```

**JavaScript**

```javascript
const res = await fetch("https://api.youraiconnector.com/v1/whatsapp-templates/send", {
  method: "POST",
  headers: {
    "X-API-Key": "YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    contactId: "contact123",
    whatsappTemplateId: "template_abc123",
  }),
});
const data = await res.json();
```

**Python**

```python
import requests

res = requests.post(
    "https://api.youraiconnector.com/v1/whatsapp-templates/send",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={
        "contactId": "contact123",
        "whatsappTemplateId": "template_abc123",
    },
)
data = res.json()
```

**Risposta**

```json
{
  "success": true,
  "data": "WhatsApp template message sent successfully"
}
```

Una richiesta a cui mancano sia un identificatore di contatto che entrambi gli identificatori di modello restituisce `400`. Se al tuo account mancano le credenziali di messaggistica necessarie per l'invio, la risposta è `403`.

---

## Crea o aggiorna il template live di una campagna

Una seconda coppia di endpoint per il template di apertura di una campagna, definiti tramite percorso invece che tramite un `campaign_id` nel corpo della richiesta. Questi sono quelli da utilizzare per una campagna già attiva: a differenza di [Crea un template](#create-a-template) sopra, l'aggiornamento qui comporta anche il reinvio delle bozze di follow-up della campagna per la revisione, in modo che il template di apertura e i relativi follow-up rimangano sincronizzati.

`POST /whatsapp-templates/campaign/{campaignId}` crea il template di apertura della campagna. `PUT /whatsapp-templates/campaign/{campaignId}` lo modifica: la campagna deve già avere un template, altrimenti verrà restituito `400`.

| Campo | Obbligatorio | Descrizione |
|---|---|---|
| `name` | Sì | Un nome per il template. |
| `language` | Sì | Codice lingua, ad esempio `en`, `es`, `de`, `pt_BR`, `zh_CN`. |
| `body` | Sì | Il testo del messaggio, fino a 1024 caratteri. |
| `variables` | Sì | Elenco ordinato dei nomi delle variabili utilizzate nel corpo. Passare un array vuoto se il template non ne utilizza nessuna. |

**cURL** (creazione)

```bash
curl -X POST "https://api.youraiconnector.com/v1/whatsapp-templates/campaign/campaign123?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "welcome_message",
    "language": "en",
    "body": "Hi {{first_name}}, thanks for reaching out!",
    "variables": ["first_name"]
  }'
```

**JavaScript**

```javascript
const res = await fetch("https://api.youraiconnector.com/v1/whatsapp-templates/campaign/campaign123", {
  method: "POST",
  headers: {
    "X-API-Key": "YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    name: "welcome_message",
    language: "en",
    body: "Hi {{first_name}}, thanks for reaching out!",
    variables: ["first_name"],
  }),
});
const data = await res.json();
```

**Python**

```python
import requests

res = requests.post(
    "https://api.youraiconnector.com/v1/whatsapp-templates/campaign/campaign123",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={
        "name": "welcome_message",
        "language": "en",
        "body": "Hi {{first_name}}, thanks for reaching out!",
        "variables": ["first_name"],
    },
)
data = res.json()
```

**Risposta**

```json
{
  "success": true,
  "campaign_status": "pending",
  "template_sid": "HXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
  "message": "WhatsApp template created and campaign updated successfully."
}
```

Per modificare, cambiare il metodo in `PUT` e utilizzare gli stessi campi: questo invia nuovamente il template di apertura (e le bozze di follow-up della campagna, su una campagna WhatsApp API) per la revisione.

Una campagna che non appartiene al proprio account restituisce `404`; una campagna appartenente a un altro account per il quale non si è autorizzati restituisce `403`. La modifica di una campagna senza un template esistente restituisce `400`.

---

## Invia un template a un contatto esistente

Un'alternativa più semplice, basata sul percorso, rispetto a [Invia un template a un contatto](#send-a-template-to-a-contact) sopra: sia il template che il contatto devono già esistere; nulla viene cercato per nome o creato al volo.

`POST /whatsapp-templates/{templateId}/send-to-contact`

| Campo | Obbligatorio | Descrizione |
|---|---|---|
| `contactId` | Sì | L'ID del contatto. Deve appartenere al proprio account. |

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/whatsapp-templates/template_abc123/send-to-contact?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "contactId": "contact123" }'
```

**JavaScript**

```javascript
const res = await fetch(
  "https://api.youraiconnector.com/v1/whatsapp-templates/template_abc123/send-to-contact",
  {
    method: "POST",
    headers: {
      "X-API-Key": "YOUR_API_KEY",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ contactId: "contact123" }),
  }
);
const data = await res.json();
```

**Python**

```python
import requests

res = requests.post(
    "https://api.youraiconnector.com/v1/whatsapp-templates/template_abc123/send-to-contact",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={"contactId": "contact123"},
)
data = res.json()
```

**Risposta**

```json
{
  "success": true,
  "data": "WhatsApp template message sent successfully"
}
```

> **Crediti:** L'invio consuma crediti, con lo stesso tariffario dell'endpoint precedente. Un `contactId` mancante o non presente nel proprio account restituisce `403`; un `templateId` inesistente restituisce `404`.

---

## Invio massivo di un template

Invia un template a molti contatti in un'unica chiamata, con un'anteprima dei costi che è possibile mostrare prima di confermare.

### Stima prima il costo

Restituisce il costo dell'invio, suddiviso per paese di destinazione, senza inviare nulla o scalare crediti. Il prezzo del modello è per paese di destinazione, quindi deve essere calcolato lato server in base ai contatti reali anziché stimato lato client.

`POST /whatsapp-templates/{templateId}/estimate-bulk-cost`

| Campo | Obbligatorio | Descrizione |
|---|---|---|
| `contactIds` | Sì | Contatti da quotare, fino a 500 per chiamata. I duplicati vengono conteggiati una sola volta. |

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/whatsapp-templates/template_abc123/estimate-bulk-cost?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "contactIds": ["contact123", "contact456"] }'
```

**JavaScript**

```javascript
const res = await fetch(
  "https://api.youraiconnector.com/v1/whatsapp-templates/template_abc123/estimate-bulk-cost",
  {
    method: "POST",
    headers: {
      "X-API-Key": "YOUR_API_KEY",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ contactIds: ["contact123", "contact456"] }),
  }
);
const data = await res.json();
```

**Python**

```python
import requests

res = requests.post(
    "https://api.youraiconnector.com/v1/whatsapp-templates/template_abc123/estimate-bulk-cost",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={"contactIds": ["contact123", "contact456"]},
)
data = res.json()
```

**Risposta**

```json
{
  "success": true,
  "data": {
    "countries": [
      {
        "countryCode": "1",
        "name": "United States",
        "iso": "US",
        "flag": "🇺🇸",
        "contactCount": 120,
        "costPerContact": 0.5,
        "subtotal": 60.0
      }
    ],
    "totalContacts": 120,
    "totalTemplateCost": 60.0,
    "templateCategory": "marketing",
    "skippedContacts": 2
  }
}
```

`skippedContacts` conta gli ID mancanti, non tuoi o privi di numero di telefono: la stima copre solo i restanti, quindi un valore diverso da zero significa che l'invio reale raggiungerà meno contatti di quelli selezionati.

### Invia il batch

Invia il modello a ogni contatto nell'elenco, risolvendo eventuali variabili intelligenti per contatto e addebitando i crediti per ogni invio.

`POST /whatsapp-templates/{templateId}/bulk-send`

| Campo | Obbligatorio | Descrizione |
|---|---|---|
| `contactIds` | Sì | Contatti a cui inviare, fino a 5000 per chiamata. |

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/whatsapp-templates/template_abc123/bulk-send?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "contactIds": ["contact123", "contact456"] }'
```

**JavaScript**

```javascript
const res = await fetch(
  "https://api.youraiconnector.com/v1/whatsapp-templates/template_abc123/bulk-send",
  {
    method: "POST",
    headers: {
      "X-API-Key": "YOUR_API_KEY",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ contactIds: ["contact123", "contact456"] }),
  }
);
const data = await res.json();
```

**Python**

```python
import requests

res = requests.post(
    "https://api.youraiconnector.com/v1/whatsapp-templates/template_abc123/bulk-send",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={"contactIds": ["contact123", "contact456"]},
)
data = res.json()
```

**Risposta**

```json
{
  "success": true,
  "data": { "sent": 118, "failed": 2, "total": 120 }
}
```

Un contatto che fallisce (non trovato, non presente nel tuo account o errore di invio) viene ignorato e conteggiato in `failed` invece di interrompere il batch. Un `contactIds` vuoto, più di 5000 ID su un invio (500 su una stima) o un `templateId` mancante restituiscono `400`.

---

## Riprova un messaggio fallito

Due endpoint per rispedire un messaggio fallito, senza creare un nuovo record di messaggio o spendere nuovamente crediti.

`POST /whatsapp-templates/messages/{contactId}/{messageId}/retry-template` riprova specificamente un messaggio modello fallito: risolve nuovamente il contenuto del modello dalla campagna se il messaggio fallito non lo contiene già. Solo i messaggi con stato `failed` e tipo `template` possono essere riprovati in questo modo.

`POST /whatsapp-templates/messages/{contactId}/{messageId}/retry` è indipendente dal canale e funziona per qualsiasi messaggio non basato su modello fallito (ad esempio WhatsApp Web), inviandolo al percorso di spedizione corretto in base al canale del messaggio. Accetta lo stato `failed`, `failed_connection`, `limit_exceeded` o `queued_retry`.

Nessuno dei due endpoint richiede un corpo della richiesta.

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/whatsapp-templates/messages/contact123/msg_abc789/retry-template?apiKey=YOUR_API_KEY"
```

**JavaScript**

```javascript
const res = await fetch(
  "https://api.youraiconnector.com/v1/whatsapp-templates/messages/contact123/msg_abc789/retry-template",
  { method: "POST", headers: { "X-API-Key": "YOUR_API_KEY" } }
);
const data = await res.json();
```

**Python**

```python
import requests

res = requests.post(
    "https://api.youraiconnector.com/v1/whatsapp-templates/messages/contact123/msg_abc789/retry-template",
    headers={"X-API-Key": "YOUR_API_KEY"},
)
data = res.json()
```

**Risposta**

```json
{
  "success": true,
  "data": "Message retry initiated successfully"
}
```

Per la versione indipendente dal canale, sostituisci il percorso con `.../msg_abc789/retry`. Un messaggio il cui stato non è idoneo per il riinvio, o (sull'endpoint del modello) che non è un messaggio modello, restituisce `400`. Un contatto o un messaggio mancante restituisce `404`.

---

## Profilo WhatsApp Business

Gestisci il profilo WhatsApp Business (informazioni, indirizzo, descrizione, email, siti web, categoria aziendale e logo) mostrato ai contatti su WhatsApp. Funziona sia su una connessione gestita che su un account che esegue il proprio WhatsApp Business Account.

### Salva il profilo

`PUT /whatsapp-templates/profile`

| Campo | Obbligatorio | Descrizione |
|---|---|---|
| `phoneNumber` | Sì | Il numero WhatsApp a cui appartiene questo profilo. Deve essere connesso al tuo account. |
| `about` | No | Breve testo "Informazioni" mostrato sul profilo. |
| `address` | No | Indirizzo aziendale. |
| `description` | No | Descrizione aziendale più lunga. |
| `email` | No | Email di contatto mostrata sul profilo. |
| `websites` | No | Array di URL di siti web. Ognuno deve essere un URL valido. |
| `vertical` | No | Categoria aziendale, ad esempio `Retail` o `Professional Services`. |
| `profilePictureHandle` | No | L'handle restituito dall'endpoint di caricamento immagini sottostante, per impostare la foto del profilo. |

**cURL**

```bash
curl -X PUT "https://api.youraiconnector.com/v1/whatsapp-templates/profile?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "phoneNumber": "+31612345678",
    "about": "We reply within a few hours",
    "email": "support@example.com",
    "websites": ["https://example.com"]
  }'
```

**JavaScript**

```javascript
const res = await fetch("https://api.youraiconnector.com/v1/whatsapp-templates/profile", {
  method: "PUT",
  headers: {
    "X-API-Key": "YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    phoneNumber: "+31612345678",
    about: "We reply within a few hours",
    email: "support@example.com",
    websites: ["https://example.com"],
  }),
});
const data = await res.json();
```

**Python**

```python
import requests

res = requests.put(
    "https://api.youraiconnector.com/v1/whatsapp-templates/profile",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={
        "phoneNumber": "+31612345678",
        "about": "We reply within a few hours",
        "email": "support@example.com",
        "websites": ["https://example.com"],
    },
)
data = res.json()
```

**Risposta**

```json
{
  "success": true,
  "data": "WhatsApp Business profile updated successfully"
}
```

Un `phoneNumber` mancante, un URL di sito web non valido o un `phoneNumber` non connesso al tuo account restituisce `400` o `404`.

### Carica un'immagine del profilo

Scarica un'immagine da un URL fornito e la carica su WhatsApp, restituendo un handle. Passa quell'handle come `profilePictureHandle` nella chiamata di salvataggio del profilo sopra per impostarla come foto: questo endpoint carica solo l'immagine, non la imposta autonomamente.

`POST /whatsapp-templates/profile/picture`

| Campo | Obbligatorio | Descrizione |
|---|---|---|
| `phoneNumber` | Sì | Il numero WhatsApp a cui appartiene questo profilo. |
| `fileUrl` | Sì | Un URL pubblicamente raggiungibile dell'immagine da caricare. |

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/whatsapp-templates/profile/picture?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "phoneNumber": "+31612345678",
    "fileUrl": "https://example.com/logo.png"
  }'
```

**JavaScript**

```javascript
const res = await fetch("https://api.youraiconnector.com/v1/whatsapp-templates/profile/picture", {
  method: "POST",
  headers: {
    "X-API-Key": "YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    phoneNumber: "+31612345678",
    fileUrl: "https://example.com/logo.png",
  }),
});
const data = await res.json();
```

**Python**

```python
import requests

res = requests.post(
    "https://api.youraiconnector.com/v1/whatsapp-templates/profile/picture",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={
        "phoneNumber": "+31612345678",
        "fileUrl": "https://example.com/logo.png",
    },
)
data = res.json()
```

**Risposta**

```json
{
  "success": true,
  "data": "1234567890123456"
}
```

`data` è l'handle dell'immagine caricata. Un `phoneNumber` o `fileUrl` mancante, o un `phoneNumber` senza token di accesso WhatsApp archiviato, restituisce `400`; un `fileUrl` non raggiungibile o non valido restituisce un errore che descrive il motivo per cui il download non è riuscito.

---

## Controlla lo stato di un mittente

Esegue il polling (e aggiorna) lo stato di invio in tempo reale di un numero WhatsApp connesso con il provider di messaggistica. Utile per confermare che un numero sia effettivamente in grado di inviare messaggi prima di farvi affidamento.

`GET /whatsapp-templates/sender-status/{phoneNumber}`

**cURL**

```bash
curl "https://api.youraiconnector.com/v1/whatsapp-templates/sender-status/+31612345678" \
  -H "X-API-Key: YOUR_API_KEY"
```

**JavaScript**

```javascript
const res = await fetch(
  "https://api.youraiconnector.com/v1/whatsapp-templates/sender-status/+31612345678",
  { headers: { "X-API-Key": "YOUR_API_KEY" } }
);
const data = await res.json();
```

**Python**

```python
import requests

res = requests.get(
    "https://api.youraiconnector.com/v1/whatsapp-templates/sender-status/+31612345678",
    headers={"X-API-Key": "YOUR_API_KEY"},
)
data = res.json()
```

**Risposta**

```json
{
  "success": true,
  "data": "ONLINE"
}
```

`data` è uno tra `ONLINE` (invio normale), `PENDING` (ancora in fase di verifica) o `DELETED` (il provider non riconosce più questo mittente: riconnetti il numero). Un `phoneNumber` senza informazioni aziendali WhatsApp archiviate restituisce `404`.

---

## Genera modelli di follow-up con l'IA

La piattaforma può scrivere per te i modelli di follow-up WhatsApp di una campagna — i solleciti inviati quando una conversazione si interrompe — basandosi sulle istruzioni e sull'obiettivo della campagna stessa. Esiste un endpoint di lavoro che viene eseguito in background, oltre a tre endpoint più datati mantenuti per le integrazioni esistenti. Tutti utilizzano crediti IA.

### Avvia un lavoro di generazione

`POST /campaigns/{campaignId}/template-generation`

| Campo | Obbligatorio | Descrizione |
|---|---|---|
| `type` | No | `all` (l'impostazione predefinita) scrive l'intero set di follow-up. `cold_only` scrive solo i messaggi per i contatti che non hanno mai risposto. |

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/campaigns/campaign_abc123/template-generation?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "type": "all" }'
```

**JavaScript**

```javascript
const res = await fetch(
  "https://api.youraiconnector.com/v1/campaigns/campaign_abc123/template-generation",
  {
    method: "POST",
    headers: {
      "X-API-Key": "YOUR_API_KEY",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ type: "all" }),
  }
);
const data = await res.json();
```

**Python**

```python
import requests

res = requests.post(
    "https://api.youraiconnector.com/v1/campaigns/campaign_abc123/template-generation",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={"type": "all"},
)
data = res.json()
```

**Risposta** (`202`)

```json
{ "success": true, "campaign_id": "campaign_abc123", "type": "all" }
```

La chiamata restituisce una risposta non appena il lavoro viene messo in coda. Leggi la campagna (`GET /campaigns/{campaignId}`, vedi l'[API Campagne](campaigns.md)) e monitora il suo oggetto `template_generation_status` finché non termina:

| Campo | Descrizione |
|---|---|
| `status` | `processing` mentre il lavoro è in esecuzione, poi `completed` o `failed`. |
| `progress` | Da 0 a 100. |
| `current_template`, `total_templates` | Quanti modelli sono stati scritti finora, rispetto a quanti ne scriverà il lavoro — 11 per una campagna in uscita o combinata, 9 altrimenti. |
| `error` | Il motivo per cui un lavoro `failed` si è interrotto, ad esempio crediti insufficienti. |
| `started_at`, `completed_at` | Quando il lavoro è iniziato e terminato. |

I modelli generati vengono salvati nella campagna come qualsiasi altro, quindi appaiono in [Elenco modelli](#list-templates) e devono comunque passare attraverso l'approvazione di WhatsApp prima di poter essere inviati. Un `400` significa che `type` era diverso da `all` o `cold_only`; un `404` significa che la campagna non esiste o appartiene a un altro account.

Gli Agenti hanno una versione gemella di questa chiamata, `POST /agents/{agentId}/template-generation`, che scrive i follow-up per un Agente e termina durante la chiamata nel caso tipico — vedi [Genera messaggi di follow-up](agents.md#generate-follow-up-messages) nell'API Agenti IA.

### Gli endpoint di generazione precedenti

Tre endpoint precedenti svolgono lo stesso lavoro e sono mantenuti affinché le integrazioni esistenti continuino a funzionare. Il nuovo codice dovrebbe utilizzare l'endpoint di lavoro sopra indicato.

| Endpoint | Cosa fa |
|---|---|
| `POST /whatsapp-templates/campaign/{campaignId}/generate-async` | Avvia la generazione del follow-up per la campagna in background e restituisce `202` con `{ "success": true, "data": { "result": "success", "message": "..." } }`. I crediti vengono addebitati in anticipo (saltato su un account che utilizza la propria chiave IA) e l'oggetto `template_generation_status` della campagna riporta il progresso esattamente come sopra. |
| `POST /whatsapp-templates/campaign/{campaignId}/generate-followups` | Genera tutti e nove i modelli di follow-up durante la chiamata — per una campagna creata prima dell'esistenza dei follow-up automatici, o una che necessita di essere riscritta — e restituisce `200` con `templatesGenerated` all'interno di `data`. |
| `POST /whatsapp-templates/agent/{agentId}/generate-followups` | La stessa generazione sincrona gestita dall'Agente. La risposta aggiunge `agent_id`, `campaign_id` e `target`: `"campaign"` quando i modelli sono stati scritti sulla campagna dell'Agente, `"agent"` (con `campaign_id: null`) quando l'Agente non ha una campagna e sono stati memorizzati sull'Agente stesso. Un Agente mancante o esterno è un `404`. |

Tutti e tre richiedono i follow-up automatici sull'account e crediti sufficienti — un `400` indica quale manca — e la coppia indirizzata alla campagna restituisce `403` quando la campagna appartiene a un altro account.

---

## Errori dell'API dei template

Gli endpoint dei template restituiscono il formato di errore standard:

```json
{
  "success": false,
  "error": "Template not found"
}
```

Un `404` su questi endpoint solitamente significa che la risorsa non è stata trovata: o non esiste o appartiene a un altro account. Alcuni endpoint (la creazione/aggiornamento con ambito campagna e gli invii a un contatto esistente) restituiscono invece `403` quando la campagna o il contatto appartengono a qualcun altro anziché non esistere affatto. Alcuni endpoint includono anche un campo `error_code` che rispecchia lo stato HTTP. I codici condivisi che ogni endpoint può restituire — `400`, `401`, `403` (il tuo piano non include l'accesso API), `429` (limite di frequenza) e `500` — sono elencati con indicazioni sui tentativi in [Errori e impaginazione](errors-and-pagination.md).

---

## Passaggi successivi

- [Autenticazione](authentication.md) — i quattro modi per autenticare una richiesta.
- [Errori e limiti di frequenza](errors-and-pagination.md) — codici di stato e il limite di 300 richieste/min.
- [API Campagne](campaigns.md) — gestisci le campagne a cui sono allegati i modelli.
