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 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:

  1. El sistema de negocio firma y hace POST de un JSON payload a https://your-server:8644/webhooks/<route-name>.
  2. Hermes valida la signature HMAC para confirmar que el remitente es de confianza.
  3. Un template renderiza los campos del JSON en un mensaje legible.
  4. 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:

  • events es opcional. Si tu sistema de negocio envía un tipo de evento mediante X-Webhook-Event o event_type, puedes restringir la route a order.created.
  • secret se usa para la validación de la signature HMAC. Si la route no tiene secret, cae en el secret global.
  • deliver_only: true habilita el Direct Delivery y salta el LLM.
  • prompt es 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_id apunta 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_id de 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" en deliver_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:

  1. 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.
  2. El Direct Delivery es inherentemente más seguro. Como salta el LLM, no hay riesgo de prompt injection que pueda disparar acciones del agent.
  3. Limita el conjunto de herramientas. Si una route debe entrar en modo agent, deshabilita herramientas peligrosas como terminal y file para esa route.
  4. 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.
  5. Usa templates restrictivos. Evita abusar de {__raw__}; incluye solo los campos que necesites en el prompt.

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.