# Webhook di fine chiamata

> A fine telefonata l'agente vocale manda al tuo server un JSON firmato con i dati della chiamata, il contatto e le informazioni estratte.

Pagina: https://supportfast.ai/it/guida/sviluppatori/webhook-fine-chiamata/ · Sezione: Sviluppatori · Aggiornata il 30 ottobre 2026

## A cosa serve

Con il webhook di fine chiamata puoi:

- salvare ogni chiamata, con esito e riepilogo, nel tuo CRM o gestionale;
- aprire una pratica o un ticket con i dati che l'agente ha raccolto;
- passare la chiamata a Zapier o Make, e da lì a centinaia di app.

**La chiamata finisce** — L'analisi prepara esito, riepilogo e dati estratti. → **SupportFast invia** — Una richiesta POST con il JSON, firmata con la tua chiave. → **Il tuo server riceve** — Controlla la firma, risponde e salva i dati.

> **Prima di iniziare**
>
> - La funzione «Webhook di fine chiamata» del piano.
> - Un indirizzo HTTPS raggiungibile da Internet che accetti richieste POST e risponda entro 10 secondi.

## Attivarlo

1. **Apri il passo Post Chiamata**
   Nell'agente vocale vai in Profilo Agente › Modifica Profilo › Post Chiamata: è il quarto passo della configurazione. Ci arrivi anche dal riepilogo del Profilo Agente, con il pulsante dell'area Azioni Post Chiamata, che si chiama Modifica, o Configura se l'area è ancora da impostare.

2. **Accendi il webhook**
   Nel riquadro Webhook attiva Attiva il webhook e scrivi l'URL webhook, che deve iniziare con `https://`.

3. **Scegli le opzioni**
   Invia solo per chiamate completate, acceso di serie, manda il webhook solo per le chiamate riuscite, spiegate [più sotto](https://supportfast.ai/it/guida/sviluppatori/webhook-fine-chiamata.md#quando-parte). Includi URL della registrazione audio, acceso di serie, aggiunge il link dell'audio. Se la registrazione è spenta nel passo Generali, il link resta vuoto.

4. **Salva e copia la chiave**
   Premi Salva modifiche: la chiave viene creata in quel momento. Nel riquadro Chiave Segreta Webhook (Secret HMAC) premi Mostra la chiave o Copia la chiave e mettila nella configurazione del tuo server.

Con Rigenera la chiave ne crei una nuova. La conferma avvisa che «Le firme fatte con la chiave attuale non saranno più valide: aggiorna il sistema che riceve il webhook.». Lettura e rigenerazione valgono subito, senza salvare.

![Passo Post Chiamata dell'agente vocale: webhook acceso con l'URL https://www.esempio.it/webhook/fine-chiamata, le opzioni Invia solo per chiamate completate e Includi URL della registrazione accese, e la chiave segreta nascosta con Mostra, Copia e Rigenera.](https://supportfast.ai/_astro/05-webhook-fine-chiamata.8TSAhlpP.webp)

_Nel passo Post Chiamata accendi il webhook, scrivi l’URL e copia la chiave segreta._

## Quando parte

Il webhook parte dopo l'analisi di fine chiamata: esito, riepilogo, sentiment e variabili estratte sono già pronti nel JSON.

Una chiamata è **riuscita** quando qualcuno ha risposto e ha detto almeno una parola, oppure quando è stata trasferita a un collega. Una segreteria, o una risposta senza parole, non conta. È la stessa definizione di [Chiamate: elenco e dettaglio](https://supportfast.ai/it/guida/agente-vocale/chiamate.md#chiamata-riuscita), e nel JSON corrisponde a `call.reached` uguale a `true`.

- Con Invia solo per chiamate completate acceso, il webhook parte solo per le chiamate riuscite, comprese le trasferite: nonostante il nome, non conta lo stato «Completata».
- Con l'opzione spenta parte per ogni chiamata conclusa, anche mai risposta o finita in segreteria. In quei casi `call.reached` vale `false` e `call.endReason` dice perché la chiamata si è chiusa.

## Cosa riceve il tuo server

Una richiesta `POST` con il corpo in JSON e questi header:

| Header | Valore |
| --- | --- |
| `Content-Type` | `application/json` |
| `X-Webhook-Signature` | `sha256=` seguito dalla firma HMAC SHA-256 del corpo, in esadecimale. |
| `X-Webhook-Call-Id` | L'identificativo della chiamata, lo stesso di `call.id`. |

**JSON · esempio con dati di prova**

```
{
  "call": {
    "customerNumber": "+390212345678",
    "agentNumber": "+390612345678",
    "direction": "inbound",
    "startedAt": "19/10/2026 10:12",
    "endedAt": "19/10/2026 10:15",
    "duration": "3 min 5 s",
    "reached": true,
    "result": "appointment_booked",
    "resultText": "Il cliente ha prenotato un tagliando.",
    "sentiment": "positive",
    "summary": "Mario Rossi chiede un tagliando. L'agente propone giovedì 22 ottobre alle 9:30 e il cliente accetta.",
    "transcript": "AI: Buongiorno, Officina Rossi, come posso aiutarla?\n\nHUMAN: Vorrei prenotare un tagliando.",
    "transferName": null,
    "recordingUrl": "https://www.esempio.it/registrazione-di-esempio.mp3",
    "appointment": {
      "startsAt": "22/10/2026 09:30",
      "calendarName": "Tagliando",
      "startsAtIso": "2026-10-22T07:30:00.000Z",
      "uid": "prenotazione-esempio-123"
    },
    "variables": { "nome_cliente": "Mario Rossi", "targa": "AB123CD" },
    "id": "chiamata-esempio-001",
    "conversationId": "conversazione-esempio-001",
    "status": "ended",
    "endReason": "agent_endcall",
    "errorDetail": null,
    "durationSec": 185,
    "startedAtIso": "2026-10-19T08:12:04.000Z",
    "endedAtIso": "2026-10-19T08:15:09.000Z"
  },
  "messages": [
    { "role": "assistant", "content": "Buongiorno, Officina Rossi, come posso aiutarla?" },
    { "role": "user", "content": "Vorrei prenotare un tagliando." }
  ],
  "contact": {
    "fullName": "Mario Rossi",
    "email": "mario.rossi@esempio.it",
    "phone": "+390212345678"
  },
  "event": "telephone.ended",
  "variables": { "nome_cliente": "Mario Rossi", "targa": "AB123CD" }
}
```

- **`event` (Testo)**: Sempre `telephone.ended`.

- **`call` (Oggetto)**: I dati della chiamata, con gli stessi nomi delle variabili `{{call.*}}`: cosa contiene ogni campo è in [Dati della chiamata](https://supportfast.ai/it/guida/automazioni/variabili.md#chiamata). I campi leggibili sono nel fuso del workspace; quelli con `Iso` sono date in UTC. I campi in codice hanno questi valori:

- `direction`: `inbound` o `outbound`;
- `reached`: `true` se la chiamata è riuscita, come spiegato in [Quando parte](https://supportfast.ai/it/guida/sviluppatori/webhook-fine-chiamata.md#quando-parte), altrimenti `false`;
- `result`: `resolved`, `unresolved`, `abandoned`, `appointment_booked`, `transferred`, `no_interaction`, `no_answer`, `voicemail` o `spam`;
- `sentiment`: `positive`, `neutral` o `negative`;
- `status`: `ended`, `failed` o `transferred`;
- `endReason`, il motivo di chiusura: `agent_endcall` (chiusa dall'agente), `user_hangup` (riagganciata dal cliente), `timeout` (durata massima raggiunta), `silence_timeout` (silenzio prolungato), `transfer` (trasferita), `voicemail` (segreteria telefonica), `no_answer` (nessuna risposta), `busy` (occupato), `rejected` (rifiutata), `invalid_number` (numero non valido), `blocked` (bloccata dalla compagnia telefonica), `sip_error` (errore di linea) o `error` (errore tecnico).

  La durata si conta dalla risposta, senza lo squillo: per una chiamata mai risposta `durationSec` vale 0 e `duration` è vuoto.

- **`messages` (Lista)**: La conversazione, messaggio per messaggio: `role` vale `assistant` per l'agente e `user` per il cliente.

- **`contact` (Oggetto o null)**: Nome completo, email e telefono del contatto. È `null` quando alla chiamata non è legato un contatto, per esempio se chi chiama ha il numero nascosto.

- **`variables` (Oggetto)**: Le variabili estratte dalla chiamata, con i nomi che hai scelto in Estrazione Dati e Variabili. Vuoto se l'estrazione è spenta. Lo stesso oggetto è anche in `call.variables`.

Un dato che manca arriva `null` o vuoto: per esempio l'appuntamento, se non è stato preso, o il link dell'audio, se nessuno ha risposto o la registrazione non è ancora pronta.

## Verificare la firma

La firma ti dice che la richiesta arriva davvero da SupportFast e non è stata modificata. Calcola l'HMAC SHA-256 del corpo con la chiave segreta, sul testo così come lo ricevi e prima di trasformarlo in oggetto: anche uno spazio diverso cambia la firma. Scrivilo in esadecimale con davanti `sha256=` e confrontalo con l'header `X-Webhook-Signature`.

**Node.js con Express**

```
const crypto = require("crypto");
const express = require("express");

const app = express();
const SEGRETO = process.env.SUPPORTFAST_WEBHOOK_SECRET;

app.post("/webhook/fine-chiamata", express.raw({ type: "application/json" }), (req, res) => {
  const ricevuta = req.get("X-Webhook-Signature") || "";
  const attesa = "sha256=" + crypto.createHmac("sha256", SEGRETO).update(req.body).digest("hex");
  const valida = ricevuta.length === attesa.length &&
    crypto.timingSafeEqual(Buffer.from(ricevuta), Buffer.from(attesa));
  if (!valida) return res.sendStatus(401);

  res.sendStatus(200);
  const dati = JSON.parse(req.body.toString("utf8"));
  // salva dati.call, dati.contact e dati.variables nel tuo gestionale
});

app.listen(3000);
```

**PHP**

```
<?php
$segreto = getenv('SUPPORTFAST_WEBHOOK_SECRET');
$corpo = file_get_contents('php://input');
$ricevuta = $_SERVER['HTTP_X_WEBHOOK_SIGNATURE'] ?? '';
$attesa = 'sha256=' . hash_hmac('sha256', $corpo, $segreto);

if (!hash_equals($attesa, $ricevuta)) {
    http_response_code(401);
    exit;
}

http_response_code(200);
$dati = json_decode($corpo, true);
// salva $dati['call'], $dati['contact'] e $dati['variables'] nel tuo gestionale
```

## Se il tuo server non risponde

- Se la connessione non riesce, se passano i 10 secondi o se rispondi con un codice `5xx`, riprova dopo 1, 3 e 10 secondi. In tutto, al massimo quattro invii.
- Con un codice `4xx` non riprova.
- Non segue i reindirizzamenti: un codice `3xx` conta come errore e non si ritenta.
- Non invia a indirizzi interni o privati, solo a server raggiungibili da Internet.
- Dopo l'ultimo tentativo l'invio si ferma. La chiamata resta comunque nella pagina Chiamate dell'agente.

> **Consiglio**
>
> **Rispondi subito, lavora dopo.** Rispondi `200` appena hai verificato la firma e fai dopo le operazioni lente. Per non salvare due volte la stessa chiamata dopo un nuovo tentativo, controlla `X-Webhook-Call-Id`.

## Come provarlo

1. **Prepara chi riceve**
   Usa il tuo server o un indirizzo di prova che ti mostri le richieste in arrivo, come quelli di Zapier o Make. Mettilo in URL webhook e salva.

2. **Fai una chiamata vera**
   Chiama l'agente dal tuo cellulare, parla qualche secondo e chiudi. Con Invia solo per chiamate completate acceso, una chiamata in cui non dici nulla non fa partire il webhook.

3. **Controlla cosa è arrivato**
   Dopo l'analisi di fine chiamata arriva la richiesta. Verifica la firma e controlla i campi che ti servono.

## Con Zapier, Make o il tuo gestionale

In **Zapier** usa il trigger *Catch Hook* dell'app *Webhooks by Zapier*; in **Make** il modulo *Custom webhook*. Copia l'indirizzo che ti danno in URL webhook: dopo la prima chiamata i campi del JSON sono disponibili nei passi successivi. Questi strumenti non verificano la firma da soli: tieni riservato l'indirizzo.

Per il tuo **gestionale** chiedi al fornitore se ha un indirizzo adatto, o fallo preparare a uno sviluppatore con l'esempio qui sopra.

## In alternativa: un'automazione sugli eventi di telefonia

Se ti servono solo alcuni dati, o vuoi mandarli in più posti, usa un'automazione con un evento della categoria Telefonia, come Chiamata terminata. Con il nodo API chiami il tuo server con i campi che scegli; con gli altri nodi mandi un'email o un WhatsApp.

|   | Webhook di fine chiamata | Automazione |
| --- | --- | --- |
| Dove si imposta | Nel passo Post Chiamata dell'agente vocale, riquadro Webhook | Nelle automazioni del workspace |
| Dati inviati | Sempre tutti, nello stesso JSON | Quelli che scegli tu |
| Quando parte | A fine chiamata, anche per le trasferite | All'evento scelto: Chiamata terminata non parte per le trasferite |
| Sicurezza | Firma HMAC con la chiave | Gli header che imposti nel nodo API |
| Consumi | Nessuna esecuzione | Ogni partenza conta nelle esecuzioni del mese |
| Piano | «Webhook di fine chiamata» | Le automazioni e, per il nodo API, «API e webhook» |

Vedi [Eventi di partenza (trigger)](https://supportfast.ai/it/guida/automazioni/trigger.md) e [Chiamare un'API esterna](https://supportfast.ai/it/guida/sviluppatori/chiamate-api.md).

## Domande frequenti

**La firma non corrisponde mai.**

Controlla di usare la chiave attuale e che la firma sia in esadecimale minuscolo, con davanti `sha256=`. Il calcolo è spiegato in [Verificare la firma](https://supportfast.ai/it/guida/sviluppatori/webhook-fine-chiamata.md#firma).

**Posso mandare i dati a più indirizzi?**

Il webhook ha un solo indirizzo per agente. Per più destinazioni passa da Zapier o Make, oppure usa un'automazione.

## Leggi anche

- [Post Chiamata: dati, email, webhook](https://supportfast.ai/it/guida/agente-vocale/post-chiamata.md): Le variabili da estrarre e l'email di riepilogo.

- [Cosa puoi collegare](https://supportfast.ai/it/guida/sviluppatori/panoramica.md): Tutti i collegamenti per sviluppatori.
