SLO API
Base path: /api/v1/slos
Implementation reference: internal/handlers/slo.go, models in internal/models/slo.go.
Endpoints
| Method | Path | Description | Auth Required |
|---|---|---|---|
| GET | /slos | List SLOs with pagination | Yes |
| GET | /slos/:id | Get a single SLO by ID | Yes |
| POST | /slos | Create a new SLO | Yes |
| PUT | /slos/:id | Update an existing SLO | Yes |
| DELETE | /slos/:id | Soft-delete an SLO (sets active=false) | Yes |
SLO Model
{
"id": 1,
"name": "API Availability",
"description": "99.9% availability for the API service",
"target": 99.9,
"time_window": "30d",
"metric_type": "availability",
"metric_query": "rate(http_requests_total{job=\"api\",status=~\"5..\"}[5m])",
"team_id": 1,
"created_by": 1,
"active": true,
"created_at": "2026-06-01T10:00:00Z",
"updated_at": "2026-06-01T10:00:00Z"
}Supported time_window values: 1h, 24h, 7d, 30d, 90d.
Supported metric_type values: availability, latency, throughput.
GET /slos
Returns a paginated list of active SLOs (where active = true). Results are ordered by created_at DESC.
Query Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
page | int | 1 | Page number (1-indexed) |
page_size | int | 10 | Items per page (max 100) |
Response (200 OK):
{
"slos": [
{
"id": 1,
"name": "API Availability",
"description": "99.9% availability for the API service",
"target": 99.9,
"time_window": "30d",
"metric_type": "availability",
"metric_query": "rate(http_requests_total{job=\"api\",status=~\"5..\"}[5m])",
"team_id": 1,
"created_by": 1,
"active": true,
"created_at": "2026-06-01T10:00:00Z",
"updated_at": "2026-06-01T10:00:00Z"
}
],
"total": 1,
"page": 1,
"page_size": 10,
"has_next": false
}GET /slos/:id
Returns a single SLO by its numeric ID.
Response (200 OK):
{
"id": 1,
"name": "API Availability",
"description": "99.9% availability for the API service",
"target": 99.9,
"time_window": "30d",
"metric_type": "availability",
"metric_query": "rate(http_requests_total{job=\"api\",status=~\"5..\"}[5m])",
"team_id": 1,
"created_by": 1,
"active": true,
"created_at": "2026-06-01T10:00:00Z",
"updated_at": "2026-06-01T10:00:00Z"
}POST /slos
Creates a new SLO. The created_by field is automatically set to the authenticated user's ID.
Request:
{
"name": "API Latency P99",
"description": "P99 latency under 500ms",
"target": 99.9,
"time_window": "7d",
"metric_type": "latency",
"metric_query": "histogram_quantile(0.99, rate(http_request_duration_seconds_bucket[5m]))",
"team_id": 2
}Response (201 Created):
{
"id": 2,
"created_at": "2026-06-11T10:00:00Z",
"updated_at": "2026-06-11T10:00:00Z"
}PUT /slos/:id
Updates an existing SLO. All fields are optional — only provided fields are updated. The update query is built dynamically based on non-nil fields (internal/handlers/slo.go:172).
Request:
{
"name": "API Latency P99 (Updated)",
"target": 99.95,
"active": true
}Response (200 OK):
{
"message": "SLO updated successfully"
}DELETE /slos/:id
Performs a soft delete by setting active = false. The record remains in the database.
Response (200 OK):
{
"message": "SLO deleted successfully"
}Error Codes
| HTTP Status | Scenario |
|---|---|
400 | Invalid SLO ID in path, malformed request body |
404 | SLO not found |
500 | Database error |