Skip to content
Median
Esc
↑↓navigate↵open⌘Jpreview
On this page

Analytics and logs

Read the analytics page's numbers, run explorer queries, and read the log over the REST API, the CLI and MCP.

Everything on the Insights tab is readable from outside the app. How the pages work, what each tile counts and what gets logged is in the help center: Read your analytics and Search your logs.

Analytics

The same numbers are on the management API. The API returns more than the page draws, like conversations by hour, top pages, sentiment and the knowledge base’s shape.

Endpoint Returns
GET /v1/analytics/overview The headline numbers: open conversations, this week against last, satisfaction over the last 30 days, and open signals
GET /v1/analytics/conversations, /satisfaction, /signals, /knowledge, /billing One day per bucket. days is 7, 30 or 90, default 30. from defaults to exactly days ago, so pass your own midnight to match the page.
GET /v1/analytics/activity Log entries per day. Owners and admins.
GET /v1/analytics/datasets/{dataset} A dataset’s field ids, kinds, values and time fields. The CLI’s analytics fields <dataset> and MCP’s median.analytics.describe({ dataset })
POST /v1/analytics/explore One explorer query. days is a whole number from 1 to 366, default 30, counted back from today in UTC. Anything else returns invalid_request. from moves the start.
POST /v1/analytics/records The rows a query matched. days and from work as for explore. limit is 1 to 200, default 50. sort is { "by": "time" or a field id, "direction": "desc" or "asc" }. fields lists the field ids each row reads out.

A query takes the same steps as the builder:

Key Takes
measure { "op", "field" }. op is count, distinct, sum, avg, median, p75, p90, p95, p99, min, max or percent. percent takes where, one filter, instead of field.
filters { "field", "op", "value" } each. op is is, isNot, in, notIn, gt, gte, lt, lte, contains, notContains, isSet or isNotSet. in and notIn take a list of up to 50 values.
match all (default) or any
groupBy A field id, or null
top, order, other 1 to 20 (default 8); natural (default), largest or smallest; true (default) folds the rest into __other, false leaves them off
bucket day, week, month, hour, weekday, or null
when { "field", "scope" }, scope range (default) or all
compare true adds previous: the same measure over the days just before the window, one value per group. Ignored with scope all.

Money in /billing is in microcredits, 1,000,000 to the dollar.

median analytics explore --days 90 \
  --query '{"dataset":"conversations","measure":{"op":"count"},"groupBy":"channel","bucket":"week"}'

# The handoff rate by channel, against the 30 days before
median analytics explore --days 30 \
  --query '{"dataset":"conversations","measure":{"op":"percent","where":{"field":"handedOff","op":"is","value":true}},"groupBy":"channel","compare":true}'
curl https://api.median.sh/v1/analytics/explore \
  -H "Authorization: Bearer $MEDIAN_KEY" \
  -H "content-type: application/json" \
  -d '{"days":90,"query":{"dataset":"conversations","measure":{"op":"count"},"groupBy":"channel","bucket":"week"}}'
return await median.analytics.explore({
  days: 90,
  query: { dataset: "conversations", measure: { op: "count" }, groupBy: "channel", bucket: "week" },
});

Queries take field ids rather than labels, like channel for Channel. GET /v1/analytics/datasets/{dataset} lists a dataset’s field ids. Every command and flag is in the CLI reference. The MCP server is on MCP.

Logs

Owners and admins can read the log from outside the app.

Surface Calls
API GET /v1/logs and GET /v1/logs/{id}
CLI median logs list and median logs get <id>
MCP median.billing.logs({ filters, paginationOpts }) and median.billing.logEntry({ id })
  • GET /v1/logs takes from, to, search, category, outcome, actorKind, actorId, conversationId and usage=true. The range defaults to the last 30 days.
  • category is one of ai, tools, knowledge, conversations, customers, signals, integrations, webhooks, email, team, keys, access, settings, site, billing, api or system.
  • Pages hold up to 200 entries, default 100. Keep snapshot fixed across pages. A page can come back short, or empty, before isDone is true.
  • GET /v1/logs/{id} returns the entry, what it touched, and up to 50 entries about the same conversation.
median logs list --category tools --outcome failed
curl "https://api.median.sh/v1/logs?category=tools&outcome=failed" \
  -H "Authorization: Bearer $MEDIAN_KEY"

Every flag is in the CLI reference.

Was this page helpful?