Aggregate statistics over a filtered set of records, without listing the records. Use this for any
"how many", "what's the breakdown", or "what's the total" question: it is dramatically cheaper than paging
a collection and counting client-side.
One workspace endpoint serves every analyzable resource. Name the resource and request the stats you want
as query parameters:
GET /api/v2/workspaces/{workspace_id}/stats?resource=contact&count=true&count_by[property]=is_active&filter[tag_ids]=42A flag of true computes the stat; an object-style query supplies a stat's parameters. Omit a stat (or pass
false) to skip it. Calling with only resource returns a 422 that lists the stats and property values the
named resource supports, so the endpoint is self-describing.
Narrowing the set
The same selectors the resource's own index accepts, composed with AND:
filter- simple field matches, e.g.filter[tag_ids]=42for contactsstable_id- a one-off Refine filter token, e.g. fromPOST /workspaces/{workspace_id}/contacts/filtersstored_filter_id- a saved Refine filter id
Omit all three to report on every record of that resource in the workspace.
Beyond the index's own keys, filter takes a created_at window on every resource
(created_at_after inclusive, created_at_before exclusive, ISO 8601 only, with an offset's +
sent as %2B), and on order the two attribution keys a sales dashboard needs: funnel_id
(orders attributed to that funnel) and product_id (orders containing that product, from any
channel). Every id filter (id, contact_id, page_id, tag_ids, funnel_id, product_id)
takes a numeric id or a public_id, comma-separated for several; an id that is not this
workspace's is a 422 naming it, never a silent zero:
GET /api/v2/workspaces/{workspace_id}/stats?resource=order&count=true&sum[property]=total_collected&filter[funnel_id]=41&filter[created_at_after]=2026-10-01T00:00:00ZLarge sets
Every stat is computed over the whole matching set, bounded in time rather than in rows: each query has a
statement timeout, and the request has an overall time budget. A stat that cannot finish in time is not
returned; it is named in unavailable, with unavailable_reason saying whether to narrow the filter or to
ask for it on its own, rather than computed over part of the set.
count has one fallback of its own. Past 100,000 matches, if counting the whole set cannot finish in time,
it returns 100,000 with count_capped_at beside it - the real total is higher, so narrow the filter.
When no requested stat can be computed in time, the response is a 422, not a 503: retrying it unchanged
fails the same way, so narrow it instead.
Access
Computing a statistic persists nothing, so a token with read-only access may call it. Authorization
follows the category of the resource being analyzed: contact requires read access to Contacts, order
requires read access to Store, form_submission requires read access to Forms.
Form submissions per page
form_submission reports on the same rows GET /workspaces/{workspace_id}/form_submissions lists: one per
form post on a ClickFunnels page. count_by[property]=page_id returns the submission count of every page in
one call, so counting a funnel's submissions no longer means paging the whole log:
GET /api/v2/workspaces/{workspace_id}/stats?resource=form_submission&count_by[property]=page_id&filter[page_id]=41,42These are form posts, not opt-ins: checkout submits and repeat posts by the same contact count too. For
opt-ins as the funnel dashboard counts them, read optins from GET /funnels/{funnel_id}/stats or
GET /pages/{page_id}/stats.
It has no Refine filter class, so stable_id and stored_filter_id are refused with a 422 for it.
| Time | Status | User Agent | |
|---|---|---|---|
Retrieving recent requests… | |||