All REST endpoints live under /api/v1/. Base URL: https://<server>:7701.
Authentication
Most endpoints require a JWT in the Authorization header:
Authorization: Bearer <jwt>
Get one via POST /api/v1/auth/login. Tokens are HS256, 24-hour TTL.
Roles
viewer — read-only access to agents, policies, events.
admin — everything, including policy mutation and approvals.
Setup-flow creates the first admin; subsequent users are created by admins.
Public endpoints (no auth)
| Method | Path | Purpose |
|---|
| GET | /health | Liveness + DB check |
| GET | /api/v1/auth/status | Is setup complete? Returns {configured: bool} |
| POST | /api/v1/auth/setup | Create initial admin (one-time) |
| POST | /api/v1/auth/login | Exchange username/password for JWT |
| GET | /api/v1/ca.pem | Server CA certificate (for agents) |
Viewer endpoints (JWT required)
Agents
| Method | Path | Purpose |
|---|
| GET | /api/v1/agents | List connected daemons |
| GET | /api/v1/daemons?include_archived=bool | List daemons with archive filter |
| GET | /api/v1/daemons/{id} | Daemon detail |
| GET | /api/v1/discovered-agents | List AI processes observed across fleet |
| GET | /api/v1/discovered-agents/{id} | Discovered agent detail |
Policies
| Method | Path | Purpose |
|---|
| GET | /api/v1/policies | List all policy versions |
| GET | /api/v1/policies/{version} | Single version (YAML + Cedar) |
| GET | /api/v1/policy-assignments | List assignments |
| GET | /api/v1/policy-assignments/{id} | One assignment |
| GET | /api/v1/daemons/{id}/effective-policy | Merged effective policy for a daemon |
Events
| Method | Path | Purpose |
|---|
| GET | /api/v1/events | Paginated event query |
| GET | /api/v1/events/stream | Server-sent events (live tail) |
Query params for /api/v1/events:
agent_id — filter by daemon
kind — filter by event kind
verdict — allow/deny/alert
drift_detected=true
limit (default 100, max 1000)
before_ts — pagination cursor
Approvals (roadmap)
| Method | Path | Purpose |
|---|
| GET | /api/v1/approvals | List pending approval requests |
Admin endpoints
Policies
| Method | Path | Purpose |
|---|
| POST | /api/v1/policies | Apply new policy version (body: {yaml: "..."}) |
| DELETE | /api/v1/policies/{version} | Delete a policy version |
Assignments
| Method | Path | Purpose |
|---|
| POST | /api/v1/policy-assignments | Create assignment |
| DELETE | /api/v1/policy-assignments/{id} | Delete assignment |
Body for POST:
"target_id": "4f27e3c1-..."
target_type: "daemon" or "agent_type".
Discovered-agent management
| Method | Path | Purpose |
|---|
| PATCH | /api/v1/discovered-agents/{id} | Update display name |
| DELETE | /api/v1/daemons/{id} | Delete daemon + its discovered agents |
Event injection
| Method | Path | Purpose |
|---|
| POST | /api/v1/events/inject | Inject a synthetic event (testing/bridging) |
Body is an Event JSON — see events.proto.
Approvals (roadmap)
| Method | Path | Purpose |
|---|
| POST | /api/v1/approvals/{id}/approve | Approve |
| POST | /api/v1/approvals/{id}/deny | Deny |
Enrollment tokens
| Method | Path | Purpose |
|---|
| POST | /api/v1/enrollment-tokens | Create a new token |
| GET | /api/v1/enrollment-tokens | List (metadata only) |
| DELETE | /api/v1/enrollment-tokens/{id} | Revoke |
Examples
Login
curl -sS -X POST https://tyr.example.com:7701/api/v1/auth/login \
-H "content-type: application/json" \
-d '{"username":"admin","password":"..."}' | jq -r .token
Apply a policy
curl -sS -X POST https://tyr.example.com:7701/api/v1/policies \
-H "Authorization: Bearer $JWT" \
-H "content-type: application/json" \
-d "$(jq -Rs '{yaml: .}' < policy.yaml)"
Live-tail events
curl -sS -N -H "Authorization: Bearer $JWT" \
https://tyr.example.com:7701/api/v1/events/stream
Each message is an SSE data: line with a JSON event.
Errors
Errors return HTTP 4xx/5xx with {"error": "<message>"}.
| Code | When |
|---|
| 400 | Bad request / invalid YAML / validation failure |
| 401 | Missing or invalid JWT |
| 403 | Role insufficient |
| 404 | Resource not found |
| 409 | Conflict (e.g. setup already completed) |
| 500 | Server error |