POST /api/visualize/data returns the data behind a GraphJSON visualization. Use it from server code when you want GraphJSON to query and aggregate data but will render or process the result yourself.
Endpoint#
POST https://api.graphjson.com/api/visualize/data
Basic request#
const response = await fetch(
"https://api.graphjson.com/api/visualize/data",
{
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
api_key: process.env.GRAPHJSON_API_KEY,
collection: "product_events",
IANA_time_zone: "America/Los_Angeles",
graph_type: "Single Line",
start: "30 days ago",
end: "now",
filters: [["event", "=", "checkout_completed"]],
aggregation: "Count",
metric: null,
split: null,
granularity: "Day",
compare: "30 days ago",
customizations: {}
})
}
);
const data = await response.json();
if (!response.ok) {
throw new Error(data.error || `GraphJSON returned ${response.status}`);
}
The easiest way to produce a valid payload is to build the chart in the visualizer and select Export → As Data API Call.
Request fields#
| Field | Type | Required | Description |
|---|---|---|---|
api_key |
string | Yes | Workspace API key |
collection |
string | No | Collection name; default all_events |
IANA_time_zone |
string | Recommended | Calendar and formatting zone; default America/Los_Angeles |
graph_type |
string | Yes | Requested result shape |
start |
string or integer | Yes | Relative time, parseable time, or Unix seconds |
end |
string or integer | Yes | Relative time, parseable time, or Unix seconds |
filters |
array | No | Filter conditions or OR groups; default [] |
aggregation |
string | Depends | Count, Sum, Avg, or a supported percentile |
metric |
string or null | Depends | Numeric field for non-count aggregations |
split |
string or null | Depends | String field used to group series or categories |
granularity |
string | No | Auto, Minute, Hour, Day, Week, or Month |
compare |
string | No | Offset applied to the comparison window |
compare_filters |
array | No | Second population for Compare Line |
numerator_filters |
array | No | Numerator for Ratio Line |
denominator_filters |
array | No | Denominator for Ratio Line |
order |
string | No | Ascending or Descending, primarily for Samples |
customizations |
object | No | Rendering options; hideMissing also affects time-series filling |
Graph types#
Accepted collection visualization types include:
Samples
Single Line
Multi Line
Stacked Line
Cumulative Line
Ratio Line
Compare Line
Single Value
Table
Bar Chart
Pie Chart
The SQL visualization flow also supports Funnel.
Filters#
A flat list combines conditions with AND:
[
["event", "=", "checkout_completed"],
["plan", "=", "pro"]
]
Nested groups combine each group with AND and the groups with OR:
[
[
["event", "=", "checkout_completed"],
["plan", "=", "pro"]
],
[
["event", "=", "subscription_renewed"],
["plan", "=", "pro"]
]
]
Supported operators:
=
≠
includes
excludes
>
<
> and < are numeric. Equality attempts to match a numeric-looking value as either its string or numeric representation; sending consistent field types is still strongly recommended.
Time values#
Relative examples:
30 minutes ago
12 hours ago
7 days ago
4 weeks ago
3 months ago
1 year ago
now
Numeric values are interpreted as Unix seconds. Start and end boundaries are exclusive.
Response shapes#
Time-series response:
{
"result": [
{"timestamp": "2026-07-24", "Count": 83},
{"timestamp": "2026-07-25", "Count": 91}
],
"compare_result": [
{"timestamp": "2026-07-24", "Count": 72},
{"timestamp": "2026-07-25", "Count": 80}
],
"metadata": {
"granularity": "Day",
"combined": 174,
"compare_combined": 152
}
}
The exact value key reflects the aggregation, metric, and split.
Samples response:
{
"result": [
{
"timestamp": 1785081600,
"json": {
"event": "checkout_completed",
"user_id": "usr_42"
}
}
]
}
Table-like response:
{
"result": [
{"plan": "pro", "Count": 184},
{"plan": "starter", "Count": 96}
],
"metadata": {}
}
Treat result, optional compare_result, and metadata as the stable conceptual envelope. Value keys vary with the query.
Run saved-style SQL#
Send sql_query instead of collection visualizer controls:
{
"api_key": "your_api_key",
"sql_query": "SELECT toUnixTimestamp(toStartOfDay(toDateTime(timestamp))) AS day, count() AS signups FROM product_events WHERE JSONExtractString(json, 'event') = 'signup_completed' GROUP BY day ORDER BY day",
"graph_type": "Single Line",
"timestamp_column": "day",
"value_column": "signups"
}
Column mappings:
| Graph shape | Mapping fields |
|---|---|
| Single Line | timestamp_column, value_column |
| Multi / Stacked Line | timestamp_column, value_column, split_column |
| Funnel / Bar / Pie / Single Value | label_column, value_column |
| Table | No mapping required |
SQL results are capped at 2,000 rows and mutation queries are blocked.
Security#
Call this endpoint from your server. It can query workspace data, and the request contains the API key.
For customer-facing data, construct a fixed query on the server, enforce the allowed tenant filter, and return only the fields needed by the client.