Skip to content

SLO API

Base path: /api/v1/slos

Implementation reference: internal/handlers/slo.go, models in internal/models/slo.go.

Endpoints

MethodPathDescriptionAuth Required
GET/slosList SLOs with paginationYes
GET/slos/:idGet a single SLO by IDYes
POST/slosCreate a new SLOYes
PUT/slos/:idUpdate an existing SLOYes
DELETE/slos/:idSoft-delete an SLO (sets active=false)Yes

SLO Model

json
{
  "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:

ParameterTypeDefaultDescription
pageint1Page number (1-indexed)
page_sizeint10Items per page (max 100)

Response (200 OK):

json
{
  "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):

json
{
  "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:

json
{
  "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):

json
{
  "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:

json
{
  "name": "API Latency P99 (Updated)",
  "target": 99.95,
  "active": true
}

Response (200 OK):

json
{
  "message": "SLO updated successfully"
}

DELETE /slos/:id

Performs a soft delete by setting active = false. The record remains in the database.

Response (200 OK):

json
{
  "message": "SLO deleted successfully"
}

Error Codes

HTTP StatusScenario
400Invalid SLO ID in path, malformed request body
404SLO not found
500Database error