LandfallDocs
Triggering integrations · Alertmanager

Opening a war room from an Alertmanager notification

When Alertmanager sends Landfall a firing notification, Landfall opens an incident and its war room, or attaches the notification to the incident its alert group already opened. This setup is shared by every rule engine that delivers through Alertmanager: Prometheus, Loki's ruler and Grafana. Do it once, then follow your engine's page for its rules.

It is not about reading telemetry; see Prometheus, Loki or Grafana. The two are independent.

Rule engine
Prometheus, Loki or Grafana
→
Alertmanager
webhook_configs receiver
→
Landfall
opens or attaches an incident

How it works

Alertmanager posts each notification to POST https://api.landfalls.ai/triggers/alertmanager. It authenticates with a per-organization shared secret in the X-Landfall-Alertmanager-Secret header, because an Alertmanager receiver can send a static header but cannot sign a body the way PagerDuty and GitHub webhooks do. The secret alone identifies your organization, so the URL carries no organization name. Landfall reads a body as an Alertmanager notification when it has "version": "4" and an alerts list. Alertmanager's groupKey is the attach identity, so every notification for one alert group lands on one incident.

Prometheus, Loki's ruler and Grafana all reach this endpoint through Alertmanager, with the same secret, so every incident opened this way carries an Alertmanager badge. The rule's own name, labels and summary say which condition fired. Grafana can also skip Alertmanager and post to its own endpoint; see Grafana.

What you'll need

  • An owner or admin on your Landfall organization, to issue the webhook secret.
  • Alertmanager v0.28.0 or later. The receiver below sets its header with http_config.http_headers, which older versions reject at amtool check-config.
  • A network path from wherever Alertmanager runs to Landfall's public API.

1. Issue the webhook secret

There is no button for this in the app yet. An owner or admin issues it through the API with their own session.

Terminal
SESSION=$(curl -s -X POST https://api.landfalls.ai/auth/login \
  -H "Content-Type: application/json" \
  -d '{"email":"<you>","password":"<your password>","orgSlug":"<your-org>"}' \
  | jq -r .accessToken)

curl -X POST https://api.landfalls.ai/o/<your-org>/triggers/alertmanager-secret \
  -H "Authorization: Bearer $SESSION"

The response is { "secret": "<64 hex characters>" }, shown once. Store it now; Landfall keeps only its SHA-256 hash and can never show it again. Issuing a new one replaces the hash at once, with no overlap, so the old secret stops working immediately. That is also how you rotate it. Each issue is recorded in the audit log as trigger.alertmanager_webhook_secret.issued. This secret is separate from your organization's ingest token and Opsgenie secret, so rotating one never revokes the others.

2. Point Alertmanager at Landfall

Add a webhook_configs receiver to alertmanager.yml that targets the endpoint and sends the secret from step 1 as a header. http_config.http_headers is the field that sets a custom header; authorization: only ever sets the Authorization header.

alertmanager.yml
route:
  receiver: landfall
  group_by: ['alertname']
  group_wait: 30s
  group_interval: 5m
  repeat_interval: 4h

receivers:
  - name: landfall
    webhook_configs:
      - url: https://api.landfalls.ai/triggers/alertmanager
        send_resolved: true
        http_config:
          http_headers:
            X-Landfall-Alertmanager-Secret:
              secrets:
                - <the secret from step 1>
SettingValue
URLhttps://api.landfalls.ai/triggers/alertmanager
HeaderX-Landfall-Alertmanager-Secret
Header valueThe secret from step 1
Notificationsfiring opens or attaches. resolved is accepted and changes nothing, so send_resolved can stay on.

Then confirm the config loaded on Alertmanager's own Status page. Alertmanager shows anything under a secrets: field, and the receiver's url, as <secret>.

Alertmanager · Status
Alertmanager's Status page Config block, with a route to the landfall receiver and its webhook_configs entry, where the X-Landfall-Alertmanager-Secret header value and the url both read <secret>.
The route sends everything to the landfall receiver, grouped by alertname. Alertmanager itself prints the header value and the URL as <secret>. The rest of the global block is Alertmanager's own defaults.

What Alertmanager's fields become

Alertmanager fieldBecomes
alertnameThe incident title, read from commonLabels, then groupLabels, then the first alert's labels. Falls back to "Alertmanager alert".
service, jobThe affected entity, as service:<name>. service wins over job when both are present.
severitycritical is SEV1, page is SEV2, anything else or none is SEV3.
alerts[0].startsAtWhen the incident occurred. Falls back to the time Landfall received it.
summary, descriptionThe incident's summary, shown on its row in the Incidents list. summary is read from the common annotations, then the first alert's; description is used the same way when there is no summary. Falls back to the alert name.
runbook_url, generatorURLLinks on the incident. A runbook_url annotation becomes a runbook Beacon reads when its investigation starts; each alert's generatorURL becomes a link to the expression that fired.
groupKeyThe attach identity. See Repeats and recovery.

3. Test it

Post a sample notification shaped like Alertmanager's own, without waiting for a rule to fire.

Terminal · Worked example
curl -i -X POST https://api.landfalls.ai/triggers/alertmanager \
  -H "X-Landfall-Alertmanager-Secret: <your secret>" \
  -H "Content-Type: application/json" \
  -d '{
    "version": "4",
    "status": "firing",
    "groupKey": "{}:{alertname=\"CheckoutHighErrorRate\"}",
    "receiver": "landfall",
    "groupLabels": { "alertname": "CheckoutHighErrorRate" },
    "commonLabels": { "alertname": "CheckoutHighErrorRate", "severity": "page", "service": "checkout" },
    "commonAnnotations": { "summary": "checkout 5xx rate above 2% for 5 minutes" },
    "alerts": [{
      "status": "firing",
      "labels": { "alertname": "CheckoutHighErrorRate", "severity": "page", "service": "checkout" },
      "startsAt": "2026-10-06T09:00:00Z",
      "fingerprint": "abc123"
    }]
  }'

The answer is 202 with "outcome": "opened", the new incident's id and a link to its war room. The incident is titled CheckoutHighErrorRate at SEV2 (from severity=page), with service:checkout as its entity. In the Incidents list its row shows an Alertmanager badge, the checkout entity and the summary. Post the same body again and the answer is "outcome": "attached" with the same incident id.

Resolve the test incident when you are done. Its group stays tied to it (see below), so change the alertname and the groupKey for the next test.

Repeats and recovery

Alertmanager keeps the same groupKey for every repeat notification of a group that keeps firing, at its repeat_interval. A repeat attaches to the incident the group opened and writes nothing new.

The lookup has no time bound and does not check the incident's status. A group that fires again after its incident was resolved still attaches to that incident and opens nothing. The route above groups by alert name, so give every rule in every engine a distinct name. A rule that shares a name with another engine's rule attaches to that rule's incident instead of opening its own.

A resolved notification is accepted and changes nothing. Landfall never resolves an incident on its own; a person does.

Troubleshooting

What you seeWhat it means
401The header is missing, malformed, or does not match this organization's current secret. Issuing a new secret invalidates the previous one at once, so check Alertmanager has the latest value.
amtool check-config fails on http_headersAlertmanager is older than v0.28.0. Upgrade it; the older headers key does not work.
202 with "outcome": "ignored"The body's version is not "4", its status is not firing, or it has no groupKey. Landfall accepts it and does nothing.
Alertmanager retries a delivery again and againShould not happen for an authenticated delivery. Every authenticated outcome, including one Landfall ignores, is a 2xx, so an odd payload never turns into a retry storm. The only other answers are a 401 for a wrong secret and a 503 for a Landfall-side failure.
An incident opens with no service attachedExpected when the alert has neither a service nor a job label. Landfall does not guess a name.
A firing group opens nothing newIts groupKey already opened an incident, open or resolved. See Repeats and recovery.
Two incidents for one alert groupShould not happen while the groupKey stays the same. Check Alertmanager's group_by labels did not change between deliveries, since that changes the groupKey.

Reference

EndpointPOST https://api.landfalls.ai/triggers/alertmanager
AuthA per-organization shared secret in x-landfall-alertmanager-secret. The secret picks the organization; there is no organization in the path.
Issue or rotatePOST https://api.landfalls.ai/o/<your-org>/triggers/alertmanager-secret, owner or admin. Shown once; a new one replaces the old at once.
Recognized by"version": "4" and an alerts list. Only a firing notification with a groupKey opens or attaches.
Attach identityAlertmanager's groupKey, matched against every incident it opened, with no time bound or status check.
Each deliveryfiring with a new groupKey opens an incident (202 opened). firing with a known one attaches and writes nothing (202 attached). resolved changes nothing (202 ignored). An active maintenance window that covers it opens nothing (202 suppressed).
Rejected payloadsAn unrecognized version or a missing groupKey is 202 {"outcome":"ignored"}, never a 4xx, so Alertmanager does not retry it. A wrong secret is the one 401. A body over 512 KB is refused. A Landfall-side failure is a 503, which Alertmanager retries.
Incident badgeAlertmanager

How every trigger source fits together is on Integrations architecture.