SmartCQ
Integrazioni

Webhook

Inoltra gli eventi della tua organizzazione verso un sistema esterno con firma HMAC e nuovi tentativi automatici.

I webhook ti permettono di ricevere notifiche asincrone quando succede qualcosa nell'organizzazione SmartCQ. Sono utili se hai un CRM o un gestionale già in uso e vuoi mantenerlo allineato con quello che SmartCQ osserva, per esempio una disiscrizione o il completamento di una campagna. La consegna avviene tramite una coda e una finestra di elaborazione: non è un canale sincrono né una garanzia di latenza in tempo reale.

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 ricevere gli eventi senza fare polling continuo.
  • Vuoi un audit trail interno: registri ogni cambio rilevante in un sistema terzo.

Eventi disponibili

EventoQuando si generaPayload
contact.createdUno o più contatti vengono creati (a mano, da import, da API, da moduli esterni){ records: [{ contactId, before: null, after, changedFields }] }
contact.updatedUno o più contatti cambiano: anagrafica, fase, stato email, assegnatario, archiviazione, ripristino, unione duplicati{ records: [{ contactId, before, after, changedFields }] }
contact.deletedUno o più contatti vengono eliminati (cestino) o assorbiti da un'unione duplicati{ records: [{ contactId, before, after: null, changedFields }] }
contact.email_status_changedLo stato email di un contatto cambia (bounce, unsubscribe, segnalazione spam, riattivazione){ contactId, email, from, to, reason, webhookEventType? }
campaign.completedUna campagna ha finito il dispatch (tutti i send chiamati, qualunque esito){ campaignId, name, kind, completedAt, stats }

Eventi con diff — gli eventi contact.created/updated/deleted viaggiano in batch: un evento può contenere più record (es. un import CSV ne genera uno per blocco, non uno per contatto). Per ogni record, before e after contengono i soli campi cambiati (changedFields li elenca); contact.created ha lo snapshot completo in after, contact.deleted uno snapshot compatto in before. Per il record completo, interroga l'API con il contactId.

Notacontact.email_status_changed copre in modo unificato bounce, segnalazione spam e disiscrizione. Il consumer legge from e to per capire la transizione. Non ci sono eventi paralleli email.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

  1. Vai su Impostazioni → Integrazioni e API → Webhook.
  2. Clicca Aggiungi webhook.
  3. Scegli il tipo di evento, inserisci l'URL del tuo endpoint e un'etichetta opzionale.
  4. SmartCQ genera un secret HMAC unico per quel webhook. Copialo subito: dopo non sarà più mostrato.

La gestione dei webhook è riservata al Titolare. L'URL deve usare HTTPS, essere pubblicamente raggiungibile e accettare richieste POST con corpo JSON; indirizzi privati, locali o riservati vengono rifiutati.

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.

Gestire i duplicati

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

Nuovi tentativi e finestra di consegna

Se la consegna fallisce per un errore di rete o una risposta diversa da 2xx, SmartCQ programma fino a quattro nuovi tentativi. Le attese indicate sono il momento dal quale il tentativo diventa disponibile, non un orario di consegna garantito:

TentativoAttesa minima
1° nuovo tentativonon prima di 1 minuto
2° nuovo tentativonon prima di 5 minuti
3° nuovo tentativonon prima di 30 minuti
4° nuovo tentativonon prima di 2 ore

Dopo cinque tentativi complessivi falliti — il primo invio e quattro nuovi tentativi — la consegna entra in stato parked e non viene più riprovata. La trovi nella sezione Ultime consegne della pagina Webhook.

Nota — Oggi SmartCQ elabora la coda una volta al giorno, nella finestra pianificata delle 06:02 UTC. Un tentativo già disponibile viene quindi eseguito nel primo giro giornaliero utile. I recapiti sono indipendenti per ogni webhook: un indirizzo lento o irraggiungibile non ritarda gli altri.

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 configurazione. Gli eventi storici restano visibili per tracciabilità, ma non vengono consegnati ad altri indirizzi.

Buone pratiche

  • Mantieni l'endpoint snello: rispondi 2xx velocemente e accoda l'elaborazione vera in secondo piano.
  • Registra x-smartcq-event-id per tracciare cosa hai ricevuto.
  • Non fidarti dell'ordine: gli eventi possono arrivare fuori ordine se uno è andato in retry. Riconcilia leggendo il timestamp createdAt.
  • Controlla la versione: l'header x-smartcq-event-version indica lo schema del payload. SmartCQ aumenta la versione quando introduce una modifica incompatibile.

Vuoi farlo nella tua area SmartCQ?

Webhook si gestisce direttamente nella dashboard.

On this page