Skip to content
GitHub
Developer

API Usage

Spectral exposes a REST API via FastAPI. All routes are versioned under /api/v1/. This guide covers authentication, common workflows, required headers, and error handling. For the full endpoint reference, start the API server and visit /docs (Swagger UI).

See ADR-006 for the versioning strategy rationale.


Terminal window
uv run --package spectral-api python -m spectral_api
open http://localhost:8000/docs # Swagger UI
open http://localhost:8000/redoc # ReDoc (alternative)

All request/response schemas are auto-generated from Pydantic models.


All endpoints are prefixed with /api/v1/. The OTLP trace ingestion endpoint follows the OpenTelemetry standard and lives at /otel/v1/traces.

/api/v1/auth/login # Auth (non-workspace)
/api/v1/account/... # Account-scoped
/api/v1/workspaces/{workspace_id}/... # Workspace-scoped via URL path
/api/v1/operations/... # Platform-only operations
/otel/v1/traces # OTLP standard endpoint

Every /api/* route requires authentication except:

  • POST /api/v1/auth/register
  • POST /api/v1/auth/login
  • POST /api/v1/auth/callback
  • POST /api/v1/auth/reset-password
  • GET /api/v1/auth/oauth/{provider}
  • GET /api/v1/health (also /api/health)
Terminal window
# Register
curl -X POST http://localhost:8000/api/v1/auth/register \
-H "Content-Type: application/json" \
-d '{"email": "dev@test.com", "password": "devpass", "tenant_name": "Dev"}'
# Login
curl -X POST http://localhost:8000/api/v1/auth/login \
-H "Content-Type: application/json" \
-d '{"email": "dev@test.com", "password": "devpass"}'
# -> { "access_token": "eyJ...", "user_id": "...", ... }

Pass the token as Authorization: Bearer <token> on subsequent requests.

API keys are scoped to a workspace and grant two scopes: read:agents (fetch agent config) and write:traces (push OTEL traces).

Terminal window
# Create a key (requires admin:workspace scope)
curl -X POST http://localhost:8000/api/v1/workspaces/<workspace_id>/keys \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{"name": "CI Pipeline"}'
# -> { "key": "sk_live_...", "key_id": "..." } (plaintext shown once)
# Use the key
curl http://localhost:8000/api/v1/workspaces/<workspace_id>/agents \
-H "Authorization: Bearer sk_live_..."

HeaderWhenExample
AuthorizationAlways (except public paths)Bearer eyJ... or Bearer sk_live_...
X-Workspace-IdWorkspace-scoped routesX-Workspace-Id: 550e8400-...
Content-TypePOST/PUT with JSON bodyapplication/json

Authorization uses 11 action:resource scopes:

ScopeDescription
read:workspaceRead workspace data (scans, changesets, traces)
write:workspaceCreate/update workspace data
approve:agentsAccept changesets, promote agent configs
admin:workspaceWorkspace settings, API keys, invites
admin:accountAccount-level management
read:agentsFetch agent configuration (API key scope)
write:tracesPush OTEL traces (API key scope)
read:operationsRead operations-staff data
write:operationsWrite operations-staff data
admin:operationsAdministrative operations-staff actions
delete:operationsDestructive operations-staff actions

POST /api/v1/auth/register -> account + first workspace
GET /api/v1/auth/me -> user profile + workspace list
POST /api/v1/workspaces/{workspace_id}/keys -> API key for programmatic access
POST /api/v1/workspaces/{id}/agents -> create workspace agent
POST /api/v1/workspaces/{id}/evaluations/rubrics -> create rubric with scoring dimensions
POST /api/v1/workspaces/{id}/evaluations/objectives -> create objective function
POST /api/v1/workspaces/{id}/traces -> ingest traces
or /otel/v1/traces -> OTLP trace ingestion
POST /api/v1/workspaces/{id}/scans -> start scan (202 Accepted, async)
GET /api/v1/workspaces/{id}/scans/{scan_id} -> poll for status, results
GET /api/v1/workspaces/{id}/scans/{scan_id}/events -> structured event log
GET /api/v1/workspaces/{id}/scans/{scan_id}/cost -> cost breakdown by model
GET /api/v1/workspaces/{id}/changesets -> list proposed Change Sets
GET /api/v1/workspaces/{id}/changesets/{id} -> detail with explainability
POST /api/v1/workspaces/{id}/changesets/{id}/accept -> accept and promote
POST /api/v1/workspaces/{id}/changesets/{id}/apply -> apply to managed templates
GET /api/v1/workspaces/{id}/control-plane -> cross-workflow KPIs
GET /api/v1/workspaces/{id}/morning-briefing -> daily snapshot
GET /api/v1/workspaces/{id}/workflow-overview -> workflow health overview

All errors follow RFC 9457 Problem Details format:

{
"type": "https://spectral.dev/errors/not-found",
"title": "Resource Not Found",
"status": 404,
"detail": "Scan abc123 not found"
}
StatusMeaning
400Bad request — invalid parameters or business rule violation
401Not authenticated — missing or invalid token
403Forbidden — authenticated but lacks required scope
404Not found — resource doesn’t exist or not in tenant
422Validation error — request body failed Pydantic validation
429Rate limited
500Server error

Domain errors from spectral.platform.shared.errors map automatically: NotFoundError -> 404, InvalidTransitionError -> 400, BusinessRuleViolationError -> 400.


Collections return a paginated wrapper:

{"results": [...], "pagination": {"total": 42, "limit": 20, "offset": 0}}

Single items return the object directly (flat, no wrapper).

Errors use RFC 9457 Problem Details (see above).


The API is organized into 20 resource-based router modules:

GroupPrefixDescription
Auth/api/v1/auth/*Registration, login, logout, OAuth, password reset, profile
Accounts/api/v1/account/*Account management, members, invites
Workspaces/api/v1/workspaces/{workspace_id}/*Workspace CRUD, members, autonomy settings, health
Keys.../keysAPI key lifecycle (create, list, revoke)
Agents.../agents/*Agent CRUD, configuration, templates
Agent.../agent/*Agent chat, conversations, approvals
Scans.../scans/*Scan lifecycle, events, cost, reports, scheduling
Changesets.../changesets/*Changeset lifecycle (accept, apply, reject, rollback)
Changeset Clusters.../changesets/{id}/clusters/*Failure cluster browsing and curation
Changeset Experiments.../changesets/experiments/*Experiment tracking
Changeset Validation.../changesets/{id}/validation/*Holdout validation runs
Rubrics.../evaluations/rubrics/*Rubric CRUD, generation, suggestions
Objectives.../evaluations/objectives/*Objective function CRUD
Samples.../samples/*Sample set management
Traces.../traces/*Trace browsing, feedback
Inference.../agents/{id}/infer-templateTemplate inference from scan context
Dashboard/api/v1/workspaces/{workspace_id}/...Control plane, morning briefing, workflow overview
Supervisor.../supervisor/*State, next-action, nightly plan, frontier report, failures
OTEL/otel/v1/tracesOTLP trace ingestion and stats
Operations/api/v1/operations/*Model health, model config (requires operations account role)

For the complete list of endpoints with request/response schemas, see the Swagger UI at /docs.