PilotFoxDocs

Tools

Every tool the MCP server offers, its parameters and the permission it needs.

Every tool runs one route of the REST API with the caller's credential: one authorization path, so a tool needs the same permission as its route, checks site access the same way and answers the same data. The tool reference below lists every tool with its arguments, its permission and the route it runs. It is generated from the server's own tools/list answer, and the backend's tests fail when it falls behind.

A client sees only the tools its credential allows: an API key gets the tools of its permissions, an OAuth token those of its scopes and the person's role together. Calling a tool the credential does not have is a JSON-RPC error, -32602 "Tool create_goal not found".

How a tool runs

The tool's arguments become the route's request:

  • Arguments named in the route's path (siteId, and id, sessionId or userId where the route has them) fill the path. An empty value, . or .. is refused before the route runs (bad_request, "Invalid id" for an id).
  • body, for the tools that have it, is the route's JSON request body.
  • Every other argument goes to the query string, to the REST parameter of the same name; filters is sent as JSON, as the REST API expects. The route's page in the API reference documents the values each parameter takes (GET /api/v1/sites/{siteId}/pages for the pages tool, for example).
  • list_sites takes no organization: it reads the credential's own organization.

The route then validates the request, checks the credential's access to the site and runs. When the client cancels an MCP request, a GET tool's route stops its query too.

Arguments shared by the reports

Site

siteId is the site's public id, the same value as the tracking script's data-site attribute. list_sites returns the ids the credential can reach.

Time window

Every tool that takes start, end, last and all needs a time window, given in exactly one of three ways:

ArgumentsWindow
lastThe last 30m, 12h, 7d…, up to 400d.
start and endTwo dates (YYYY-MM-DD, in the time zone tz, end included), or two ISO instants with an offset (end excluded). Both in the same form.
alltrue: all time.

The tool's input schema (and the reference below) marks each of these arguments as optional, because the REST route checks the combination, not the schema; the description of start says that every call needs exactly one window. A call without a window, or with two forms, fails with this error result:

{"code":"bad_request","message":"Invalid request","details":[{"in":"querystring","path":"/","code":"custom","message":"exactly one of start+end, last or all is required"}]}

This holds for overview, timeseries, breakdown, pages, geo_countries, geo_points, events, event_names, errors, vitals, sessions, users, analyze_funnel, journeys, retention, revenue_summary, revenue_breakdown and annotations. The one exception is events with since (a realtime tail of the events since an ISO instant within the last 24 hours), which takes no window. The other tools (list_sites, get_site, live, session, user, goals, funnels, segments, and the create, update, save and delete tools) have no window arguments. If you write instructions for an assistant, tell it to pass a window, such as "last": "28d".

tz is an IANA time zone (default: the site's). bucket sets the time series' step (default: chosen from the window's length). compare (previous or year) adds the previous period of the same length, or the same period a year earlier, to overview, timeseries and revenue_summary, the only tools that take it. See Time windows, filters and comparisons for the details.

Filters and saved segments

filters is a list of conditions, all of which must hold (at most 20): { "dim": "country", "op": "eq", "values": ["US"] }. The dimensions and operators are the REST API's, listed in Time windows, filters and comparisons.

segment applies a saved segment: pass the id of one returned by the segments tool, and its filters apply, merged with any filters you add. These two calls give the same numbers when segment ae378024-… holds those two filters:

{ "siteId": "SITE_ID", "last": "7d", "segment": "ae378024-68b3-43b3-8ba3-5860a3a5beec" }
{
  "siteId": "SITE_ID",
  "last": "7d",
  "filters": [
    { "dim": "device_type", "op": "eq", "values": ["desktop"] },
    { "dim": "referrer_domain", "op": "eq", "values": ["google.com"] }
  ]
}

An API key sees only the segments shared with the organization; an OAuth token also sees the person's own private segments. A segment the credential cannot see answers not_found "Segment not found".

Paging

Lists return one page at a time. breakdown, pages, errors and revenue_breakdown take limit and offset, and their meta.totalCount gives the number of rows. events, sessions and users take limit and cursor: pass the previous page's meta.nextCursor as cursor to get the next one (it is null on the last page). See Pagination.

Results and error results

A successful call returns one text block holding the route's JSON response, { "data": …, "meta": … }, with every string cleaned of invisible and control characters (see Tool results are data, not instructions). A tool whose route answers 204 No Content, such as delete_goal, returns {}.

tools/call result of breakdown (dim: referrer_domain, limit: 2), abridged
{
  "content": [
    {
      "type": "text",
      "text": "{\"data\":[{\"value\":\"google.com\",\"visitors\":72,\"sessions\":78,\"pageviews\":177,\"bounce_rate\":35.8974358974359,\"avg_session_duration\":90.77826923076924,\"percentage\":36.18090452261307},{\"value\":\"news.ycombinator.com\",\"visitors\":22,\"sessions\":23,\"pageviews\":49,\"bounce_rate\":47.82608695652174,\"avg_session_duration\":87.45765217391305,\"percentage\":11.055276381909549}],\"meta\":{\"window\":{\"from\":\"2026-10-20T20:39:21.096Z\",\"to\":\"2026-10-27T20:39:21.096Z\",\"tz\":\"UTC\",\"bucket\":\"day\"},\"totalCount\":7,\"cache\":\"miss\"}}"
    }
  ]
}

A call that fails returns isError: true and a text block:

FailureText
The route refused the requestThe REST error object, e.g. {"code":"not_found","message":"Site not found"} or {"code":"bad_request","message":"Invalid request","details":[{"in":"querystring","path":"/last","code":"custom","message":"last must look like 30m, 12h or 7d"}]}
The arguments do not match the tool's input schemaInput validation error: Invalid arguments for tool overview: siteId: Invalid input: expected string, received undefined
The MCP request was cancelled{"code":"aborted"}

A site the credential cannot reach answers not_found, whether it exists or not.

Write tools

The tools whose Effect is "adds" or "changes or deletes" in the reference write. They need goals:write, funnels:write or annotations:write, and their body is the request body of their REST route.

Goal bodies

create_goal takes { name, condition, icon? } and update_goal any of these fields (at least one). name has 1 to 100 characters; icon is one character or null; condition is one of:

kindFields
pagepath (a glob: * matches one path segment, ** any run), hostname?, props?
eventname (the custom event's name), hostname?, props?
outbound, click, form, copymatch? (a glob), hostname?

props is a list of up to 10 property conditions { key, op, value }, with op one of eq, neq, contains, gt, lt. A site holds at most 100 goals. The full schema is in the API reference: create a goal, update a goal.

create_goal arguments
{
  "siteId": "SITE_ID",
  "body": { "name": "Viewed pricing", "condition": { "kind": "page", "path": "/pricing" } }
}

Funnel bodies

save_funnel takes { name, steps, windowSeconds? }, and analyze_funnel { steps, windowSeconds? } plus a time window. steps holds 2 to 10 conditions of the goal form above, each with an optional label (1 to 100 characters). Without windowSeconds, a funnel counts the steps within one session; with it (1 to 7,776,000 seconds), it follows each user across sessions and keeps the steps within that many seconds of the first. analyze_funnel only reads: it reports the conversion of steps you have not saved. See analyze a funnel and save a funnel.

analyze_funnel arguments
{
  "siteId": "SITE_ID",
  "last": "7d",
  "body": {
    "steps": [
      { "kind": "page", "path": "/" },
      { "kind": "page", "path": "/pricing", "label": "Pricing" }
    ]
  }
}
analyze_funnel result (the text block, parsed)
{
  "data": {
    "unit": "sessions",
    "windowSeconds": null,
    "steps": [
      { "step": 1, "label": null, "condition": { "kind": "page", "path": "/" }, "count": 95, "conversion": 100, "dropoff": null, "median_seconds": null },
      { "step": 2, "label": "Pricing", "condition": { "kind": "page", "path": "/pricing" }, "count": 24, "conversion": 25.263157894736842, "dropoff": 74.73684210526316, "median_seconds": 108.122 }
    ]
  },
  "meta": { "window": { "from": "2026-10-20T20:31:17.841Z", "to": "2026-10-27T20:31:17.841Z", "tz": "UTC", "bucket": "day" } }
}

Annotation bodies

create_annotation takes the annotation's own fields only: title, startsAt and optionally description, endsAt, color and icon (see its reference). The annotation is always private to the organization's members and shown on this site only.

create_annotation arguments
{
  "siteId": "SITE_ID",
  "body": { "title": "Pricing page redesign", "startsAt": "2026-10-20T09:00:00Z", "color": "blue" }
}

Safety

  • Writes are marked. Every tool carries MCP tool annotations, hints a client can use to ask before it acts:

    AnnotationMeaning here
    readOnlyHint: trueReads only. Every GET tool, and analyze_funnel, which is a POST that only reads.
    readOnlyHint: false, destructiveHint: falseAdds something and changes nothing that exists (the create and save tools).
    readOnlyHint: false, destructiveHint: trueChanges or deletes something that exists (the update and delete tools).
    openWorldHint: falseOn every tool: none reaches anything outside PilotFox.

    Annotations are hints for the client. What a tool may do is decided by the credential's permissions, checked by the REST route on every call.

  • create_annotation cannot publish. It has no isPublic and no scope, and refuses them (Input validation error: … Unrecognized key: "isPublic") before anything is stored. The REST route refuses a public or organization-wide annotation from any MCP call as well. So text a model read in a tool result can never reach share links, public-site visitors or the organization's other sites through MCP.

  • Nothing beyond goals, funnels and annotations. No tool manages sites, members, API keys, share links, settings or data deletion.

  • Give assistants read-only credentials unless they must write, and prefer clients that ask before a write. A model can be steered by text your visitors sent; see Tool results are data, not instructions.

Tool reference

ToolPermissionEffectWhat it does
list_sitessite:readread-onlyThe sites this credential can see.
get_siteanalytics:readread-onlyOne site: name, domain, time zone, settings.
overviewanalytics:readread-onlyVisitors, sessions, pageviews, bounce, duration.
timeseriesanalytics:readread-onlyMetrics per time bucket.
breakdownanalytics:readread-onlyTop values of one dimension.
pagesanalytics:readread-onlyPages with entries, exits, bounce and time on page.
liveanalytics:readread-onlyVisitors right now, top pages, referrers, countries.
geo_countriesanalytics:readread-onlyVisitors per country.
geo_pointsanalytics:readread-onlyVisitors binned on a map grid.
eventssessions:readread-onlyThe raw event list, newest first.
event_namesanalytics:readread-onlyCustom event names with counts.
errorsanalytics:readread-onlyJavaScript errors grouped by fingerprint.
vitalsanalytics:readread-onlyCore Web Vitals percentiles.
sessionssessions:readread-onlySessions, newest first.
sessionsessions:readread-onlyOne session with its events.
usersusers:readread-onlyVisitors and identified users.
userusers:readread-onlyOne user's profile and traits.
goalsgoals:readread-onlyThe site's goals.
create_goalgoals:writeaddsCreates a goal: {name, condition, icon?}.
update_goalgoals:writechanges or deletesUpdates a goal.
delete_goalgoals:writechanges or deletesDeletes a goal.
funnelsfunnels:readread-onlyThe site's saved funnels.
analyze_funnelfunnels:readread-onlyConversion through steps: {steps}.
save_funnelfunnels:writeaddsSaves a funnel: {name, steps}.
delete_funnelfunnels:writechanges or deletesDeletes a funnel.
journeysanalytics:readread-onlyThe most common page paths.
retentionanalytics:readread-onlyCohort retention.
revenue_summaryrevenue:readread-onlyRevenue, payments, refunds, average order and conversion of paying visitors, in one currency.
revenue_breakdownrevenue:readread-onlyRevenue by one dimension of the paying visit (channel, referrer_domain, utm_source, country…) or affiliate.
segmentssegments:readread-onlySaved segments; pass one's id as segment.
annotationsanalytics:readread-onlyChart annotations.
create_annotationannotations:writeaddsCreates a private annotation on this site's charts: {title, startsAt, description?, endsAt?, color?, icon?}.

list_sites

The sites this credential can see.

  • Permission: site:read
  • Runs: GET /api/v1/orgs/{orgId}/sites, with orgId set to the credential's organization
  • Annotations: readOnlyHint: true, openWorldHint: false

No arguments.

get_site

One site: name, domain, time zone, settings.

  • Permission: analytics:read
  • Runs: GET /api/v1/sites/{siteId}
  • Annotations: readOnlyHint: true, openWorldHint: false
ArgumentTypeRequiredDescription
siteIdstringyesThe site's public id (list_sites)

overview

Visitors, sessions, pageviews, bounce, duration.

  • Permission: analytics:read
  • Runs: GET /api/v1/sites/{siteId}/overview
  • Annotations: readOnlyHint: true, openWorldHint: false
ArgumentTypeRequiredDescription
siteIdstringyesThe site's public id (list_sites)
startstringnoWindow start: a date (YYYY-MM-DD, in tz) or an ISO instant; with end. Every call needs exactly one window: start+end, last or all
endstringnoWindow end: a date (inclusive) or an ISO instant (exclusive); with start
laststringnoInstead of start/end: the last 30m, 12h, 7d, … (at most 400d)
tzstringnoIANA time zone; default the site's
allbooleannotrue: all time instead of a window
bucket"minute" | "5m" | "15m" | "hour" | "day" | "week" | "month" | "year"noTime bucket of the answer's series or trends; default from the window's length
compare"previous" | "year"noAlso the previous period of the same length, or the same period a year earlier, under previous
filters{ dim: string; op: string; values: (string | number | boolean)[] }[]noFilters, ANDed, e.g. [{dim: 'country', op: 'eq', values: ['US']}]
segmentstringnoA saved segment's id (segments): its filters apply

timeseries

Metrics per time bucket.

  • Permission: analytics:read
  • Runs: GET /api/v1/sites/{siteId}/timeseries
  • Annotations: readOnlyHint: true, openWorldHint: false
ArgumentTypeRequiredDescription
siteIdstringyesThe site's public id (list_sites)
startstringnoWindow start: a date (YYYY-MM-DD, in tz) or an ISO instant; with end. Every call needs exactly one window: start+end, last or all
endstringnoWindow end: a date (inclusive) or an ISO instant (exclusive); with start
laststringnoInstead of start/end: the last 30m, 12h, 7d, … (at most 400d)
tzstringnoIANA time zone; default the site's
allbooleannotrue: all time instead of a window
bucket"minute" | "5m" | "15m" | "hour" | "day" | "week" | "month" | "year"noTime bucket of the answer's series or trends; default from the window's length
compare"previous" | "year"noAlso the previous period of the same length, or the same period a year earlier, under previous
filters{ dim: string; op: string; values: (string | number | boolean)[] }[]noFilters, ANDed, e.g. [{dim: 'country', op: 'eq', values: ['US']}]
segmentstringnoA saved segment's id (segments): its filters apply
metricsstringnoComma list of metrics (default all)

breakdown

Top values of one dimension.

  • Permission: analytics:read
  • Runs: GET /api/v1/sites/{siteId}/breakdown
  • Annotations: readOnlyHint: true, openWorldHint: false
ArgumentTypeRequiredDescription
siteIdstringyesThe site's public id (list_sites)
startstringnoWindow start: a date (YYYY-MM-DD, in tz) or an ISO instant; with end. Every call needs exactly one window: start+end, last or all
endstringnoWindow end: a date (inclusive) or an ISO instant (exclusive); with start
laststringnoInstead of start/end: the last 30m, 12h, 7d, … (at most 400d)
tzstringnoIANA time zone; default the site's
allbooleannotrue: all time instead of a window
bucket"minute" | "5m" | "15m" | "hour" | "day" | "week" | "month" | "year"noTime bucket of the answer's series or trends; default from the window's length
filters{ dim: string; op: string; values: (string | number | boolean)[] }[]noFilters, ANDed, e.g. [{dim: 'country', op: 'eq', values: ['US']}]
segmentstringnoA saved segment's id (segments): its filters apply
limitintegernoRows per page (default 50)
offsetintegernoRows to skip, for the next page (default 0)
dimstringyesDimension, e.g. country, browser, referrer_domain, utm_source
metricstringnoRanks the values: visitors (default), sessions, pageviews, bounce_rate or avg_session_duration

pages

Pages with entries, exits, bounce and time on page.

  • Permission: analytics:read
  • Runs: GET /api/v1/sites/{siteId}/pages
  • Annotations: readOnlyHint: true, openWorldHint: false
ArgumentTypeRequiredDescription
siteIdstringyesThe site's public id (list_sites)
startstringnoWindow start: a date (YYYY-MM-DD, in tz) or an ISO instant; with end. Every call needs exactly one window: start+end, last or all
endstringnoWindow end: a date (inclusive) or an ISO instant (exclusive); with start
laststringnoInstead of start/end: the last 30m, 12h, 7d, … (at most 400d)
tzstringnoIANA time zone; default the site's
allbooleannotrue: all time instead of a window
bucket"minute" | "5m" | "15m" | "hour" | "day" | "week" | "month" | "year"noTime bucket of the answer's series or trends; default from the window's length
filters{ dim: string; op: string; values: (string | number | boolean)[] }[]noFilters, ANDed, e.g. [{dim: 'country', op: 'eq', values: ['US']}]
segmentstringnoA saved segment's id (segments): its filters apply
limitintegernoRows per page (default 50)
offsetintegernoRows to skip, for the next page (default 0)
viewstringnoall, entry or exit
groupstringnopage or section
searchstringnoCase-insensitive match on the pathname or the title

live

Visitors right now, top pages, referrers, countries.

  • Permission: analytics:read
  • Runs: GET /api/v1/sites/{siteId}/live
  • Annotations: readOnlyHint: true, openWorldHint: false
ArgumentTypeRequiredDescription
siteIdstringyesThe site's public id (list_sites)

geo_countries

Visitors per country.

  • Permission: analytics:read
  • Runs: GET /api/v1/sites/{siteId}/geo/countries
  • Annotations: readOnlyHint: true, openWorldHint: false
ArgumentTypeRequiredDescription
siteIdstringyesThe site's public id (list_sites)
startstringnoWindow start: a date (YYYY-MM-DD, in tz) or an ISO instant; with end. Every call needs exactly one window: start+end, last or all
endstringnoWindow end: a date (inclusive) or an ISO instant (exclusive); with start
laststringnoInstead of start/end: the last 30m, 12h, 7d, … (at most 400d)
tzstringnoIANA time zone; default the site's
allbooleannotrue: all time instead of a window
bucket"minute" | "5m" | "15m" | "hour" | "day" | "week" | "month" | "year"noTime bucket of the answer's series or trends; default from the window's length
filters{ dim: string; op: string; values: (string | number | boolean)[] }[]noFilters, ANDed, e.g. [{dim: 'country', op: 'eq', values: ['US']}]
segmentstringnoA saved segment's id (segments): its filters apply

geo_points

Visitors binned on a map grid.

  • Permission: analytics:read
  • Runs: GET /api/v1/sites/{siteId}/geo/points
  • Annotations: readOnlyHint: true, openWorldHint: false
ArgumentTypeRequiredDescription
siteIdstringyesThe site's public id (list_sites)
startstringnoWindow start: a date (YYYY-MM-DD, in tz) or an ISO instant; with end. Every call needs exactly one window: start+end, last or all
endstringnoWindow end: a date (inclusive) or an ISO instant (exclusive); with start
laststringnoInstead of start/end: the last 30m, 12h, 7d, … (at most 400d)
tzstringnoIANA time zone; default the site's
allbooleannotrue: all time instead of a window
bucket"minute" | "5m" | "15m" | "hour" | "day" | "week" | "month" | "year"noTime bucket of the answer's series or trends; default from the window's length
filters{ dim: string; op: string; values: (string | number | boolean)[] }[]noFilters, ANDed, e.g. [{dim: 'country', op: 'eq', values: ['US']}]
segmentstringnoA saved segment's id (segments): its filters apply
binstringyesh3 (H3 cells, sized by res) or grid (a latitude/longitude grid, sized by precision)
resintegernoWith bin h3: the H3 resolution, 2 to 7 (default 4)
precisionintegernoWith bin grid: decimals of the grid's degrees, 0 to 2 (default 1)

events

The raw event list, newest first.

  • Permission: sessions:read
  • Runs: GET /api/v1/sites/{siteId}/events
  • Annotations: readOnlyHint: true, openWorldHint: false
ArgumentTypeRequiredDescription
siteIdstringyesThe site's public id (list_sites)
startstringnoWindow start: a date (YYYY-MM-DD, in tz) or an ISO instant; with end. Every call needs exactly one window: start+end, last or all
endstringnoWindow end: a date (inclusive) or an ISO instant (exclusive); with start
laststringnoInstead of start/end: the last 30m, 12h, 7d, … (at most 400d)
tzstringnoIANA time zone; default the site's
allbooleannotrue: all time instead of a window
bucket"minute" | "5m" | "15m" | "hour" | "day" | "week" | "month" | "year"noTime bucket of the answer's series or trends; default from the window's length
filters{ dim: string; op: string; values: (string | number | boolean)[] }[]noFilters, ANDed, e.g. [{dim: 'country', op: 'eq', values: ['US']}]
segmentstringnoA saved segment's id (segments): its filters apply
cursorstringnometa.nextCursor of the previous page
limitintegernoRows per page (default 50)
sincestringnoInstead of a window, the realtime tail: events since this ISO instant (≤ 24 h)

event_names

Custom event names with counts.

  • Permission: analytics:read
  • Runs: GET /api/v1/sites/{siteId}/events/names
  • Annotations: readOnlyHint: true, openWorldHint: false
ArgumentTypeRequiredDescription
siteIdstringyesThe site's public id (list_sites)
startstringnoWindow start: a date (YYYY-MM-DD, in tz) or an ISO instant; with end. Every call needs exactly one window: start+end, last or all
endstringnoWindow end: a date (inclusive) or an ISO instant (exclusive); with start
laststringnoInstead of start/end: the last 30m, 12h, 7d, … (at most 400d)
tzstringnoIANA time zone; default the site's
allbooleannotrue: all time instead of a window
bucket"minute" | "5m" | "15m" | "hour" | "day" | "week" | "month" | "year"noTime bucket of the answer's series or trends; default from the window's length
filters{ dim: string; op: string; values: (string | number | boolean)[] }[]noFilters, ANDed, e.g. [{dim: 'country', op: 'eq', values: ['US']}]
segmentstringnoA saved segment's id (segments): its filters apply
limitintegernoAt most this many names (default 50)

errors

JavaScript errors grouped by fingerprint.

  • Permission: analytics:read
  • Runs: GET /api/v1/sites/{siteId}/errors
  • Annotations: readOnlyHint: true, openWorldHint: false
ArgumentTypeRequiredDescription
siteIdstringyesThe site's public id (list_sites)
startstringnoWindow start: a date (YYYY-MM-DD, in tz) or an ISO instant; with end. Every call needs exactly one window: start+end, last or all
endstringnoWindow end: a date (inclusive) or an ISO instant (exclusive); with start
laststringnoInstead of start/end: the last 30m, 12h, 7d, … (at most 400d)
tzstringnoIANA time zone; default the site's
allbooleannotrue: all time instead of a window
bucket"minute" | "5m" | "15m" | "hour" | "day" | "week" | "month" | "year"noTime bucket of the answer's series or trends; default from the window's length
filters{ dim: string; op: string; values: (string | number | boolean)[] }[]noFilters, ANDed, e.g. [{dim: 'country', op: 'eq', values: ['US']}]
segmentstringnoA saved segment's id (segments): its filters apply
limitintegernoRows per page (default 50)
offsetintegernoRows to skip, for the next page (default 0)

vitals

Core Web Vitals percentiles.

  • Permission: analytics:read
  • Runs: GET /api/v1/sites/{siteId}/vitals
  • Annotations: readOnlyHint: true, openWorldHint: false
ArgumentTypeRequiredDescription
siteIdstringyesThe site's public id (list_sites)
startstringnoWindow start: a date (YYYY-MM-DD, in tz) or an ISO instant; with end. Every call needs exactly one window: start+end, last or all
endstringnoWindow end: a date (inclusive) or an ISO instant (exclusive); with start
laststringnoInstead of start/end: the last 30m, 12h, 7d, … (at most 400d)
tzstringnoIANA time zone; default the site's
allbooleannotrue: all time instead of a window
bucket"minute" | "5m" | "15m" | "hour" | "day" | "week" | "month" | "year"noTime bucket of the answer's series or trends; default from the window's length
filters{ dim: string; op: string; values: (string | number | boolean)[] }[]noFilters, ANDed, e.g. [{dim: 'country', op: 'eq', values: ['US']}]
segmentstringnoA saved segment's id (segments): its filters apply

sessions

Sessions, newest first.

  • Permission: sessions:read
  • Runs: GET /api/v1/sites/{siteId}/sessions
  • Annotations: readOnlyHint: true, openWorldHint: false
ArgumentTypeRequiredDescription
siteIdstringyesThe site's public id (list_sites)
startstringnoWindow start: a date (YYYY-MM-DD, in tz) or an ISO instant; with end. Every call needs exactly one window: start+end, last or all
endstringnoWindow end: a date (inclusive) or an ISO instant (exclusive); with start
laststringnoInstead of start/end: the last 30m, 12h, 7d, … (at most 400d)
tzstringnoIANA time zone; default the site's
allbooleannotrue: all time instead of a window
bucket"minute" | "5m" | "15m" | "hour" | "day" | "week" | "month" | "year"noTime bucket of the answer's series or trends; default from the window's length
filters{ dim: string; op: string; values: (string | number | boolean)[] }[]noFilters, ANDed, e.g. [{dim: 'country', op: 'eq', values: ['US']}]
segmentstringnoA saved segment's id (segments): its filters apply
cursorstringnometa.nextCursor of the previous page
limitintegernoRows per page (default 50)
sortstringnoLargest or latest first by: started (default), ended, duration, pageviews or events
viewstringnoall (default), identified, with_replay, converted, bounced or with_errors
searchstringnoSubstring of the user id, entry or exit page or referrer domain; the user's name or email with users:read

session

One session with its events.

  • Permission: sessions:read
  • Runs: GET /api/v1/sites/{siteId}/sessions/{sessionId}
  • Annotations: readOnlyHint: true, openWorldHint: false
ArgumentTypeRequiredDescription
siteIdstringyesThe site's public id (list_sites)
sessionIdstringyesA session's session_id (sessions)

users

Visitors and identified users.

  • Permission: users:read
  • Runs: GET /api/v1/sites/{siteId}/users
  • Annotations: readOnlyHint: true, openWorldHint: false
ArgumentTypeRequiredDescription
siteIdstringyesThe site's public id (list_sites)
startstringnoWindow start: a date (YYYY-MM-DD, in tz) or an ISO instant; with end. Every call needs exactly one window: start+end, last or all
endstringnoWindow end: a date (inclusive) or an ISO instant (exclusive); with start
laststringnoInstead of start/end: the last 30m, 12h, 7d, … (at most 400d)
tzstringnoIANA time zone; default the site's
allbooleannotrue: all time instead of a window
bucket"minute" | "5m" | "15m" | "hour" | "day" | "week" | "month" | "year"noTime bucket of the answer's series or trends; default from the window's length
filters{ dim: string; op: string; values: (string | number | boolean)[] }[]noFilters, ANDed, e.g. [{dim: 'country', op: 'eq', values: ['US']}]
segmentstringnoA saved segment's id (segments): its filters apply
cursorstringnometa.nextCursor of the previous page
limitintegernoRows per page (default 50)
sortstringnoLargest or latest first by: last_seen (default), first_seen, sessions, pageviews or events
searchstringnoCase-insensitive substring of the user id, or of the user's name or email trait

user

One user's profile and traits.

  • Permission: users:read
  • Runs: GET /api/v1/sites/{siteId}/users/{userId}
  • Annotations: readOnlyHint: true, openWorldHint: false
ArgumentTypeRequiredDescription
siteIdstringyesThe site's public id (list_sites)
userIdstringyesA user's user_id (users)

goals

The site's goals.

  • Permission: goals:read
  • Runs: GET /api/v1/sites/{siteId}/goals
  • Annotations: readOnlyHint: true, openWorldHint: false
ArgumentTypeRequiredDescription
siteIdstringyesThe site's public id (list_sites)

create_goal

Creates a goal: {name, condition, icon?}.

  • Permission: goals:write
  • Runs: POST /api/v1/sites/{siteId}/goals
  • Annotations: readOnlyHint: false, destructiveHint: false, openWorldHint: false
ArgumentTypeRequiredDescription
siteIdstringyesThe site's public id (list_sites)
bodyobjectyesThe JSON request body of the REST route

update_goal

Updates a goal.

  • Permission: goals:write
  • Runs: PATCH /api/v1/sites/{siteId}/goals/{id}
  • Annotations: readOnlyHint: false, destructiveHint: true, openWorldHint: false
ArgumentTypeRequiredDescription
siteIdstringyesThe site's public id (list_sites)
idstringyesThe definition's id
bodyobjectyesThe JSON request body of the REST route

delete_goal

Deletes a goal.

  • Permission: goals:write
  • Runs: DELETE /api/v1/sites/{siteId}/goals/{id}
  • Annotations: readOnlyHint: false, destructiveHint: true, openWorldHint: false
ArgumentTypeRequiredDescription
siteIdstringyesThe site's public id (list_sites)
idstringyesThe definition's id

funnels

The site's saved funnels.

  • Permission: funnels:read
  • Runs: GET /api/v1/sites/{siteId}/funnels
  • Annotations: readOnlyHint: true, openWorldHint: false
ArgumentTypeRequiredDescription
siteIdstringyesThe site's public id (list_sites)

analyze_funnel

Conversion through steps: {steps}.

  • Permission: funnels:read
  • Runs: POST /api/v1/sites/{siteId}/funnels/analyze
  • Annotations: readOnlyHint: true, openWorldHint: false
ArgumentTypeRequiredDescription
siteIdstringyesThe site's public id (list_sites)
startstringnoWindow start: a date (YYYY-MM-DD, in tz) or an ISO instant; with end. Every call needs exactly one window: start+end, last or all
endstringnoWindow end: a date (inclusive) or an ISO instant (exclusive); with start
laststringnoInstead of start/end: the last 30m, 12h, 7d, … (at most 400d)
tzstringnoIANA time zone; default the site's
allbooleannotrue: all time instead of a window
bucket"minute" | "5m" | "15m" | "hour" | "day" | "week" | "month" | "year"noTime bucket of the answer's series or trends; default from the window's length
filters{ dim: string; op: string; values: (string | number | boolean)[] }[]noFilters, ANDed, e.g. [{dim: 'country', op: 'eq', values: ['US']}]
segmentstringnoA saved segment's id (segments): its filters apply
bodyobjectyesThe JSON request body of the REST route

save_funnel

Saves a funnel: {name, steps}.

  • Permission: funnels:write
  • Runs: POST /api/v1/sites/{siteId}/funnels
  • Annotations: readOnlyHint: false, destructiveHint: false, openWorldHint: false
ArgumentTypeRequiredDescription
siteIdstringyesThe site's public id (list_sites)
bodyobjectyesThe JSON request body of the REST route

delete_funnel

Deletes a funnel.

  • Permission: funnels:write
  • Runs: DELETE /api/v1/sites/{siteId}/funnels/{id}
  • Annotations: readOnlyHint: false, destructiveHint: true, openWorldHint: false
ArgumentTypeRequiredDescription
siteIdstringyesThe site's public id (list_sites)
idstringyesThe definition's id

journeys

The most common page paths.

  • Permission: analytics:read
  • Runs: GET /api/v1/sites/{siteId}/journeys
  • Annotations: readOnlyHint: true, openWorldHint: false
ArgumentTypeRequiredDescription
siteIdstringyesThe site's public id (list_sites)
startstringnoWindow start: a date (YYYY-MM-DD, in tz) or an ISO instant; with end. Every call needs exactly one window: start+end, last or all
endstringnoWindow end: a date (inclusive) or an ISO instant (exclusive); with start
laststringnoInstead of start/end: the last 30m, 12h, 7d, … (at most 400d)
tzstringnoIANA time zone; default the site's
allbooleannotrue: all time instead of a window
bucket"minute" | "5m" | "15m" | "hour" | "day" | "week" | "month" | "year"noTime bucket of the answer's series or trends; default from the window's length
filters{ dim: string; op: string; values: (string | number | boolean)[] }[]noFilters, ANDed, e.g. [{dim: 'country', op: 'eq', values: ['US']}]
segmentstringnoA saved segment's id (segments): its filters apply
stepsintegernoPages per path, 2 to 10 (default 3)
start_pagestringnoA path glob such as /blog/**: each path starts at the session's first page matching it
end_pagestringnoA path glob: each path ends at its first page matching it, within steps; sessions without one drop out
groupstringnopage (default) or section (/a/b/c counts as /a/**)

retention

Cohort retention.

  • Permission: analytics:read
  • Runs: GET /api/v1/sites/{siteId}/retention
  • Annotations: readOnlyHint: true, openWorldHint: false
ArgumentTypeRequiredDescription
siteIdstringyesThe site's public id (list_sites)
startstringnoWindow start: a date (YYYY-MM-DD, in tz) or an ISO instant; with end. Every call needs exactly one window: start+end, last or all
endstringnoWindow end: a date (inclusive) or an ISO instant (exclusive); with start
laststringnoInstead of start/end: the last 30m, 12h, 7d, … (at most 400d)
tzstringnoIANA time zone; default the site's
allbooleannotrue: all time instead of a window
bucket"minute" | "5m" | "15m" | "hour" | "day" | "week" | "month" | "year"noTime bucket of the answer's series or trends; default from the window's length
filters{ dim: string; op: string; values: (string | number | boolean)[] }[]noFilters, ANDed, e.g. [{dim: 'country', op: 'eq', values: ['US']}]
segmentstringnoA saved segment's id (segments): its filters apply
unitstringnoday, week (default) or month
periodsintegernoOffset columns (0, 1, 2, … periods later), at most 92 days, 53 weeks or 24 months; default one per cohort

revenue_summary

Revenue, payments, refunds, average order and conversion of paying visitors, in one currency.

  • Permission: revenue:read
  • Runs: GET /api/v1/sites/{siteId}/revenue/summary
  • Annotations: readOnlyHint: true, openWorldHint: false
ArgumentTypeRequiredDescription
siteIdstringyesThe site's public id (list_sites)
startstringnoWindow start: a date (YYYY-MM-DD, in tz) or an ISO instant; with end. Every call needs exactly one window: start+end, last or all
endstringnoWindow end: a date (inclusive) or an ISO instant (exclusive); with start
laststringnoInstead of start/end: the last 30m, 12h, 7d, … (at most 400d)
tzstringnoIANA time zone; default the site's
allbooleannotrue: all time instead of a window
bucket"minute" | "5m" | "15m" | "hour" | "day" | "week" | "month" | "year"noTime bucket of the answer's series or trends; default from the window's length
compare"previous" | "year"noAlso the previous period of the same length, or the same period a year earlier, under previous
filters{ dim: string; op: string; values: (string | number | boolean)[] }[]noFilters, ANDed, e.g. [{dim: 'country', op: 'eq', values: ['US']}]
segmentstringnoA saved segment's id (segments): its filters apply
currencystringnoISO 4217 code; every amount is in its minor unit; default the site's

revenue_breakdown

Revenue by one dimension of the paying visit (channel, referrer_domain, utm_source, country…) or affiliate.

  • Permission: revenue:read
  • Runs: GET /api/v1/sites/{siteId}/revenue/breakdown
  • Annotations: readOnlyHint: true, openWorldHint: false
ArgumentTypeRequiredDescription
siteIdstringyesThe site's public id (list_sites)
startstringnoWindow start: a date (YYYY-MM-DD, in tz) or an ISO instant; with end. Every call needs exactly one window: start+end, last or all
endstringnoWindow end: a date (inclusive) or an ISO instant (exclusive); with start
laststringnoInstead of start/end: the last 30m, 12h, 7d, … (at most 400d)
tzstringnoIANA time zone; default the site's
allbooleannotrue: all time instead of a window
filters{ dim: string; op: string; values: (string | number | boolean)[] }[]noFilters, ANDed, e.g. [{dim: 'country', op: 'eq', values: ['US']}]
segmentstringnoA saved segment's id (segments): its filters apply
limitintegernoRows per page (default 50)
offsetintegernoRows to skip, for the next page (default 0)
currencystringnoISO 4217 code; every amount is in its minor unit; default the site's
dimstringyesA breakdown dimension (as breakdown), or affiliate

segments

Saved segments; pass one's id as segment.

  • Permission: segments:read
  • Runs: GET /api/v1/sites/{siteId}/segments
  • Annotations: readOnlyHint: true, openWorldHint: false
ArgumentTypeRequiredDescription
siteIdstringyesThe site's public id (list_sites)

annotations

Chart annotations.

  • Permission: analytics:read
  • Runs: GET /api/v1/sites/{siteId}/annotations
  • Annotations: readOnlyHint: true, openWorldHint: false
ArgumentTypeRequiredDescription
siteIdstringyesThe site's public id (list_sites)
startstringnoWindow start: a date (YYYY-MM-DD, in tz) or an ISO instant; with end. Every call needs exactly one window: start+end, last or all
endstringnoWindow end: a date (inclusive) or an ISO instant (exclusive); with start
laststringnoInstead of start/end: the last 30m, 12h, 7d, … (at most 400d)
tzstringnoIANA time zone; default the site's
allbooleannotrue: all time instead of a window
bucket"minute" | "5m" | "15m" | "hour" | "day" | "week" | "month" | "year"noTime bucket of the answer's series or trends; default from the window's length

create_annotation

Creates a private annotation on this site's charts: {title, startsAt, description?, endsAt?, color?, icon?}.

  • Permission: annotations:write
  • Runs: POST /api/v1/sites/{siteId}/annotations
  • Annotations: readOnlyHint: false, destructiveHint: false, openWorldHint: false
ArgumentTypeRequiredDescription
siteIdstringyesThe site's public id (list_sites)
bodyobjectyesThe annotation: private to the organization's members, on this site only. No other fields.
body.titlestringyesUp to 120 characters
body.descriptionstring | nullnoUp to 2000 characters
body.startsAtstringyesAn ISO instant with offset, e.g. 2026-10-01T09:00:00Z
body.endsAtstring | nullnoFor a range: an ISO instant after startsAt
body.color"blue" | "salmon" | "green" | "amber" | "red" | "violet" | "gray" | nullno
body.iconstring | nullnoOne character, e.g. an emoji

On this page