Observer
Observer

Webhook payload reference

JSON shapes for every event type Observer emits.

Every webhook delivery is a POST with a JSON body and the headers:

Content-Type: application/json
X-Observer-Event: <event-type>
X-Observer-Delivery: <delivery-uuid>
X-Observer-Signature: sha256=<hex>   (when a signing secret is configured)

The body is always:

{
  "event_type": "<event-type>",
  "event_id": "<delivery-uuid>",
  "occurred_at": "<ISO8601>",
  "data": { ... }
}

The data field shape varies by event type. The reference below documents each.

metric.status_changed

A metric's status flipped after dwell gating.

{
  "data": {
    "org_id": "org_...",
    "metric_id": "<uuid>",
    "metric_title": "checkout-api 5xx ratio",
    "old_status": "healthy",
    "new_status": "unhealthy",
    "value": 0.024,
    "timestamp": "<ISO8601>"
  }
}

metric.no_data

A metric entered no_data: the agent could not collect a sample.

{
  "data": {
    "org_id": "org_...",
    "metric_id": "<uuid>",
    "metric_title": "checkout-api 5xx ratio",
    "reason": "ECONNREFUSED",
    "timestamp": "<ISO8601>"
  }
}

page.status_changed

A status page's rolled-up status flipped.

{
  "data": {
    "org_id": "org_...",
    "page_id": "<uuid>",
    "page_title": "Acme Cloud",
    "old_status": "healthy",
    "new_status": "degraded",
    "computed_at": "<ISO8601>"
  }
}

slo.burn_started

An SLO crossed below its target.

{
  "data": {
    "org_id": "org_...",
    "slo_id": "<uuid>",
    "slo_name": "checkout-api availability",
    "service_id": "<uuid>",
    "service_name": "checkout-api",
    "burn_event_id": "<uuid>",
    "started_at": "<ISO8601>",
    "error_budget_burned_pct": 12.4,
    "target_pct": 99.9,
    "window_days": 30
  }
}

slo.burn_resolved

An SLO recovered. The matching burn_event_id from the prior slo.burn_started is included so consumers can pair the two.

{
  "data": {
    "org_id": "org_...",
    "slo_id": "<uuid>",
    "slo_name": "checkout-api availability",
    "service_id": "<uuid>",
    "service_name": "checkout-api",
    "burn_event_id": "<uuid>",
    "resolved_at": "<ISO8601>",
    "final_budget_remaining_pct": 87.2,
    "target_pct": 99.9,
    "window_days": 30
  }
}

agent.offline

An agent missed its expected heartbeat window.

{
  "data": {
    "org_id": "org_...",
    "agent_id": "<uuid>",
    "agent_name": "agent-eu-west-1",
    "last_heartbeat_at": "<ISO8601>",
    "version": "1.2.3"
  }
}

incident.created

A new incident row was created. Fires for both drafts and published incidents on insert.

{
  "data": {
    "org_id": "org_...",
    "incident_id": "<uuid>",
    "title": "...",
    "severity": "major",
    "state": "draft",
    "is_customer_scoped": false,
    "affected_service_ids": ["<uuid>"],
    "affected_service_names": ["checkout-api"]
  }
}

incident.published

A draft incident was published. The incident is now visible on the public page.

{
  "data": {
    "org_id": "org_...",
    "incident_id": "<uuid>",
    "title": "...",
    "severity": "major",
    "state": "published",
    "published_at": "<ISO8601>",
    "is_customer_scoped": false,
    "affected_service_ids": ["<uuid>"],
    "affected_service_names": ["checkout-api"]
  }
}

incident.updated

Title, severity, affected services, or visibility changed.

{
  "data": {
    "org_id": "org_...",
    "incident_id": "<uuid>",
    "changed_fields": ["title", "severity"]
  }
}

incident.message_added

A new message was appended to an incident timeline.

{
  "data": {
    "org_id": "org_...",
    "incident_id": "<uuid>",
    "message_id": "<uuid>",
    "message_type": "Identified",
    "description": "...",
    "occurred_at": "<ISO8601>"
  }
}

incident.resolved

resolved_at was set on the incident. Posting a Resolved message also fires this event because the appendMessage path auto-flips the parent state.

{
  "data": {
    "org_id": "org_...",
    "incident_id": "<uuid>",
    "title": "...",
    "severity": "major",
    "resolved_at": "<ISO8601>"
  }
}

incident.deleted

An incident was soft-deleted via DELETE.

{
  "data": {
    "org_id": "org_...",
    "incident_id": "<uuid>",
    "deleted_at": "<ISO8601>"
  }
}

incident.auto_drafted

The auto-incident worker created a DRAFT incident from an unhealthy metric flip. The draft is not visible to customers until it is published via the email CTA, the console, or the API.

{
  "data": {
    "org_id": "org_...",
    "incident_id": "<uuid>",
    "metric_id": "<uuid>",
    "metric_title": "checkout-api 5xx ratio",
    "severity": "major",
    "trigger_reason": "checkout-api 5xx ratio read 0.04 against threshold 0.02 at <ISO8601>",
    "value": 0.04,
    "threshold": 0.02,
    "affected_service_ids": ["<uuid>"],
    "url": "https://use.observer/console/<org>/updates/edit/<incident_id>"
  }
}

incident.auto_published

An auto-drafted incident was published via the signed-token email link. Equivalent to incident.published but distinguished so subscribers can listen specifically for the auto-publish flow.

{
  "data": {
    "org_id": "org_...",
    "incident_id": "<uuid>",
    "title": "Investigating elevated errors on checkout-api 5xx ratio",
    "severity": "major",
    "state": "published",
    "published_at": "<ISO8601>",
    "affected_service_ids": ["<uuid>"],
    "url": "https://use.observer/console/<org>/updates/edit/<incident_id>"
  }
}

incident.auto_dismissed

An auto-drafted incident was dismissed via the signed-token email link, OR auto-expired after 24h with no action. reason is operator_dismiss or auto_expired.

{
  "data": {
    "org_id": "org_...",
    "incident_id": "<uuid>",
    "title": "Investigating elevated errors on checkout-api 5xx ratio",
    "dismissed_at": "<ISO8601>",
    "reason": "auto_expired"
  }
}

maintenance.scheduled

A maintenance window was created.

{
  "data": {
    "org_id": "org_...",
    "maintenance_id": "<uuid>",
    "title": "...",
    "scheduled_start_at": "<ISO8601>",
    "scheduled_end_at": "<ISO8601>",
    "affected_service_ids": ["<uuid>"],
    "affected_service_names": ["checkout-api"]
  }
}

maintenance.starting_soon

Cron fires this once per maintenance row when scheduled_start_at is within the next hour. Idempotent via maintenance_starting_soon_fired_at.

{
  "data": {
    "org_id": "org_...",
    "maintenance_id": "<uuid>",
    "title": "...",
    "scheduled_start_at": "<ISO8601>"
  }
}

maintenance.started

actual_start_at was set (manual API call or cron auto-transition).

{
  "data": {
    "org_id": "org_...",
    "maintenance_id": "<uuid>",
    "title": "...",
    "actual_start_at": "<ISO8601>",
    "scheduled_end_at": "<ISO8601>"
  }
}

maintenance.completed

actual_end_at was set. Posting a Resolved message on a maintenance also fires this event because the appendMessage path flips the parent state.

{
  "data": {
    "org_id": "org_...",
    "maintenance_id": "<uuid>",
    "title": "...",
    "actual_start_at": "<ISO8601>",
    "actual_end_at": "<ISO8601>"
  }
}

maintenance.canceled

canceled_at was set before completion.

{
  "data": {
    "org_id": "org_...",
    "maintenance_id": "<uuid>",
    "title": "...",
    "canceled_at": "<ISO8601>"
  }
}

Signature verification

When a signing secret is configured, every delivery carries:

X-Observer-Signature: sha256=<hex>

hex is HMAC-SHA-256(secret, raw_body). Recompute on the receiving side and compare in constant time. Reject deliveries whose signatures do not match.

Was this page helpful?