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 parameter | Description |
|---|---|
dateFrom | ISO 8601 lower bound; defaults to 7 days ago |
dateTo | ISO 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 "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:
| Field | Type | Description |
|---|---|---|
total | number | Total trace count for the range |
tracesToday | number | Count from local UTC midnight |
successTraces | number | Status not in flagged/escalated/blocked |
flaggedTraces | number | status: 'flagged' |
escalatedTraces | number | status: 'escalated' |
blockedTraces | number | status: 'blocked' |
avgConfidence | number | Mean of outputDecision.confidenceScore || confidence, 0-1 |
daily[] | array | One element per day in range, each { date, total, success, flagged, escalated, blocked, avgConfidence } |
byAgent[] | array | One element per agentId with the same status breakdown |
reviewQueue | object | { open, overdue, avgAgeHours } |
reviewsByDay[] | array | One 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 parameter | Default | Description |
|---|---|---|
sinceHours | 24 | Rolling window for the comparison subject |
baselineDays | 7 | Baseline 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 parameter | Description |
|---|---|
dateFrom, dateTo | Define 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-idheader and clamps the underlying query to that workspace. Omit the header for an org-wide rollup; an invalid workspace ID returns403 WORKSPACE_FORBIDDEN. /founderis internal. The endpoint exists in the route table for Adjudon staff with a super-admin JWT. Customer JWTs receive403; the endpoint never leaks cross-tenant data./seedis dev-only. The endpoint is mounted only in non-production environments. A production-deployed Adjudon returns404for the path. Demo data on production goes throughPOST /onboarding/seed-demoinstead.- 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