{% extends "base.html" %} {% block title %}Alert ingestion{% endblock %} {% block content %}

Alert ingestion

Send Prometheus Alertmanager, Grafana or any JSON alerts to Vigil. Each firing alert opens an incident, routes to your channels and (optionally) shows on a status page; the matching resolve closes it.

{% if plan.ingest %}Enabled on {{ plan.name }}{% else %}Pro & Enterprise{% endif %}
{% if not plan.ingest %}

Bring your existing alerts into Vigil

Alert ingestion is part of the Pro and Enterprise plans (or the Platform module of a Custom plan). Connect Alertmanager, Grafana or your own tooling and get one incident timeline, escalation, acknowledgements, status-page updates and subscriber notifications for every alert, not just the ones Vigil's own monitors raise.

Upgrade
{% endif %}
{% for s in sources %}

{{ s.name }}

{{ kinds.get(s.kind, s.kind) }} · {{ s.received_count }} alert{{ '' if s.received_count == 1 else 's' }} received · last {{ s.last_received_at|timeago }}
{% if user.can_edit %}
{% endif %}
Endpoint URL (keep it secret: the token is the only authentication)
{{ endpoint_base }}{{ s.token }}
Routes to: {% for cid in s.channel_ids %}{% if cid in channel_names %}{{ channel_names[cid] }}{% endif %}{% else %}no channels (incidents only){% endfor %}  ·  Status pages: {% for pid in s.status_page_ids %}{% if pid in page_names %}{{ page_names[pid] }}{% endif %}{% else %}none{% endfor %}
Setup snippet for {{ kinds.get(s.kind, s.kind) }} {% if s.kind == 'alertmanager' %}
alertmanager.yml: add a receiver and route to it
receivers:
  - name: vigil
    webhook_configs:
      - url: {{ endpoint_base }}{{ s.token }}
        send_resolved: true
        max_alerts: 50

route:
  receiver: vigil
  group_by: [alertname, instance]
  repeat_interval: 4h
{% elif s.kind == 'grafana' %}
Grafana → Alerting → Contact points → New: type Webhook
Name:        Vigil
Integration: Webhook
URL:         {{ endpoint_base }}{{ s.token }}
HTTP Method: POST
# then add the contact point to a notification policy.
# Provisioning (YAML):
apiVersion: 1
contactPoints:
  - orgId: 1
    name: Vigil
    receivers:
      - uid: vigil
        type: webhook
        settings:
          url: {{ endpoint_base }}{{ s.token }}
          httpMethod: POST
{% else %}
POST one alert, a list, or {"alerts": [...]}. Same id with status resolved closes the incident.
curl -X POST {{ endpoint_base }}{{ s.token }} \
  -H 'Content-Type: application/json' \
  -d '{"id": "db-primary", "status": "firing", "severity": "critical",
       "title": "Postgres primary unreachable",
       "description": "Connection refused from app-1, app-2",
       "url": "https://runbooks.example.com/postgres", "labels": {"team": "platform"}}'

# later:
curl -X POST {{ endpoint_base }}{{ s.token }} \
  -H 'Content-Type: application/json' \
  -d '{"id": "db-primary", "status": "resolved"}'
Accepted status values: firing, critical, warning, down, error → opens; resolved, ok, up, recovered → closes.
{% endif %}
Response: {"received": n, "opened": n, "resolved": n}. Bodies over 256 KB are rejected (413).
{% if user.can_edit %}
Edit routing
{% for c in channels %}{% else %}
No channels yet. Add one.
{% endfor %}
{% for p in pages %}{% else %}
No status pages yet.
{% endfor %}
{% endif %}
{% else %}

No sources yet

Create one on the right to get an endpoint URL for Alertmanager, Grafana or your own scripts.

{% endfor %}

Add a source

Alertmanager: the standard v4 webhook receiver. Grafana: unified alerting contact point (webhook). Generic: any script or tool that can POST JSON.
Incident titles are prefixed with this, e.g. [Prod Alertmanager] HighErrorRate.
{% for c in channels %}{% else %}
No channels yet. Add one to get notified; incidents are recorded either way.
{% endfor %}
{% for p in pages %}{% else %}
No status pages yet. Create one to publish ingested incidents and notify subscribers.
{% endfor %}
{% if plan.ingest and user.can_edit %} {% elif not plan.ingest %}Upgrade to enable {% else %}
Your role is view-only.
{% endif %}

How it works

  • Firing alert → new incident titled [source] alertname (kind external), a down event to the channels, and an opened post to status-page subscribers.
  • Repeated firing of the same alert (same fingerprint) updates that incident; channels are only re-alerted if the incident has been quiet for over an hour.
  • Resolved alert → the incident closes with its duration, channels get an up event, subscribers get resolved.
  • Acknowledge, comment and write postmortems on ingested incidents under Incidents, like any other.
  • Webhook channels receive the usual JSON (event, monitor, title, message, link) with monitor.mode = "ingest" and the alert labels as tags, plus alert and source objects.
{% endblock %}