INTEGRACIÓN
Webhooks
Recibe notificaciones en tiempo real de eventos en tu cuenta, firmadas con HMAC.
Los webhooks te avisan en el momento en que pasa algo relevante — una tarea que se finaliza, una cita que se reserva — en vez de tener que consultar la API periódicamente para ver si algo cambió.
Configuración
Da de alta un webhook desde el Backoffice (sección «Webhooks») indicando la URL de destino y a qué eventos te suscribes, o por MCP con webhooks_crear(url, eventos_suscritos, tenant=None). El secreto devuelto (para verificar la firma de cada entrega) solo se enseña esa vez — apúntalo, no se puede volver a leer después.
{
"id": 7,
"tenant_id": null,
"url": "https://tuservidor.com/webhooks/guilda",
"eventos": ["tarea.finalizada", "nota.creada"],
"secreto": "3f8a...solo-se-enseña-una-vez",
"activo": 1
}
Formato del payload
{
"evento": "tarea.finalizada",
"datos": {
"tarea_id": 42,
"nombre": "Reunión de seguimiento",
"duracion_segundos": 2460
}
}
Cabeceras de cada entrega
| Cabecera | Contenido |
|---|---|
X-Guilda-Event | Nombre del evento, p. ej. tarea.finalizada. |
X-Guilda-Signature | sha256=<hex> — HMAC-SHA256 del cuerpo, ver abajo. |
Verificar la firma
La firma es un HMAC-SHA256 calculado sobre el cuerpo crudo tal cual se envía, usando el secreto de ese webhook como clave — mismo esquema que GitHub/Stripe, no uno propio. Recalcúlala y compárala con X-Guilda-Signature antes de procesar el evento; hazlo siempre sobre el cuerpo recibido tal cual, nunca sobre un JSON reserializado (el orden de las claves o los espacios pueden cambiar, y la firma no coincidiría aunque el contenido sea «el mismo»).
import hashlib
import hmac
def firma_valida(cuerpo_crudo: bytes, cabecera_recibida: str, secreto: str) -> bool:
esperada = "sha256=" + hmac.new(secreto.encode(), cuerpo_crudo, hashlib.sha256).hexdigest()
return hmac.compare_digest(cabecera_recibida, esperada)
Reintentos
Si tu endpoint no responde con un código 2xx, la entrega se reintenta hasta 3 veces con espera (inmediato, +30s, +5min) antes de darla por fallida. Cada intento queda registrado — el log de entregas (con el código HTTP o el error de cada uno) es visible desde el Backoffice, para depurar un webhook que no está respondiendo.
Catálogo de eventos
| Evento | Se dispara cuando... |
|---|---|
tarea.finalizada | Se finaliza una tarea con duración (ver Modelos de datos). |
nota.creada | Se crea una nota — no se dispara al editarla, solo al crearla. |
cita.reservada | Se crea una reserva de Cal.diy vía citas_crear_reserva. |
correo.mensaje_nuevo | Una sincronización de correo trae mensajes nuevos (uno por sincronización con novedades, no uno por mensaje). |
db.py, sería ruido en el uso diario normal del registro de actividad.Gestión por MCP
| Tool | Descripción |
|---|---|
webhooks_listar(tenant=None) | Lista los webhooks configurados (sin el secreto). |
webhooks_crear(url, eventos_suscritos, tenant=None) | Da de alta un webhook nuevo. |
webhooks_borrar(webhook_id) | Borra un webhook (y su historial de entregas). |