Avisos por Slack, Teams y webhook
Además del correo, los avisos de falla y de normalizado pueden llegar a Slack, Microsoft Teams o a tu propio sistema (webhook). Cada canal recibe exactamente los mismos avisos que el correo: uno cuando algo empieza a fallar y otro cuando lleva varios minutos seguidos funcionando bien. Las caídas que vuelven dentro de ese plazo son parte del mismo aviso.
Disponible en los planes Básico y Profesional (hasta 5 canales activos). Los configura un administrador de la empresa en la pestaña Canales, con el segundo factor activo.
Slack
- En Slack, crea una app (o usa una existente) y activa Incoming Webhooks.
- Elige el canal y copia la dirección, que empieza con
https://hooks.slack.com/services/. - En Canales, elige Slack, ponle un nombre, pega la dirección y presiona Agregar. Usa Enviar prueba para comprobarlo.
Microsoft Teams
Teams recibe avisos con la app Workflows (los antiguos conectores de Microsoft 365 están en retiro).
- En el canal de Teams, abre Más opciones (…) → Workflows y elige la plantilla Send webhook alerts to a channel.
- Guarda el flujo y copia la dirección que te entrega.
- En Canales, elige Microsoft Teams y pega la dirección.
Webhook a tu sistema
Enviamos un POST con un JSON a una dirección https tuya. Solo se aceptan direcciones públicas, no seguimos redirecciones y esperamos hasta 10 segundos por la respuesta. Responde con cualquier código 2xx. Si respondes 408, 429 o 5xx, o no respondemos a tiempo, reintentamos con espera creciente durante 2 horas; cualquier otro 4xx detiene los reintentos de ese aviso.
Cabeceras:
Content-Type: application/jsonX-Tecdex-Event: el tipo de evento.X-Tecdex-Delivery: identificador del aviso. Es el mismo en cada reintento: úsalo para no procesar dos veces el mismo aviso.X-Tecdex-Signature: firma, con la format=<segundos unix>,v1=<firma>.
Ejemplo de aviso de falla:
{
"version": 1,
"id": "6f1c2d1e-9a7b-4c51-8f0e-2b1f5c3a9d10",
"event": "failure",
"account": "acme",
"system": "Sitio web",
"title": "ACME · Sitio web con falla",
"text": "ACME · Sitio web con falla\nQué falla: Disponibilidad\nDesde: 26-10-2026 09:00 (UTC-03:00)\n…",
"language": "es",
"url": "https://monitoreo.tecdex.net/c/acme/incidentes",
"sent_at": "2026-10-26T12:00:05Z",
"since": "2026-10-26T12:00:00Z",
"recovery_wait_minutes": 10,
"checks": [{"name": "Disponibilidad", "detail": "No responde dentro del tiempo límite"}]
}
Campos:
version: versión del formato (hoy1). Podemos agregar campos nuevos sin cambiar la versión; nunca cambiamos ni quitamos los existentes.id: identificador único del aviso (igual a la cabeceraX-Tecdex-Delivery).event:failure(empezó a fallar),failure_update(falla además otra verificación del mismo sistema),recovery(normalizado) otest(mensaje de prueba).account: identificador de tu empresa.system: el sistema monitoreado (vacío entest).titleytext: el aviso redactado en el idioma del canal (language:es,enopt).url: dónde ver el detalle en el portal (puede sernull).sent_at: cuándo lo enviamos (UTC).- En
failureyfailure_update:since(desde cuándo falla, UTC),recovery_wait_minutes(minutos seguidos bien para avisar normalizado) ychecksconnameydetail(puede sernull). - En
recovery:started_atyended_at(período con fallas, UTC),duration_seconds,failures(caídas en el período) ychecksconnameyfailures.
Verificar la firma
Al crear el webhook te mostramos una sola vez su secreto (empieza con whsec_). Guárdalo en tu sistema. Si lo pierdes o se filtra, usa Rotar secreto: el anterior deja de servir.
Calcula HMAC-SHA256 con el secreto sobre el texto <t>.<cuerpo> (el cuerpo tal como llegó, sin volver a armar el JSON) y compáralo con v1. Rechaza además los avisos con t de más de 5 minutos de diferencia con tu reloj, para que nadie pueda repetir uno viejo. Ejemplo en Python:
import hashlib
import hmac
import time
def verificar(secreto, cabecera, cuerpo, ahora=None, tolerancia=300):
"""secreto: el whsec_… · cabecera: X-Tecdex-Signature · cuerpo: bytes tal como llegaron."""
try:
partes = dict(p.split("=", 1) for p in cabecera.split(","))
t = int(partes["t"])
except (ValueError, KeyError):
return False
if abs((ahora or time.time()) - t) > tolerancia:
return False
esperado = hmac.new(secreto.encode(), f"{t}.".encode() + cuerpo, hashlib.sha256).hexdigest()
return hmac.compare_digest(esperado, partes.get("v1", ""))