Skip to content

Analytics API

REST endpoints for the Analytics area of Lepsto.

The Analytics area publishes 19 REST endpoints. Paths are relative to https://api.lepsto.com; see Authentication for the required header.

GET/analytics/catalog

Read the analytics semantic catalog: every entity this product may chart, with its declared metrics, dimensions and person-graph identity kinds. Call this FIRST to discover the exact `entity`, `metric` and `dimension` names analytics_metric_query and analytics_funnel_run accept — those names are resolved against this catalog and a name that is not in it is rejected. A metric `unit` describes raw money scale and its currency dimension; a dimension label link names the related entity and columns used for readable group labels. `dropped_metrics`, when present, lists metrics left out of `entities` that cannot be queried: `reason` is type_unknown (a metric type this analytics build does not support yet), aggregate_unknown (a ratio part with an unsupported aggregate) or column_missing (a count_distinct without a column).

MCP tool: analytics_catalog_get

Parameters

No parameters.

Response

Returns object.

FieldTypeAlwaysDescription
cycle
object | null
•
—
entities
object[]
•
—
product_id
string
•
—
generated_at
string
•
—
dropped_metrics
object[]
—
—
GET/analytics/dashboards

List the saved dashboards of the current product, newest first. Narrow by an exact tag or by a case-insensitive substring of the name or slug. Returns definitions, not results.

MCP tool: analytics_dashboard_list

Parameters

NameInTypeRequiredDescription
tagquery
string
—
Exact tag the dashboard must carry
qquery
string
—
Case-insensitive substring of the name or slug

Response

Returns object.

FieldTypeAlwaysDescription
dashboards
object[]
•
—
POST/analytics/dashboards

Save a named dashboard for the current product: up to forty tiles, each either a reference to a saved insight by its uuid (from analytics_insight_list) or a block of markdown, each placed on a twelve-column grid. The slug is the address the dashboard is read by and cannot be changed later. `filters` (up to 8) are the filters the board offers its viewers: {key, label, dimension, map?}. A filter applies to every series whose entity has a dimension named exactly `dimension`; for an entity whose field is named differently, `map` names it ({"googleads_campaign_daily": "campaign_id"}). Similar names are never matched. On a funnel a filter applies to its FIRST step only — it picks who enters, and later steps follow those people even where their entity has no such field (a signup with no utm_campaign) — so a funnel is filtered when its first step has the dimension and unfiltered otherwise. Values are supplied per run (analytics_dashboard_run). Build in order: headline numbers → pivot by campaign → daily dynamics. Example for guidance, not a template: 4–6 bold_number tiles for spend, clicks, visits, unique visitors, pricing and signups with compare; a pivot with cost by campaign_id and group_label campaign_name, clicks, page_view count and unique_visitors by utm_campaign, and a funnel visit → url starts_with /pricing → signup_completed grouped by utm_campaign, every step labelled; rows_label Кампания and formulas cost per click (f1 = A / B) and cost per signup (f2 = A / E). Then a daily line of visits. Offer filters for country and campaign; map campaign to utm_campaign on events and campaign_id on Google Ads. Returns the stored dashboard plus warnings[] {code, message, path} about the board itself: a hard-coded campaign id (an eq, or an in/not_in of up to 5 ids, on utm_campaign or campaign_id) when another tile groups by that field. It does not re-check the saved insights the tiles reference; their warnings come from analytics_insight_create and analytics_insight_update. Stores the arrangement only; it does not run it. Every insight a tile names must already exist in this product, so a stored dashboard always resolves.

MCP tool: analytics_dashboard_create

Parameters

NameInTypeRequiredDescription
slugbody
string
•
—
namebody
string
•
—
tilesbody
object[]
•
—
tagsbody
string[]
—
—
filtersbody
object[]
—
—

Response

Returns object.

FieldTypeAlwaysDescription
id
string (uuid)
•
—
name
string
•
—
slug
string
•
—
tags
string[]
—
—
tiles
object[]
•
—
filters
object[]
—
—
warnings
object[]
•
—
created_at
string (date-time)
•
—
created_by
string | null
•
—
product_id
string (uuid)
•
—
updated_at
string (date-time)
•
—
DELETE/analytics/dashboards/:id

Permanently delete one saved dashboard of the current product. The insights its tiles referred to are not deleted.

MCP tool: analytics_dashboard_delete

Parameters

NameInTypeRequiredDescription
idpath
string (uuid)
•
The dashboard's uuid; slugs are not accepted here

Response

Returns object.

FieldTypeAlwaysDescription
id
string (uuid)
•
—
deleted
booleanone of: true
•
—
PATCH/analytics/dashboards/:id

Change fields of a saved dashboard of the current product. Only the fields supplied are changed; the rest keep their stored values. Supplying tiles replaces the whole arrangement, so send the tiles you want to keep along with the new ones; supplying filters replaces them the same way. The slug cannot be changed — create a new dashboard instead. `filters` (up to 8) are the filters the board offers its viewers: {key, label, dimension, map?}. A filter applies to every series whose entity has a dimension named exactly `dimension`; for an entity whose field is named differently, `map` names it ({"googleads_campaign_daily": "campaign_id"}). Similar names are never matched. On a funnel a filter applies to its FIRST step only — it picks who enters, and later steps follow those people even where their entity has no such field (a signup with no utm_campaign) — so a funnel is filtered when its first step has the dimension and unfiltered otherwise. Values are supplied per run (analytics_dashboard_run). Build in order: headline numbers → pivot by campaign → daily dynamics. Example for guidance, not a template: 4–6 bold_number tiles for spend, clicks, visits, unique visitors, pricing and signups with compare; a pivot with cost by campaign_id and group_label campaign_name, clicks, page_view count and unique_visitors by utm_campaign, and a funnel visit → url starts_with /pricing → signup_completed grouped by utm_campaign, every step labelled; rows_label Кампания and formulas cost per click (f1 = A / B) and cost per signup (f2 = A / E). Then a daily line of visits. Offer filters for country and campaign; map campaign to utm_campaign on events and campaign_id on Google Ads. Returns the stored dashboard plus warnings[] {code, message, path} about the board itself: a hard-coded campaign id (an eq, or an in/not_in of up to 5 ids, on utm_campaign or campaign_id) when another tile groups by that field. It does not re-check the saved insights the tiles reference; their warnings come from analytics_insight_create and analytics_insight_update.

MCP tool: analytics_dashboard_update

Parameters

NameInTypeRequiredDescription
namebody
string
—
—
tilesbody
object[]
—
—
tagsbody
string[]
—
—
filtersbody
object[]
—
—
idpath
string (uuid)
•
The dashboard's uuid; slugs are not accepted here

Response

Returns object.

FieldTypeAlwaysDescription
id
string (uuid)
•
—
name
string
•
—
slug
string
•
—
tags
string[]
—
—
tiles
object[]
•
—
filters
object[]
—
—
warnings
object[]
•
—
created_at
string (date-time)
•
—
created_by
string | null
•
—
product_id
string (uuid)
•
—
updated_at
string (date-time)
•
—
GET/analytics/dashboards/:idOrSlug

Read one saved dashboard of the current product by its slug or its id. Returns the tiles and their layout, not results.

MCP tool: analytics_dashboard_get

Parameters

NameInTypeRequiredDescription
idOrSlugpath
string
•
The dashboard's slug, or its uuid

Response

Returns object.

FieldTypeAlwaysDescription
id
string (uuid)
•
—
name
string
•
—
slug
string
•
—
tags
string[]
—
—
tiles
object[]
•
—
filters
object[]
—
—
created_at
string (date-time)
•
—
created_by
string | null
•
—
product_id
string (uuid)
•
—
updated_at
string (date-time)
•
—
POST/analytics/dashboards/:idOrSlug/run

Run every tile of a saved dashboard of the current product and return one entry per tile, in board order: the tile itself, and what it produced. An insight tile carries exactly what analytics_insight_run answers for that insight; a text tile carries a null result, because its content is the tile. `from` and `to` override the window of every insight tile for this call only, changing nothing stored. `filters` gives values to the board's filters by key ({"country": {"op": "eq", "value": "DE"}}); a series the filter cannot reach runs unfiltered and is listed in its tile's `filters_skipped`. A funnel series takes a filter on its first step only, so it is filtered exactly when that step's entity has the dimension; otherwise it is listed with every step (on a pivot, every <key>.<step> column) as not filtered. `compare` also reads a second range, returned per tile as `compare` (totals, and points laid over the current buckets; a funnel compares its last step; a pivot compares its totals only), whose `compare.window` is always the exact range read: "previous_period" is the window right before with as many days as have elapsed of this one (a window running past today counts through today); "previous_week" is the same days one week earlier; {from, to} is any range of up to 366 whole UTC days (YYYY-MM-DD, inclusive, to not before from), clipped to today, starting no later than today, and it may overlap the window (each is read on its own, so shared days count in both). Points pair by position, day 1 with day 1: a compared range of another length leaves the current buckets past its end with value and prev_bucket null, and a longer one's tail is cut from the points (its total still covers the whole range). A range with no data is totals 0 (null for an average or ratio) and points 0, not a missing compare. To compare yesterday with today: from and to today with compare {from: yesterday, to: yesterday}, or from yesterday to today with "previous_period" (yesterday and today against the two days before). A tile that fails carries an error with an HTTP status and does not stop the rest of the board, so check each tile's result before reading numbers. The call answers only when every tile is done; a heavy board (many tiles, many series) is better loaded tile by tile with analytics_dashboard_tile-run, after analytics_dashboard_get for the layout.

MCP tool: analytics_dashboard_run

Parameters

NameInTypeRequiredDescription
frombody
string (date-time)
—
Inclusive window start; overrides the stored window
tobody
string (date-time)
—
Inclusive window end; overrides the stored window
filtersbody
object
—
Values for the dashboard's filters, by filter key: a filter without its dimension, e.g. {"country": {"op": "eq", "value": "DE"}}. A key the dashboard does not declare is a 400
comparebody
string | objectone of: previous_period, previous_week
—
Also read a second range; each insight tile then carries `compare`, whose `window` is the exact range read. "previous_period": as many days as have elapsed of this window, ending the day before it starts. "previous_week": the same days one week earlier. {from, to}: any range of up to 366 whole UTC days (YYYY-MM-DD, inclusive), clipped to today; it may overlap this window
idOrSlugpath
string
•
The dashboard's slug, or its uuid

Response

Returns object.

FieldTypeAlwaysDescription
tiles
object[]
•
—
dashboard
object
•
—
POST/analytics/dashboards/:idOrSlug/tiles/:tileId/run

Run one tile of a saved dashboard of the current product, by the tile's id (from analytics_dashboard_get), and return that tile's entry: the tile itself and what it produced — the same entry analytics_dashboard_run gives that tile for the same body. Takes the same `from`, `to`, `filters` and `compare` ("previous_period", "previous_week" or {from, to}; to compare yesterday with today, from and to today with compare {from: yesterday, to: yesterday}) as analytics_dashboard_run, checked against the whole board the same way (a filter key the board does not declare is a 400), and a funnel takes a filter on its first step only, exactly as there. Use it to fill a heavy board in progressively, one call per tile, keeping at most about 6 calls in flight per board (as many as analytics_dashboard_run runs at once). A text tile carries a null result; a tile that fails carries an error with an HTTP status rather than failing the call; a tile id the board does not have is a 404.

MCP tool: analytics_dashboard_tile-run

Parameters

NameInTypeRequiredDescription
frombody
string (date-time)
—
Inclusive window start; overrides the stored window
tobody
string (date-time)
—
Inclusive window end; overrides the stored window
filtersbody
object
—
Values for the dashboard's filters, by filter key: a filter without its dimension, e.g. {"country": {"op": "eq", "value": "DE"}}. A key the dashboard does not declare is a 400
comparebody
string | objectone of: previous_period, previous_week
—
Also read a second range; each insight tile then carries `compare`, whose `window` is the exact range read. "previous_period": as many days as have elapsed of this window, ending the day before it starts. "previous_week": the same days one week earlier. {from, to}: any range of up to 366 whole UTC days (YYYY-MM-DD, inclusive), clipped to today; it may overlap this window
idOrSlugpath
string
•
The dashboard's slug, or its uuid
tileIdpath
string (uuid)
•
The tile's id, as analytics_dashboard_get returns it

Response

Returns object.

FieldTypeAlwaysDescription
tile
object
•
—
result
object | null
•
—
POST/analytics/funnels/run

Run an ordered conversion funnel over the analytics semantic layer for the current product. Supply filters on a step to narrow its rows; omit filters to apply no step filters. Each step names a semantic entity and is counted in resolved persons from the identity graph, so a person is counted once per step no matter how many rows or identifiers they produced. Deterministic: entity, dimension and metric names are resolved against the semantic catalog, never generated. A step whose entity has a `propertiesColumn` in the catalog also accepts filters on `props.<key>`, compared as a string. Step filters support legacy {dimension, eq} or op eq, neq, in, not_in, starts_with, is_null, is_not_null; in and not_in take 1–100 values of one type; starts_with takes a string and works on text dimensions. neq and not_in retain NULL rows. Give each step a label (1–60 characters, e.g. Дошли до /pricing); every returned step carries label — the declared one, or its entity and filters when it has none. Prefer this over analytics_query_run whenever the question is a conversion between ordered steps.

MCP tool: analytics_funnel_run

Parameters

NameInTypeRequiredDescription
stepsbody
object[]
•
Ordered funnel steps, 2 to 5
frombody
string
•
Inclusive first day (UTC)
tobody
string
•
Inclusive last day (UTC)
window_daysbody
integer
—
Maximum days between two CONSECUTIVE steps for the later one to count
grainbody
stringone of: day, week, month
—
When set, also return per-step persons bucketed by step-entry time
person_filterbody
stringone of: exclude_identified
—
`exclude_identified` drops the rows of identified people: a person who has an email or a phone in the analytics person graph. The link is the row's identifier, not time, so a visitor's earlier anonymous rows are dropped too once that visitor is identified. Rows with no identifier (cookieless events) are never excluded, because there is nothing to resolve them by. The person graph is rebuilt on a schedule (hourly by default), so a newly identified person is excluded only after the next rebuild. Omit the field to count everyone.

Response

Returns object.

FieldTypeAlwaysDescription
meta
object
•
—
steps
object[]
•
—
series
object[]
—
—
GET/analytics/insights

List the saved insights of the current product, newest first. Narrow by an exact tag or by a case-insensitive substring of the name or slug. Returns definitions, not results.

MCP tool: analytics_insight_list

Parameters

NameInTypeRequiredDescription
tagquery
string
—
Exact tag the insight must carry
qquery
string
—
Case-insensitive substring of the name or slug

Response

Returns object.

FieldTypeAlwaysDescription
insights
object[]
•
—
POST/analytics/insights

Save a named insight for the current product: one to eight series over the analytics semantic layer, an optional formula combining them by key, a time window and how to display it. Use display bold_number for headline KPIs with dashboard compare, pivot for rows × metrics, line for daily dynamics, and steps for funnels. Give every series a human label when there are several. Filters neq and not_in keep NULL rows. Money stays raw; set the series format {kind: money, scale, currency} so readers see its scale and currency. Each series may have a trimmed display label (1–60 characters). Use series format for display, group_label for a grouped metric's label dimension, and formula_label with formula_format for a named formula. For several formulas use formulas [{key f1..f4, label 1–60, expr, format}] (up to 4) instead of formula — never both (400); each is evaluated exactly as formula is and its number is total[key] (and a pivot cell keyed by it). A percent value is a fraction (0.128 means 12.8%). display facts draws the first series as the base bar (100%) and each next series as a bar with its value and % of the base — use it for independent facts about the same visitors (e.g. base = visited from ads, then reached /pricing, clicked CTA, signed up), unlike steps which are sequential; it is for kind number only (400 otherwise) and runs like any number insight. Chart displays (display-only; refused with 400 at display, stacked or combo when the series cannot be drawn, saying what fits): pie for shares of a whole — one metric series with group_by, or 2–8 ungrouped metric series of one unit (format kind, and currency and scale for money), no percent, no formula; area for volume over time, kind trend only; stacked: true (bar or area only) stacks 2+ series or one grouped series of one unit, no percent, no formula; bar_horizontal for a ranking — one grouped metric series, or 2–8 ungrouped series of one unit (a funnel under kind number counts as its last step), no formula; combo for two scales over time (e.g. cost as bars, signups as a line) — kind trend, 2–4 ungrouped metric series, combo {line: [keys]} names the line series or formulas (default the last series), at least one series stays a bar; all bars must share one unit and all lines one unit (format kind, currency and scale for money; no format is a number), else 400 — move the odd series to the line or split the insight. A number insight may combine a funnel (its value is its last step over the window, ungrouped) with metrics in a formula, e.g. cost per signup = cost / funnel to signup_completed. A single metric series in a trend or number insight may use group_by with per-series top_n (1–20, default 8); grouped insights cannot have a formula. display steps shows a funnel as its steps (persons and conversion per step) and is the default for kind funnel; every other kind defaults to line, and steps is refused on them. Give every funnel step a label (1–60 characters): it is the step's column title and steps label; without one it reads as its entity and filters. A funnel series may set hidden_steps [0-based step indexes] — display-only, e.g. hide the entry step that another funnel already shows: hidden steps still count and every number, formula and total is unchanged; at least one step must stay visible. display pivot is a table of rows per group value across series: every series (a metric, or a funnel by a dimension of its first step) may carry its own group_by; rows are joined by the group value as an exact string. A grouped funnel counts a person in EVERY group they entered by, each from their first entry with that value, so a funnel row equals the same funnel with its first step filtered to that value; rows can overlap and its total is the distinct people (the ungrouped funnel), not the sum of rows. Join keys are exact, so the values must match (events.utm_campaign must equal the Google Ads campaign_id); formula runs per row and over the totals, and a formula or sort names a funnel series by its LAST step only (E means E.<last>); sort {by: series key | formula | f1..f4, dir} and top_n (1–50, default 20) order and cap the rows, the rest fold into other; rows_label (1–40) titles the row-header column. Worked example, the ads campaign table: display pivot, rows_label Кампания, series A label Расход = googleads_campaign_daily cost by campaign_id (format money), B label Клики = clicks by campaign_id, E label Путь = funnel by utm_campaign with steps [{label Уникальные, events page_view}, {label Дошли до /pricing, path starts_with /pricing}, {label Регистрации, signup_completed}], formulas [{key f1, label Цена клика, expr A / B, format money}, {key f2, label Цена регистрации, expr A / E, format money}], sort {by A, dir desc}. The slug is the address the insight is read by and cannot be changed later. A save is refused (400, naming the field to fix) for several series without a label, for display pivot without group_by on any series, and for a series whose request does not suit the kind (series.N.request: trend needs metric requests, number metric or funnel requests, funnel needs funnel requests, retention needs retention requests; only display pivot mixes metric and funnel series) — the same insight would fail to run. Otherwise it returns the stored insight plus warnings[] {code, message, path}: advice that does not block the save — series that differ only in one filter value of a dimension other than event_name, with no group_by yet and not combined by one formula (use group_by or pivot), a formula over money without a money formula_format (or a money formulas entry without a money format), a funnel step without a label (it would show as its entity and filters), a money-looking metric without a unit or series format, a window that starts after today (it has no days yet), a daily table longer than 31 rows (use line). A window.to after today is fine: a run clips it to today, so from a fixed date to a later date is the way to say since <date>. Stores the definition only; it does not run it. Series requests are validated with the same schemas analytics_metric_query and analytics_funnel_run accept, so a stored insight always runs.

MCP tool: analytics_insight_create

Parameters

NameInTypeRequiredDescription
slugbody
string
•
—
namebody
string
•
—
descriptionbody
string
—
—
kindbody
stringone of: trend, funnel, number, retention
•
—
seriesbody
object[]
•
—
formulabody
string | null
—
—
formula_labelbody
string
—
—
formula_formatbody
object
—
Display format for a raw value. kind percent means a fraction: 0.128 displays as 12.8%. Money stays raw at the declared scale; readers convert it for display with this format.
formulasbody
object[]
—
Up to four named formulas over the series keys, each its own column or line; use instead of formula
rows_labelbody
string
—
Pivot only: the title of the row-header column, 1 to 40 characters (e.g. Кампания)
windowbody
object
•
—
grainbody
stringone of: day, week, month
—
—
displaybody
stringone of: line, bar, bold_number, table, steps, pivot, facts, pie, area, bar_horizontal, combo
—
How to show the insight. Defaults to steps for a funnel insight, line otherwise. steps is for a funnel only; facts is for kind number only; pivot is a table of rows per group value across series; pie, area, bar_horizontal and combo are refused when the series cannot be drawn that way
stackedbody
boolean
—
Display area or bar only: stack the series (or the groups of one grouped series); all in one unit. Defaults to false
combobody
object
—
Display combo only: which series draw as the line
sortbody
object
—
Pivot only: which column orders the rows, and the direction
top_nbody
integer
—
Pivot only: rows kept, 1 to 50 (default 20); the rest are folded into other
tagsbody
string[]
—
—
targetbody
object | null
—
—

Response

Returns object.

FieldTypeAlwaysDescription
id
string (uuid)
•
—
kind
stringone of: trend, funnel, number, retention
•
—
name
string
•
—
slug
string
•
—
sort
object
—
Pivot only: which column orders the rows, and the direction
tags
string[]
—
—
combo
object
—
Display combo only: which series draw as the line
grain
stringone of: day, week, month
—
—
top_n
integer
—
Pivot only: rows kept, 1 to 50 (default 20); the rest are folded into other
series
object[]
•
—
target
object | null
—
—
window
object
•
—
display
stringone of: line, bar, bold_number, table, steps, pivot, facts, pie, area, bar_horizontal, combo
—
—
formula
string | null
—
—
stacked
boolean
—
Display area or bar only: stack the series (or the groups of one grouped series); all in one unit. Defaults to false
formulas
object[]
—
Up to four named formulas over the series keys, each its own column or line; use instead of formula
warnings
object[]
•
—
created_at
string (date-time)
•
—
created_by
string | null
•
—
product_id
string (uuid)
•
—
rows_label
string
—
Pivot only: the title of the row-header column, 1 to 40 characters (e.g. Кампания)
updated_at
string (date-time)
•
—
description
string
—
—
formula_label
string
—
—
formula_format
object
—
Display format for a raw value. kind percent means a fraction: 0.128 displays as 12.8%. Money stays raw at the declared scale; readers convert it for display with this format.
DELETE/analytics/insights/:id

Permanently delete one saved insight of the current product. Dashboards referring to it will no longer resolve it.

MCP tool: analytics_insight_delete

Parameters

NameInTypeRequiredDescription
idpath
string (uuid)
•
The insight's uuid; slugs are not accepted here

Response

Returns object.

FieldTypeAlwaysDescription
id
string (uuid)
•
—
deleted
booleanone of: true
•
—
PATCH/analytics/insights/:id

Change fields of a saved insight of the current product. Only the fields supplied are changed; the rest keep their stored values. The slug cannot be changed — create a new insight instead. Returns the stored insight plus warnings[] for the row as it now stands. An update is refused only for what it changes: missing labels when it replaces series, pivot without group_by when it changes display or series, a chart display that cannot be drawn when it changes kind, display, series, stacked, combo or a formula; the same findings on an older insight come back as warnings. Switching display drops a stored stacked or combo the new display does not use (the response shows them gone). A series replaced here carries its own hidden_steps (display-only; omit it to show every step).

MCP tool: analytics_insight_update

Parameters

NameInTypeRequiredDescription
namebody
string
—
—
descriptionbody
string
—
—
kindbody
stringone of: trend, funnel, number, retention
—
—
seriesbody
object[]
—
—
formulabody
string | null
—
—
formula_labelbody
string | null
—
—
formula_formatbody
object | null
—
Display format for a raw value. kind percent means a fraction: 0.128 displays as 12.8%. Money stays raw at the declared scale; readers convert it for display with this format.
formulasbody
object[] | null
—
Up to four named formulas over the series keys, each its own column or line; use instead of formula
rows_labelbody
string | null
—
—
windowbody
object
—
—
grainbody
stringone of: day, week, month
—
—
displaybody
stringone of: line, bar, bold_number, table, steps, pivot, facts, pie, area, bar_horizontal, combo
—
—
stackedbody
boolean | null
—
Display area or bar only: stack the series (or the groups of one grouped series); all in one unit. Defaults to false
combobody
object | null
—
—
sortbody
object | null
—
—
top_nbody
integer | null
—
—
tagsbody
string[]
—
—
targetbody
object | null
—
—
idpath
string (uuid)
•
The insight's uuid; slugs are not accepted here

Response

Returns object.

FieldTypeAlwaysDescription
id
string (uuid)
•
—
kind
stringone of: trend, funnel, number, retention
•
—
name
string
•
—
slug
string
•
—
sort
object
—
Pivot only: which column orders the rows, and the direction
tags
string[]
—
—
combo
object
—
Display combo only: which series draw as the line
grain
stringone of: day, week, month
—
—
top_n
integer
—
Pivot only: rows kept, 1 to 50 (default 20); the rest are folded into other
series
object[]
•
—
target
object | null
—
—
window
object
•
—
display
stringone of: line, bar, bold_number, table, steps, pivot, facts, pie, area, bar_horizontal, combo
—
—
formula
string | null
—
—
stacked
boolean
—
Display area or bar only: stack the series (or the groups of one grouped series); all in one unit. Defaults to false
formulas
object[]
—
Up to four named formulas over the series keys, each its own column or line; use instead of formula
warnings
object[]
•
—
created_at
string (date-time)
•
—
created_by
string | null
•
—
product_id
string (uuid)
•
—
rows_label
string
—
Pivot only: the title of the row-header column, 1 to 40 characters (e.g. Кампания)
updated_at
string (date-time)
•
—
description
string
—
—
formula_label
string
—
—
formula_format
object
—
Display format for a raw value. kind percent means a fraction: 0.128 displays as 12.8%. Money stays raw at the declared scale; readers convert it for display with this format.
GET/analytics/insights/:idOrSlug

Read one saved insight of the current product by its slug or its id. Returns the definition, not results.

MCP tool: analytics_insight_get

Parameters

NameInTypeRequiredDescription
idOrSlugpath
string
•
The insight's slug, or its uuid

Response

Returns object.

FieldTypeAlwaysDescription
id
string (uuid)
•
—
kind
stringone of: trend, funnel, number, retention
•
—
name
string
•
—
slug
string
•
—
sort
object
—
Pivot only: which column orders the rows, and the direction
tags
string[]
—
—
combo
object
—
Display combo only: which series draw as the line
grain
stringone of: day, week, month
—
—
top_n
integer
—
Pivot only: rows kept, 1 to 50 (default 20); the rest are folded into other
series
object[]
•
—
target
object | null
—
—
window
object
•
—
display
stringone of: line, bar, bold_number, table, steps, pivot, facts, pie, area, bar_horizontal, combo
—
—
formula
string | null
—
—
stacked
boolean
—
Display area or bar only: stack the series (or the groups of one grouped series); all in one unit. Defaults to false
formulas
object[]
—
Up to four named formulas over the series keys, each its own column or line; use instead of formula
created_at
string (date-time)
•
—
created_by
string | null
•
—
product_id
string (uuid)
•
—
rows_label
string
—
Pivot only: the title of the row-header column, 1 to 40 characters (e.g. Кампания)
updated_at
string (date-time)
•
—
description
string
—
—
formula_label
string
—
—
formula_format
object
—
Display format for a raw value. kind percent means a fraction: 0.128 displays as 12.8%. Money stays raw at the declared scale; readers convert it for display with this format.
POST/analytics/insights/:idOrSlug/run

Run a saved insight of the current product and return its numbers: every series executed over the resolved window and aligned onto the same buckets, the formula evaluated bucket by bucket, a total per series, optional series_labels keyed by series key, and whether the target was met. Grouped metric insights return ranked groups (top_n plus other for count/sum), and meta with group_by and group counts. Money stays raw at its scale; series_format tells the app how to convert and display it. When grouped by currency, each value group carries its own format and currency; mixed-currency headlines, formula totals, and the other group are null with a reason in meta. A funnel insight also returns steps: per series key, every step over the whole window with label, persons, conversion_from_first and conversion_from_prev — a step nobody reached is 0, never missing; its series and total remain the last step per bucket. A pivot insight returns pivot: rows {key, label, cells} per group value merged across series by exact string key (a cell is null where that series has no row), other (the rows past top_n), total and total_reasons, sort and meta {rows_total, rows_dropped, top_n}; a funnel series is one cell per step keyed <key>.<stepIndex> with series_steps labels, and step_pct on each row, on other and as total_step_pct gives each step cell over that row's first step (1 for step 0, null when step 0 is 0), so a cell reads 41 · 13.6 %; rows_label is the row-header title when the insight declares one. An insight with formulas returns formulas (per key, bucket by bucket; absent for a pivot, whose numbers are the cells f1..f4), formula_labels and formula_formats keyed by formula key in definition order, and each formula's total under total[key]; compare carries formulas and total[key] the same way. Totals are honest: count and sum are summed over all rows; count_distinct, avg and ratio are read ungrouped over the window; a grouped funnel's rows overlap (a person is in every group they entered by), so its step totals are the ungrouped funnel — distinct people — and its other is read on its own: the distinct people who entered by any group past top_n. Where a total cannot be read it is null with the reason in total_reasons (other follows the same rule), never a wrong number. A pivot has no buckets: series is empty and formula null. Missing count/sum buckets are zero. The window comes from the stored definition — relative windows and the current cycle are resolved at call time — and `from` and `to` override it for this call only, changing nothing stored. Use this rather than rebuilding the insight out of analytics_metric_query calls: the alignment and the formula are what make the numbers comparable.

MCP tool: analytics_insight_run

Parameters

NameInTypeRequiredDescription
frombody
string (date-time)
—
Inclusive window start; overrides the stored window
tobody
string (date-time)
—
Inclusive window end; overrides the stored window
idOrSlugpath
string
•
The insight's slug, or its uuid

Response

Returns object.

FieldTypeAlwaysDescription
meta
object
—
—
extra
object
—
—
pivot
object
—
—
steps
object
—
—
total
object
•
—
groups
object[]
—
—
series
object
•
—
window
object
•
—
compare
object
—
—
formula
object[] | null
•
—
insight
object | null
•
—
formulas
object
—
—
formula_label
string
—
—
series_format
object
•
—
series_labels
object
—
—
target_status
string | nullone of: met, missed
•
—
formula_labels
object
—
—
filters_skipped
object[]
—
—
formula_formats
object
—
—
POST/analytics/metrics/query

Compute declared metrics from the analytics semantic layer for the current product, bucketed by time. Supply group_by to split each time bucket by one dimension; omit it to aggregate without dimension grouping. Deterministic: entity, metric and dimension names are resolved against the semantic catalog, never generated. Prefer this over analytics_query_run whenever the question is a metric over time — no LLM. Where the catalog gives an entity a `propertiesColumn`, `group_by` and a filter dimension also accept `props.<key>` to read one raw event property; property values always compare as strings. Filters support legacy {dimension, eq} or op eq, neq, in, not_in, starts_with, is_null, is_not_null; in and not_in take 1–100 values of one type; starts_with takes a string and works on text dimensions. neq and not_in retain NULL rows.

MCP tool: analytics_metric_query

Parameters

NameInTypeRequiredDescription
entitybody
string
•
Semantic view name from the catalog
metricsbody
string[]
•
Declared metric names to compute. A metric of type `count_distinct` must be the only one: request it separately
grainbody
stringone of: day, week, month
•
Time bucket size
frombody
string
•
Inclusive first day (UTC)
tobody
string
•
Inclusive last day (UTC)
group_bybody
string
—
One declared dimension, or `props.<key>`, to group by
filtersbody
object[]
—
Filters on declared dimensions or `props.<key>`: legacy eq, or op eq, neq, in, not_in (1–100 values of one type), starts_with (string value on text dimensions), is_null, is_not_null. neq and not_in retain NULL rows.
person_filterbody
stringone of: exclude_identified
—
`exclude_identified` drops the rows of identified people: a person who has an email or a phone in the analytics person graph. The link is the row's identifier, not time, so a visitor's earlier anonymous rows are dropped too once that visitor is identified. Rows with no identifier (cookieless events) are never excluded, because there is nothing to resolve them by. The person graph is rebuilt on a schedule (hourly by default), so a newly identified person is excluded only after the next rebuild. Omit the field to count everyone.

Response

Returns object.

FieldTypeAlwaysDescription
meta
object
•
—
series
object[]
•
—
POST/analytics/persons/timeline

Return one resolved person's profile and their chronological activity across every identity-bearing semantic entity of the current product. Address the person either by person_id or by any single identifier (email, phone, users_id, anonymous_id), which is normalised exactly as the identity graph normalised it. Deterministic: no LLM, and only catalog-declared columns are returned. Prefer this over analytics_query_run whenever the question is about one specific person.

MCP tool: analytics_person_timeline

Parameters

NameInTypeRequiredDescription
person_idbody
string
—
Graph person id, when already known
identifierbody
object
—
Any single identifier belonging to the person
frombody
string
—
Inclusive first day (UTC); unbounded when omitted
tobody
string
—
Inclusive last day (UTC); unbounded when omitted
limitbody
integer
—
Maximum events to return, newest first

Response

Returns object.

FieldTypeAlwaysDescription
meta
object
•
—
events
object[]
•
—
person
object
•
—
truncated
boolean
•
—
POST/analytics/query

Answer a natural-language analytics question for the current product. Fallback surface: it routes the question to analytics_metric_query or analytics_funnel_run when it fits one of them and returns that tool's exact request and response in `structured`; it generates SQL only when neither fits. Call analytics_metric_query, analytics_funnel_run or analytics_person_timeline directly when you already know the shape of the question — those are deterministic and cheaper.

MCP tool: analytics_query_run

Parameters

NameInTypeRequiredDescription
qbody
string
•
Natural-language analytics question

Response

Returns object.

FieldTypeAlwaysDescription
sql
string
•
—
rows
object[]
•
—
answer
string
•
—
truncated
boolean
•
—
structured
object
—
—
explanation
string
•
—
POST/analytics/retention/run

Measure day-N retention over the analytics semantic layer for the current product: of the subjects whose FIRST matching cohort event falls in a bucket, how many produced a return event on day N (within `return_window_days` after it). The cohort key is `subject` — an event property (`props.<key>`, e.g. the customer product id) or `identity` for the entity's declared identity columns — and each subject is counted exactly once. Deterministic: entity and dimension names are resolved against the semantic catalog, never generated. A bucket whose day-N horizon has not elapsed yet is still returned, with `retained` and `rate` NULL rather than 0 — null means "not measurable yet", 0 means "measured, nobody came back", and a caller must not confuse them. `total` therefore covers the measurable buckets ONLY, so a half-elapsed cohort never drags the headline rate down; `meta.unmeasurable_buckets` says how many were left out.

MCP tool: analytics_retention_run

Parameters

NameInTypeRequiredDescription
entitybody
string
•
Semantic view name from the catalog
subjectbody
string
•
Cohort key: "identity" or `props.<key>`
cohortbody
object
—
The starting event; empty filters mean any row of the entity
returnbody
object
—
The coming-back event; empty filters mean any row of the entity
daybody
integer
•
N: a subject is retained if it has a return event at least N days after its cohort event
return_window_daysbody
integer
—
Length of the window that opens on day N; a return event must fall inside it
frombody
string
•
Inclusive first day of the cohort range (UTC)
tobody
string
•
Inclusive last day of the cohort range (UTC)
grainbody
stringone of: day, week, month
•
Cohort bucket size, applied to each subject's FIRST cohort event

Response

Returns object.

FieldTypeAlwaysDescription
meta
object
•
—
total
object
•
—
buckets
object[]
•
—
Was this page helpful?
Esc

Start typing to search the docs.

↑↓navigate↵select