Skip to main content

Analytics

The Analytics API is the read-only aggregation surface that powers the dashboard's Overview, Anomalies, and Decision Mining views. The endpoints aggregate over the org's DecisionTrace collection in MongoDB — no separate analytics warehouse, no event-stream copy, no batch export. Every read is a live query against the authoritative trace store, scoped by the same workspace and PII guarantees that govern the rest of the platform. Tested against API version v1. JWT auth on every endpoint; workspace scope comes from the x-workspace-id header (or org-wide when omitted).

This is a read-only resource. The trace data the analytics read from is mutated by POST /traces; nothing here writes.

Endpoints

GET  /api/v1/analytics
GET /api/v1/analytics/anomalies
GET /api/v1/analytics/decision-patterns
GET /api/v1/analytics/agent-compare
GET /api/v1/analytics/comparison
GET /api/v1/analytics/founder ── super-admin only
POST /api/v1/analytics/seed ── dev-only, owner role required

The /founder endpoint is reserved for Adjudon-internal staff and returns 403 to every customer JWT. The /seed endpoint is mounted only when NODE_ENV !== 'production' — production deployments do not expose it.

Get the dashboard rollup

GET /api/v1/analytics

The big one. Returns the aggregated rollup that drives the dashboard Overview: total traces, today's count, success / flagged / escalated / blocked counts, average confidence, the daily-bucket chart series for the requested date range, the per-agent breakdown, the review-queue size, and the reviews-by-day series.

Query parameterDescription
dateFromISO 8601 lower bound; defaults to 7 days ago
dateToISO 8601 upper bound; defaults to now

The daily-bucket fill is clamped to a 90-day ceiling (MAX_DAYS = 90) so a dateFrom of 2025-01-01 does not return 365 individual buckets. Ranges beyond 90 days return the latest 90 buckets and a hint in the response metadata that the range was clamped.

curl
curl "https://api.adjudon.com/api/v1/analytics?dateFrom=2026-04-01&dateTo=2026-05-06" \
-H "Authorization: Bearer $ADJUDON_JWT" \
-H "x-workspace-id: $WORKSPACE_ID"

The aggregation runs as a single Mongo $facet — one round-trip, multiple parallel pipelines. The compound index (organizationId, workspaceId, deletedAt, timestamp) keeps the read sub-200 ms at typical org sizes; the dashboard's 5-minute client-side cache absorbs repeated reads on the same range.

The response is shaped:

FieldTypeDescription
totalnumberTotal trace count for the range
tracesTodaynumberCount from local UTC midnight
successTracesnumberStatus not in flagged/escalated/blocked
flaggedTracesnumberstatus: 'flagged'
escalatedTracesnumberstatus: 'escalated'
blockedTracesnumberstatus: 'blocked'
avgConfidencenumberMean of outputDecision.confidenceScore || confidence, 0-1
daily[]arrayOne element per day in range, each { date, total, success, flagged, escalated, blocked, avgConfidence }
byAgent[]arrayOne element per agentId with the same status breakdown
reviewQueueobject{ open, overdue, avgAgeHours }
reviewsByDay[]arrayOne element per day, { date, resolved, approved, rejected }

Errors: 400 VALIDATION_ERROR (malformed date), 401, 403 (workspace access), 500.

Anomaly detection

GET /api/v1/analytics/anomalies

Compares the rolling window (default 24 h) against a baseline (default 7 d) and surfaces deviations significant enough to draw operator attention. The anomalyService runs four detectors in parallel: confidence-score drift, status-distribution shift, per-agent volume spike or drop, and per-policy match-rate inflection. Each anomaly carries a severity, a metric, the observed value, the baseline value, and a human-readable narrative the dashboard renders directly.

Query parameterDefaultDescription
sinceHours24Rolling window for the comparison subject
baselineDays7Baseline window the subject is compared against

Errors: 401, 403, 500.

Decision-pattern mining

GET /api/v1/analytics/decision-patterns

Returns aggregates suitable for the Decision Mining surface: counts grouped by status, by agentId, and by day. Used to spot candidate patterns for the Auto-Approval Engine before a human cohort reaches the 50-observation maturation floor. The endpoint does not itself mature patterns; it surfaces the data operators read to propose them.

Compare agents head-to-head

GET /api/v1/analytics/agent-compare

Returns one row per agent with success / flagged / escalated / blocked counts and average confidence. Used by the dashboard's agent-vs-agent comparison view (typical use case: which agent drove the most blocks last quarter? which has the lowest confidence?).

Period-over-period comparison

GET /api/v1/analytics/comparison

Returns the same rollup as GET / but for two periods side-by-side — current vs previous of the same length — so the dashboard can render delta percentages without the client doing the second query itself.

Query parameterDescription
dateFrom, dateToDefine the current period; previous period is the equal-length window immediately before it

Common gotchas

  • Read-only. Nothing on this resource writes. Mutations to trace data go through POST /traces; mutations to policy / review / agent state go through their respective resources.
  • PII-scrubbed at read. Trace payloads surface here only via aggregates (counts, averages, percentages); when an endpoint surfaces individual rationales (e.g. anomaly narratives), the payload is re-scrubbed via piiScrubber.scrubPayload() per Cardinal Rule. The PII guarantee on the trace ingestion path carries forward to every read on this surface.
  • 90-day daily-bucket ceiling. Date ranges spanning more than 90 days return the latest 90 daily buckets. Wider trend analysis happens via GET /usage/history (12-month rolling) or via the Reports API for scheduled exports.
  • Workspace scope is implicit. Every endpoint reads the x-workspace-id header and clamps the underlying query to that workspace. Omit the header for an org-wide rollup; an invalid workspace ID returns 403 WORKSPACE_FORBIDDEN.
  • /founder is internal. The endpoint exists in the route table for Adjudon staff with a super-admin JWT. Customer JWTs receive 403; the endpoint never leaks cross-tenant data.
  • /seed is dev-only. The endpoint is mounted only in non-production environments. A production-deployed Adjudon returns 404 for the path. Demo data on production goes through POST /onboarding/seed-demo instead.
  • No analytics warehouse. Adjudon does not maintain a separate analytics store. Every read is a live aggregate against MongoDB; the latency budget on this surface is governed by the compound index on DecisionTrace, not by ETL freshness.

See also

  • Traces API — the source of truth this resource aggregates
  • Auto-Approval — what the decision-pattern mining feeds into
  • Reports API — scheduled export jobs for ranges that exceed the 90-day daily-bucket ceiling
  • Usage API — the trace-counter surface, distinct from this aggregation surface
  • Error Codes — the broader error taxonomy