Skip to main content

Webhook

TapToChat può inviare una richiesta HTTPS al tuo server ogni volta che succede qualcosa: una nuova conversazione, un messaggio, un’assegnazione. Ogni richiesta è firmata, così puoi verificare che arrivi da noi.

Configurare un webhook

I webhook fanno parte del piano Pro. Owner e admin li gestiscono in Impostazioni.

  1. Apri Impostazioni → Webhook e scegli Aggiungi webhook.
  2. Assegnagli un nome e l’URL https che deve ricevere gli eventi.
  3. Scegli gli eventi da inviare.
  4. Copia il segreto di firma. Viene mostrato una sola volta; potrai rigenerarlo in seguito.
Apri Impostazioni → Webhook

Eventi

Ogni webhook riceve solo gli eventi a cui è iscritto.

EventoInviato quando
conversation.createdUn visitatore avvia una conversazione, su qualsiasi canale.
conversation.assignedUna conversazione viene assegnata a un agente.
conversation.closedUna conversazione viene chiusa.
message.createdViene salvato un messaggio: di un visitatore, di un agente o una risposta automatica.
tag.addedViene aggiunto un tag a una conversazione.
note.createdUn agente aggiunge una nota interna o esegue un comando come /summary, il cui risultato viene salvato come nota (kind command_result).
integration.connectedViene collegata un’integrazione.
integration.disconnectedViene scollegata un’integrazione.
integration.errorLa sincronizzazione di un’integrazione non riesce.
webhook.testScegli Invia evento di prova in Impostazioni. Non viene mai inviato in altri casi.

Payload

Ogni richiesta è una POST con un corpo JSON, sempre nello stesso formato:

{
  "id": "6f1c2b0e-8a7d-4c1e-9b3a-2d5e7f9a1c4b",
  "event": "message.created",
  "created_at": "2026-10-01T09:30:00.000Z",
  "organization_id": "0c9a1f4e-3b2d-4e5f-8a6b-7c8d9e0f1a2b",
  "data": {
    "message": {
      "id": "a1b2c3d4-…",
      "conversation_id": "e5f6a7b8-…",
      "sender_type": "visitor",
      "sender_id": null,
      "content": "Hello, is anyone there?",
      "channel": "web",
      "created_at": "2026-10-01T09:30:00.000Z"
    },
    "conversation": { "id": "e5f6a7b8-…", "status": "open", "visitor_name": "Ada", "…": "…" }
  }
}
  • id: l’id dell’evento. Una consegna ritentata ha lo stesso id, quindi usalo per ignorare i duplicati.
  • event: il nome dell’evento, come nella tabella qui sopra.
  • data: cosa è successo. I campi dipendono dall’evento; un evento di messaggio contiene il messaggio e la relativa conversazione.

Header

  • X-TapToChat-Signature: la firma: v1= seguito da un HMAC-SHA256 in esadecimale.
  • X-TapToChat-Timestamp: quando la richiesta è stata firmata, in secondi Unix.
  • X-TapToChat-Event: il nome dell’evento.
  • X-TapToChat-Delivery-Id: questa consegna. Ogni nuovo tentativo ha lo stesso id.

Verificare la firma

Calcola un HMAC-SHA256 del timestamp, di un punto e del corpo grezzo della richiesta, usando come chiave il tuo segreto di firma, e confrontalo con l’header della firma in tempo costante. Rifiuta le richieste il cui timestamp si discosta di più di 5 minuti dal tuo orologio, così una richiesta intercettata non può essere riprodotta.

Usa come chiave l’intero segreto, compreso il prefisso whsec_. Verifica il corpo grezzo prima di analizzarlo: un JSON serializzato di nuovo non corrisponderà.

import crypto from 'node:crypto'

// The raw request body, exactly as received: verify before parsing JSON.
export function verifyTapToChat(rawBody, headers, secret) {
  const timestamp = headers['x-taptochat-timestamp']
  const signature = headers['x-taptochat-signature']
  if (!timestamp || !signature) return false

  // Refuse old requests, so a captured one cannot be replayed later.
  if (Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) return false

  const expected =
    'v1=' + crypto.createHmac('sha256', secret).update(`${timestamp}.${rawBody}`).digest('hex')
  const a = Buffer.from(signature)
  const b = Buffer.from(expected)
  return a.length === b.length && crypto.timingSafeEqual(a, b)
}

Nuovi tentativi

Rispondi con un qualsiasi stato 2xx entro 10 secondi per confermare una consegna. In caso contrario viene ritentata, fino a 6 tentativi in tutto.

Le attese tra un tentativo e l’altro sono 30s, 60s, 120s, 240s, 480s.

Una risposta 4xx diversa da 408 o 429 interrompe subito i nuovi tentativi, e lo stesso vale per un redirect: i redirect non vengono seguiti, quindi indica l’URL finale.

Occasionalmente una consegna può arrivare più di una volta. Usa l’id nel corpo per elaborare ogni evento una sola volta.

Disattivazione automatica

Dopo 20 consegne consecutive non riuscite, il webhook viene disattivato e le Impostazioni ne mostrano il motivo. Correggi il ricevitore, poi riattivalo; il conteggio riparte da zero.

Da sapere

  • L’URL deve usare https e puntare a un indirizzo pubblico.
  • I messaggi che gli agenti inviano dall’app mobile di TapToChat non generano ancora message.created. Quelli inviati dalla dashboard web e da tutti i canali sì.

Qualcosa non funziona come descritto? Contattaci.