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
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/monitorsList 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/monitorsCreate 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_idGet a single monitor with full details.
PATCH /api/sinks/:sink_id/monitors/:monitor_idUpdate a monitor. Supports partial updates.
notification_channelsarray (replaces all existing)notification_channelsDELETE /api/sinks/:sink_id/monitors/:monitor_idDelete a monitor and all associated channels/alerts.
POST /api/sinks/:sink_id/monitors/:monitor_id/testSend 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/alertsList 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.extest/sequin_web/controllers/sink_monitor_controller_test.exsFiles to Modify
lib/sequin_web/router.ex— add API routes under existing/apiscopeImplementation Notes
/apiendpoints)sink_consumer_controller.ex)Sequin.Errorfor consistent error responseschannel_typeandidAcceptance Criteria