Skip to content

API Reference

Brokkr provides a comprehensive REST API for managing deployments, agents, stacks, templates, and work orders across your Kubernetes clusters.

The broker serves an interactive Swagger UI (with request/response schemas, auth requirements, and try-it-out testing) at http://<broker-url>/swagger-ui, and the OpenAPI spec at http://<broker-url>/docs/openapi.json.

All API endpoints are prefixed with /api/v1/ and require authentication via PAK (Prefixed API Key) in the Authorization header.

Terminal window
# All requests require a PAK in the Authorization header
curl -H "Authorization: Bearer <your-pak>" http://localhost:3000/api/v1/...

There are four types of PAKs:

  • Admin PAK: Full access to all endpoints
  • Agent PAK: Access to agent-specific endpoints (target state, events, heartbeat)
  • Generator PAK: The tenant credential — creates and manages the generator’s own stacks, deployment objects, and templates
  • Read-only console PAK: An ephemeral credential the broker mints per process and embeds in the served operator console. It is a read-only admin: GET/HEAD requests pass, plus POST /auth/pak and POST /deployment-objects/:id/diagnostics; every other mutating request is rejected with 403. It is never persisted and is not issued through the API

All four share the same token format, and the token does not encode the role — the broker resolves the identity by hash lookup. POST /auth/pak reports which identity a PAK resolves to, returning admin, agent, generator, and readonly. The generator field is the caller’s tenant ID; readonly is true only for the console PAK. See Multi-Tenancy for the tenant model.

Stacks are collections of Kubernetes resources managed as a unit.

Method Endpoint Description
GET /stacks List all stacks (admin: all, ?pak_id= scopes to one tenant; generator: own only)
POST /stacks Create a new stack
GET /stacks/:id Get stack by ID
PUT /stacks/:id Update a stack
DELETE /stacks/:id Delete a stack
GET /stacks/:id/labels List stack labels
POST /stacks/:id/labels Add label to stack
DELETE /stacks/:id/labels/:label Remove label from stack
GET /stacks/:id/annotations List stack annotations
POST /stacks/:id/annotations Add annotation to stack
DELETE /stacks/:id/annotations/:key Remove annotation
GET /stacks/:id/deployment-objects List deployment objects
POST /stacks/:id/deployment-objects Create deployment object (application/json envelope, or raw application/yaml body with ?deletion_marker=)
POST /stacks/:id/deployment-objects/from-template Instantiate template
GET /stacks/:id/health Aggregated stack health (computed on read)
GET /stacks/:id/events Retained Kubernetes events (6h window; since, limit)
GET /stacks/:id/logs Retained pod log lines (6h window; since, limit)

Agents run in Kubernetes clusters and apply deployment objects.

Method Endpoint Description
GET /agents List agents. Admin sees the whole fleet; a generator PAK sees exactly the agents registered with it (the system generator is excluded — system_generator_not_a_tenant)
POST /agents Register a new agent (optional generator_ids pre-registers additional generators)
GET /agents/:id Get agent by ID
PUT /agents/:id Update an agent
DELETE /agents/:id Delete an agent
GET /agents/:id/target-state Get agent’s target state
POST /agents/:id/heartbeat Record agent heartbeat (agent PAK only; admin PAK rejected)
GET /agents/:id/labels List agent labels
POST /agents/:id/labels Add label to agent
DELETE /agents/:id/labels/:label Remove label from agent
GET /agents/:id/annotations List agent annotations
POST /agents/:id/annotations Add annotation to agent
DELETE /agents/:id/annotations/:key Remove annotation from agent
GET /agents/:id/stacks List agent’s associated stacks
GET /agents/:id/targets List agent’s stack targets
POST /agents/:id/targets Add stack target (requires registration with the stack’s generator)
DELETE /agents/:id/targets/:stack_id Remove stack target (requires registration with the stack’s generator)
GET /agents/:id/registrations List the agent’s generator registrations
POST /agents/:id/rotate-pak Rotate agent PAK
PATCH /agents/:id/health-status Agent reports deployment health
GET /agents/:id/events List agent events
POST /agents/:id/events Record agent event
GET /agents/:id/diagnostics/pending Pending diagnostics for agent
GET /agents/:agent_id/webhooks/pending Pending webhook deliveries (auto-claims)
GET /agents/ Search agents by query string

Registration with a generator — Brokkr’s tenant — is the agent’s consent boundary, and it governs every path by which a stack reaches an agent. A stack target can only be added or removed when the agent is registered with the target stack’s owning generator; otherwise the request returns 403 agent_not_registered (admin PAK cannot bypass this gate). Label and annotation matches are filtered by the same rule at read time: a match associates a stack with an agent only when the agent is registered with that stack’s owning generator, so an agent with no registrations receives nothing from matching, and two tenants may reuse the same label vocabulary without colliding. The served set returned by GET /agents/:id/target-state is therefore the union of explicit targets (gated at creation) plus label and annotation matches within the agent’s registered generators.

Every agent is auto-registered with the system generator at creation, granting access to system/fleet stacks; generator_ids in POST /agents pre-registers additional generators. See Generator Registration and Application Scopes, Multi-Tenancy, and the agent registration how-to.

Broker-computed, read-only fleet surface returning measured signals only (no health verdicts). Admin PAK only — agent and generator PAKs cannot read the fleet. Every field is computed on read from data the broker already holds; the rollup is assembled with bounded grouped queries (no per-agent fan-out).

Method Endpoint Description
GET /fleet Per-agent fleet records for all agents (rollup); ?pak_id= scopes to agents registered with one tenant
GET /agents/:id/fleet-status One agent’s fleet record plus its 20 most recent events

Each fleet record carries: agent_id, name, status, ws_connected, connected_since, last_heartbeat, heartbeat_age_seconds, pending_object_count, pending_work_orders, claimed_work_orders, last_event_at, seconds_since_last_event, health_failing, health_degraded, k8s_reachable, and k8s_api_latency_ms. The *_age_seconds / seconds_since_* fields are now - timestamp, clamped to be non-negative.

k8s_reachable (and the optional k8s_api_latency_ms, in milliseconds) is the one fleet signal the broker cannot compute itself: whether each agent can reach its own Kubernetes API. The agent self-reports it on the heartbeat cycle (a lightweight GET /version probe carried in the heartbeat body / WS heartbeat frame), and the broker stores and trusts the latest snapshot per agent. Both are null until an agent first reports — an agent that never reports leaves them null without affecting the rest of the rollup.

Reusable stack templates with Tera templating and JSON Schema validation.

Method Endpoint Description
GET /templates List all templates
POST /templates Create a new template
GET /templates/:id Get template by ID
PUT /templates/:id Update a template
DELETE /templates/:id Delete a template
GET /templates/:id/labels List template labels
POST /templates/:id/labels Add label to template
DELETE /templates/:id/labels/:label Remove label from template
GET /templates/:id/annotations List template annotations
POST /templates/:id/annotations Add annotation to template
DELETE /templates/:id/annotations/:key Remove annotation from template

A generator may read, modify, and instantiate only its own templates plus system templates (those with a null generator_id, created by admin). Another generator’s template returns 403 template_not_accessible, on the template reads and on POST /stacks/:id/deployment-objects/from-template alike.

Transient operations like container builds routed to agents.

Method Endpoint Description
GET /work-orders List all work orders
POST /work-orders Create a new work order
GET /work-orders/:id Get work order by ID
DELETE /work-orders/:id Cancel a work order
POST /work-orders/:id/claim Claim a work order (agent)
POST /work-orders/:id/complete Complete a work order (agent)
GET /agents/:id/work-orders/pending Get pending work orders for agent
GET /work-order-log List completed work orders
GET /work-order-log/:id Get completed work order details

External systems that create deployment objects.

Method Endpoint Description
GET /generators List all generators
POST /generators Create a new generator
GET /generators/:id Get generator by ID
PUT /generators/:id Update a generator
DELETE /generators/:id Delete a generator
POST /generators/:id/rotate-pak Rotate generator PAK
POST /generators/:id/register Register an agent with the generator (agent_id optional for agent self-registration; re-registering returns 409 already_registered)
DELETE /generators/:id/register Deregister an agent (cascades: removes the agent’s targets for the generator’s stacks)
GET /generators/:id/registered-agents List agents registered with the generator
Method Endpoint Description
GET /agent-events List agent events (admin only); ?pak_id= scopes to agents registered with one tenant
GET /agent-events/:id Get agent event by ID
GET /deployment-objects/:id Get deployment object by ID
POST /auth/pak Verify a PAK; returns admin, agent, generator, readonly
GET /paks List tenants (non-system generators) as {id, name} for a scope selector (admin only)

GET /paks returns the tenants a scope selector can offer. Despite its auth OpenAPI tag, the path is /api/v1/paks — it is not under /api/v1/auth/. It is admin-gated; the read-only console PAK qualifies. The system generator is never listed.

The IDs it returns are what ?pak_id=<generator uuid> accepts on GET /fleet, GET /stacks, and GET /agent-events. Omitting it returns the unscoped listing; an unknown but well-formed UUID returns an empty 200; a malformed UUID returns 400.

pak_id is a view filter, not an authorization boundary. All three endpoints already require admin (/stacks also serves generator PAKs, which are self-scoped and unaffected by the parameter), and an admin who omits it sees every tenant. Real isolation comes from the generator PAK’s own scoping and from agent registration — see Multi-Tenancy.

Method Endpoint Description
GET /webhooks List webhook subscriptions
POST /webhooks Create webhook subscription
GET /webhooks/event-types List available event types
GET /webhooks/:id Get webhook subscription
PUT /webhooks/:id Update webhook subscription
DELETE /webhooks/:id Delete webhook subscription
POST /webhooks/:id/test Test webhook delivery
GET /webhooks/:id/deliveries List webhook deliveries
GET /webhook-deliveries List recent deliveries of all subscriptions (admin; status, limit, offset). See the delivery feed.
POST /webhook-deliveries/:id/result Report delivery result (agent)
Method Endpoint Description
GET /admin/audit-logs Query audit logs (limit default 100, max 1000; offset; actor/action/resource/time filters)
POST /admin/config/reload Reload broker configuration
GET /admin/ws/connections Snapshot of active WebSocket connections
Method Endpoint Description
GET /deployment-objects/:id/health Get deployment health
POST /deployment-objects/:id/diagnostics Request a diagnostic collection
GET /diagnostics/:id Get diagnostic request and result
POST /diagnostics/:id/claim Claim a diagnostic request (agent)
POST /diagnostics/:id/result Submit diagnostic result (agent)

Most list endpoints return the full collection without pagination. The exceptions take query parameters: /admin/audit-logs (limit/offset), the stack telemetry endpoints (since/limit, clamped to the 6-hour retention window), /work-order-log (work_type, success, agent_id, limit), /webhooks/:id/deliveries (status, limit, offset), and /webhook-deliveries (status, limit default 50 and maximum 200, offset).

The broker also serves three WebSocket upgrade endpoints — the internal agent channel (/internal/ws/agent), the per-stack live tail (/api/v1/stacks/:id/live), and the admin-only consumer-facing fleet live stream (/api/v1/fleet/live, which pushes per-agent fleet records). These are not part of the OpenAPI spec; see the WebSocket Protocol reference and the Fleet Reference.

The broker exposes health endpoints (not under /api/v1/):

Endpoint Description
/healthz Basic health check
/readyz Readiness probe
/metrics Prometheus metrics

See Health Endpoints for details.

All API errors return a JSON body with a stable machine-readable code, a human-readable message (wording may change between releases), and optional structured details (crates/brokkr-broker/src/api/v1/error.rs):

{
"code": "agent_not_found",
"message": "No agent with id 550e8400-e29b-41d4-a716-446655440000",
"details": null
}

Match on code, not message — the codes are part of the SDK contract. See Stable Error Codes for the catalog.

Common HTTP status codes:

  • 400 - Bad request (invalid input)
  • 401 - Unauthorized (missing or invalid PAK)
  • 403 - Forbidden (valid PAK but insufficient permissions; includes agent_not_registered when targeting a stack without registration with its generator)
  • 404 - Not found
  • 409 - Conflict (unique constraint violations)
  • 422 - Unprocessable entity (validation, foreign-key, check, or not-null violations)
  • 500 - Internal server error

The API does not currently implement rate limiting. For production deployments, consider placing a reverse proxy in front of the broker.