A valid request URL is required to generate request examples{
"steps": [
{
"step": 1,
"name": "$auth.signed_up",
"contacts": 480,
"conversion": 1
},
{
"step": 2,
"name": "checkout.opened",
"contacts": 210,
"conversion": 0.4375
},
{
"step": 3,
"name": "checkout.paid",
"contacts": 88,
"conversion": 0.1833
}
],
"window_days": 7,
"from": "2026-07-03T00:00:00Z",
"to": "2026-08-02T00:00:00Z"
}{
"error": {
"code": "forbidden",
"message": "your role does not allow this action"
}
}{
"error": {
"code": "forbidden",
"message": "your role does not allow this action"
}
}{
"error": {
"code": "forbidden",
"message": "your role does not allow this action"
}
}{
"error": {
"code": "forbidden",
"message": "your role does not allow this action"
}
}Compute a funnel's results
Requires analytics:read. The drop-off, computed from the raw events at read time.
A contact enters the funnel when their earliest step-one event falls inside [from, to) (default: the last 30 days). They reach step N with the earliest step-N event at or after the moment step N-1 was reached, no later than window_days after entering — the window anchors at step one. Completion may run past to by the window: the range bounds who enters, never who finishes.
Every step is present in the answer, at zero when nobody reached it — a step nobody reached is a zero the chart must draw, not a hole. conversion is against step one: “of those who entered”.
A valid request URL is required to generate request examples{
"steps": [
{
"step": 1,
"name": "$auth.signed_up",
"contacts": 480,
"conversion": 1
},
{
"step": 2,
"name": "checkout.opened",
"contacts": 210,
"conversion": 0.4375
},
{
"step": 3,
"name": "checkout.paid",
"contacts": 88,
"conversion": 0.1833
}
],
"window_days": 7,
"from": "2026-07-03T00:00:00Z",
"to": "2026-08-02T00:00:00Z"
}{
"error": {
"code": "forbidden",
"message": "your role does not allow this action"
}
}{
"error": {
"code": "forbidden",
"message": "your role does not allow this action"
}
}{
"error": {
"code": "forbidden",
"message": "your role does not allow this action"
}
}{
"error": {
"code": "forbidden",
"message": "your role does not allow this action"
}
}Authorizations
A staff session token, uk_st_…. Minted by sign-up, sign-in or the two-factor exchange. Only a 401 means it is spent; not_a_member (403) is about the organization named in X-Organization-Id and leaves the token good for the others.
Headers
The organization the caller is acting on — the org_… code that appears in the panel URL. It identifies; the membership JOIN is what authorizes, so a forged code reads nothing: the answer is not_a_member (403), which does not mean the session is over. Absent, the session's default organization answers, or — if that membership was revoked while the session was open — any other one the caller still holds.
Path Parameters
Query Parameters
Which environment to act in. A view parameter, valid only on the staff surface — a machine credential never chooses its environment, it is resolved from the key.
live, test Entry range start (inclusive). Default: 30 days ago.
Entry range end (exclusive). Default: now.
Response
One row per step, in order, dense.
Show child attributes
Show child attributes
The window the read actually answered over, and what the plan did to it.
Every analytics read carries one. analytics_retention is a plan LIMIT and never a gate: asking for a year on a plan that keeps a month answers 200 over the month, with clamped true and from moved forward to the horizon — there is no 402 anywhere in this module.
Unlike the staff audit window, which only filters a read, this horizon is also enforced in storage: a nightly sweep deletes analytics past each organization's retention. So data beyond from is not merely hidden, and an upgrade recovers the horizon rather than the history.
Show child attributes
Show child attributes