§ 00Cosa sono i webhook
Quando succede qualcosa dal lato EasyLiveChat — un cliente scrive nel tuo widget, un agente chiude una conversazione, avviene un'azione rilevante per l'audit — facciamo un POST HTTPS in uscita verso ogni URL che hai registrato. Il body è JSON e contiene il payload completo dell'evento, così il tuo server reagisce senza polling.
Pensalo come l'immagine speculare dell'API REST. L'API permette al tuo codice di raggiungere EasyLiveChat. I webhook permettono a EasyLiveChat di raggiungere il tuo codice. La maggior parte delle integrazioni usa entrambi.
Ogni endpoint registrato ha il proprio secret. Firmiamo ogni body con HMAC-SHA256 usando quel secret e inviamo il digest hex nell'header x-easylivechat-signature. Il tuo server ricalcola l'HMAC con lo stesso secret e confronta — match significa che la richiesta è davvero nostra, mismatch significa scartarla.
§ 01Disponibilità per piano
Gli endpoint webhook possono essere creati in ogni piano a pagamento e durante la prova gratuita di 14 giorni. Nessuna fatturazione per evento — il fan-out su più endpoint è incluso.
Lo stream audit.event è solo Enterprise, controllato dall'entitlement auditWebhookExport. message.created e conversation.updated scattano in ogni piano che consente l'accesso API.
§ 02Configurare un endpoint
Aggiungi un endpoint in https://app.livechattools.com/settings/webhooks. Genereremo un secret casuale per endpoint e te lo mostreremo una sola volta alla creazione. Trattalo come una password — copialo subito nel secret store del tuo server.
- URL — Deve essere https:// e risolvere a un IP pubblico. Rifiutiamo indirizzi loopback, privati e di metadati cloud sia in fase di creazione che di consegna.
- Eventi — Scegli nomi di eventi specifici o iscriviti a * (tutti gli eventi). I wildcard sono comodi per i prototipi, ma elenchi di eventi più stretti rendono il tuo handler più facile da ragionare.
- Secret — Generato automaticamente, mostrato una volta. Usato per firmare ogni consegna. Se lo perdi, elimina l'endpoint e creane uno nuovo — non c'è percorso di recupero.
Attivo per impostazione predefinita. Puoi revocare un endpoint in qualsiasi momento dalla stessa pagina — le consegne si fermano all'istante.
§ 03Forma del payload
Ogni consegna è un POST con content-type: application/json. Gli header identificano l'evento e portano la firma; l'envelope del body è sempre { event, deliveredAt, data }:
POST https://your-server.example.com/webhook
content-type: application/json
user-agent: EasyLiveChat-Webhooks/1.0
x-easylivechat-event: message.created
x-easylivechat-signature: sha256=<hex>
{
"event": "message.created",
"deliveredAt": "2026-05-27T08:55:25.841Z",
"data": {
"conversationId": "cmp...",
"message": {
"id": "cmp...",
"body": "Hi!",
"senderType": "CUSTOMER",
"createdAt": "2026-05-27T08:55:25.840Z"
}
}
}event è lo stesso valore dell'header x-easylivechat-event. La forma di data varia per evento — vedi il catalogo eventi sotto.
§ 04Verifica la firma
Chiunque conosca l'URL del tuo endpoint può POSTarci spazzatura. La firma HMAC è il modo per distinguere le nostre richieste da quelle contraffatte. Ricomputala con il tuo secret e rifiuta la richiesta in caso di mismatch.
Leggi i byte grezzi del body (NON fare json.parse prima — riserializzare riordinerà le chiavi e romperà l'hash). Rimuovi il prefisso sha256= dall'header. Calcola HMAC-SHA256(rawBody, secret) e confronta in modo timing-safe con l'hex ricevuto.
Node.js
import crypto from 'node:crypto';
import express from 'express';
const SECRET = process.env.WEBHOOK_SECRET;
const app = express();
app.use(express.raw({ type: 'application/json' }));
app.post('/webhook', (req, res) => {
const received = (req.header('x-easylivechat-signature') || '').replace(/^sha256=/, '');
const expected = crypto.createHmac('sha256', SECRET).update(req.body).digest('hex');
const ok =
received.length === expected.length &&
crypto.timingSafeEqual(Buffer.from(received, 'hex'), Buffer.from(expected, 'hex'));
if (!ok) return res.status(401).send('bad signature');
const event = JSON.parse(req.body.toString('utf8'));
// handle event.event, event.data...
res.status(200).send('ok');
});Python (Flask)
import hmac, hashlib, os
from flask import Flask, request, abort
SECRET = os.environ["WEBHOOK_SECRET"].encode()
app = Flask(__name__)
@app.post("/webhook")
def webhook():
received = request.headers.get("x-easylivechat-signature", "").removeprefix("sha256=")
expected = hmac.new(SECRET, request.get_data(), hashlib.sha256).hexdigest()
if not hmac.compare_digest(received, expected):
abort(401)
event = request.get_json()
# handle event["event"], event["data"]...
return "ok", 200curl (debugging)
# Recompute the signature locally and compare with the header. echo -n "$RAW_BODY" | openssl dgst -sha256 -hmac "$WEBHOOK_SECRET"
timingSafeEqual / hmac.compare_digest — usa sempre un confronto a tempo costante in modo che gli attaccanti non possano sondare il secret byte per byte.
§ 05Catalogo eventi
Oggi la piattaforma scatena quattro tipi di evento. Ne aggiungiamo altri man mano che le funzionalità arrivano — iscriviti a * se vuoi compatibilità futura.
| Evento | Si attiva quando | Forma dei dati |
|---|---|---|
| message.created | Un nuovo messaggio arriva su una conversazione, indipendentemente da chi l'ha mandato (cliente in entrata, agente in uscita, invio via API REST). | { conversationId, message } |
| conversation.updated | Lo stato di una conversazione (OPEN · SNOOZED · CLOSED) o il suo assignedAgentId cambia. | { conversationId, status?, assignedAgentId? } |
| audit.event | Ogni volta che viene scritta una riga di audit-log — login agente, cambio ruolo, integrazione creata, chiave revocata, ecc. (Piano Enterprise.) | { action, entity, entityId, actorId, metadata } |
| webhook.test | Clicchi su "Test" in Impostazioni → Webhook. Firmato e formato esattamente come un evento reale. | { tenantId, test: true } |
Iscriviti a * per ricevere ogni evento attuale e futuro. Iscriviti a nomi specifici se vuoi limitare ciò che il tuo handler deve conoscere.
§ 06Testa l'integrazione
Il pulsante "Test" in Impostazioni → Webhook lancia un evento webhook.test al tuo endpoint e riporta lo stato HTTP upstream e il tempo trascorso. Usalo per validare il tuo handler prima di puntare traffico reale.
Il payload di test usa esattamente lo stesso envelope, gli stessi nomi di header e lo stesso schema HMAC degli eventi di produzione — se la tua verifica passa per webhook.test, passerà per message.created e tutto il resto.
§ 07Retry e timeout
Diamo al tuo server 10 secondi per rispondere. Qualsiasi stato non-2xx o errore di rete è un fallimento. Le consegne fallite vengono ritentate fino a 5 volte con backoff esponenziale a partire da 2 secondi, così un endpoint instabile ha più possibilità prima che rinunciamo a quell'evento.
Non garantiamo consegna exactly-once — con flapping di rete lo stesso evento può arrivare due volte. Rendi il tuo handler idempotente: deduplica su data.message.id interno (o l'id sensato per quell'evento).
§ 08Checklist sicurezza
- Usa sempre https:// — gli endpoint http:// puri sono rifiutati alla creazione.
- Blocchiamo IP privati, loopback e di metadati cloud sia in creazione che in consegna, così un record DNS mal configurato non può essere usato per fare pivoting nella tua rete.
- Confronta le firme con un equal timing-safe (Node crypto.timingSafeEqual, Python hmac.compare_digest, Go hmac.Equal).
- Ruota eliminando l'endpoint e creandone uno nuovo con lo stesso URL. Aggiorna il tuo secret store in modo atomico.