API Reference
Brokkr provides a comprehensive REST API for managing deployments, agents, stacks, templates, and work orders across your Kubernetes clusters.
Interactive API Documentation
Section titled “Interactive API Documentation”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.
API Overview
Section titled “API Overview”All API endpoints are prefixed with /api/v1/ and require authentication via PAK (Prefixed API Key) in the Authorization header.
Authentication
Section titled “Authentication”# All requests require a PAK in the Authorization headercurl -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/HEADrequests pass, plusPOST /auth/pakandPOST /deployment-objects/:id/diagnostics; every other mutating request is rejected with403. 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.
Core Resources
Section titled “Core Resources”Stacks
Section titled “Stacks”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
Section titled “Agents”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.
Fleet Legibility
Section titled “Fleet Legibility”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.
Templates
Section titled “Templates”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.
Work Orders
Section titled “Work Orders”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 |
Generators
Section titled “Generators”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 |
Other Endpoints
Section titled “Other Endpoints”| 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) |
Tenant Scoping
Section titled “Tenant Scoping”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_idis a view filter, not an authorization boundary. All three endpoints already require admin (/stacksalso 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.
Webhooks
Section titled “Webhooks”| 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 |
Health Monitoring & Diagnostics
Section titled “Health Monitoring & Diagnostics”| 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) |
Pagination
Section titled “Pagination”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).
WebSocket Endpoints
Section titled “WebSocket Endpoints”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.
Health Endpoints
Section titled “Health Endpoints”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.
Error Handling
Section titled “Error Handling”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; includesagent_not_registeredwhen targeting a stack without registration with its generator)404- Not found409- Conflict (unique constraint violations)422- Unprocessable entity (validation, foreign-key, check, or not-null violations)500- Internal server error
Rate Limiting
Section titled “Rate Limiting”The API does not currently implement rate limiting. For production deployments, consider placing a reverse proxy in front of the broker.