DOCS

Events reference

All system events emitted by HowlOps: webhook events, WebSocket events, and in-app feed events.

HowlOps events are emitted in three delivery channels:

  1. Webhook: HTTP POST to your endpoint (Webhooks reference)
  2. WebSocket: WSS /api/v1/ws real-time stream
  3. In-app notification feed: /api/v1/notifications/feed

Webhook events

Outbound webhook deliveries use the stable monitor.* namespace. See the Webhooks reference for the full payload shape.

EventTrigger
monitor.downA monitor or heartbeat opens an incident (check failing / heartbeat missed)
monitor.upA monitor or heartbeat recovers
monitor.ssl_expiryA monitored endpoint's TLS certificate is approaching expiry
testManual test delivery from the UI

Heartbeat-sourced events reuse the same monitor.down / monitor.up event names; the payload carries heartbeat_id (with monitor_id empty) to distinguish them.

WebSocket events

Connect to WSS /api/v1/ws?token=<workspace_api_token>. The token must be a workspace API token (howlops_<hex>), not an OAuth or JWT token. Each message is a JSON object with channel, type, and data fields.

The channel field is the routing key clients use to subscribe to specific event streams. Frames without a channel are still delivered but the frontend drops them unless listening for all frames.

incident.created

json
{
  "channel": "monitors.status",
  "type": "incident.created",
  "data": {
    "incident_id": "uuid",
    "monitor_id": "uuid",
    "status": "open",
    "severity": "critical | warning | info"
  }
}

incident.acknowledged

json
{
  "channel": "monitors.status",
  "type": "incident.acknowledged",
  "data": {
    "incident_id": "uuid",
    "monitor_id": "uuid"
  }
}

incident.resolved

json
{
  "channel": "monitors.status",
  "type": "incident.resolved",
  "data": {
    "incident_id": "uuid",
    "monitor_id": "uuid"
  }
}

incident.assigned

json
{
  "channel": "monitors.status",
  "type": "incident.assigned",
  "data": {
    "incident_id": "uuid",
    "monitor_id": "uuid"
  }
}

monitor.status_changed

json
{
  "channel": "monitors.status",
  "type": "monitor.status_changed",
  "data": {
    "monitor_id": "uuid",
    "status": "up | down | paused",
    "response_time_ms": 142,
    "checked_at": "ISO 8601"
  }
}

heartbeat.ping_received

json
{
  "channel": "heartbeats.status",
  "type": "heartbeat.ping_received",
  "data": {
    "heartbeat_id": "uuid",
    "status": "up | missed",
    "last_ping_at": "ISO 8601 | null"
  }
}

Keep-alive ping

There is no application-level tick JSON event. To keep the connection alive, the server sends a WebSocket protocol PING control frame every 30 seconds to each connected client. Browsers and standard WebSocket libraries answer these PING frames automatically, so no application-level pong or handling is required.

In-app notification feed events

Returned by GET /api/v1/notifications/feed (paginated). Real-time updates are pushed on the notifications.feed WebSocket channel.

The type field identifies the event kind. The documented values correspond to the categories recognized by the feed:

typeCategoryMeaning
downincidentMonitor or heartbeat opened an incident
upincidentMonitor or heartbeat recovered
mass_outageincidentMulti-region outage opened
ssl_expiryincidentCertificate approaching expiry
incidentincidentGeneric incident event
recoveredincidentIncident resolved
adminadminPlatform admin broadcast
broadcastadminSystem-wide announcement
announcementadminPlatform announcement
billingbillingBilling or plan change
limitbillingTier limit notice
usagebillingUsage quota alert
planbillingPlan change

Feed item shape:

json
{
  "id": "uuid",
  "tenant_id": "uuid",
  "user_id": "uuid",
  "type": "down",
  "title": "Production API is down",
  "body": "Monitor detected failure at 10:00 UTC",
  "severity": "critical",
  "incident_id": "uuid",
  "monitor_id": "uuid",
  "category": "incident",
  "reactions": [],
  "read_at": null,
  "created_at": "ISO 8601"
}

Note: read_at is null when unread and an ISO 8601 timestamp when read. There is no boolean read field. There is no link field; callers construct the deep link from incident_id or monitor_id.

Severity levels

SeverityDescription
criticalService is fully unavailable or data loss is possible
warningService is degraded, slow responses, or partial failures
infoInformational: recovery, maintenance, or system notices

See also

Was this page helpful?