Documentación

Webhooks

Recibe eventos de conversaciones, tickets y presupuesto en tu servidor, firmados y con reintentos.

Configura endpoints en Configuración → Webhooks. Cada endpoint tiene una URL, un secreto y la lista de eventos a los que se suscribe.

Eventos

Evento Cuándo se envía
conversation.started Se abre una conversación nueva en el widget.
conversation.handoff El agente escala a una persona (por intención, horario, presupuesto o error técnico).
conversation.resolved La conversación se cierra, de forma automática o por una persona.
ticket.created Se crea un ticket desde el panel, el portal, la API o un flujo. data.ticket y data.source.
ticket.updated Cambian datos del ticket sin cambio de estado. data.ticket y data.changes con los campos modificados.
ticket.status_changed Un ticket cambia de estado. data.from, data.to y data.ticket.
ticket.reply_added Se publica una respuesta visible al solicitante. data.entry con author_kind y author_label.
ticket.note_added Se guarda una nota interna. Evento separado para que una integración pueda no suscribirse.
ticket.merged Otros tickets se fusionan en uno. data.ticket y data.merged_ids.
ticket.satisfaction_rated El solicitante califica un ticket resuelto. data.score y data.comment.
ticket.deleted Se elimina un ticket. data.ticket_id, data.external_id y data.title.
help.article_published Se publica una revisión de un artículo. data.center_id, data.article_id, data.slug, data.revision.
help.article_unpublished Se retira un artículo del portal. Mismos datos.
budget.exceeded El costo de IA del mes superó el presupuesto de la cuenta; el agente pasa a escalar a humano.
communication.updated Cambia el estado de un mensaje enviado o recibido. Consulta la guía de comunicaciones.

Los eventos ticket.* y help.* se confirman en la misma transacción que el cambio: si el cambio se guardó, el evento existe. Llegan con event_id estable (el mismo en cada reintento) y data.actor indica si actuó una persona (user_id), una clave de API (api_key_id) o el sistema. Solo los endpoints de producción reciben estos eventos; un endpoint creado después de un evento no lo recibe.

Formato

{
  "id": "0192f1c3-...",
  "event_id": "0192f1c2-...",
  "event": "ticket.reply_added",
  "environment": "live",
  "tenant_id": "0192f0aa-...",
  "created_at": "2026-09-01T15:04:05.000Z",
  "data": {
    "ticket": { "id": "0192f1b9-...", "status": "open", "external_id": "CASE-100" },
    "entry": { "id": "…", "author_kind": "requester", "author_label": "Ana", "is_internal": false, "content": "Sigo sin acceso" },
    "actor": { "kind": "api_key", "api_key_id": "…" }
  }
}

Los eventos de conversación y presupuesto conservan el formato anterior sin event_id ni environment.

Cabeceras:

Cabecera Contenido
x-talkhero-event Nombre del evento.
x-talkhero-delivery Id único de la entrega (para deduplicar).
x-talkhero-timestamp Milisegundos Unix en el momento del envío.
x-talkhero-signature sha256=<HMAC_SHA256(secreto, timestamp + "." + cuerpo)>

Verificar la firma

Calcula el HMAC sobre timestamp + "." + cuerpo crudo con el secreto del endpoint y compáralo en tiempo constante. Rechaza timestamps con más de 5 minutos de diferencia para evitar repeticiones.

import crypto from "node:crypto";

export function verifyTalkHero(req, secret) {
  const timestamp = req.headers["x-talkhero-timestamp"];
  const expected = "sha256=" + crypto.createHmac("sha256", secret).update(`${timestamp}.${req.rawBody}`).digest("hex");
  const given = req.headers["x-talkhero-signature"] ?? "";
  return expected.length === given.length && crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(given));
}

Reintentos

Responde 2xx en menos de 10 segundos. Cualquier otra respuesta o un timeout provoca reintentos con espera exponencial (30 s, 1 min, 2 min, 4 min, 8 min), hasta 6 intentos. El estado de cada entrega (pending, retrying, delivered, failed) queda registrado en tu cuenta.

Los eventos pueden llegar más de una vez: usa event_id (o x-talkhero-delivery en los eventos anteriores) para deduplicar.