Headers
Body
Event types
Each destination chooses which of these it receives. Agent health, hosted check, SLO, and SLA Ledger events are only delivered to org-wide destinations.Metric alerts and resolves
A metric alert that went out is always closed by a resolve, so an incident opened downstream (PagerDuty, Jira, your own system) never stays open.- A resolve goes only to destinations that received the alert. Nobody gets “recovered” for an alert they never saw.
- Resolves pass every filter, snooze and page binding, so what was opened can close.
- A resolve’s
statusishealthyand itsseverityisnull, including when an outage ended in no data. - The title says why it closed:
recovered, oralert closed:followed bydeleted,paused (plan),monitoring changed,agent removed,removed from pageorno data. - An alert can be sent again with the same metric when it is still true after a snooze ends or monitoring resumes. The body says why, for example “Still unhealthy after the snooze ended.”
Signature verification
When a signing secret is configured, every delivery carries three headers:X-Observer-Signature signs the timestamp and the raw
body together: hex is HMAC-SHA-256(secret, "${timestamp}.${rawBody}"),
where timestamp is the value in X-Observer-Timestamp. Recompute
this on the receiving side and compare in constant time. Reject
deliveries whose signatures do not match, and reject deliveries whose
timestamp is more than five minutes from the receiver’s clock to bound
replay.
X-Observer-Signature-Legacy signs the body only:
HMAC-SHA-256(secret, rawBody). It is deprecated and exists for
receivers that have not migrated to the timestamp-prefixed scheme.
Verify against X-Observer-Signature for new receivers.
Hash the raw request bytes, not a re-serialized copy of the parsed JSON.
Node.js
IdempotencyUse
event_id from the body as the idempotency key when persisting
events. Retried deliveries reuse the same id, so a unique-key check
prevents double-processing.Legacy webhook subscriptions
Webhook subscriptions created before Alerts existed keep delivering. They can no longer be created or edited; new webhooks are added on the Alerts page. A legacy subscription receives the event’s raw JSON rather than the body above:event_type, event_id, occurred_at, org_id, and event-specific fields.
Incident and maintenance events also repeat those fields under data. Requests
are signed with the same three headers. A legacy subscription whose URL is a
Slack incoming webhook receives a Slack-formatted message instead.
For metric.status_changed, old_status and new_status are the raw
statuses the check recorded. old_verdict and new_verdict are the
statuses after the metric’s no-data treatment, which is what the status
page shows. A resolve carries resolve: true. When it closed for a
reason other than recovery it also carries resolve_reason (for
example metric_deleted) or cause (for example snooze_ended).
Legacy subscriptions can carry events that Alerts does not deliver, such as
incident.created, incident.updated, incident.deleted,
maintenance.started, maintenance.canceled, page.status_changed, and the auto-incident events
below.
incident.auto_drafted
Observer created a draft incident from an unhealthy metric change. The draft is not visible on the status page until it is published. Fields:org_id, incident_id, metric_id, metric_title, severity,
trigger_reason, value, threshold, affected_service_ids, url.
incident.auto_published
An auto-drafted incident was published from the email link.incident.published fires for the same publish. Fields: org_id,
incident_id, title, severity, state, published_at,
affected_service_ids, url.
incident.auto_dismissed
An auto-drafted incident was dismissed from the email link, or expired after 24 hours with no action.reason is operator_dismiss or auto_expired.
Fields: org_id, incident_id, title, dismissed_at, reason.
