Chart Generation
The Chart Generation endpoint takes the SQL result of an assistant message and returns it as a chart, in one of three formats: a Chart.js config for frontend rendering, raw PNG bytes, or an authenticated URL that serves a server-rendered PNG on demand.
Chart operates on message items produced by the Text-to-SQL agent — any message without a sql_query returns MessageNoSQLQueryError (see Errors).
Generate Chart
Generates a chart from a message's SQL query results. The output field in the request body controls the response format.
Path parameters
- Name
conversation_id- Type
- string (UUID)
- Required
- Description
ID of the conversation containing the message.
- Name
message_id- Type
- string (UUID)
- Required
- Description
ID of the assistant message that contains the SQL query result.
Authorization
- Name
MINDS_API_KEY- Type
- string
- Required
- Description
Generate the Minds API key here and use it for authorization.
Request body
- Name
intent- Type
- object
- Required
- Description
The chart specification. Its required fields depend on
intent.type— see the chart-type sections below.
- Name
output- Type
- string
- Required
- Description
Response format. One of
"chartjs"(default),"png", or"image_url". See Choosing the right output format below.
Choosing the right output format
chartjs(default): Best when you have a frontend capable of rendering Chart.js charts. Gives full control over styling and interactivity.png: Best when you need a static image immediately — e.g. embedding in a Slack message, email, or PDF report.image_url: Best when an authenticated client wants to defer fetching the image until it's viewed. The URL requires authentication, so it can't be dropped into an HTML<img>tag — to embed in HTML, fetch the PNG and re-host it.
Bar and Line Charts
Bar charts are best for categorical comparisons. Line charts are best for time-series data and trends. Both share the same intent structure.
- Name
type- Type
- "bar" | "line"
- Required
- Description
Chart type.
- Name
x- Type
- string
- Required
- Description
Column name for the X-axis.
- Name
y- Type
- string | string[]
- Required
- Description
Column name(s) for Y-axis values. Use an array to plot multiple metrics as separate series.
- Name
series- Type
- string
- Required
- Description
Column to split data into multiple series. Ignored if
yis an array.
- Name
aggregate- Type
- string
- Required
- Description
Aggregation function:
"sum","avg","count","min","max". Defaults to"sum".
- Name
limit- Type
- integer
- Required
- Description
Maximum categories / points to display (1–10000). Defaults to 50 for
bar, 365 forline(time-series).
- Name
max_series- Type
- integer
- Required
- Description
Maximum series to display (1–100). Defaults to 12.
- Name
title- Type
- string
- Required
- Description
Chart title.
Temporal columns on line charts are auto-detected from native datetime types or from string values that parse as dates (≥80% success rate). Numeric columns are never interpreted as timestamps.
Pie Chart
Best for showing composition or distribution of a whole. Recommended for fewer than 8 categories.
- Name
type- Type
- "pie"
- Required
- Description
Chart type.
- Name
label- Type
- string
- Required
- Description
Column name for category labels.
- Name
value- Type
- string
- Required
- Description
Column name for numeric values.
- Name
aggregate- Type
- string
- Required
- Description
Aggregation function. Defaults to
"sum".
- Name
limit- Type
- integer
- Required
- Description
Maximum slices (1–10000). Defaults to 12. Excess categories are grouped into "Other".
- Name
title- Type
- string
- Required
- Description
Chart title.
Scatter Chart
Best for showing correlation between two numeric variables.
- Name
type- Type
- "scatter"
- Required
- Description
Chart type.
- Name
x- Type
- string
- Required
- Description
Column name for the X-axis (must be numeric).
- Name
y- Type
- string
- Required
- Description
Column name for the Y-axis (must be numeric).
- Name
series- Type
- string
- Required
- Description
Column to split data into multiple series.
- Name
limit- Type
- integer
- Required
- Description
Maximum data points (1–10000). Defaults to 1000.
- Name
max_series- Type
- integer
- Required
- Description
Maximum series (1–100). Defaults to 12.
- Name
title- Type
- string
- Required
- Description
Chart title.
Metadata object
Both chartjs and image_url responses include a meta object:
| Field | Type | Description |
|---|---|---|
row_count | integer | Total rows in the source data |
used_rows | integer | Rows processed after null removal |
points | integer | Number of data points in the chart |
series | integer | Number of series / datasets |
fields | object | Field type hints (temporal, quantitative, nominal) |
Warning codes
| Code | Description |
|---|---|
ROW_LIMIT | Data exceeded the 10,000-row processing limit |
TRUNCATED | Data points truncated to the configured limit |
SERIES_TRUNCATED | Number of series truncated to the configured max_series |
SERIES_IGNORED | series column ignored because y is an array |
UNKNOWN_SERIES | Specified series column not found in the data |
Error responses
| Status | Cause |
|---|---|
400 | Invalid chart intent, invalid SQL query, invalid chart image token, or message lacks a SQL query |
404 | Conversation or message not found |
500 | Server-side error during chart generation |
See the Errors reference for the shared {"detail": "..."} response format.
Request
curl --request POST \
--url 'https://mdb.ai/api/v1/conversations/123e4567-e89b-12d3-a456-426614174000/items/123e4567-e89b-12d3-a456-426614174001/chart' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer MINDS_API_KEY' \
--data '{
"intent": {
"type": "bar",
"x": "month",
"y": "total_sales",
"title": "Monthly Sales"
},
"output": "chartjs"
}'
Response (chartjs)
{
"format": "chartjs",
"config": {
"type": "bar",
"data": {
"labels": ["Jan", "Feb", "Mar"],
"datasets": [
{ "label": "Total Sales", "data": [50000, 62000, 71000] }
]
},
"options": {}
},
"meta": {
"row_count": 1000,
"used_rows": 500,
"points": 3,
"series": 1,
"fields": {
"month": "temporal",
"total_sales": "quantitative"
}
},
"warnings": []
}
Response (png)
HTTP/1.1 200 OK
Content-Type: image/png
Cache-Control: no-store
<raw PNG bytes — 1600x800px at 100 DPI>
Response (image_url)
{
"image_url": "/api/v1/conversations/{conversation_id}/items/{message_id}/chart?token={token}",
"meta": {
"row_count": 1000,
"used_rows": 500,
"points": 3,
"series": 1
},
"warnings": []
}
Serve Chart Image
Serves a server-rendered PNG for a chart whose POST response was output: "image_url". The chart is rendered on demand each time the URL is fetched — the token does not cache an image.
Path parameters
- Name
conversation_id- Type
- string (UUID)
- Required
- Description
ID of the conversation containing the message.
- Name
message_id- Type
- string (UUID)
- Required
- Description
ID of the assistant message whose chart should be served.
Query parameters
- Name
token- Type
- string
- Required
- Description
Opaque chart token returned by the POST endpoint when
outputisimage_url. An invalid token returns400.
Authorization
- Name
MINDS_API_KEY- Type
- string
- Required
- Description
The GET endpoint requires the same authentication header as POST. The token alone is not sufficient.
Response
Returns raw PNG bytes with Content-Type: image/png and Cache-Control: private, no-store. Image dimensions are 1600×800 at 100 DPI.
Request
curl --request GET \
--url 'https://mdb.ai/api/v1/conversations/123e4567-e89b-12d3-a456-426614174000/items/123e4567-e89b-12d3-a456-426614174001/chart?token=<token>' \
--header 'Authorization: Bearer MINDS_API_KEY' \
--output chart.png
Response
HTTP/1.1 200 OK
Content-Type: image/png
Cache-Control: private, no-store
<raw PNG bytes — 1600x800px at 100 DPI>
Processing limits
| Limit | Value |
|---|---|
| Maximum rows processed | 10,000 |
| Default series limit | 12 |
| Default categorical limit (bar) | 50 |
| Default temporal limit (line) | 365 |
| Default scatter limit | 1,000 |
| Default pie limit | 12 |
| Server-rendered image size | 1600 × 800 px at 100 DPI |
Usage examples
Multi-metric line chart as PNG
Each entry in the y array becomes a separate series.
{
"intent": {
"type": "line",
"x": "month",
"y": ["revenue", "expenses", "profit"],
"title": "Monthly Financial Overview"
},
"output": "png"
}
Grouped bar chart via image URL
Splits revenue by product_line, capped at 5 series.
{
"intent": {
"type": "bar",
"x": "quarter",
"y": "revenue",
"series": "product_line",
"aggregate": "sum",
"max_series": 5,
"title": "Quarterly Revenue by Product Line"
},
"output": "image_url"
}
Two-step image URL flow
Step 1 — request an image URL:
POST /api/v1/conversations/{conversation_id}/items/{message_id}/chart
{
"intent": { "type": "bar", "x": "region", "y": "total_sales", "title": "Sales by Region" },
"output": "image_url"
}
Step 2 — fetch the image with the returned token:
GET /api/v1/conversations/{conversation_id}/items/{message_id}/chart?token={token}
Authorization: Bearer MINDS_API_KEY
The GET request must include the same authentication headers as the POST. The response is raw PNG bytes.