Webhook
Inoltra gli eventi del tuo tenant verso un sistema esterno (CRM, gestionale, data warehouse) con firma HMAC e retry automatico.
I webhook ti permettono di ricevere notifiche in tempo reale quando succede qualcosa nel tuo tenant SmartCQ. Sono utili se hai un CRM o un gestionale già in uso e vuoi mantenerlo allineato con quello che SmartCQ osserva (un contatto si è disiscritto, una campagna è completata, ecc.).
Quando usarli
- Hai un CRM esterno: vuoi che si aggiorni quando un contatto cambia stato email (bounce, unsubscribe, segnalazione spam).
- Hai una dashboard custom o un data warehouse: vuoi che riceva gli eventi appena succedono, senza fare polling.
- Vuoi un audit trail interno: registri ogni cambio rilevante in un sistema terzo.
Eventi disponibili
| Evento | Quando si genera | Payload |
|---|---|---|
contact.email_status_changed | Lo stato email di un contatto cambia (bounce, unsubscribe, segnalazione spam, riattivazione) | { contactId, email, from, to, reason, webhookEventType? } |
campaign.completed | Una campagna ha finito il dispatch (tutti i send chiamati, qualunque esito) | { campaignId, name, kind, completedAt, stats } |
Nota —
contact.email_status_changedcopre in modo unificato bounce, segnalazione spam e disiscrizione. Il consumer leggefrometoper capire la transizione. Non ci sono eventi paralleliemail.bounced,email.complained,email.unsubscribed.
Puoi sottoscriverti a un evento specifico, a tutti gli eventi di uno scope (contact.*, campaign.*) o a tutti gli eventi (*).
Configurare un webhook
- Vai su Impostazioni → Webhook dal tuo tenant.
- Clicca Aggiungi webhook.
- Scegli il tipo di evento, inserisci l'URL del tuo endpoint e un'etichetta opzionale.
- SmartCQ genera un secret HMAC unico per quel webhook. Copialo subito: dopo non sarà più mostrato.
L'URL deve essere pubblicamente raggiungibile e accettare richieste POST con body JSON.
Come arrivano gli eventi
SmartCQ invia una richiesta POST al tuo URL con questi header:
Content-Type: application/json
User-Agent: SmartCQ-Webhook/1
x-smartcq-signature: sha256=<hex>
x-smartcq-event-id: <uuid>
x-smartcq-event-type: <type>
x-smartcq-event-version: <number>
x-smartcq-delivery-id: <uuid>
Il body ha questa struttura:
{
"id": "<event-uuid>",
"type": "contact.email_status_changed",
"version": 1,
"tenantId": "<tenant-uuid>",
"createdAt": "2026-05-10T08:00:00.000Z",
"payload": {
"contactId": "...",
"email": "...",
"from": "active",
"to": "bounced",
"reason": "webhook",
"webhookEventType": "email.bounced"
}
}
Verifica firma HMAC
L'header x-smartcq-signature è calcolato come sha256=<hex(HMAC-SHA256(body, secret))> sul body raw della richiesta.
Esempio Node.js:
import { createHmac, timingSafeEqual } from "node:crypto";
function verify(rawBody: string, header: string, secret: string): boolean {
const expected = "sha256=" + createHmac("sha256", secret).update(rawBody).digest("hex");
const a = Buffer.from(expected);
const b = Buffer.from(header);
if (a.length !== b.length) return false;
return timingSafeEqual(a, b);
}
Esempio Python (Flask):
import hmac, hashlib
def verify(raw_body: bytes, header: str, secret: str) -> bool:
expected = "sha256=" + hmac.new(secret.encode(), raw_body, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, header)
Rispondi con un 2xx entro 8 secondi: se vai oltre o rispondi con errore, SmartCQ riprova.
Idempotency
Ogni delivery ha un x-smartcq-delivery-id univoco. Se il tuo endpoint è retry-safe, puoi ignorarlo. Altrimenti, salva l'id ricevuto e scarta i duplicati che hanno lo stesso x-smartcq-event-id (uguale per tutti i tentativi sullo stesso evento).
Retry esponenziale
Se la consegna fallisce (errore di rete o risposta non-2xx), SmartCQ riprova con backoff esponenziale:
| Tentativo | Delay |
|---|---|
| 1° retry | dopo 1 minuto |
| 2° retry | dopo 5 minuti |
| 3° retry | dopo 30 minuti |
| 4° retry | dopo 2 ore |
| 5° retry | dopo 12 ore |
Dopo 5 fallimenti consecutivi l'evento entra in stato parked e non viene più riprovato. Lo trovi nella sezione "Ultime consegne" della pagina webhook con badge rosso.
Nota — Il dispatcher di SmartCQ gira una volta al giorno sul piano attuale. La latenza tipica è quindi ~24h, accettabile per scenari di sincronizzazione asincrona (CRM esterno, data warehouse). Per scenari real-time c'è una roadmap su upgrade a frequenza oraria.
Disabilitare e cancellare
- Disabilita un webhook: gli eventi successivi non vengono più inoltrati a quell'URL. Il webhook resta in lista, riattivabile in qualsiasi momento.
- Elimina: rimuove definitivamente la subscription. Gli eventi storici restano visibili (audit-style) ma non saranno mai consegnati ad altri URL.
Buone pratiche
- Mantieni l'endpoint snello: rispondi 2xx velocemente, accoda l'elaborazione vera in background.
- Logga
x-smartcq-event-idper tracciare lato tuo cosa hai ricevuto. - Non fidarti dell'ordine: gli eventi possono arrivare fuori ordine se uno è andato in retry. Riconcilia leggendo il timestamp
createdAt. - Versiona il consumer: l'header
x-smartcq-event-versionti dice lo schema del payload. SmartCQ bumpа la versione ai cambi breaking.