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.
Method Path Purpose 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.
Method Path Purpose GET /eventsStored events. Filters: since, entity, template, source, severity, limit, offset.
Method Path Purpose 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.
Method Path Purpose 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).
Method Path Purpose POST /huntRun a natural-language hunt. Body: { "query": "..." } (NL string). LLM translates → EventQuery → events. Requires llm.backend configured.
Method Path Purpose 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).
Method Path Purpose GET /attack/coverageMITRE coverage grid: (tactic, technique) → rule count + last fired.
Method Path Purpose 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.
# 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"} '
curl http://127.0.0.1:8080/api/v1/attack/coverage
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"} '