Skip to content

Webhook

El canal de webhook genérico es el fallback. Cuando necesitas empujar alertas a una superficie de chat, sistema de ticketing o relay in-house que Ongrid no habla nativamente (Microsoft Teams, Mattermost, Rocket Chat, OpsGenie, PagerDuty, tu propio router), apunta un webhook genérico a él y el pipeline de alertas postea el JSON canónico de mensaje de Ongrid.

Usa el canal dedicado cuando exista uno

Para Slack / Feishu / DingTalk / WeCom / Telegram, los canales dedicados renderizan payloads más ricos (attachments de Slack, firma). Alcanza el webhook genérico solo cuando no hay canal dedicado.

Payload

El body es la forma canónica notify.Message, JSON-encoded verbatim:

json
{
  "severity": "critical",
  "subject": "node-01 swap_high",
  "body": "swap_in_pages > 1000 for 5m",
  "source": "alert",
  "labels": {
    "rule": "swap_high",
    "incident_id": "1234",
    "device_id": "7",
    "host": "node-01"
  },
  "dedupe_key": "alert:swap_high:device=7",
  "occurred_at": "2026-05-30T14:02:35Z"
}

Sin envelope, sin msgtype, sin aplanar. El receptor recibe exactamente los campos que produjo el pipeline de alertas. Construido por NewGenericWebhookSender.

Firma HMAC opcional

Cuando rellenas el campo Secret, cada request lleva un header X-Ongrid-Signature:

text
X-Ongrid-Signature: sha256=<hex>

Donde <hex> es hex(HMAC-SHA256(secret, body)) sobre los bytes exactos posteados. El signer es signGenericWebhook.

Verificando del lado del receptor

python
# Python receiver
import hmac, hashlib

def verify(secret, body_bytes, header):
    expected = "sha256=" + hmac.new(
        secret.encode(), body_bytes, hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(expected, header)
go
// Go receiver
func verify(secret string, body, header []byte) bool {
    mac := hmac.New(sha256.New, []byte(secret))
    mac.Write(body)
    expected := []byte("sha256=" + hex.EncodeToString(mac.Sum(nil)))
    return hmac.Equal(expected, header)
}

Siempre verifica la firma cuando el endpoint es público

Una URL de webhook genérico sin firma está abierta a cualquiera que aprenda la URL. El header de firma es lo único que autentica "esto viene de Ongrid".

Forma del request

PropiedadValor
MétodoPOST
Content-Typeapplication/json
User-Agentongrid-notify/1.0
BodyJSON de notify.Message
Sig headerX-Ongrid-Signature: sha256=… (solo cuando hay secret)
TimeoutTimeout por-request del http.Client (default 15s)

Criterio de éxito

El Sender trata HTTP 2xx (200–299) como éxito. Cualquier otra cosa — incluyendo redirects 3xx, 4xx, 5xx — es unexpected status: … y cuenta como una entrega fallida para el pipeline de dampening. El body de la respuesta no se parsea; a Ongrid no le importa qué JSON eche de vuelta tu relay.

Retry y dampening

La semántica de retry es propiedad del pipeline de alertas, no del Sender. El Sender postea exactamente una vez por llamada Send(ctx, msg). El pipeline decide:

  • Ventana de dampening. Por-regla, default 5 minutos. La misma dedupe key dispara como mucho una vez por ventana.
  • Repeat-on-still-firing. Default 1 hora. Si un incidente sigue abierto después de esta ventana, el canal recibe una re-notify para que no se pierda en el historial del chat.
  • Mensaje de recovery. Disparado cuando la alerta se limpia.

El trabajo del Sender es empujar los bytes. El trabajo del pipeline es decidir cuándo.

Sin retry automático en falla de transporte

Si el receptor está caído en el momento en que el Sender postea, el mensaje se pierde (logueado como error de entrega, mostrado en las stats de entrega por-canal). El pipeline no encola y reintenta después. El razonamiento: una alerta de 5 minutos stale entregada tres minutos después del recovery es más confusa que una faltante. Usa un receptor robusto, o capa tu propia queue entre Ongrid y un downstream poco fiable.

Setup

  1. Levanta un endpoint HTTP que acepte POST + application/json. Elige un secret fuerte que compartirás con Ongrid.
  2. En Ongrid: Settings → Channels → New → Provider = webhook → Endpoint = tu URL → Secret = el secret compartido.
  3. Pulsa Test. El mensaje de prueba es el notify.Message{Severity: "info", Subject: "Ongrid test", …} sintético. Verifica el header de firma en los logs de tu receptor.

Recetas

Microsoft Teams (incoming webhook)

El incoming webhook de Teams acepta una forma de payload distinta (un MessageCard). La ruta más simple es poner un adapter pequeño entre Ongrid y Teams:

python
# server.py - listens on /ongrid-to-teams
@app.post("/ongrid-to-teams")
def relay(msg: dict):
    teams_url = os.environ["TEAMS_WEBHOOK"]
    card = {
        "@type": "MessageCard",
        "@context": "https://schema.org/extensions",
        "themeColor": {"critical":"D92F2F","warning":"F2C037","info":"36A64F"}.get(msg["severity"], "6F7A87"),
        "title": msg["subject"],
        "text": msg["body"],
    }
    requests.post(teams_url, json=card)

Apunta el canal de webhook de Ongrid a https://your-relay/ongrid-to-teams.

PagerDuty Events API v2

Mismo patrón: un relay pequeño que traduce {severity, subject, body, dedupe_key} a un payload events.v2 de PagerDuty. El campo dedup_key de PD mapea 1:1 al dedupe_key de Ongrid, así que el mismo incidente en Ongrid es la misma alerta en PD.

Splunk HEC / Elastic ingest

Apunta el canal al endpoint HEC con el token de Splunk en la URL. Splunk acepta el JSON canónico de Ongrid; indexa por severity y labels.rule para búsqueda downstream.

Referencia de campos

Ver Message para la fuente de verdad. Campos estables:

CampoTipoNotas
severitystringcritical / warning / info.
subjectstringNombre de regla + target — una línea.
bodystringDetalle multi-línea. Puede contener saltos de línea.
sourcestringalert / test / etc.
labelsmap[string]stringrule, incident_id, device_id, custom.
dedupe_keystringpipeline:rule:label-set. Estable por identidad.
occurred_atstring RFC3339UTC. El momento en que disparó el evaluator de alertas.

Los campos nuevos son aditivos — los receptores deberían ignorar keys desconocidas.

Relacionado