---
title: "Endpoint webhook"
description: "Gestisci più URL webhook con segreti e filtri degli eventi per ogni endpoint."
---

Il sistema di webhook basato su endpoint ti consente di registrare **più**
destinazioni per organizzazione, ciascuna con il proprio segreto, il proprio
stato e la propria sottoscrizione a un sottoinsieme di tipi di evento. Questo è
il modello consigliato per tutte le nuove integrazioni.

Confrontalo con il [webhook legacy a URL singolo](/api-reference/organizations#legacy-single-url-webhook),
mantenuto per la compatibilità con le versioni precedenti ma con supporto per un solo URL per
organizzazione.

## Endpoint

| Metodo | Percorso | Ruolo richiesto | Descrizione |
|--------|------|---------------|-------------|
| `GET` | `/v1/developer/webhook-endpoints` | `admin+` | Elenca gli endpoint |
| `POST` | `/v1/developer/webhook-endpoints` | `admin+` | Crea un endpoint |
| `PATCH` | `/v1/developer/webhook-endpoints/{endpoint_id}` | `admin+` | Aggiorna etichetta / URL / eventi / stato |
| `DELETE` | `/v1/developer/webhook-endpoints/{endpoint_id}` | `admin+` | Elimina un endpoint |
| `POST` | `/v1/developer/webhook-endpoints/{endpoint_id}/rotate-secret` | `admin+` | Sostituisce il segreto di firma |
| `POST` | `/v1/developer/webhook-endpoints/{endpoint_id}/test` | `admin+` | Invia una consegna di test firmata |
| `GET` | `/v1/developer/webhook-deliveries` | `admin+` | Esamina i risultati recenti delle consegne degli endpoint e delle consegne legacy |

## Oggetto endpoint

```json
{
  "id": "c4d5e6f7-...",
  "label": "Production — Call events",
  "url": "https://example.com/thunderphone/hook",
  "events": ["telephony.incoming", "telephony.complete"],
  "status": "active",
  "agent_id": 42,
  "agent_name": "Support Agent",
  "secret_hint": "a1b2…9f0e",
  "paused_at": null,
  "pause_last_error": "",
  "pause_undelivered_count": null,
  "created_at": "2026-04-20T18:24:10.113Z",
  "updated_at": "2026-04-20T18:24:10.113Z"
}
```

| Campo | Tipo | Descrizione |
|-------|------|-------------|
| `id` | UUID | ID dell'endpoint |
| `label` | string | Nome visualizzato, 1–120 caratteri |
| `url` | string | URL HTTPS; `http://localhost` consentito per lo sviluppo |
| `events` | array di string | Tipi di evento sottoscritti (vedi [valori validi](#valid-event-types)). Un array vuoto sottoscrive a tutti gli eventi tranne gli eventi espliciti per turno (`telephony.turn` / `web.turn`) |
| `status` | string | `active`, `disabled` (messo in pausa manualmente) o `failing` (impostato automaticamente quando una consegna esaurisce il programma di tentativi di 24 h senza un singolo 2xx) |
| `agent_id` | integer \| null | Agente a cui è limitato questo endpoint; `null` indica l'intera organizzazione |
| `agent_name` | string \| null | Nome dell'agente limitato, oppure `null` per un endpoint a livello di organizzazione |
| `secret_hint` | string | Primi 4 e ultimi 4 caratteri del segreto di firma con un'ellissi (`a1b2…9f0e`): sufficienti per confrontare il segreto salvato localmente senza esporre il valore completo |
| `paused_at` | timestamp \| null | Quando ThunderPhone ha impostato l'endpoint su `failing`. `null` quando è `active` o `disabled` |
| `pause_last_error` | string | L'ultimo errore di consegna quando l'endpoint è stato messo in pausa, ad esempio `HTTP 503: Service Unavailable`. Vuoto salvo se è `failing` |
| `pause_undelivered_count` | integer \| null | Eventi non consegnati dall'ultima consegna riuscita dell'endpoint, conteggiati quando è stato messo in pausa |
| `created_at`, `updated_at` | timestamp | |

<Note>
  Il `secret` completo dell'endpoint viene restituito **una sola volta** al momento della creazione e
  mai più. Conservalo in modo sicuro: se lo perdi,
  [ruotalo](#rotate-the-signing-secret) per ottenerne uno nuovo.
</Note>

### Tipi di evento validi

`events` viene convalidato rispetto a questo set esatto: i valori al di fuori dell'elenco
restituiscono `400`. Consulta il [catalogo degli eventi](/it/webhooks/events) per la struttura
del payload di ogni tipo.

- `telephony.incoming`, `telephony.complete`, `telephony.tool`, `telephony.turn`
- `web.incoming`, `web.complete`, `web.tool`, `web.turn`
- `sms.sent`, `sms.failed`
- `sms.received` (riservato; non ancora emesso)
- `call.graded`, `call.data_extracted`, `call.transfer_completed`
- `campaign.completed`
- `issue.reported`, `issue.escalated`
- `test-call.completed`
- `alert.triggered`

`issue.escalated` non ha alcun contesto agente e viene inviato solo agli
endpoint a livello di organizzazione.

`voice.ready` e `voice.failed` non possono essere selezionati esplicitamente. Per riceverli,
crea un endpoint a livello di organizzazione con `events: []`. Un elenco di eventi vuoto
riceve ogni evento supportato tranne `telephony.turn` e `web.turn`,
che devono essere selezionati esplicitamente.

### Stati dell'endpoint

- `active` — le consegne avvengono normalmente.
- `disabled` — messo in pausa manualmente tramite `PATCH`. Non vengono inviate richieste. Non modifichiamo mai lo stato di un endpoint `disabled`; decidere di riportarlo a `active` spetta sempre a te.
- `failing` — impostato automaticamente quando una consegna all'endpoint esaurisce l'intero programma di nuovi tentativi (8 tentativi in 24 ore) senza mai ricevere un 2xx. Un endpoint in stato di errore non riceve ulteriore traffico. In questo caso inviamo un'email ai proprietari e agli amministratori della tua organizzazione e la dashboard mostra l'endpoint in pausa con un pulsante **Riattiva**. Una volta corretto l'endpoint, riporta il suo stato a `active` tramite `PATCH`; le consegne il cui programma di nuovi tentativi non è ancora terminato riprendono dal punto in cui si erano interrotte.

---

## Elenca endpoint

<CodeGroup>
```bash cURL
curl https://api.thunderphone.com/v1/developer/webhook-endpoints \
  -H "Authorization: Bearer sk_live_YOUR_API_KEY"
```
</CodeGroup>

Restituisce un array di [oggetti endpoint](#endpoint-object).
Passa `?agent_id=42` per restituire solo gli endpoint associati a quell'agente.

### Endpoint con ambito agente

Gli endpoint a livello di organizzazione ricevono ogni evento corrispondente. Un endpoint con
`agent_id` riceve solo gli eventi corrispondenti per le chiamate gestite da quell'agente;
gli eventi senza contesto agente, come `alert.triggered`, non lo raggiungono mai. Puoi
anche creare e gestire questi endpoint dalla sezione
**Webhook** del builder dell'agente.

---

## Crea un endpoint

<CodeGroup>
```bash cURL
curl -X POST https://api.thunderphone.com/v1/developer/webhook-endpoints \
  -H "Authorization: Bearer sk_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "label":  "Production — Call events",
    "url":    "https://example.com/thunderphone/hook",
    "events": ["telephony.incoming", "telephony.complete"]
  }'
```

```python Python
result = requests.post(
    "https://api.thunderphone.com/v1/developer/webhook-endpoints",
    headers={"Authorization": "Bearer sk_live_YOUR_API_KEY"},
    json={
        "label":  "Production — Call events",
        "url":    "https://example.com/thunderphone/hook",
        "events": ["telephony.incoming", "telephony.complete"],
    },
).json()
secret = result["secret"]
endpoint_id = result["id"]
```
</CodeGroup>

### Campi della richiesta

| Campo | Tipo | Obbligatorio | Descrizione |
|-------|------|----------|-------------|
| `label` | string | sì | 1–120 caratteri |
| `url` | string | sì | URL HTTPS (`http` consentito solo per `localhost` / `127.0.0.1`) |
| `events` | array | no | Se vuoto o omesso, effettua l'iscrizione a tutti gli eventi tranne `telephony.turn` / `web.turn`, che richiedono un'iscrizione esplicita. Devi usare i valori elencati in [Tipi di evento validi](#valid-event-types); i duplicati vengono rimossi |
| `agent_id` | integer \| null | no | Limita la consegna a un agente in questa organizzazione; ometti il campo o usa `null` per un endpoint valido per l'intera organizzazione |

Restituisce `201 Created` con l'[oggetto Endpoint](#endpoint-object) più
un campo `secret` aggiuntivo al livello superiore contenente la chiave di firma non elaborata: una
stringa esadecimale di 48 caratteri:

```json
{
  "id": "c4d5e6f7-…",
  "label": "Production — Call events",
  "url": "https://example.com/thunderphone/hook",
  "events": ["telephony.incoming", "telephony.complete"],
  "status": "active",
  "secret_hint": "a1b2…9f0e",
  "created_at": "2026-04-20T18:24:10.113Z",
  "updated_at": "2026-04-20T18:24:10.113Z",
  "secret": "a1b2c37e08d94f5b16a2c8d90e7f3a4b5c6d7e8f90a19f0e"
}
```

<Warning>
  `secret` viene restituito **solo alla creazione**. Le risposte `GET` successive
  includono solo `secret_hint`. Copia il valore completo nel tuo gestore dei segreti
  prima di chiudere la risposta.
</Warning>

---

## Aggiorna un endpoint

<CodeGroup>
```bash cURL
curl -X PATCH https://api.thunderphone.com/v1/developer/webhook-endpoints/c4d5e6f7-... \
  -H "Authorization: Bearer sk_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "label":  "Production — Call + Grade events",
    "events": ["telephony.incoming", "telephony.complete", "call.graded"]
  }'
```
</CodeGroup>

| Campo | Tipo | Descrizione |
|-------|------|-------------|
| `label` | string | |
| `url` | string | |
| `events` | array | |
| `status` | string | `active` o `disabled`. Imposta `active` per riattivare un endpoint contrassegnato dal server come `failing` |
| `agent_id` | integer \| null | Imposta un ID agente per limitare l'endpoint oppure `null` per renderlo valido per l'intera organizzazione |

Restituisce `200 OK` con l'[oggetto Endpoint](#endpoint-object) aggiornato.

---

## Ruota il segreto di firma

Sostituisci il segreto di firma di un endpoint, ad esempio quando è stato smarrito o
potrebbe essere stato divulgato. Per un endpoint con ambito agente puoi usare anche la
dashboard: apri la sezione **Webhook** dell'agente e seleziona
**Rigenera segreto** sull'endpoint. Gli endpoint a livello di organizzazione vengono
ruotati tramite l'API.

<CodeGroup>
```bash cURL
curl -X POST https://api.thunderphone.com/v1/developer/webhook-endpoints/c4d5e6f7-.../rotate-secret \
  -H "Authorization: Bearer sk_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'
```
</CodeGroup>

| Campo | Tipo | Obbligatorio | Descrizione |
|-------|------|----------|-------------|
| `include_copies` | booleano | no | Valore predefinito `true`. Assegna inoltre il nuovo segreto agli altri endpoint della tua organizzazione che hanno lo stesso URL e lo stesso segreto corrente, ad esempio copie di questo endpoint su altri agenti, in modo che un unico ricevitore continui a verificare con un solo segreto |

Restituisce `200 OK`:

```json
{
  "endpoint": { "id": "c4d5e6f7-...", "secret_hint": "7f3a…c21d", "...": "..." },
  "secret": "7f3a90b2c4d5e6f708192a3b4c5d6e7f8091a2b3c4d5c21d",
  "rotated_endpoint_ids": ["c4d5e6f7-..."]
}
```

| Campo | Tipo | Descrizione |
|-------|------|-------------|
| `endpoint` | oggetto | L'[oggetto Endpoint](#endpoint-object) con il nuovo `secret_hint` |
| `secret` | stringa | Il nuovo segreto di firma. Restituito solo in questa risposta |
| `rotated_endpoint_ids` | array di UUID | Ogni endpoint che ora utilizza il nuovo segreto |

<Warning>
  Il vecchio segreto smette di essere utilizzato immediatamente: la consegna successiva,
  inclusi i tentativi, viene firmata con quello nuovo. Finché il tuo ricevitore non dispone
  del nuovo segreto, le consegne non superano il controllo della firma; se risponde
  con uno stato non 2xx, vengono ritentate secondo la normale pianificazione di 24 h,
  quindi aggiorna tempestivamente il ricevitore. Se il tuo ricevitore viene distribuito
  in fasi, configuralo per accettare entrambi i segreti durante la distribuzione — gli helper
  di verifica dell'SDK accettano un elenco di segreti (vedi
  [Verifica le firme dei webhook](/it/guides/verify-webhook-signatures)).
</Warning>

---

## Invia una consegna di test

Invia un evento sintetico `webhook.test` a un endpoint utilizzando la normale
pipeline di consegna, inclusa la serializzazione JSON canonica, entrambe le
intestazioni di firma, la registrazione della consegna e la gestione dei tentativi.
Il test è indirizzato all'endpoint selezionato indipendentemente dal relativo filtro `events`.

<CodeGroup>
```bash cURL
curl -X POST https://api.thunderphone.com/v1/developer/webhook-endpoints/c4d5e6f7-.../test \
  -H "Authorization: Bearer sk_live_YOUR_API_KEY"
```
</CodeGroup>

L'endpoint riceve un envelope simile a questo:

```json
{
  "data": {
    "message": "ThunderPhone webhook test",
    "sent_at": "2026-07-17T20:12:34.567890+00:00"
  },
  "event_id": "2ad6507c-7d19-4498-9b2d-7e8f944ab5a1",
  "type": "webhook.test"
}
```

L'API restituisce `200 OK` dopo il primo tentativo, anche se la destinazione
restituisce un errore. Esamina `success`, `status`, `response_code` e `error`
per verificare l'esito della consegna:

```json
{
  "success": true,
  "event_id": "2ad6507c-7d19-4498-9b2d-7e8f944ab5a1",
  "event_type": "webhook.test",
  "status": "delivered",
  "response_code": 204,
  "error": ""
}
```

`webhook.test` è sintetico e non può essere aggiunto all'iscrizione `events`
di un endpoint. Se il primo tentativo non riesce, ThunderPhone lo ritenta una volta
circa un minuto dopo e poi si interrompe; la consegna mostra quindi `status: "failed"`
in [Debug delle consegne](#debug-deliveries). Una consegna di test non contrassegna mai
l'endpoint come `failing`.

Per configurare un trigger in base alla struttura di un evento reale, passa un
`event_type` facoltativo. La consegna rimane sintetica e contiene `"sample": true`;
gli esempi relativi alle chiamate usano `call_id: 0` e `agent_id: 0`.

```bash
curl -X POST https://api.thunderphone.com/v1/developer/webhook-endpoints/c4d5e6f7-.../test \
  -H "Authorization: Bearer sk_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"event_type":"call.graded"}'
```

`event_type` accetta qualsiasi valore tra i [Tipi di evento validi](#valid-event-types).
Ometterlo mantiene il comportamento generico di `webhook.test`.

---

## Elimina un endpoint

<CodeGroup>
```bash cURL
curl -X DELETE https://api.thunderphone.com/v1/developer/webhook-endpoints/c4d5e6f7-... \
  -H "Authorization: Bearer sk_live_YOUR_API_KEY"
```
</CodeGroup>

Restituisce `204 No Content`. La consegna all'URL si interrompe immediatamente;
i tentativi in corso vengono annullati.

---

## Debug delle consegne

Prima di concludere che un webhook non sia stato inviato, esamina
[`GET /v1/developer/webhook-deliveries`](/api-reference/webhook-deliveries).
Mostra i tentativi recenti di entrambi i sistemi webhook, inclusi l'ID della chiamata,
l'origine dell'URL, lo stato HTTP, il numero di tentativi, la categoria di errore consentita
e l'orario del prossimo tentativo. Non restituisce mai il payload dell'evento, la trascrizione,
il testo dell'errore memorizzato, il corpo della risposta o il percorso dell'URL.

Puoi visualizzare la stessa cronologia recente anche in **Agenti → seleziona un agente → Webhook →
Consegne recenti**. Le righe mostrano l'etichetta dell'endpoint e l'origine dell'URL utilizzata dall'ultimo
tentativo. Si tratta di uno stato operativo, non di un registro di audit immutabile: l'eliminazione di un endpoint
elimina anche le relative righe di consegna.

Per un `404` di n8n, verifica innanzitutto che il workflow sia attivo, accetti `POST` e utilizzi
l'URL webhook di produzione anziché l'URL di test. Un `401` o `403` indica un problema di
autenticazione o di convalida della firma; i timeout indicano latenza o disponibilità della destinazione;
gli errori TLS indicano la catena di certificati, il nome host o la scadenza.

---

## Correlati

<CardGroup cols={2}>
  <Card title="Catalogo degli eventi" icon="list" href="/it/webhooks/events">
    L'elenco completo dei valori `events` a cui puoi iscriverti.
  </Card>
  <Card title="Panoramica dei webhook" icon="bolt" href="/it/webhooks/overview">
    Verifica della firma e semantica di consegna.
  </Card>
</CardGroup>
