Skip to main content

API

The hub exposes a client-agnostic REST API used by the UI and any future client (CLI, Grafana data source). All responses are JSON. Times are RFC3339 (UTC); durations are milliseconds.

  • Base path/api/v1.
  • Time range — most query endpoints accept start and end (RFC3339); omitted, they default to the last 15 minutes.
  • Projects (tenancy) — every data endpoint is project-scoped: the X-Avuru-Tenant header selects a project, omitted requests read the default project. GET /api/v1/projects lists what exists.
  • Authentication — with auth enabled (the default), endpoints require the session cookie set by POST /api/v1/auth/login or the OIDC flow. Roles (admin/editor/viewer) and per-project grants are enforced server-side; the selected project is validated against the caller's grants (403 otherwise). Read endpoints need viewer, mutations need editor, and rows marked admin need the global admin role. GET /healthz and GET /api/v1/auth/config are always open. Since v0.5.0, a personal API token sent as Authorization: Bearer avurut_… authenticates a request as its owner, with the owner's live roles and grants; the bearer path never falls through — a bad or expired token is a 401, not an anonymous session.
  • Login rate limiting — failed password attempts are counted on three axes: email + address, address, and (since v0.4.0) the account alone, so guesses spread across many addresses can no longer walk past the per-account lockout. A tripped limit returns 429 and blocks only login for that account, over a self-healing one-minute window; established sessions and successful logins are unaffected.
  • Cross-origin writes — mutating requests are checked with Origin against the Host the hub received. Behind a proxy that rewrites Host, name the real origins in auth.trustedOrigins or relax the check with auth.originCheck (enforce | log | off); an OIDC publicUrl is trusted automatically.

Endpoints

Method & pathPurpose
GET /healthzLiveness probe (always 200, even during a ClickHouse outage).
GET /api/v1/statusHub build info + ClickHouse reachability.
GET /api/v1/capabilitiesThe install's active module set — the UI sidebar follows it.
GET /api/v1/auth/configLogin-page bootstrap: {enabled, methods, forceSSO, demoEnabled}. Always registered, auth on or off.
POST /api/v1/auth/loginLocal login — body {email, password}; sets the session cookie. Rate-limited.
POST /api/v1/auth/logoutEnd the current session (server-side, so revocation is immediate).
GET /api/v1/auth/meThe caller's identity: user (id, email, name, anonymous, origin) + grants.
POST /api/v1/auth/passwordSelf-service password change — body {currentPassword, newPassword}. The current password is required; every other session of the caller is ended and the calling session's cookie is re-minted, so you stay signed in. Local accounts only (origin=local); SSO callers get a 409 — their credential lives at the IdP. Rate-limited per account.
POST /api/v1/auth/demoOne-click read-only demo sign-in — starts a session as the demo viewer using server-held credentials (no request body). Registered only when demo mode is enabled (auth.demo.enabled); rate-limited.
GET /api/v1/auth/oidc/startBegin the OIDC authorization-code + PKCE flow — redirects to the IdP (400 if OIDC is not configured).
GET /api/v1/auth/oidc/callbackIdP redirect target — validates state, exchanges the code, starts the session.
GET /api/v1/auth/oidc/mappingThe merged OIDC group→role mapping: chart-declared rules (source: config, read-only) and UI-authored ones (source: db), each with editable and shadowed flags — a shadowed rule names a group the chart also declares; it stays visible but never grants. Registered only when OIDC is configured — no provider means nothing to map, so the honest answer is 404. Admin.
PUT /api/v1/auth/oidc/mapping/{group}Create or update an authored rule — {role, projects}. On a chart collision the rule is stored and marked shadowed rather than silently ignored or refused. Applies at the group's next sign-in or token refresh; reaches every replica within ~15 s. Admin.
DELETE /api/v1/auth/oidc/mapping/{group}Delete an authored rule (404 if none has that group). Chart-declared rules cannot be deleted here. Admin.
POST /api/v1/auth/oidc/mapping/resetDelete every authored rule, returning the mapping to exactly what the chart declares. Admin.
GET /api/v1/tokensThe caller's personal API tokens — prefix, name, createdAt, expiresAt, lastUsedAt and tokenHash (the revoke handle). Never the raw token. A global admin may list another user's with ?user=. Any signed-in user — deliberately no role floor, so a user whose grants were revoked can still clean up the credentials they handed out.
POST /api/v1/tokensMint a token — {name, expiresInDays} (0 or omitted = never expires). The 201 response is the only place the raw avurut_… value ever appears; only its SHA-256 is stored. The token authenticates as its owner's live identity on every request, so disabling the owner disables the token.
DELETE /api/v1/tokens/{hash}Revoke a token by its tokenHash. Self-service; a global admin may revoke anyone's. An unknown — or another user's — hash answers 404, not 403, which would confirm the hash exists.
GET /api/v1/usersList users with role grants and origin (local/oidc). Admin.
POST /api/v1/usersCreate a local user — {email, name, password, grants}. Admin.
PUT /api/v1/users/{id}Update a user — any of name, password, disabled, grants. A password is accepted only for local accounts; setting one on an SSO user is refused, so an admin cannot mint a credential that bypasses the identity provider. Admin.
DELETE /api/v1/users/{id}Delete a user. Permitted only once the user is disabled — a deliberate second step, so removal is never one click. For an SSO user this removes the local record only; because disabled is what the SSO callback checks, deleting a disabled SSO user undoes their lockout. Admin.
GET /api/v1/projectsProject list: default, config-defined projects (projects chart value / AVURUOBS_PROJECTS), UI-managed projects, and tenants auto-discovered from data. Each entry carries a source, a label and an editable flag.
POST /api/v1/projectsCreate a UI-managed project — {id, label}, where id is an immutable tenant slug. A reserved (default/config) or duplicate id is a 409. Admin.
PUT /api/v1/projects/{id}Rename a UI-managed project's label{label}. default and config-defined projects are read-only (409). Admin.
DELETE /api/v1/projects/{id}Delete a UI-managed project (its telemetry ages out by retention). default and config-defined projects are read-only (409). Admin.
GET /api/v1/projects/{id}/keysList the project's ingest API keys — prefix, name, createdBy, createdAt and keyHash (the delete handle). Never returns the raw secret. Admin.
POST /api/v1/projects/{id}/keysMint an ingest API key — {name}. The 201 response is the only place the raw key ever appears; only its SHA-256 is stored. Admin.
DELETE /api/v1/projects/{id}/keys/{hash}Revoke a key by its keyHash. Takes effect within the gateway's verdict cache TTL. 204, or 404 if no live key matches. Admin.
GET /api/v1/collection/overlayThe stored collection overlay — per-signal on/off plus the shared namespace-exclusion list. Registered only when collection.runtimeControl.enabled (default off); its state is echoed in GET /api/v1/capabilities. Admin.
PUT /api/v1/collection/overlayReplace the overlay. A closed schema: anything outside it — including free-form collector config — is rejected, so the endpoint adds no injection surface. Since v0.5.0 the overlay is applied at runtime: the hub writes it through to its own sensor ConfigMaps and rolls the DaemonSet, so the sensor follows within seconds. Admin.
DELETE /api/v1/collection/overlayClear the overlay, returning collection to the chart defaults. Admin.
GET /api/v1/system/statusComponent health, per-signal storage (rows, bytes, compression, configured retention and the TTL the tables enforce) disk usage, and the ClickHouse connection (address, database, user — never the password). Includes a Schema component reporting applied versus expected migrations, so a half-migrated install names itself instead of failing every query. Admin.
GET /api/v1/servicesServices with RED aggregates over the window.
GET /api/v1/service-mapService nodes plus call edges (caller→callee from trace spans, enriched with OBI network flow bytes and per-edge health — RTT p95, failed connections — when infra-metrics is active). Trace-derived edges also carry client-side p50Ms/p95Ms — the caller's own view of that call, distinct from the callee's server-side p95 on the node. Both fields are omitted (not zero) on edges derived only from network flows, which have no span to measure.
GET /api/v1/tracesSearch traces (filters + keyset pagination — see below).
GET /api/v1/traces/overviewPer-(service, operation) RED metrics (count, errors, P50/P95/P99).
GET /api/v1/traces/heatmapLatency × time histogram (sparse cells) over root spans.
GET /api/v1/traces/{traceId}Full span tree for one trace (attributes, events, links).
GET /api/v1/traces/{traceId}/logsLogs correlated to a trace.
GET /api/v1/spans/{spanId}Resolve a span id to its containing trace (404 if unknown) — powers the span-id search.
GET /api/v1/logsSearch logs (filters + keyset pagination).
GET /api/v1/metrics/redBucketed RED series per service — service (empty = busiest top), points, includeAux.
GET /api/v1/health/groupsConsolidated group health over the window: per-service status from RED, tier-grouped, with critical-dependency propagation. Module service-health. includeAux.
GET /api/v1/health/groups/{name}One group's health, including each member's base vs. effective status and its critical-dependency chain (404 if the group is absent).
GET /api/v1/auth/permissionsThe role model and, per area of the product, the lowest role that can read it and the lowest that can change it — derived by the hub from the guards its routes registered with. Any signed-in caller.
GET /api/v1/service-groupsThe group definitions (name, tier, selector) as opposed to their health: chart-declared groups tagged source: config and read-only, UI-authored ones source: db. Module service-health.
POST /api/v1/service-groupsCreate a group. Admin role. 409 when the name is chart-declared or already taken.
PUT /api/v1/service-groups/{name}Edit a group's tier and selector. Admin role. 409 on a chart-declared name, 404 if no authored group has it.
DELETE /api/v1/service-groups/{name}Delete a group. Admin role. Same 409/404 rules as the update.
GET /api/v1/alertsCurrently-firing alerts + recent fire/resolve history. Module alerting.
GET /api/v1/alerts/rulesThe configured alerting rules and channels (channel secrets redacted). Module alerting.
GET /api/v1/alerts/channelsThe configured notification channels (secrets redacted). Module alerting.
POST /api/v1/alerts/channelsCreate a notification channel. Admin role.
PUT /api/v1/alerts/channels/{name}Update a notification channel. Admin role.
DELETE /api/v1/alerts/channels/{name}Delete a notification channel. Admin role.
POST /api/v1/alerts/channels/{name}/testSend a test notification through a channel (same SSRF policy as the evaluator; 503 if delivery is not configured). Admin role.
GET /api/v1/errors/issuesDeduplicated error issues — status, service, q, sort filters. Module error-tracking.
GET /api/v1/errors/issues/{fingerprint}One issue: stack trace, first/last seen, count, source, representative trace.
GET /api/v1/errors/issues/{fingerprint}/eventsOccurrences of an issue (keyset paginated).
GET /api/v1/errors/issues/{fingerprint}/histogramOccurrence histogram over the window.
POST /api/v1/errors/issues/{fingerprint}/statusTriage an issue — unresolved / resolved / ignored.
GET /api/v1/green/summaryPer-service energy (Wh) and carbon (gCO2e) over the window, with the coverage ratio and unattributed bucket. Module green (requires infra-metrics).
GET /api/v1/green/budgetsMonthly carbon budgets per service group: used, projected, ratio, and warn/exceeded status. Module green.
GET /api/v1/green/reportCSRD-ready export — per-app numbers plus a methodology block (formula, factor provenance, coverage). Module green.
GET /api/v1/infra/nodesNode utilization (kubeletstats): latest CPU/memory/network, pod counts, points-bucketed series.
GET /api/v1/infra/podsPod utilization, busiest first — node scopes to one node, limit caps rows.
GET /api/v1/agentsSensor inventory: per-node telemetry freshness per signal — windowSec (default 600) bounds "fresh".
GET /api/v1/profiles/servicesServices with CPU profiling samples in the window, busiest first.
GET /api/v1/profiles/flamegraphOne service's aggregated flame graph (service required) — inclusive values, self at leaves.
POST /v1development/profilesOTLP profiles ingest (protobuf) — the sensor's profiler exports here. Deliberately outside /api/v1: it is the otlphttp exporter's default profiles path, and a documented profiles-only exception to "the hub is never in the telemetry byte-path" until the ClickHouse exporter supports profiles.
POST /internal/v1/ingest-keys/validateNot a client API. The gateway's ingest-key validation call, guarded by a shared token the chart generates; it is registered only when that token is configured. Listed here so the route is not mistaken for an unauthenticated hole: it answers {valid, project} for a key and is the reason the hub stays out of the telemetry byte-path.

GET /api/v1/traces accepts:

ParamMeaning
service, operationFilter by service / operation. service matches traces the service participates in, not only the ones it roots.
statusok or error.
tagsSpan-attribute equality, comma-separated: http.status_code=500,http.method=GET.
ordernewest (default), oldest, or slowest.
minDurationMs, maxDurationMsDuration band.
includeAuxtrue to include auxiliary traffic (health checks, /actuator/*, metrics). Excluded by default.
limit, cursorPage size and opaque keyset cursor (nextCursor in the response).

GET /api/v1/traces/heatmap additionally takes tags, includeAux, timeBuckets and durationBuckets. GET /api/v1/logs takes service, severity, q (full-text), limit and cursor.

:::note Planned Remote configuration (OpAMP) and streaming (WebSocket) surfaces are on the roadmap and will be documented as their UIs arrive. :::