Report & dashboard builder
Methods for building analytical reports — the same reports you see in the dashboard under Report Builder, but through the API. Useful if you want charts and tables based on your data inside your own system (internal analytics, a dashboard, a reporting bot, etc.) without opening the dashboard.
How it works in a nutshell
Reports are built from the events you send to Graspil (see Event reference). To find out which events and fields are available for your bot, use the
events,event-fields, andutm-labelsmethods — they tell you what you can plug into filters and the report itself.The report itself is described by a single JSON object,
report_config— it specifies what to count (which event, which aggregation), how to filter, and how to group. Its format is described in detail below — it's the same format used by the visual report builder in the dashboard.Before saving a report, you can run it as a dry run with the
previewmethod — see the first rows of the result and make sure everything is calculated the way you expect.Once the report is ready, save it with the
savemethod. Saved reports can be listed vialist.
Authentication
If your API key is tied to a single bot (a regular key from the "My Bots" section — see Authorization), you don't need to specify anything else — all methods apply to that bot.
If you're using a key from the API Keys section that's been issued for several bots or all of your bots, every request must explicitly state which bot it's for — via the Resource-Key header, or the resource_key field (for POST) / query parameter (for GET). The value is the bot's public key: the part before the colon in the bot's API key, which you can see in the "My Bots" section next to the key icon (format bot_key:api_key).
Response format
Successful response:
{ "ok": true, "data": { ... } }Error response:
Report configuration (report_config)
This is the main object that describes a report. It's passed to the preview and save methods, and it's also what saved reports return. It has two parts: source_request (what to count and how) and settings (the date range):
source_request
What to count and how — report type (type / type_chart), events, filters, groupings. Described below
settings.params
The date range the report is built for. The resource (bot) is filled in automatically from your key — you don't need to pass :resource_key yourself
settings.params parameter
Type
Required
Description
:date_from
string
yes
Start of the period, format YYYY-MM-DD HH:MM:SS
:date_to
string
yes
End of the period, format YYYY-MM-DD HH:MM:SS
Report types (source_request.type / type_chart)
type
type_chart
What it shows
When to use it
trends
line
A metric's dynamics over days — an "events/users over time" chart
The most common type: "how many events/users were there each day"
trends
table
Same as above, but as a table instead of a chart. Note: table uses a shorter set of agr values — see below
When you need exact daily numbers rather than a picture
list
list
A list of raw rows from the events table (or another table), without aggregation
When you need a list of specific events rather than a summarized number — e.g. an activity log
funnels
funnels
A funnel: how many users went through a chain of events step by step
"How many of the people who opened a product page made it to checkout"
retention
retention
Retention: did users come back and repeat an action after N days
"How many users who paid once paid again a week later"
Depending on type, different fields of source_request are filled in — they're described in the sections below.
Trends and tables (type: "trends")
requests
array
yes
One or more metrics on the same chart/table — see "Metric (requests)" below
filters
array|null
no
A shared filter, applied to all metrics at once — see "Filters" below
separators
array
no
Splits a metric into several lines/rows by a field — see "Breakdown (separators)" below
Metric (requests)
Each item in the requests array is one metric (one line on the chart / one row in the table):
type
string
yes
Always "trend"
event_id
int|null
no
ID of the event being counted (see the events method below). null means counting all events
event_name
string
yes
Event name — just for readability, doesn't affect the calculation
label
string
no
A label for the metric that shows up in the result (e.g. the chart line's name)
agr
string
yes
How to aggregate — see the table below
filters
array|null
no
A filter for this metric only (on top of the shared source_request.filters)
Aggregations (agr)
The allowed values depend on type_chart.
type_chart: "table":
total
Total number of events
total_uniq
Number of unique users who had the event
avg
Average number of events per user
min
Minimum number of events per user
max
Maximum number of events per user
median
Median number of events per user
type_chart: "line", "bar", "area", "pie", etc. (any chart):
total
Total number of events
total_uniq_user_id
Number of unique users who had the event
total_uniq_session_id
Number of unique sessions with this event
total_uniq_app_session_id
Number of unique Mini App sessions with this event
avg_user_id
Average number of events per user
min_user_id
Minimum number of events per user
max_user_id
Maximum number of events per user
median_user_id
Median number of events per user
property_sum
Sum of a numeric event field (agr_field) — e.g. sales total
property_avg
Average value of a numeric event field
property_min
Minimum value of a numeric event field
property_max
Maximum value of a numeric event field
property_median
Median value of a numeric event field
Don't mix the two sets. A request with type_chart: "table" and agr: "total_uniq_user_id" fails with Unsupported aggregation. Use the bare form (total_uniq) for tables.
For property_* aggregations, the agr_field parameter is also required — which field to aggregate. Two values are available:
events.value_int— the "raw" value exactly as it was sent invalue_num, without converting it to normal units and without currency conversion. For monetary events this is the smallest unit of the currency (e.g. kopecks for RUB)events.value_amount— the same value, converted to normal units (rubles instead of kopecks) and to the exchange rate of the currency set in the key owner's profile
If you're totalling money (sales, revenue, etc.), use agr_field: "events.value_amount". With events.value_int, the total for monetary events will usually look 100x too large (or more, if the event's unit isn't kopecks/cents).
Example: sales total by day, in the profile's currency:
Filters
Filters narrow down which events are included in the calculation. They're written as a nested array [operator, ...arguments] — the same style as the audience filters in the broadcast API, except fields come from the events table (use the event-fields method below to see which ones are available).
Logic:
["and", condition1, condition2, ...],["or", ...]Comparison:
["=", "field", value],["!=", ...],[">", ...],["<", ...],[">=", ...],["<=", ...]Value sets:
["in", "field", [value1, value2, ...]]Range:
["between", "field", from, to]
Example: only purchases of 1000 or more:
A single condition is a flat array [operator, field, value]. Do not wrap it in an extra array ([[">=", "events.value_int", 1000]] is invalid and the API rejects it with "expected a single condition, got a nested array"). For several conditions, combine them explicitly with ["and", ...] / ["or", ...] — a bare list of conditions (without "and"/"or") is also invalid.
Breakdown (separators)
A breakdown shows the same metric split out separately for each value of a chosen field — for example, a separate line on the chart for every custom event property value.
You can specify several separators at once — the breakdown then runs across the combination of all the listed fields.
separators items must be objects with a whitelisted property (a fixed set of events.* columns, or anything prefixed events.properties.* / user.* / user.custom_fields.*). A bare string like "utm_source" is invalid and fails with Wrong separator property.
To break a report down by UTM source/medium/campaign, don't use separators — the UTM values aren't exposed as plain events.properties.* fields, they live behind internal encoded id columns (events.f_param_id_*) used by the dedicated UTM report machinery. Use type_chart: "utm_trends" / "utm_table" instead, see "UTM breakdown" below — that's what the visual report builder itself uses for UTM breakdowns.
UTM breakdown (type_chart: "utm_trends" / "utm_table")
A dedicated report type for splitting a metric out by UTM tag (source/medium/campaign) without picking specific tag values up front — for example, "sales per day, split by UTM tag".
type_chart
What it shows
utm_trends
A chart over time, one line per UTM combination (analogous to line)
utm_table
A flat summary table, one row per UTM combination, no time buckets (analogous to table)
requests
array
yes
Same format as regular trends. For property_* aggregations, agr_field is required (just like in regular trends): for money totals use agr_field: "events.value_amount" (with currency conversion). There is no longer an automatic field default — omitting agr_field returns an error
breakdown_limit
int
no
Max number of distinct UTM combinations returned (5–500, default 25) — which combinations to break down by is chosen automatically, you don't specify them
row_limit
int
no
Max rows returned (1–5000, default 100)
granularity
string
no
Bucket size for utm_trends, day or others — ignored for utm_table
Event list (type: "list")
Returns raw rows without aggregation — for example, a log of the latest events.
table
string
yes
Source table, usually "events"
columns
array
yes
Which fields to return, e.g. ["events.date", "events.user_id", "events.event_type_id"]
filters
array|null
no
Filter — same format as in "Filters" above
order
object
no
Sorting, e.g. { "events.date": "desc" }
limit
int
no
Number of rows to return, default 50, max 1000
offset
int
no
Offset for paginated retrieval
Funnel (type: "funnels")
Shows how many users made it from the first funnel event to the last.
requests
array
yes
Funnel steps in order — each item uses the same format as "Metric" above (the agr field doesn't matter much, usually total)
funnel_window
int
no
How much time a user is given to complete the whole funnel
funnel_window_unit
string
no
Unit for funnel_window: second, minute, hour, day, week, month. Defaults to 14 days
funnel_order_type
string
no
How strictly the step order is checked — see the table below
separators
array
no
Breaks down the funnel by a field, same as in trends
funnel_order_type
Behavior
ordered
Steps must occur in the given order, with any other actions allowed in between
strict
The next step must happen right after the previous one, with no other actions in between
unordered
Step order doesn't matter
Example (this shows the source_request contents; wrap it in a report_config together with settings — see "Report configuration"), a "viewed product → paid" funnel with a 30-day window:
Retention (type: "retention")
Shows what share of users who performed a starting action came back and performed it (or another action) again after a given number of days/weeks.
target_entity
object
yes
The starting event — who counts as "entering the cohort". Format: { "type": "event", "event_id": ..., "event_name": "..." }
returning_entity
object
yes
The event that counts as "coming back". Same format as target_entity
retention_total_intervals
int
no
How many intervals to show, default 8
granularity
string
no
Interval step — day or week
retention_type
string
no
The logic used to build the cohort — see the table below
separators
array
no
Breaks down retention by a field
retention_type
Logic
retention_first_time
The cohort includes the first matching action within the period (default)
retention_first_time_ever
A user only joins the cohort if their very first action ever (regardless of the period) matches the condition
retention_recurring
A user can belong to several cohorts — one for each interval in which they performed the starting action
Example (this shows the source_request contents; wrap it in a full report_config — see "Report configuration"), did users who opened the bot come back to open it again 8 days later:
Methods
GET /v1/reports/resources
Returns the bot (or bots) your key has access to. Useful for keys from the "API Keys" section issued for several bots — to find out which resource_key values are available and which to use in the other methods.
You don't need to pass Resource-Key for this method.
Example request
Response
GET /v1/reports/events
Returns the list of events that can be used in a report for a specific bot (the event_id field in metrics).
Parameters
resource_key
string
only for keys with access to several bots
See "Authentication" above
Example request
Response
GET /v1/reports/event-fields
Returns the list of event fields that can be used in filters. The set of fields is fixed and doesn't depend on the bot or a specific event.
Example request
Response
type is one of: number, string, date.
GET /v1/reports/utm-labels
Returns the UTM tags (sources, mediums, campaigns) actually seen for your bot — handy for offering the user a pick list in a filter instead of guessing values.
Parameters
resource_key
string
only for keys with access to several bots
See "Authentication" above
Example request
Response
POST /v1/reports/preview
Runs a report without saving it and returns the first 10 rows of the result — useful for checking that the report is set up correctly before saving it.
Parameters
resource_key
string
only for keys with access to several bots
See "Authentication" above
report_config
object
yes
The report configuration — see the section above
Example request
Response
POST /v1/reports/save
Saves a report — after that it shows up in the dashboard under "Report Builder" and is available via the list method.
Parameters
resource_key
string
only for keys with access to several bots
See "Authentication" above
name
string
yes
Report name
report_config
object
yes
The report configuration — see the section above
Example request
Response
uuid is the saved report's identifier — use it to find the report in list, or open it in the dashboard.
GET /v1/reports/list
Returns previously saved reports.
Parameters
resource_key
string
no
If set, only that bot's reports are returned. If omitted, reports for all bots available to the key are returned
Example request
Response
Possible errors
400
A required parameter is missing (e.g. report_config or :date_from/:date_to), or a parameter has an invalid format
401
The API key is missing or invalid
403
The method isn't available on your plan (Premium required), the resource isn't accessible to this key, or save/list were called with a non-personal key
404
No bot was found for the given resource_key
500 / 502
Internal server error — retry the request later
Example error:
Last updated