Skip to content

REST API

The REST API is served from the same FastAPI process as the dashboard. Default base URL: http://127.0.0.1:8080/api/v1.

All endpoints return JSON, use ISO-8601 timestamps with Z suffix, and accept the standard ?limit=&offset= pair on list endpoints. Errors use the standard FastAPI shape: { "detail": "..." } with the appropriate HTTP status.

MethodPathPurpose
GET/healthLiveness + dependency status (DB, receivers, detectors).
GET/configEffective configuration with secrets redacted. Rate-limited (429 on abuse).
GET/statsThroughput, queue depth, dedup count, ML model state.
MethodPathPurpose
GET/eventsStored events. Filters: since, entity, template, source, severity, limit, offset.
MethodPathPurpose
GET/alertsList alerts. Filters: since, severity, rule, entity, limit, offset.
GET/alerts/{alert_id}Single alert with full context.
POST/alerts/{alert_id}/feedbackSubmit analyst label (true_positive, false_positive, benign) with optional note.
GET/alerts/{alert_id}/feedbackPaginated feedback audit log for an alert (FeedbackEvent[]feedback, note, `origin: dashboard
POST/alerts/{alert_id}/explainTrigger LLM-generated root-cause explanation (async). Requires llm.backend configured.
GET/alerts/{alert_id}/explanationFetch the cached LLM explanation, if any.
MethodPathPurpose
GET/entities/searchFuzzy search across IPs, users, hosts, processes, files, domains.
GET/entities/{entity_uuid}/timelineChronological events involving the entity.
GET/entities/{entity_uuid}/risk-historyDecayed risk score over time.
GET/entities/{entity_uuid}/baselineUEBA baseline (warm-up status, top templates, source-IP spread).
MethodPathPurpose
POST/huntRun a natural-language hunt. Body: { "query": "..." } (NL string). LLM translates → EventQuery → events. Requires llm.backend configured.
MethodPathPurpose
GET/sigma/rulesPaginated list of loaded rules with tactic, technique, logsource. The detail endpoint’s yaml_source field carries the raw YAML.
GET/sigma/rules/{rule_id}Full rule detail including yaml_source, metadata, last-fired-at.
GET/sigma/rules/{rule_id}/timeline24-bucket hourly fire histogram. Query: ?bucket=hour&window=24h.
PATCH/sigma/rules/{rule_id}Toggle enabled state or override metadata.
POST/sigma/rulesPersist a custom rule (YAML in body). Add ?dry_run=true to validate without writing — returns the three-stage verdict (yaml / schema / compile).
GET/sigma/rule-suggestionsPatterns with enough true-positive feedback to qualify for LLM rule suggestion. Paginated.
POST/sigma/rule-suggestions/{pattern_key}Generate (or fetch cached) Sigma YAML draft from a pattern.
DELETE/sigma/rule-suggestions/{pattern_key}Discard a suggestion (204).
MethodPathPurpose
GET/attack/coverageMITRE coverage grid: (tactic, technique) → rule count + last fired.
MethodPathPurpose
GET/anomaly/timelineBlended anomaly score over time, plus per-detector breakdown.

The current build runs unauthenticated by default — the dashboard is intended to live behind a private network or reverse proxy.

Rate-limiting is on by default (api_rate_limit_enabled: true) and uses three separate buckets:

  • api_list_rate_limit (default 60/minute) — list endpoints (/events, /alerts, /entities/search, /sigma/rules)
  • api_detail_rate_limit (default 300/minute) — detail endpoints (/alerts/{id}, /entities/{uuid}/*, /sigma/rules/{id})
  • api_coverage_rate_limit (default 10/minute) — the expensive /attack/coverage

Exceeded buckets respond with 429 Too Many Requests. Configure a shared limit across replicas via api_rate_limit_redis_url.

CORS is opt-in via api_allowed_origins. Set api_trust_proxy_headers: true only behind a trusted reverse proxy — it makes the rate-limiter key off X-Forwarded-For instead of the TCP peer.

See the API hardening config for every knob.

Terminal window
# Latest 50 alerts in the last 24h
curl 'http://127.0.0.1:8080/api/v1/alerts?since=24h&limit=50'
# Mark an alert as a false positive
curl -X POST 'http://127.0.0.1:8080/api/v1/alerts/<id>/feedback' \
-H 'Content-Type: application/json' \
-d '{"feedback":"fp","note":"known scheduled task","origin":"api"}'
# MITRE coverage
curl http://127.0.0.1:8080/api/v1/attack/coverage
# Natural-language hunt
curl -X POST http://127.0.0.1:8080/api/v1/hunt \
-H 'Content-Type: application/json' \
-d '{"query":"ssh brute force from 10.0.1.42 in the last 24h"}'