
# API dei Webhook

I webhook consentono alla piattaforma di notificare i tuoi altri sistemi nel momento in cui accade qualcosa: un nuovo contatto, una risposta, un appuntamento prenotato e altro ancora. Questa API gestisce le **sottoscrizioni** stesse: quali URL ricevono quali eventi. Per sapere come ricevere e verificare i payload che il tuo endpoint ottiene, consulta [Webhook](../integrations/webhooks.md).

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 qui utilizzano l'intestazione `X-API-Key` (e una forma di parametro di query per cURL).

::: note
**Nota:** I webhook devono essere abilitati per il tuo account. In caso contrario, questi endpoint restituiranno un `403`.
:::


---

## Come vengono indirizzate le sottoscrizioni

Ogni sottoscrizione ha un `id` e un `name` opzionale. Entrambi possono essere utilizzati come `{webhookId}` nel percorso per aggiornare, eliminare, testare, verificare lo stato e riabilitare.

> **Preferisci il nome.** Gli ID delle sottoscrizioni sono posizionali, quindi possono cambiare dopo l'eliminazione di un'altra sottoscrizione. Se imposti un `name` stabile durante la creazione di una sottoscrizione, indirizzala tramite il nome per evitare sorprese.

---

## Elenca le sottoscrizioni

`GET /webhooks`

**cURL**

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

**JavaScript**

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

**Python**

```python
import requests

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

**Risposta**

```json
{
  "success": true,
  "webhooks": [
    {
      "id": "0",
      "name": "Order updates hook",
      "url": "https://hooks.example.com/incoming",
      "subscribed_to": ["Contact Created", "Replies"],
      "subscribed_to_tags": [],
      "created_at": "2026-06-09T12:00:00.000Z",
      "signing_enabled": true,
      "signing_secret_created_at": "2026-07-15T09:30:00.000Z",
      "retries_enabled": true,
      "enabled": true,
      "apply_to_sub_accounts": false
    }
  ]
}
```

`signing_enabled` e `retries_enabled` sono opzioni attivabili per abbonamento, entrambe disattivate a meno che non vengano abilitate. Vedi [Payload firmati](#signed-payloads) e [Tentativi di invio](#retries).

`apply_to_sub_accounts` è l'opzione di ereditarietà dell'agenzia: vedi [Un unico abbonamento per tutti gli account cliente](#one-subscription-for-all-client-accounts-agencies). Disattivata per impostazione predefinita e inerte sugli account che non hanno account cliente.

`enabled` è l'interruttore di accensione/spegnimento dell'abbonamento: vedi [Disattivazione di un abbonamento](#switching-a-subscription-off). Gli abbonamenti disattivati rimangono elencati qui.

Il segreto di firma non viene mai incluso qui: leggilo da [`GET /webhooks/{id}/signing-secret`](#read-the-signing-secret).

---

## Elenca i tipi di evento sottoscrivibili

Restituisce le stringhe esatte che puoi utilizzare in `subscribed_to`. Usalo per scoprire i nomi degli eventi validi invece di inserirli nel codice.

`GET /webhooks/events`

**cURL**

```bash
curl "https://api.youraiconnector.com/v1/webhooks/events" \
  -H "X-API-Key: YOUR_API_KEY"
```

**JavaScript**

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

**Python**

```python
import requests

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

**Risposta**

La risposta è `{"success": true, "events": [...]}`, dove `events` contiene attualmente 22 stringhe esatte: Contact Created, Human Alerted, Appointment Booked, Replies, Reads, Deliveries, Credits Spent, Credits Recharged, Low Credit Balance, Contact Paused, Contact Do Not Disturb, Contact Unarchived, New Message, Contact Resumed, Chat Concluded, Task Created, Task Updated, Task Completed, Daily Summary Created, Channel Connected, Broadcast Started e Broadcast Completed (Channel Connected è accettato in `subscribed_to` ma al momento non viene emesso da nulla, quindi non basare nulla su di esso).

Per il significato di ogni evento e il codice `event` inviato nel payload, vedi [I 22 eventi webhook](../integrations/webhooks.md#the-22-webhook-events). Questo endpoint è l'elenco autorevole in ogni momento: leggilo in tempo reale invece di codificare i nomi in modo rigido.

---

## Crea una sottoscrizione

`POST /webhooks`

| Campo | Obbligatorio | Descrizione |
|---|---|---|
| `url` | Sì | URL HTTPS che riceverà i payload degli eventi tramite `POST`. Deve essere raggiungibile pubblicamente. |
| `subscribed_to` | Sì | Un array non vuoto di nomi di eventi (vedi `/webhooks/events`). |
| `name` | No | Un nome visualizzato. Utilizzabile anche come `{webhookId}` in seguito. Per impostazione predefinita è un nome con timestamp. |
| `subscribed_to_tags` | No | ID dei tag che restringono quali tag producono una notifica di riepilogo della conversazione. Non limita gli eventi dell'abbonamento a tali tag: per ricevere una richiesta quando viene applicato un tag specifico, imposta un URL webhook su quel tag nella scheda **Tag** dell'agente (o della campagna). |
| `retries_enabled` | No | Booleano, predefinito `false`. Consente di attivare i [tentativi](#retries) per le consegne non riuscite. |
| `generate_signing_secret` | No | Booleano, predefinito `false`. Crea un [segreto di firma](#signed-payloads) HMAC con l'abbonamento. Il segreto viene restituito una volta, come `signing_secret` di primo livello nella risposta. |
| `enabled` | No | Booleano, predefinito `true`. Passa `false` per creare l'abbonamento disattivato. Vedi [Disattivazione di un abbonamento](#switching-a-subscription-off). |
| `apply_to_sub_accounts` | No | Booleano, predefinito `false`. Su un account agenzia, `true` fa sì che questo abbonamento riceva anche eventi da ogni account cliente: vedi [Un unico abbonamento per tutti gli account cliente](#one-subscription-for-all-client-accounts-agencies). |

> **Regole URL:** L'URL deve utilizzare `https://` ed essere raggiungibile pubblicamente. `http://` semplice, `localhost`, indirizzi di rete privata e indirizzi interni alla piattaforma vengono rifiutati con un `400`.

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/webhooks?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://hooks.example.com/incoming",
    "subscribed_to": ["Contact Created", "Replies"],
    "name": "Order updates hook"
  }'
```

**JavaScript**

```javascript
const res = await fetch("https://api.youraiconnector.com/v1/webhooks", {
  method: "POST",
  headers: {
    "X-API-Key": "YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    url: "https://hooks.example.com/incoming",
    subscribed_to: ["Contact Created", "Replies"],
    name: "Order updates hook",
  }),
});
const data = await res.json();
```

**Python**

```python
import requests

res = requests.post(
    "https://api.youraiconnector.com/v1/webhooks",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={
        "url": "https://hooks.example.com/incoming",
        "subscribed_to": ["Contact Created", "Replies"],
        "name": "Order updates hook",
    },
)
data = res.json()
```

**Risposta**

```json
{
  "success": true,
  "webhook_id": "1",
  "webhook": {
    "id": "1",
    "name": "Order updates hook",
    "url": "https://hooks.example.com/incoming",
    "subscribed_to": ["Contact Created", "Replies"],
    "subscribed_to_tags": [],
    "created_at": "2026-06-09T12:00:00.000Z"
  }
}
```

---

## Aggiornare una sottoscrizione

Fornisci almeno uno tra `url`, `subscribed_to`, `name`, `subscribed_to_tags`, `retries_enabled`, `enabled` o `apply_to_sub_accounts`. I campi omessi mantengono i loro valori correnti. `subscribed_to` e `subscribed_to_tags` sono sostituzioni, non unioni.

`PUT /webhooks/{webhookId}`

> L'aggiornamento di un abbonamento non altera mai il suo segreto di firma: gestiscilo tramite le [rotte del segreto di firma](#signed-payloads).

> Quando l'URL cambia, la consegna per il nuovo URL viene riabilitata automaticamente, offrendo a un endpoint precedentemente non funzionante un nuovo inizio.

**cURL**

```bash
curl -X PUT "https://api.youraiconnector.com/v1/webhooks/Order%20updates%20hook" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://hooks.example.com/v2/incoming",
    "subscribed_to": ["Replies", "Chat Concluded"]
  }'
```

**JavaScript**

```javascript
const res = await fetch(
  `https://api.youraiconnector.com/v1/webhooks/${encodeURIComponent("Order updates hook")}`,
  {
    method: "PUT",
    headers: {
      "X-API-Key": "YOUR_API_KEY",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      url: "https://hooks.example.com/v2/incoming",
      subscribed_to: ["Replies", "Chat Concluded"],
    }),
  }
);
const data = await res.json();
```

**Python**

```python
import requests

res = requests.put(
    "https://api.youraiconnector.com/v1/webhooks/Order updates hook",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={
        "url": "https://hooks.example.com/v2/incoming",
        "subscribed_to": ["Replies", "Chat Concluded"],
    },
)
data = res.json()
```

**Risposta**

```json
{
  "success": true,
  "webhook_id": "0",
  "webhook": {
    "id": "0",
    "name": "Order updates hook",
    "url": "https://hooks.example.com/v2/incoming",
    "subscribed_to": ["Replies", "Chat Concluded"],
    "subscribed_to_tags": [],
    "created_at": "2026-06-09T12:00:00.000Z"
  }
}
```

Un ID o un nome sconosciuto restituisce `404` con `{ "success": false, "error": "Webhook not found" }`.

---

## Eliminare una sottoscrizione

Rimuove la sottoscrizione in modo che il suo URL smetta di ricevere payload. I suoi contatori di integrità della consegna vengono azzerati, quindi riaggiungere lo stesso URL in seguito inizierà con un record pulito.

`DELETE /webhooks/{webhookId}`

**cURL**

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

**JavaScript**

```javascript
const res = await fetch("https://api.youraiconnector.com/v1/webhooks/0", {
  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/webhooks/0",
    headers={"X-API-Key": "YOUR_API_KEY"},
)
data = res.json()
```

**Risposta**

```json
{
  "success": true
}
```

---

## Inviare un payload di test

Invia un payload di esempio all'URL della sottoscrizione in modo da poter verificare il ricevitore end-to-end. Facoltativamente, passare un `event` per controllare quale tipo di evento il campione simula. Le consegne di test non influiscono mai sui contatori di integrità della sottoscrizione.

`POST /webhooks/{webhookId}/test`

La risposta restituisce sempre `200` e riporta l'esito con un flag `delivered`: un test fallito **non** restituisce uno stato di errore. Quando `delivered` è `false`, la risposta include i dettagli dell'errore.

| Campo | Obbligatorio | Descrizione |
|---|---|---|
| `event` | No | Tipo di evento da simulare (deve essere uno tra `/webhooks/events`). Il valore predefinito è un evento di consegna. |

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/webhooks/0/test?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "event": "Contact Created" }'
```

**JavaScript**

```javascript
const res = await fetch("https://api.youraiconnector.com/v1/webhooks/0/test", {
  method: "POST",
  headers: {
    "X-API-Key": "YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ event: "Contact Created" }),
});
const data = await res.json();
```

**Python**

```python
import requests

res = requests.post(
    "https://api.youraiconnector.com/v1/webhooks/0/test",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={"event": "Contact Created"},
)
data = res.json()
```

**Risposta** (consegnata)

```json
{
  "success": true,
  "webhook_id": "0",
  "delivered": true
}
```

**Risposta** (fallita)

```json
{
  "success": true,
  "webhook_id": "0",
  "delivered": false,
  "failure_type": "permanent",
  "status_code": 404,
  "error_message": "Request failed with status code 404"
}
```

`failure_type` è uno tra `permanent`, `temporary`, `timeout`, `network` o `unknown`.

---

## Verifica lo stato della consegna

Restituisce il record dello stato della consegna per l'URL della sottoscrizione: quante consegne sono riuscite e quante sono fallite, se la consegna è attualmente in pausa dopo ripetuti errori e i dettagli dell'ultimo errore. Restituisce `"health": null` quando non è ancora stato tentato alcun invio.

`GET /webhooks/{webhookId}/health`

**cURL**

```bash
curl "https://api.youraiconnector.com/v1/webhooks/0/health" \
  -H "X-API-Key: YOUR_API_KEY"
```

**JavaScript**

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

**Python**

```python
import requests

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

**Risposta**

```json
{
  "success": true,
  "webhook_id": "0",
  "url": "https://hooks.example.com/incoming",
  "health": {
    "consecutive_failures": 0,
    "total_failures": 2,
    "total_successes": 120,
    "is_disabled": false,
    "disabled_at": null,
    "disabled_reason": null,
    "last_failure": null,
    "last_success_at": "2026-06-09T12:00:00.000Z",
    "created_at": "2026-05-01T08:00:00.000Z",
    "updated_at": "2026-06-09T12:00:00.000Z"
  }
}
```

Quando `is_disabled` è `true`, la consegna all'URL è stata sospesa automaticamente dopo ripetuti errori. Correggi il tuo ricevitore, quindi riabilitalo (qui sotto).

---

## Riabilita la consegna

Riprende la consegna per un webhook il cui URL è stato sospeso automaticamente dopo ripetuti errori. Questo resetta il flag di sospensione e i contatori degli errori, ma **non** tenta una consegna: utilizza l'endpoint di test in seguito per confermare che il tuo ricevitore sia di nuovo funzionante.

`POST /webhooks/{webhookId}/reenable`

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/webhooks/0/reenable?apiKey=YOUR_API_KEY"
```

**JavaScript**

```javascript
const res = await fetch("https://api.youraiconnector.com/v1/webhooks/0/reenable", {
  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/webhooks/0/reenable",
    headers={"X-API-Key": "YOUR_API_KEY"},
)
data = res.json()
```

**Risposta**

```json
{
  "success": true,
  "webhook_id": "0"
}
```

---

## Disattivazione di un abbonamento

`enabled` è l'interruttore di accensione/spegnimento dell'abbonamento. Disattivarlo interrompe le consegne mantenendo intatti l'URL, l'elenco degli eventi e il segreto di firma.

```bash
# Off
curl -X PUT "https://api.youraiconnector.com/v1/webhooks/0?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"enabled": false}'

# Back on
curl -X PUT "https://api.youraiconnector.com/v1/webhooks/0?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"enabled": true}'
```

- **L'assenza indica che è attivo.** Un abbonamento creato prima dell'esistenza di questo campo non ha alcun valore `enabled` memorizzato e viene consegnato normalmente. `GET /webhooks` riporta sempre un booleano concreto.
- Gli abbonamenti disattivati sono **ancora elencati** da `GET /webhooks`: è così che li trovi per riattivarli.
- Un [tentativo](#retries) in coda prima della disattivazione non riprende: il tentativo rilegge l'abbonamento al momento dell'invio e viene eliminato se è disattivato.
- Nulla di ciò che è stato soppresso durante la disattivazione viene riprodotto quando lo riattivi.

> Distinto dalla disattivazione automatica dopo ripetuti errori, che viene segnalata da [`GET /webhooks/{id}/health`](#check-delivery-health) come `is_disabled` e cancellata con [`POST /webhooks/{id}/reenable`](#re-enable-delivery). `enabled` è l'interruttore dell'account; `is_disabled` è il nostro. Nessuno dei due prevale sull'altro: un abbonamento deve essere sia attivo che non disattivato automaticamente per essere consegnato.

---

## Un unico abbonamento per tutti gli account cliente (agenzie)

Su un account agenzia, imposta `apply_to_sub_accounts: true` su un abbonamento (al momento della creazione o tramite `PUT`) e questo riceverà anche gli eventi che si verificano su ognuno degli account cliente dell'agenzia: un unico endpoint copre l'intera agenzia, invece di dover ricreare l'abbonamento su ogni account cliente.

```bash
curl -X PUT "https://api.youraiconnector.com/v1/webhooks/0?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"apply_to_sub_accounts": true}'
```

Come funziona:

- **Il blocco `user` distingue gli account.** Il blocco `user` di ogni payload identifica l'account su cui si è effettivamente verificato l'evento, in modo che il ricevitore possa instradare per cliente.
- **Le impostazioni dell'abbonamento dell'agenzia si applicano ovunque.** Il suo elenco di eventi, il [segreto di firma](#signed-payloads) e l'opzione di [riprova](#retries) vengono utilizzati anche per le consegne ereditate.
- **L'abbonamento dell'account cliente allo stesso URL ha la precedenza.** Se un account cliente ha il proprio abbonamento che punta allo stesso URL, quello viene utilizzato per gli eventi di tale account: lo stesso evento non viene mai consegnato due volte allo stesso endpoint.
- **Gli account cliente non lo vedono.** Gli abbonamenti ereditati non compaiono nell'elenco webhook dell'account cliente e il cliente non può disattivarli: solo l'agenzia li gestisce.
- **L'integrità della consegna viene monitorata per account cliente.** Un endpoint che continua a fallire viene disabilitato automaticamente per l'account le cui consegne non sono riuscite, non per l'intera agenzia.
- **`subscribed_to_tags` non viene ereditato.** L'elenco dei tag fa riferimento ai tag dell'agenzia, che non esistono sugli account cliente: la restrizione del riepilogo della conversazione si applica solo agli eventi dell'agenzia.
- **Inerte altrove.** Su un account senza account cliente, il flag viene memorizzato correttamente ma non esegue alcuna azione.

---

## Intestazioni su ogni consegna

Queste tre intestazioni vengono inviate su ogni consegna, indipendentemente dal fatto che la sottoscrizione sia firmata o meno:

| Intestazione | Significato |
|---|---|
| `X-Webhook-Delivery` | ID stabile per l'evento logico. Identico tra i tentativi: usalo per la deduplicazione. |
| `X-Webhook-Attempt` | Numero del tentativo (basato su 1). |
| `X-Webhook-Event` | Il nome dell'evento. |

---

## Payload firmati

La firma è facoltativa, disattivata per impostazione predefinita e impostata per ogni sottoscrizione. Quando una sottoscrizione ha un segreto di firma, ogni consegna include due intestazioni aggiuntive oltre alle tre inviate su ogni consegna (`X-Webhook-Delivery`, `X-Webhook-Attempt` e `X-Webhook-Event`):

| Intestazione | Significato |
|---|---|
| `X-Webhook-Signature` | `v1=<hex>`: HMAC-SHA256 della stringa `"<timestamp>.<raw request body>"`, codificata con il segreto di firma per webhook che crei e ruoti su `GET/POST/DELETE /v1/webhooks/{webhookId}/signing-secret`. |
| `X-Webhook-Timestamp` | Ora di invio, in secondi Unix. Vincolata alla firma, quindi non può essere alterata indipendentemente. |

Per verificare, ricalcola l'HMAC-SHA256 sul corpo grezzo (raw body) con il tuo segreto e confrontalo con l'intestazione. Verifica rispetto al corpo della richiesta **grezzo**. La riesecuzione della serializzazione del JSON analizzato modifica i byte e interrompe il confronto. Rifiuta le consegne il cui timestamp è al di fuori di una finestra di freschezza (300 secondi è un valore predefinito ragionevole) per prevenire il replay e confronta con una funzione a tempo costante (timing-safe).

Vedi [Payload firmati](../integrations/webhooks.md#signed-payloads-verifying-a-webhook-really-came-from-us) per esempi completi di verifica in Node e Python.

> **La firma non è la stessa cosa dell'autenticazione API.** L'API REST stessa si autentica con chiavi API anziché con OAuth (OAuth 2.1 esiste per i server MCP che registri come strumenti bot) e non esistono ancora pacchetti SDK ufficiali per npm o PyPI: chiama gli endpoint con qualsiasi client HTTP.

### Leggi il segreto di firma

`GET /webhooks/{id}/signing-secret`

```bash
curl "https://api.youraiconnector.com/v1/webhooks/0/signing-secret?apiKey=YOUR_API_KEY"
```

**Risposta**

```json
{
  "success": true,
  "webhook_id": "0",
  "signing_enabled": true,
  "signing_secret": "whsec_1a2b3c...",
  "signing_secret_created_at": "2026-07-15T09:30:00.000Z"
}
```

Quando la firma è disattivata, `signing_enabled` è `false` e `signing_secret` è `null`.

### Genera o ruota il segreto di firma

`POST /webhooks/{id}/signing-secret`

Crea un segreto (attivando la firma) o sostituisce quello esistente. Restituisce il nuovo segreto.

```bash
curl -X POST "https://api.youraiconnector.com/v1/webhooks/0/signing-secret?apiKey=YOUR_API_KEY"
```

**Risposta**

```json
{
  "success": true,
  "webhook_id": "0",
  "signing_enabled": true,
  "signing_secret": "whsec_9f8e7d...",
  "signing_secret_created_at": "2026-07-15T10:00:00.000Z"
}
```

La rotazione ha effetto immediato: la consegna successiva viene firmata solo con il nuovo segreto. Accetta brevemente entrambi i segreti mentre distribuisci la modifica a un endpoint attivo.

Puoi anche generare un segreto al momento della creazione passando `"generate_signing_secret": true` a `POST /webhooks`; la risposta includerà quindi un campo `signing_secret` di primo livello.

### Disattiva la firma

`DELETE /webhooks/{id}/signing-secret`

```bash
curl -X DELETE "https://api.youraiconnector.com/v1/webhooks/0/signing-secret?apiKey=YOUR_API_KEY"
```

**Risposta**

```json
{
  "success": true,
  "webhook_id": "0",
  "signing_enabled": false
}
```

> Tutte e tre le rotte per il segreto di firma richiedono l'autorizzazione **edit** per le integrazioni, incluso `GET`: il segreto è una credenziale che può falsificare le consegne, quindi non viene esposto ai ruoli di sola lettura.

---

## Riprova

Opzionale, disattivato per impostazione predefinita e impostato per sottoscrizione tramite il booleano `retries_enabled` su `POST /webhooks` o `PUT /webhooks/{id}`.

```bash
curl -X PUT "https://api.youraiconnector.com/v1/webhooks/0?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"retries_enabled": true}'
```

Quando abilitata, una consegna fallita viene riprovata a **1m, 5m, 30m e 2h** dopo il primo tentativo (circa 2h40m di copertura).

- **Riprovato:** risposte 5xx, timeout e errori di connessione.
- **Non riprovato:** qualsiasi 4xx. Il ricevente sta rifiutando la richiesta stessa, quindi riprodurla invariata non farebbe altro che riprodurre il rifiuto.

I tentativi rendono possibile la consegna duplicata: un endpoint che ha elaborato un evento ma è andato in timeout prima di rispondere lo vedrà di nuovo. Esegui la deduplicazione su `X-Webhook-Delivery`, che è costante tra i tentativi. Ecco perché i tentativi sono opzionali.

I contatori [delivery-health](#check-delivery-health) conteggiano un'intera consegna, non ogni tentativo: un errore viene registrato solo una volta esauriti tutti i tentativi, quindi abilitare le riprove non fa scattare prima la disabilitazione automatica.

---

## Errori

Tutti gli errori utilizzano il formato standard:

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

Casi comuni: un URL non consentito, un `subscribed_to` vuoto/non valido o campi mancanti restituiscono `400`; un ID o un nome sconosciuto restituisce `404`; e un `403` indica che i webhook non sono abilitati per il tuo account. Consulta [Errori](errors-and-pagination.md) per l'elenco completo.

---

## Passaggi successivi

- [Webhooks (ricezione dei payload)](../integrations/webhooks.md) — configura il tuo ricevitore e comprendi la struttura del payload.
- [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.
