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

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions