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

Explore any dataset

One query over any dataset Median collects, the way the analytics page’s explorer runs it: a measure, filters, a split into series and an axis. Datasets: conversations, messages, ratings, signals, usageEvents, logs, knowledgeDocs, knowledgeSuggestions, toolRequests, toolRuns, customers, tasks. Each has its own field ids; the MCP reference (median_docs with topic analytics) lists them. A query that names a field or value the dataset lacks is refused with invalid_query and a sentence saying what was wrong.

POST/analytics/explore
Authorization
AuthorizationBearer token · headerrequired
`MEDIAN_KEY` from Settings under API, or an MCP OAuth access token. A key acts as the organization; a token acts as the person who approved it.
Request body
requiredapplication/json
queryobjectrequired
Show properties
datasetstringrequired
Allowed:conversationsratingssignalslogsknowledgeDocsknowledgeSuggestionstoolRequeststoolRunscustomerstasksusageEventsmessages
measureobjectrequired
Show properties
opstringrequired
count takes no field. distinct reads an id, string or enum field. percent takes no field but a `where` filter, and gives the share of matched rows passing it, 0 to 100. The rest read a number or duration field.
Allowed:countdistinctsumavgmedianp75p90p95p99minmaxpercent
fieldstring | null
The field id the measure reads.
whereobject
percent only: the condition to count the share of. Same shape as a filter.
Show properties
fieldstringrequired
opstringrequired
valueany
filtersobject[]
Rows have to pass every filter, or any one with `match: "any"`. Enum values are their ids, booleans are true or false, durations are milliseconds. isSet and isNotSet take no value; in and notIn take a list of up to 50.
Show properties
Array of object
fieldstringrequired
opstringrequired
Allowed:isisNotgtgteltltecontainsnotContainsinnotInisSetisNotSet
valuestring | number | boolean | string | number | boolean[]
Show properties
One of:
string
string
number
number
boolean
boolean
string | number | boolean[]
Array of string | number | boolean
One of:
string
string
number
number
boolean
boolean
matchstring
all (the default) lets a row through when it passes every filter, any when it passes one.
Allowed:allany
groupBystring | null
A field id to split the rows into series by. Rows with nothing in the field land in `__none`.
topinteger
How many groups keep their name. The rest fold into `__other`, which takes one of the places.
min 1 · max 20 · default: 8
orderstring
natural keeps the field's own order (most rows first for free text). largest or smallest ranks the groups by the measure, and the ranking picks which keep their name.
default: "natural"
Allowed:naturallargestsmallest
otherboolean
false leaves the groups past `top` off instead of folding them into `__other`. The total then covers only the groups returned.
default: true
bucketstring | null
The x axis. day, week and month cut the window up and need the range scope; hour and weekday fold every row onto one clock.
Allowed:dayweekmonthhourweekday
whenobject
Show properties
fieldstring
Which of the dataset's time fields places a row. The dataset's first by default.
scopestring
range for rows inside the window, all for every row on file. Default range.
Allowed:rangeall
compareboolean
Also measure the same number of days just before the window, returned as `previous`. Ignored with the all scope.
default: false
daysinteger
How far back the window reaches, counted from the UTC midnight before now. Default 30.
min 1 · max 366
frominteger
The window's start, unix ms, in place of counting back.
Responses
200One row of values per group, one column per bucket.
bucketsinteger[] | null
When each column begins, unix ms, for a time axis. Null for a clock axis (24 hours, or Monday to Sunday) and when there is no axis.
groupsstring[]
Group keys in the values' order: the field's values, `__none`, `__other`, or `__all` for an unsplit query.
valuesnumber[][]
One list per group, one entry per column. Null where nothing measured.
totalnumber | null
The measure over every matched row at once.
matchedinteger
scannedinteger
cappedboolean
True when the scan stopped at the table's cap and older rows were not read.
previousobject
Only when the query set `compare`: the same measure over the days just before the window.
Show properties
frominteger
Where the earlier stretch starts, unix ms. It ends where the window begins.
valuesnumber[]
One value per group, in `groups` order, over the whole earlier stretch.
totalnumber | null
matchedinteger
cappedboolean
400The request is malformed, and the message names the field.
errorobject
Show properties
codestring
messagestring
401The bearer token is missing, revoked, or expired.
errorobject
Show properties
codestring
messagestring
429Too many requests. Wait the seconds in `Retry-After`. Limits depend on the plan. See [rate limits](/api/errors-and-limits#rate-limits).
errorobject
Show properties
codestring
messagestring
Request
curl -X POST "https://api.median.sh/v1/analytics/explore" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "query": {
    "dataset": "conversations",
    "measure": {
      "op": "count"
    },
    "filters": [
      {
        "field": "handedOff",
        "op": "is",
        "value": true
      }
    ],
    "groupBy": "channel",
    "bucket": "week"
  },
  "days": 30
}'
Response
{
  "buckets": [
    0
  ],
  "groups": [
    "string"
  ],
  "values": [
    [
      0
    ]
  ],
  "total": 0,
  "matched": 0,
  "scanned": 0,
  "capped": true,
  "previous": {
    "from": 0,
    "values": [
      0
    ],
    "total": 0,
    "matched": 0,
    "capped": true
  }
}