Skip to content

Sink Health Monitoring: REST API Endpoints #9

Description

@joejohnson123

Overview

Add REST API endpoints for programmatic management of sink monitors, enabling users to create and manage monitors via API alongside the UI.

Depends on: #1 (Schema), #2 (Context Module)

Endpoints

GET /api/sinks/:sink_id/monitors

List all monitors for a sink.

Response:

{
  "data": [
    {
      "id": "uuid",
      "name": "High failure rate",
      "enabled": true,
      "metric": "failed_messages",
      "monitor_type": "threshold",
      "threshold_value": 100,
      "threshold_window_seconds": 60,
      "anomaly_sensitivity": null,
      "notify_on_recovery": true,
      "cooldown_seconds": 300,
      "status": "ok",
      "last_triggered_at": null,
      "notification_channels": [
        {"id": "uuid", "channel_type": "slack"}
      ],
      "inserted_at": "2026-02-26T13:00:00Z"
    }
  ]
}

POST /api/sinks/:sink_id/monitors

Create a new monitor.

Request:

{
  "name": "High failure rate",
  "metric": "failed_messages",
  "monitor_type": "threshold",
  "threshold_value": 100,
  "threshold_window_seconds": 60,
  "notify_on_recovery": true,
  "cooldown_seconds": 300,
  "notification_channels": [
    {
      "channel_type": "slack",
      "config": {"webhook_url": "https://hooks.slack.com/..."}
    },
    {
      "channel_type": "discord",
      "config": {"webhook_url": "https://discord.com/api/webhooks/..."}
    }
  ]
}

GET /api/sinks/:sink_id/monitors/:monitor_id

Get a single monitor with full details.

PATCH /api/sinks/:sink_id/monitors/:monitor_id

Update a monitor. Supports partial updates.

  • To update channels: pass notification_channels array (replaces all existing)
  • To update just monitor fields: omit notification_channels

DELETE /api/sinks/:sink_id/monitors/:monitor_id

Delete a monitor and all associated channels/alerts.

POST /api/sinks/:sink_id/monitors/:monitor_id/test

Send a test notification to all configured channels.

Response:

{
  "results": [
    {"channel_type": "slack", "status": "ok"},
    {"channel_type": "discord", "status": "error", "error": "HTTP 403"}
  ]
}

GET /api/sinks/:sink_id/monitors/:monitor_id/alerts

List alert history for a monitor.

Query params: limit (default 25), cursor (pagination)

Response:

{
  "data": [
    {
      "id": "uuid",
      "status": "resolved",
      "metric_value": 150,
      "message": "Failed messages (150) exceeded threshold (100)...",
      "triggered_at": "2026-02-26T13:00:00Z",
      "resolved_at": "2026-02-26T13:05:00Z"
    }
  ]
}

Files to Create

  • lib/sequin_web/controllers/sink_monitor_controller.ex
  • test/sequin_web/controllers/sink_monitor_controller_test.exs

Files to Modify

  • lib/sequin_web/router.ex — add API routes under existing /api scope

Implementation Notes

  • Auth: Use existing API token authentication (same as other /api endpoints)
  • Verify sink belongs to the authenticated account
  • Follow existing controller patterns (see sink_consumer_controller.ex)
  • Use Sequin.Error for consistent error responses
  • Channel configs should NOT be returned in list/get responses (they contain secrets) — only return channel_type and id
  • Full channel config only returned when specifically editing (or use a separate endpoint)

Acceptance Criteria

  • All CRUD endpoints work with proper auth
  • Validation errors return structured error responses
  • Sink ownership verified (can't manage monitors on other accounts' sinks)
  • Channel secrets are not leaked in responses
  • Test notification endpoint reports per-channel success/failure
  • Alert history pagination works
  • Controller tests cover success and error cases

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions