Add a new chart to a dashboard board with a SQL query and chart type. Supports line, bar, pie, funnel, and other visualization types.
chart_type field controls which other request body fields are required or validated. Funnel charts are special — their SQL is auto-generated from the steps array, so pass "SELECT 1" as the query placeholder.
| Field | Type | Required | Description |
|---|---|---|---|
projectId | string | Yes | Project the chart belongs to |
query | string | Conditional | SQL query. Required for all types except retention. For funnel, pass "SELECT 1" |
chart_type | string | Yes | table · number · bar · line · pie · stacked · funnel · user_paths · retention |
title | string | Yes | Display name (minimum 1 character) |
description | string | No | Optional description |
x_axis | string | Conditional | Column for the X axis. Required for bar, line, stacked |
y_axis | string[] | Conditional | Column(s) for Y axis metrics. See per-type rules below |
group_by | string | Conditional | Column to group/stack series by. Required for stacked |
steps | FunnelStep[] | Conditional | Ordered funnel steps. Required for funnel (minimum 2) |
settings | ChartSettings | No | Type-specific configuration object |
tablenumberbar and linex_axis and at least 1 column in y_axis.
piey_axis. x_axis identifies the label column.
stackedx_axis, exactly 1 column in y_axis, and group_by.
steps, so query must be the placeholder "SELECT 1". At least 2 steps are required.
FunnelStep Objectsteps array has the following shape:
| Field | Type | Required | Description |
|---|---|---|---|
type | string | Yes | event — built-in events (page, connect, transaction); track — custom tracked events; decoded_log — decoded smart-contract events |
event | string | Yes | Event name (e.g. page, connect, transaction) |
<propertyKey> | StepFilterCondition | No | One or more property filters. Any extra key on the step object is treated as a filter. Standard columns (device, browser, os, location, referrer, ref, utm_*) are filtered directly; all other keys are extracted from properties via JSONExtractString |
StepFilterCondition)op | SQL equivalent | Notes |
|---|---|---|
equals | = 'value' | Exact match |
notEquals | != 'value' | Inverse match |
in | IN (...) | Pipe-delimited value: "metamask|rainbow|coinbase" |
notIn | NOT IN (...) | Pipe-delimited value |
gt | > value | Numeric comparison |
gte | >= value | Numeric comparison |
lt | < value | Numeric comparison |
lte | <= value | Numeric comparison |
startsWith | startsWith(col, 'v') | String prefix |
endsWith | endsWith(col, 'v') | String suffix |
includes | like '%v%' | Substring match |
settings for Funnel Charts| Field | Type | Default | Description |
|---|---|---|---|
funnelType | "closed" | "open" | "closed" | closed — strict ordering, no events between steps; open — ordered but other events may occur between steps |
conversionWindow | ConversionWindow | 1 day | Max time from Step 1 for a user to complete all steps |
breakdown | string | — | Split each funnel bar by this dimension |
ConversionWindowunit must be one of: minute · hour · day · week (7 days) · month (30 days).
breakdown valuesdevice · browser · os · referrer · ref · utm_source · utm_medium · utm_campaign · utm_term · utm_content
The top categories are shown individually. The rest collapse into “Others”.
in filtersettings.startStep is required.
settings for User Paths Charts| Field | Type | Default | Description |
|---|---|---|---|
startStep | FunnelStep | — | Required. Event where the flow begins |
endStep | FunnelStep | null | null | Optional ending event. null = open-ended |
maxSteps | integer (2–10) | 3 | Max steps to show in the flow. Values above 10 are clamped to 10 |
nodesPerStep | integer (2–10) | 5 | Max unique event nodes per step. Values above 10 are clamped to 10 |
conversionWindow | ConversionWindow | — | Time window to group the flow |
filters | string | — | JSON-encoded string of additional path filters |
query field is not used — pass "" or omit it.
settings for Retention Charts| Field | Type | Description |
|---|---|---|
retentionFilter | FunnelStep | null | Event that qualifies a returning visit as “retained”. null = any event counts |
retentionUserFilters | RetentionUserFilter[] | User-segment filters that narrow the retention cohort |
RetentionUserFilter:
| Field | Type | Description |
|---|---|---|
operand | string | User property (e.g. device, browser, os, utm_source, location) |
operator | string | Comparison operator (same set as StepFilterCondition.op) |
value | string | number | Value to compare against |
settings:
| Chart Type | Validation Rule |
|---|---|
table | query must execute successfully |
number | query must return exactly 1 row × 1 column |
bar | x_axis required; y_axis requires ≥ 1 element |
line | x_axis required; y_axis requires ≥ 1 element |
pie | y_axis requires exactly 1 element |
stacked | x_axis required; y_axis requires exactly 1 element; group_by required |
funnel | steps requires ≥ 2 FunnelStep objects; query must be "SELECT 1" or any valid SQL |
user_paths | settings.startStep required; query must execute and return valid path data |
retention | No query validation — query is ignored |
201 Created
data is the new chart’s ID. Use it with the Get Chart, Update Chart, and Delete Chart endpoints.
400 Bad Request — returned when validation fails (missing required fields, invalid SQL, wrong step count, etc.)
chart_type field controls which other request body fields are required or validated. Funnel charts are special — their SQL is auto-generated from the steps array, so pass "SELECT 1" as the query placeholder.
| Field | Type | Required | Description |
|---|---|---|---|
projectId | string | Yes | Project the chart belongs to |
query | string | Conditional | SQL query. Required for all types except retention. For funnel, pass "SELECT 1" |
chart_type | string | Yes | table · number · bar · line · pie · stacked · funnel · user_paths · retention |
title | string | Yes | Display name (minimum 1 character) |
description | string | No | Optional description |
x_axis | string | Conditional | Column for the X axis. Required for bar, line, stacked |
y_axis | string[] | Conditional | Column(s) for Y axis metrics. See per-type rules below |
group_by | string | Conditional | Column to group/stack series by. Required for stacked |
steps | FunnelStep[] | Conditional | Ordered funnel steps. Required for funnel (minimum 2) |
settings | ChartSettings | No | Type-specific configuration object |
tablenumberbar and linex_axis and at least 1 column in y_axis.
piey_axis. x_axis identifies the label column.
stackedx_axis, exactly 1 column in y_axis, and group_by.
steps, so query must be the placeholder "SELECT 1". At least 2 steps are required.
FunnelStep Objectsteps array has the following shape:
| Field | Type | Required | Description |
|---|---|---|---|
type | string | Yes | event — built-in events (page, connect, transaction); track — custom tracked events; decoded_log — decoded smart-contract events |
event | string | Yes | Event name (e.g. page, connect, transaction) |
<propertyKey> | StepFilterCondition | No | One or more property filters. Any extra key on the step object is treated as a filter. Standard columns (device, browser, os, location, referrer, ref, utm_*) are filtered directly; all other keys are extracted from properties via JSONExtractString |
StepFilterCondition)op | SQL equivalent | Notes |
|---|---|---|
equals | = 'value' | Exact match |
notEquals | != 'value' | Inverse match |
in | IN (...) | Pipe-delimited value: "metamask|rainbow|coinbase" |
notIn | NOT IN (...) | Pipe-delimited value |
gt | > value | Numeric comparison |
gte | >= value | Numeric comparison |
lt | < value | Numeric comparison |
lte | <= value | Numeric comparison |
startsWith | startsWith(col, 'v') | String prefix |
endsWith | endsWith(col, 'v') | String suffix |
includes | like '%v%' | Substring match |
settings for Funnel Charts| Field | Type | Default | Description |
|---|---|---|---|
funnelType | "closed" | "open" | "closed" | closed — strict ordering, no events between steps; open — ordered but other events may occur between steps |
conversionWindow | ConversionWindow | 1 day | Max time from Step 1 for a user to complete all steps |
breakdown | string | — | Split each funnel bar by this dimension |
ConversionWindowunit must be one of: minute · hour · day · week (7 days) · month (30 days).
breakdown valuesdevice · browser · os · referrer · ref · utm_source · utm_medium · utm_campaign · utm_term · utm_content
The top categories are shown individually. The rest collapse into “Others”.
in filtersettings.startStep is required.
settings for User Paths Charts| Field | Type | Default | Description |
|---|---|---|---|
startStep | FunnelStep | — | Required. Event where the flow begins |
endStep | FunnelStep | null | null | Optional ending event. null = open-ended |
maxSteps | integer (2–10) | 3 | Max steps to show in the flow. Values above 10 are clamped to 10 |
nodesPerStep | integer (2–10) | 5 | Max unique event nodes per step. Values above 10 are clamped to 10 |
conversionWindow | ConversionWindow | 2 weeks | Time window to group the flow |
filters | string | — | JSON-encoded string of additional path filters |
query field is not used — pass "" or omit it.
settings for Retention Charts| Field | Type | Description |
|---|---|---|
retentionFilter | FunnelStep | null | Event that qualifies a returning visit as “retained”. null = any event counts |
retentionUserFilters | RetentionUserFilter[] | User-segment filters that narrow the retention cohort |
RetentionUserFilter:
| Field | Type | Description |
|---|---|---|
operand | string | User property (e.g. device, browser, os, utm_source, location) |
operator | string | Comparison operator (same set as StepFilterCondition.op) |
value | string | number | Value to compare against |
settings:
| Chart Type | Validation Rule |
|---|---|
table | query must execute successfully |
number | query must return exactly 1 row × 1 column |
bar | x_axis required; y_axis requires ≥ 1 element |
line | x_axis required; y_axis requires ≥ 1 element |
pie | y_axis requires exactly 1 element |
stacked | x_axis required; y_axis requires exactly 1 element; group_by required |
funnel | steps requires ≥ 2 FunnelStep objects; query must be "SELECT 1" or any valid SQL |
user_paths | settings.startStep required; query must execute and return data in the expected user-path format (columns: user identifier, event name, timestamp) |
retention | No query validation — query is ignored |
201 Created
data is the new chart’s ID. Use it with the Get Chart, Update Chart, and Delete Chart endpoints.
400 Bad Request — returned when validation fails (missing required fields, invalid SQL, wrong step count, etc.)
Workspace API key (e.g. formo_xxx). Create one in the Formo dashboard under Team Settings > API Keys.
Request body for creating a chart.
Project the chart belongs to.
Visualization type. Determines which other fields are required:
chart_type | Extra required fields |
|---|---|
table | query |
number | query (must return 1 row × 1 column) |
bar | query, x_axis, y_axis (≥ 1) |
line | query, x_axis, y_axis (≥ 1) |
pie | query, y_axis (exactly 1) |
stacked | query, x_axis, y_axis (exactly 1), group_by |
funnel | steps (≥ 2), query placeholder "SELECT 1" |
user_paths | query, settings.startStep |
retention | none (query ignored) |
table, number, funnel, bar, line, pie, stacked, user_paths, retention Display name shown on the chart and board.
1SQL query that powers the chart.
funnel — pass "SELECT 1"; the actual query is auto-generated from steps.retention — can be omitted or pass ""; data is fetched from the retention pipe directly.1Optional description.
Column name for the X axis. Required for bar, line, and stacked.
Column name(s) used as Y axis metrics.
bar / line — at least 1 element required.pie / stacked — exactly 1 element required.Column to group / stack series by. Required for stacked.
Ordered list of funnel steps. Required for funnel (minimum 2 steps).
Each element is a FunnelStep — add property filters as extra keys on the step object (e.g. "rdns": { "op": "equals", "value": "io.metamask" }).
2Chart-type-specific configuration. The fields that apply depend on chart_type:
funnelType, conversionWindow, breakdownstartStep, endStep, maxSteps, nodesPerStep, conversionWindow, filtersretentionFilter, retentionUserFiltersAll fields are optional at the schema level; see per-type validation rules for which are functionally required.