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.
For discriminated TypeScript types, every documented graph shape, comparison alignment, telemetry, empty states, and defensive normalization, see Data API response contracts.
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.