Skip to main content

Conventions

Response envelope

Most endpoints wrap their payload in a standard envelope:

{
"success": true,
"message": "Success",
"timestamp": "2026-07-01T12:00:00.000000+00:00",
"data": { }
}

The meaningful result is always under data.

Some endpoints return the payload directly

A few list endpoints (notably Alerts and native scan results) return their object directly instead of wrapping it — e.g. Alerts returns { "items": […], "pagination": {…} } at the top level. Each guide shows the actual shape for its endpoints, and you can always confirm in the Swagger UI.

Pagination

There are two pagination styles depending on the endpoint:

Offset‑based (skip + limit) — vulnerabilities, native scans:

curl -s "$OFFLOAD_HOST/api/vulnerabilities/occurrences?skip=50&limit=50" \
-H "X-API-Key: $OFFLOAD_API_KEY"
{ "data": { "occurrences": [ ], "pagination": { "total": 1234, "skip": 50, "limit": 50 } } }

Page‑based (page + limit) — alerts:

curl -s "$OFFLOAD_HOST/api/alerts?page=2&limit=50" -H "X-API-Key: $OFFLOAD_API_KEY"
{ "pagination": { "current_page": 2, "total_pages": 25, "total_count": 1234, "limit": 50, "has_next": true, "has_prev": true } }

Each list endpoint documents its own limit ceiling (commonly 100–500).

Filtering & sorting

List endpoints take filters as query parameters (e.g. severity, status, source, created_after). Where sorting is supported, use sort_by + sort_order (asc / desc). Unsupported values fall back to a safe default rather than erroring. See each guide for the exact parameters.

Errors

Failed requests return a non‑2xx status and a descriptive message. Two shapes exist depending on the layer that rejected the request:

// FastAPI validation / handler error
{ "detail": "Scan result not found: scan_abc123" }
// Enveloped error
{ "success": false, "message": "Query failed: …", "error_code": 500 }
StatusMeaning
200 / 201Success (201 on resource creation)
400 Bad RequestMalformed input (e.g. unsafe kubeconfig, bad credentials)
401 UnauthorizedMissing/invalid/expired API key or session
403 ForbiddenInsufficient scope or team role
404 Not FoundResource doesn't exist or belongs to another team
409 ConflictDuplicate (e.g. a cluster name already used in your team)
422 Unprocessable EntityRequest body failed schema validation
429 Too Many RequestsRate limit exceeded
500 Internal Server ErrorUnexpected server error
404 vs 403

Because every resource is team‑scoped, requesting an ID that belongs to another team returns 404 (not 403) — the platform never confirms the existence of resources outside your team.

Rate limits

Two limits apply:

  • Per‑key — set at key creation via rate_limit_per_minute (default 60, max 600).
  • Per‑endpoint — sensitive routes have their own request‑per‑window caps.

Exceeding either returns 429. Back off and retry; for automation, keep a modest concurrency and honour 429s with exponential backoff.

IDs & timestamps

  • IDs are prefixed and opaque: osk_… (API key), clus_… (cluster), occur_… (vulnerability occurrence), alert_… (alert), scan_… (scan).
  • Timestamps are ISO‑8601 UTC strings (e.g. 2026-07-01T12:00:00Z).