Ir al contenido

Webhooks salientes

Cuando algo pasa en Chats, Smarty se lo cuenta a tu sistema: un mensaje que llega, una conversación que se resuelve, una que pasa a otra persona. Sirve para alimentar tu CRM, tu hoja de control o cualquier automatización propia sin que nadie tenga que copiar datos a mano.

  1. En el panel, entrá a Chats → Integraciones → Webhooks.
  2. Cargá la URL de tu sistema (tiene que ser https).
  3. Elegí qué eventos querés recibir.
  4. Guardá el secreto que se muestra una sola vez: con él vas a verificar que cada aviso viene de Smarty.

Abrir Webhooks en mi panel

EventoCuándo se manda
message.receivedLlegó un mensaje del cliente.
message.sentAlguien del equipo, o la IA, le mandó un mensaje al cliente.
conversation.createdNació una conversación nueva.
conversation.resolvedLa conversación se marcó como resuelta.
conversation.reopenedUna conversación resuelta volvió a abrirse.
conversation.assignedLa conversación pasó a otra persona (incluye la primera asignación).
conversation.sla_breachedSe venció el tiempo de primera respuesta o de resolución.

Las notas internas del equipo no se mandan nunca.

Cada aviso es un POST con un JSON:

{
"id": "evt_…",
"type": "message.received",
"timestamp": "2026-09-06T15:04:05Z",
"data": {
"message_id": "…",
"conversation_id": "…",
"phone_line_id": "…",
"direction": "inbound",
"type": "text",
"body": "Hola, ¿tienen stock?",
"sender_type": "customer",
"wa_message_id": "…",
"has_media": false,
"created_at": "2026-09-06T15:04:05Z"
}
}

Los eventos de conversación traen conversation_id, display_id, status, contact_phone, contact_name, assigned_agent_id, team_id, tags y crm_lead_id. conversation.resolved agrega resolved_by y resolved_at; conversation.assigned agrega previous_agent_id; conversation.sla_breached agrega sla (first_response o resolution) y due_at.

Smarty firma con el estándar Standard Webhooks. Cada pedido trae tres cabeceras:

CabeceraContenido
webhook-idId único del aviso. Si te llega dos veces, es el mismo.
webhook-timestampSegundos desde 1970 en que se mandó.
webhook-signaturev1,<firma en base64>. Puede traer más de una separada por espacio.

La firma es un HMAC-SHA256 del texto webhook-id.webhook-timestamp.cuerpo con tu secreto. Rechazá el aviso si la firma no coincide o si el webhook-timestamp tiene más de 5 minutos.

import { createHmac, timingSafeEqual } from 'node:crypto';
function esDeSmarty(req, cuerpoCrudo, secreto) {
const id = req.headers['webhook-id'];
const ts = req.headers['webhook-timestamp'];
const esperada = createHmac('sha256', Buffer.from(secreto, 'base64'))
.update(`${id}.${ts}.${cuerpoCrudo}`).digest('base64');
return req.headers['webhook-signature'].split(' ')
.some((f) => f === `v1,${esperada}`);
}

Respondé 2xx en menos de 15 segundos. Si tu sistema no contesta o devuelve error, Smarty vuelve a intentar durante unas 76 horas (a los 5 segundos, 5 minutos, 30 minutos, 2 horas, y así). Un endpoint que falla 5 días seguidos se apaga solo; si contestás 410 Gone, se apaga en el acto. Los avisos que no se pudieron entregar quedan en el panel y se pueden reenviar con un clic.

Cada aviso puede llegar más de una vez: usá webhook-id para no procesar dos veces el mismo.

¿Te sirvió esta página?