DOCUMENTI/Webhook~ 8 MIN DI LETTURA

EVENTS · HMAC · POST

EasyLiveChat ti chiama
nel momento in cui succede qualcosa.

I webhook sono il canale push di EasyLiveChat — invece di interrogare la nostra API a intervalli, ci dai un URL e noi POSTiamo ogni evento rilevante entro un secondo dal verificarsi. Ogni richiesta è firmata con HMAC-SHA256 in modo che il tuo server possa dimostrare che proviene davvero da noi.

§ 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.

  • URLDeve essere https:// e risolvere a un IP pubblico. Rifiutiamo indirizzi loopback, privati e di metadati cloud sia in fase di creazione che di consegna.
  • EventiScegli 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.
  • SecretGenerato 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", 200

curl (debugging)

# Recompute the signature locally and compare with the header.
echo -n "$RAW_BODY" | openssl dgst -sha256 -hmac "$WEBHOOK_SECRET"

timingSafeEqual / hmac.compare_digestusa 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.

EventoSi attiva quandoForma dei dati
message.createdUn 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.updatedLo stato di una conversazione (OPEN · SNOOZED · CLOSED) o il suo assignedAgentId cambia.{ conversationId, status?, assignedAgentId? }
audit.eventOgni 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.testClicchi 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.