Conecta los Webhooks de Hermes: Deja que tus Sistemas Empresariales Envíen Alertas a Telegram, Discord y Slack

La mayoría de los sistemas empresariales acaban necesitando la misma automatización: cuando cambia el estado de un pedido, se completa un pago, salta una alerta de monitoreo o termina un pipeline de CI, publicar un mensaje en un canal del equipo.
La primera versión más rápida suele ser un script que hace polling a una base de datos o API y luego deja el mensaje en Telegram, Discord, Slack u otra plataforma de chat.
El polling funciona, pero tiene costos reales a largo plazo:
- Latencia y cuota de API. Escanear cada minuto significa que la mayoría de las peticiones no devuelven nada; pasar a polling a nivel de segundo multiplica la presión sobre la API y el costo.
- Acoplamiento. El sistema de negocio termina con plantillas de mensaje y tokens de la plataforma de chat hard-coded. Cambiar de canal o grupo requiere modificar el código.
- Extensibilidad. La misma alerta podría necesitar ir a Telegram, Slack o ser resumida primero por una IA. Los scripts de polling se vuelven complejos rápidamente.
Hermes Agent incluye una plataforma de webhooks: un receptor de eventos HTTP. Tu sistema de negocio hace POST de un evento, Hermes valida la signature, renderiza el template y envía el mensaje a la plataforma de chat que hayas configurado. Si el evento es una notificación pura que no necesita razonamiento de IA, puedes habilitar el modo Direct Delivery: sin llamada al LLM, sin bucle del agent, entrega de subsegundo y costo de tokens cero.
Este post es una guía práctica para conectar sistemas de negocio a los webhooks de Hermes: habilitar la plataforma, configurar routes, tres escenarios completos del mundo real y endurecimiento de seguridad.
Dos modos: Agent processing vs. Direct Delivery
Los webhooks de Hermes soportan dos rutas de entrega. Elegir la correcta importa.
| Modo | ¿Llama al LLM? | Mejor para | Latencia | Costo |
|---|---|---|---|---|
| Agent processing | Sí | Eventos que necesitan comprensión, resumen o una decisión antes de responder/reenviar | Segundos | Costo de tokens |
| Direct Delivery | No | Notificaciones puras: pedidos, pagos, alertas, estado de CI | Subsegundo | Costo de LLM cero |
El Direct Delivery es el foco aquí. El flujo es simple:
- El sistema de negocio firma y hace POST de un JSON payload a
https://your-server:8644/webhooks/<route-name>. - Hermes valida la signature HMAC para confirmar que el remitente es de confianza.
- Un template renderiza los campos del JSON en un mensaje legible.
- El mensaje se entrega directamente a Telegram, Discord, Slack, Feishu, etc., y Hermes devuelve
200 OK.
No interviene ningún LLM, así que la velocidad, el costo y la fiabilidad se acercan a un gateway de mensajes tradicional, pero la configuración y la extensibilidad siguen siendo tan flexibles como el resto de Hermes.
Paso 1: Habilitar la plataforma de webhooks
Puedes habilitar los webhooks mediante variables de entorno para una puesta en marcha rápida o mediante config.yaml para despliegues a largo plazo.
Variables de entorno (más rápido)
Añade estas líneas a ~/.hermes/.env:
WEBHOOK_ENABLED=true
WEBHOOK_PORT=8644 # default
WEBHOOK_SECRET=your-global-secret
Reinicia el gateway:
hermes gateway restart
Confirma que el servidor está escuchando:
curl http://localhost:8644/health
Una respuesta de {"status": "ok", "platform": "webhook"} significa que está activo.
Archivo de config (recomendado para producción)
Declara el bloque platforms.webhook en ~/.hermes/config.yaml:
platforms:
webhook:
enabled: true
extra:
port: 8644
secret: "your-global-secret"
Tras reiniciar el gateway, Hermes escucha en el puerto 8644. Si el servidor está en internet público, asegúrate de que el firewall permita ese puerto. Si está detrás de NAT o no tiene IP pública, expónlo con un Cloudflare Tunnel o ngrok.
Paso 2: Configurar una route de notificaciones de negocio
Las routes viven bajo platforms.webhook.extra.routes. Cada route tiene un nombre, un filtro de events, un secret, un template de mensaje y un destino de entrega. A continuación hay un ejemplo completo de notificación de pedidos de comercio electrónico que envía pedidos nuevos a Telegram.
platforms:
webhook:
enabled: true
extra:
port: 8644
secret: "global-fallback-secret"
routes:
order-notify:
events: ["order.created"]
secret: "shopify-webhook-secret"
prompt: |
🛒 New order #{order.id}
Amount: {order.total_price} {order.currency}
Customer: {order.customer.email}
Item: {order.line_items[0].title}
deliver: "telegram"
deliver_only: true
deliver_extra:
chat_id: "-1001234567890"
Puntos clave:
eventses opcional. Si tu sistema de negocio envía un tipo de evento medianteX-Webhook-Eventoevent_type, puedes restringir la route aorder.created.secretse usa para la validación de la signature HMAC. Si la route no tiene secret, cae en elsecretglobal.deliver_only: truehabilita el Direct Delivery y salta el LLM.promptes un template. Usa notación de punto como{order.total_price}para acceder a los campos del JSON.{__raw__}vuelca todo el payload.deliver_extra.chat_idapunta a un grupo específico. Si se omite, Hermes entrega al canal principal configurado de la plataforma (lo cual requiere que esa plataforma esté habilitada y conectada).
Paso 3: Enviar eventos desde tu sistema de negocio
Tu sistema de negocio hace POST a la URL correcta. Para el ejemplo anterior:
POST https://your-server:8644/webhooks/order-notify
Usa Generic V2 signing: concatena timestamp.body, calcula HMAC-SHA256 y envíalo en el header X-Webhook-Signature-V2 junto con X-Webhook-Timestamp. La ventana de timestamp es de ±300 segundos, lo que bloquea ataques de replay.
import hmac
import hashlib
import time
import json
import requests
secret = b"shopify-webhook-secret"
body = json.dumps({
"event_type": "order.created",
"order": {
"id": 10086,
"total_price": "199.00",
"currency": "USD",
"customer": {"email": "[email protected]"},
"line_items": [{"title": "Hermes sticker pack"}]
}
}).encode()
timestamp = str(int(time.time()))
signature = hmac.new(secret, f"{timestamp}.{body.decode()}".encode(), hashlib.sha256).hexdigest()
requests.post(
"https://your-server:8644/webhooks/order-notify",
data=body,
headers={
"Content-Type": "application/json",
"X-Webhook-Signature-V2": signature,
"X-Webhook-Timestamp": timestamp,
}
)
Las signatures de GitHub y GitLab también se detectan automáticamente. Para sistemas de negocio personalizados, prefiere Generic V2.
Paso 4: Probar la route
No necesitas esperar a que el sistema de negocio esté en producción. Prueba primero en local:
hermes webhook test order-notify \
--payload '{"event_type":"order.created","order":{"id":10086,"total_price":"199.00","currency":"USD","customer":{"email":"[email protected]"},"line_items":[{"title":"Hermes sticker pack"}]}}'
hermes webhook test simula un POST para que puedas verificar el renderizado del template y la entrega. Si el mensaje no llega, revisa gateway.log o ejecuta hermes gateway run en primer plano para ver si la signature falló, el event fue filtrado o el destino de entrega no está conectado.
Escenario 1: Notificaciones de pedidos de comercio electrónico → Telegram
El ejemplo order-notify de arriba ya está completo. Algunos detalles que valen la pena destacar:
- Los valores de
chat_idde grupos de Telegram suelen ser negativos y empezar por-100. - Para apuntar a un tema específico de un foro, añade
message_thread_id: "42"endeliver_extra. {order.line_items[0].title}solo muestra el primer artículo. Para listar todo, o bien preprocesa el payload en el sistema de negocio o usa el modo agent con{__raw__}y deja que el LLM resuma.
Escenario 2: Pago exitoso → Discord
Los sistemas de pago como Stripe ya emiten webhooks. Mapea el evento de éxito de Stripe a un mensaje de Discord:
routes:
payment-success:
events: ["payment_intent.succeeded"]
secret: "stripe-webhook-secret"
prompt: |
💰 Payment received: {amount} {currency}
Order: {metadata.order_id}
Customer: {receipt_email}
deliver: "discord"
deliver_only: true
deliver_extra:
chat_id: "123456789012345678"
Stripe envía type en lugar de event_type. Si Hermes no reconoce el header del event, o bien envuelve el payload en tu sistema de negocio o deja events vacío y usa filters:
routes:
payment-success:
secret: "stripe-webhook-secret"
filters:
- field: "type"
equals: "payment_intent.succeeded"
prompt: "..."
deliver: "discord"
deliver_only: true
Escenario 3: Alertas de monitoreo → Slack
Grafana, Datadog o cualquier monitor personalizado pueden hacer POST de alertas. Envía solo alertas críticas a Slack:
routes:
critical-alert:
events: ["alert"]
secret: "monitoring-webhook-secret"
filters:
- field: "severity"
equals: "critical"
prompt: |
🚨 Critical alert
Service: {service}
Metric: {metric}
Current value: {current_value}
Threshold: {threshold}
deliver: "slack"
deliver_only: true
deliver_extra:
chat_id: "your-slack-channel-id"
Slack debe estar habilitado y conectado en el gateway. Si solo usas Slack para notificaciones de webhook, no necesitas que sea tu plataforma de chat principal; solo configura platforms.slack con un canal principal o especifica el chat_id en deliver_extra.
Avanzado: filtrar y transformar payloads con scripts
Si el JSON del sistema de negocio es desordenado o solo quieres notificar bajo condiciones específicas, escribe un script de preprocesamiento. Los scripts deben vivir bajo ~/.hermes/scripts/; las rutas relativas se resuelven ahí.
# ~/.hermes/scripts/alert-filter.py
import json
import sys
payload = json.load(sys.stdin)
if payload.get("severity") != "critical":
print("[SILENT]")
raise SystemExit(0)
payload["body"] = f"{payload['service']} critical: {payload['metric']}"
print(json.dumps(payload))
Refiérencialo en la route:
routes:
critical-alert:
events: ["alert"]
secret: "monitoring-webhook-secret"
script: "alert-filter.py"
prompt: "{body}"
deliver: "slack"
deliver_only: true
La salida JSON por stdout reemplaza el payload; la salida de texto plano por stdout se inyecta como script_output; la salida vacía o [SILENT] hace que Hermes ignore el webhook.
Seguridad: no confíes solo en HMAC
HMAC prueba que el sender es de confianza, no que el contenido del payload sea seguro. Los títulos de PR, los cuerpos de issues, las notas de pedido y los mensajes de alerta son escritos por terceros y podrían llevar instrucciones inyectadas. Por eso:
- Aísla el runtime. Si el webhook está expuesto a internet, ejecuta el gateway con un backend de terminal Docker o SSH; no expongas el host directamente a los eventos.
- El Direct Delivery es inherentemente más seguro. Como salta el LLM, no hay riesgo de prompt injection que pueda disparar acciones del agent.
- Limita el conjunto de herramientas. Si una route debe entrar en modo agent, deshabilita herramientas peligrosas como
terminalyfilepara esa route. - Mantén las aprobaciones activas. Si el agent activado por webhook necesita ejecutar comandos, deja las aprobaciones habilitadas para que las instrucciones inyectadas no se ejecuten desatendidas.
- Usa templates restrictivos. Evita abusar de
{__raw__}; incluye solo los campos que necesites en elprompt.
Hermes también incluye guardas: 30 peticiones por minuto por route de forma predeterminada, un límite de tamaño de body de 1 MB y una caché de idempotencia de 1 hora. Estos valores predeterminados son suficientes para la mayoría de las notificaciones, pero puedes ajustarlos en extra:
extra:
rate_limit: 60
max_body_bytes: 2097152
Checklist de resolución de problemas
| Síntoma | Causa probable | Qué revisar |
|---|---|---|
| El POST del sistema de negocio falla | Puerto/firewall no abierto | curl http://your-server:8644/health |
| 401 Unauthorized | Discrepancia de signature | Revisa el secret y el algoritmo HMAC; lee los logs del gateway |
| 200 OK pero no hay mensaje | El tipo de event no coincide | Revisa la lista de events y el campo event_type |
| Mensajes duplicados | Reintentos + fallo de idempotencia | Asegúrate de que el sender envíe X-Request-ID o X-GitHub-Delivery |
| Las variables del template no se expanden | Nombres de campo incorrectos | Itera con hermes webhook test |
Suscripciones dinámicas vs. routes en archivo de config
Además de las routes estáticas en config.yaml, puedes crear suscripciones dinámicamente mediante CLI:
hermes webhook subscribe order-notify \
--events "order.created" \
--prompt "New order #{order.id}, amount {order.total_price} {order.currency}" \
--deliver telegram \
--deliver-chat-id "-1001234567890" \
--deliver-only \
--description "E-commerce order notifications"
Las suscripciones dinámicas se almacenan en ~/.hermes/webhook_subscriptions.json y se cargan en caliente por el gateway: no se requiere reinicio. Las routes estáticas con el mismo nombre tienen prioridad. Para la referencia completa de comandos, consulta nuestra página del comando hermes webhook.
Resumen
La plataforma de webhooks de Hermes no es un chatbot; es un router de mensajes event-driven. Para los sistemas de negocio, su principal valor es:
- Convertir el polling en push, ahorrar cuota de API y reducir la latencia.
- Centralizar los templates de mensaje y los destinos de entrega en Hermes, de modo que cambiar de plataforma de chat o grupo no requiera un despliegue del sistema de negocio.
- El modo Direct Delivery para notificaciones de cero tokens y subsegundo.
Si ya ejecutas Hermes para tareas diarias, añadir un endpoint de webhook es casi gratis: el mismo gateway ya está ejecutándose, solo escucha en un puerto más. Tus sistemas de negocio pueden empezar a comunicarse proactivamente, y tú decides qué dicen y dónde lo dicen.
¿Nuevo en Hermes? Empieza por la guía de instalación. Para la referencia completa del comando webhook, consulta la página del comando hermes webhook. Si te interesa la automatización event-driven, lee también nuestra guía de cron solo con scripts y explicación del modo yolo.