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/logstakesfrom,to,search,category,outcome,actorKind,actorId,conversationIdandusage=true. The range defaults to the last 30 days.categoryis one ofai,tools,knowledge,conversations,customers,signals,integrations,webhooks,email,team,keys,access,settings,site,billing,apiorsystem.- Pages hold up to 200 entries, default 100. Keep
snapshotfixed across pages. A page can come back short, or empty, beforeisDoneis 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 failedcurl "https://api.median.sh/v1/logs?category=tools&outcome=failed" \
-H "Authorization: Bearer $MEDIAN_KEY"Every flag is in the CLI reference.