Skip to main content
POST
/
v1
/
api
/
chart
/
save-from-chat
Save a chart generated by the AI chat agent
curl --request POST \
  --url https://api.upsolve.ai/v1/api/chart/save-from-chat \
  --header 'Content-Type: application/json' \
  --header 'authorization: <api-key>' \
  --data '
{
  "chartConfig": {
    "title": "<string>",
    "dimensions": [
      {
        "name": "<string>",
        "field": "<string>",
        "label": "<string>",
        "format": {
          "label": "<string>",
          "formatOptions": "<string>",
          "formatLocale": "<string>",
          "labelSuffix": "<string>",
          "labelPrefix": "<string>",
          "dateFormat": "<string>"
        }
      }
    ],
    "measures": [
      {
        "name": "<string>",
        "field": "<string>",
        "label": "<string>",
        "format": {
          "label": "<string>",
          "formatOptions": "<string>",
          "formatLocale": "<string>",
          "labelSuffix": "<string>",
          "labelPrefix": "<string>",
          "dateFormat": "<string>"
        }
      }
    ],
    "comparisons": [
      {
        "name": "<string>",
        "measure": "<string>",
        "customPeriod": 123
      }
    ],
    "mapConfig": {
      "latitude": "<string>",
      "longitude": "<string>"
    },
    "filters": [
      {
        "field": "<string>",
        "value": "<string>"
      }
    ],
    "havingFilters": [
      {
        "field": "<string>",
        "operator": "<string>",
        "value": "<string>",
        "aggregation": "<string>"
      }
    ],
    "settings": {
      "secondYAxis": true,
      "colors": [
        "<string>"
      ],
      "legend": true,
      "legendPosition": "bottom",
      "stacking": true,
      "showDataLabels": true,
      "enableLegendSlider": true,
      "showAxisLabels": true,
      "debug": true,
      "pageSize": 15,
      "sliceLimit": 7
    },
    "orderBy": [
      {
        "field": "<string>"
      }
    ],
    "sqlOverride": "<string>"
  },
  "apiKey": "<string>",
  "organizationId": "<string>",
  "connectionId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
  "sql": "<string>",
  "agentId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
  "name": "<string>",
  "thumbnail": "<string>"
}
'
import requests

url = "https://api.upsolve.ai/v1/api/chart/save-from-chat"

payload = {
"chartConfig": {
"title": "<string>",
"dimensions": [
{
"name": "<string>",
"field": "<string>",
"label": "<string>",
"format": {
"label": "<string>",
"formatOptions": "<string>",
"formatLocale": "<string>",
"labelSuffix": "<string>",
"labelPrefix": "<string>",
"dateFormat": "<string>"
}
}
],
"measures": [
{
"name": "<string>",
"field": "<string>",
"label": "<string>",
"format": {
"label": "<string>",
"formatOptions": "<string>",
"formatLocale": "<string>",
"labelSuffix": "<string>",
"labelPrefix": "<string>",
"dateFormat": "<string>"
}
}
],
"comparisons": [
{
"name": "<string>",
"measure": "<string>",
"customPeriod": 123
}
],
"mapConfig": {
"latitude": "<string>",
"longitude": "<string>"
},
"filters": [
{
"field": "<string>",
"value": "<string>"
}
],
"havingFilters": [
{
"field": "<string>",
"operator": "<string>",
"value": "<string>",
"aggregation": "<string>"
}
],
"settings": {
"secondYAxis": True,
"colors": ["<string>"],
"legend": True,
"legendPosition": "bottom",
"stacking": True,
"showDataLabels": True,
"enableLegendSlider": True,
"showAxisLabels": True,
"debug": True,
"pageSize": 15,
"sliceLimit": 7
},
"orderBy": [{ "field": "<string>" }],
"sqlOverride": "<string>"
},
"apiKey": "<string>",
"organizationId": "<string>",
"connectionId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"sql": "<string>",
"agentId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"name": "<string>",
"thumbnail": "<string>"
}
headers = {
"authorization": "<api-key>",
"Content-Type": "application/json"
}

response = requests.post(url, json=payload, headers=headers)

print(response.text)
const options = {
method: 'POST',
headers: {authorization: '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
chartConfig: {
title: '<string>',
dimensions: [
{
name: '<string>',
field: '<string>',
label: '<string>',
format: {
label: '<string>',
formatOptions: '<string>',
formatLocale: '<string>',
labelSuffix: '<string>',
labelPrefix: '<string>',
dateFormat: '<string>'
}
}
],
measures: [
{
name: '<string>',
field: '<string>',
label: '<string>',
format: {
label: '<string>',
formatOptions: '<string>',
formatLocale: '<string>',
labelSuffix: '<string>',
labelPrefix: '<string>',
dateFormat: '<string>'
}
}
],
comparisons: [{name: '<string>', measure: '<string>', customPeriod: 123}],
mapConfig: {latitude: '<string>', longitude: '<string>'},
filters: [{field: '<string>', value: '<string>'}],
havingFilters: [
{
field: '<string>',
operator: '<string>',
value: '<string>',
aggregation: '<string>'
}
],
settings: {
secondYAxis: true,
colors: ['<string>'],
legend: true,
legendPosition: 'bottom',
stacking: true,
showDataLabels: true,
enableLegendSlider: true,
showAxisLabels: true,
debug: true,
pageSize: 15,
sliceLimit: 7
},
orderBy: [{field: '<string>'}],
sqlOverride: '<string>'
},
apiKey: '<string>',
organizationId: '<string>',
connectionId: '3c90c3cc-0d44-4b50-8888-8dd25736052a',
sql: '<string>',
agentId: '3c90c3cc-0d44-4b50-8888-8dd25736052a',
name: '<string>',
thumbnail: '<string>'
})
};

fetch('https://api.upsolve.ai/v1/api/chart/save-from-chat', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));
<?php

$curl = curl_init();

curl_setopt_array($curl, [
CURLOPT_URL => "https://api.upsolve.ai/v1/api/chart/save-from-chat",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'chartConfig' => [
'title' => '<string>',
'dimensions' => [
[
'name' => '<string>',
'field' => '<string>',
'label' => '<string>',
'format' => [
'label' => '<string>',
'formatOptions' => '<string>',
'formatLocale' => '<string>',
'labelSuffix' => '<string>',
'labelPrefix' => '<string>',
'dateFormat' => '<string>'
]
]
],
'measures' => [
[
'name' => '<string>',
'field' => '<string>',
'label' => '<string>',
'format' => [
'label' => '<string>',
'formatOptions' => '<string>',
'formatLocale' => '<string>',
'labelSuffix' => '<string>',
'labelPrefix' => '<string>',
'dateFormat' => '<string>'
]
]
],
'comparisons' => [
[
'name' => '<string>',
'measure' => '<string>',
'customPeriod' => 123
]
],
'mapConfig' => [
'latitude' => '<string>',
'longitude' => '<string>'
],
'filters' => [
[
'field' => '<string>',
'value' => '<string>'
]
],
'havingFilters' => [
[
'field' => '<string>',
'operator' => '<string>',
'value' => '<string>',
'aggregation' => '<string>'
]
],
'settings' => [
'secondYAxis' => true,
'colors' => [
'<string>'
],
'legend' => true,
'legendPosition' => 'bottom',
'stacking' => true,
'showDataLabels' => true,
'enableLegendSlider' => true,
'showAxisLabels' => true,
'debug' => true,
'pageSize' => 15,
'sliceLimit' => 7
],
'orderBy' => [
[
'field' => '<string>'
]
],
'sqlOverride' => '<string>'
],
'apiKey' => '<string>',
'organizationId' => '<string>',
'connectionId' => '3c90c3cc-0d44-4b50-8888-8dd25736052a',
'sql' => '<string>',
'agentId' => '3c90c3cc-0d44-4b50-8888-8dd25736052a',
'name' => '<string>',
'thumbnail' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"authorization: <api-key>"
],
]);

$response = curl_exec($curl);
$err = curl_error($curl);

curl_close($curl);

if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}
package main

import (
"fmt"
"strings"
"net/http"
"io"
)

func main() {

url := "https://api.upsolve.ai/v1/api/chart/save-from-chat"

payload := strings.NewReader("{\n \"chartConfig\": {\n \"title\": \"<string>\",\n \"dimensions\": [\n {\n \"name\": \"<string>\",\n \"field\": \"<string>\",\n \"label\": \"<string>\",\n \"format\": {\n \"label\": \"<string>\",\n \"formatOptions\": \"<string>\",\n \"formatLocale\": \"<string>\",\n \"labelSuffix\": \"<string>\",\n \"labelPrefix\": \"<string>\",\n \"dateFormat\": \"<string>\"\n }\n }\n ],\n \"measures\": [\n {\n \"name\": \"<string>\",\n \"field\": \"<string>\",\n \"label\": \"<string>\",\n \"format\": {\n \"label\": \"<string>\",\n \"formatOptions\": \"<string>\",\n \"formatLocale\": \"<string>\",\n \"labelSuffix\": \"<string>\",\n \"labelPrefix\": \"<string>\",\n \"dateFormat\": \"<string>\"\n }\n }\n ],\n \"comparisons\": [\n {\n \"name\": \"<string>\",\n \"measure\": \"<string>\",\n \"customPeriod\": 123\n }\n ],\n \"mapConfig\": {\n \"latitude\": \"<string>\",\n \"longitude\": \"<string>\"\n },\n \"filters\": [\n {\n \"field\": \"<string>\",\n \"value\": \"<string>\"\n }\n ],\n \"havingFilters\": [\n {\n \"field\": \"<string>\",\n \"operator\": \"<string>\",\n \"value\": \"<string>\",\n \"aggregation\": \"<string>\"\n }\n ],\n \"settings\": {\n \"secondYAxis\": true,\n \"colors\": [\n \"<string>\"\n ],\n \"legend\": true,\n \"legendPosition\": \"bottom\",\n \"stacking\": true,\n \"showDataLabels\": true,\n \"enableLegendSlider\": true,\n \"showAxisLabels\": true,\n \"debug\": true,\n \"pageSize\": 15,\n \"sliceLimit\": 7\n },\n \"orderBy\": [\n {\n \"field\": \"<string>\"\n }\n ],\n \"sqlOverride\": \"<string>\"\n },\n \"apiKey\": \"<string>\",\n \"organizationId\": \"<string>\",\n \"connectionId\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"sql\": \"<string>\",\n \"agentId\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"name\": \"<string>\",\n \"thumbnail\": \"<string>\"\n}")

req, _ := http.NewRequest("POST", url, payload)

req.Header.Add("authorization", "<api-key>")
req.Header.Add("Content-Type", "application/json")

res, _ := http.DefaultClient.Do(req)

defer res.Body.Close()
body, _ := io.ReadAll(res.Body)

fmt.Println(string(body))

}
HttpResponse<String> response = Unirest.post("https://api.upsolve.ai/v1/api/chart/save-from-chat")
.header("authorization", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"chartConfig\": {\n \"title\": \"<string>\",\n \"dimensions\": [\n {\n \"name\": \"<string>\",\n \"field\": \"<string>\",\n \"label\": \"<string>\",\n \"format\": {\n \"label\": \"<string>\",\n \"formatOptions\": \"<string>\",\n \"formatLocale\": \"<string>\",\n \"labelSuffix\": \"<string>\",\n \"labelPrefix\": \"<string>\",\n \"dateFormat\": \"<string>\"\n }\n }\n ],\n \"measures\": [\n {\n \"name\": \"<string>\",\n \"field\": \"<string>\",\n \"label\": \"<string>\",\n \"format\": {\n \"label\": \"<string>\",\n \"formatOptions\": \"<string>\",\n \"formatLocale\": \"<string>\",\n \"labelSuffix\": \"<string>\",\n \"labelPrefix\": \"<string>\",\n \"dateFormat\": \"<string>\"\n }\n }\n ],\n \"comparisons\": [\n {\n \"name\": \"<string>\",\n \"measure\": \"<string>\",\n \"customPeriod\": 123\n }\n ],\n \"mapConfig\": {\n \"latitude\": \"<string>\",\n \"longitude\": \"<string>\"\n },\n \"filters\": [\n {\n \"field\": \"<string>\",\n \"value\": \"<string>\"\n }\n ],\n \"havingFilters\": [\n {\n \"field\": \"<string>\",\n \"operator\": \"<string>\",\n \"value\": \"<string>\",\n \"aggregation\": \"<string>\"\n }\n ],\n \"settings\": {\n \"secondYAxis\": true,\n \"colors\": [\n \"<string>\"\n ],\n \"legend\": true,\n \"legendPosition\": \"bottom\",\n \"stacking\": true,\n \"showDataLabels\": true,\n \"enableLegendSlider\": true,\n \"showAxisLabels\": true,\n \"debug\": true,\n \"pageSize\": 15,\n \"sliceLimit\": 7\n },\n \"orderBy\": [\n {\n \"field\": \"<string>\"\n }\n ],\n \"sqlOverride\": \"<string>\"\n },\n \"apiKey\": \"<string>\",\n \"organizationId\": \"<string>\",\n \"connectionId\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"sql\": \"<string>\",\n \"agentId\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"name\": \"<string>\",\n \"thumbnail\": \"<string>\"\n}")
.asString();
require 'uri'
require 'net/http'

url = URI("https://api.upsolve.ai/v1/api/chart/save-from-chat")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["authorization"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"chartConfig\": {\n \"title\": \"<string>\",\n \"dimensions\": [\n {\n \"name\": \"<string>\",\n \"field\": \"<string>\",\n \"label\": \"<string>\",\n \"format\": {\n \"label\": \"<string>\",\n \"formatOptions\": \"<string>\",\n \"formatLocale\": \"<string>\",\n \"labelSuffix\": \"<string>\",\n \"labelPrefix\": \"<string>\",\n \"dateFormat\": \"<string>\"\n }\n }\n ],\n \"measures\": [\n {\n \"name\": \"<string>\",\n \"field\": \"<string>\",\n \"label\": \"<string>\",\n \"format\": {\n \"label\": \"<string>\",\n \"formatOptions\": \"<string>\",\n \"formatLocale\": \"<string>\",\n \"labelSuffix\": \"<string>\",\n \"labelPrefix\": \"<string>\",\n \"dateFormat\": \"<string>\"\n }\n }\n ],\n \"comparisons\": [\n {\n \"name\": \"<string>\",\n \"measure\": \"<string>\",\n \"customPeriod\": 123\n }\n ],\n \"mapConfig\": {\n \"latitude\": \"<string>\",\n \"longitude\": \"<string>\"\n },\n \"filters\": [\n {\n \"field\": \"<string>\",\n \"value\": \"<string>\"\n }\n ],\n \"havingFilters\": [\n {\n \"field\": \"<string>\",\n \"operator\": \"<string>\",\n \"value\": \"<string>\",\n \"aggregation\": \"<string>\"\n }\n ],\n \"settings\": {\n \"secondYAxis\": true,\n \"colors\": [\n \"<string>\"\n ],\n \"legend\": true,\n \"legendPosition\": \"bottom\",\n \"stacking\": true,\n \"showDataLabels\": true,\n \"enableLegendSlider\": true,\n \"showAxisLabels\": true,\n \"debug\": true,\n \"pageSize\": 15,\n \"sliceLimit\": 7\n },\n \"orderBy\": [\n {\n \"field\": \"<string>\"\n }\n ],\n \"sqlOverride\": \"<string>\"\n },\n \"apiKey\": \"<string>\",\n \"organizationId\": \"<string>\",\n \"connectionId\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"sql\": \"<string>\",\n \"agentId\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"name\": \"<string>\",\n \"thumbnail\": \"<string>\"\n}"

response = http.request(request)
puts response.read_body
{
  "status": "<string>",
  "data": {
    "chartId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
    "name": "<string>"
  }
}
{
"status": "<string>",
"error": {
"message": "<string>",
"code": "<string>",
"details": {}
}
}

Authorizations

authorization
string
header
required

Body

application/json

POST /v1/api/chart/save-from-chat Request body

chartConfig
object
required

The chart configuration exactly as returned by the chat endpoint's generateChart tool result (toolResult.result.chartConfig). Should include the sqlOverride field the agent bakes onto the config; if it doesn't, pass the query on the top-level sql field instead — without either the saved chart cannot query data when rendered on a dashboard.

apiKey
string

Upsolve API key, generated under Account → Developer settings in the Upsolve Hub. Keys are user-scoped: pass organizationId alongside the key to select which org to act on.

Minimum string length: 1
organizationId
string

The ID of the organization. Required when using Supabase JWT authentication.

connectionId
string<uuid>

Explicit connection ID to associate with the chart. Overrides the connection resolved from agentId. When both agentId and connectionId are given, the connection must belong to the agent's project. A resolvable connection (from either field) is required.

Pattern: ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$
sql
string

The chart's source SQL. Only needed when chartConfig.sqlOverride is absent — some generateChart tool-result shapes carry the query on the tool's sibling sql field instead of on the config. When both are present, chartConfig.sqlOverride wins.

agentId
string<uuid>

The project agent ID the chart was generated by (the same ID used to call the chat endpoint). When provided, the chart is linked to the agent's data connection and project so it can be rendered on any dashboard.

Pattern: ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$
name
string

Display name for the saved chart. Defaults to the chart config's title.

thumbnail
string

Optional thumbnail image (data URL) for the chart.

Response

POST /v1/api/chart/save-from-chat Positive response

status
string
required
Allowed value: "success"
data
object
required