[{"data":1,"prerenderedAt":506},["ShallowReactive",2],{"$f1gr3bkhokmg31":3},{"baseUrl":4,"keyVariable":5,"commonErrors":6,"groups":19},"https:\u002F\u002Fchartjuice.com\u002Fapi\u002Fv1","CHARTJUICE_API_KEY",[7,10,13,16],{"code":8,"status":9},"invalid_request",400,{"code":11,"status":12},"unauthorized",401,{"code":14,"status":15},"rate_limited",429,{"code":17,"status":18},"internal",500,[20,227,284,375,423,438],{"name":21,"operations":22},"Charts",[23,47,71,114,136,152,167,181,195],{"name":24,"title":25,"description":26,"method":27,"path":28,"fields":29,"errors":41,"samples":42,"response":46},"list_charts","List charts","The account's saved charts, most recently changed first. Returns each chart's id, name, type and the address a person opens it at. Use it to find a chart someone names, then read it with `get_chart`. Page through with `cursor`.","GET","\u002Fcharts",[30,37],{"name":31,"in":32,"type":33,"required":34,"description":35,"default":36},"limit","query","integer, 1 to 100",false,"How many charts to return.","50",{"name":38,"in":32,"type":39,"required":34,"description":40},"cursor","string","`next_cursor` from the previous page.",[],{"curl":43,"javascript":44,"python":45},"curl \"https:\u002F\u002Fchartjuice.com\u002Fapi\u002Fv1\u002Fcharts?limit=2\" \\\n  -H \"Authorization: Bearer $CHARTJUICE_API_KEY\"","const response = await fetch('https:\u002F\u002Fchartjuice.com\u002Fapi\u002Fv1\u002Fcharts?limit=2', {\n  headers: { Authorization: `Bearer ${process.env.CHARTJUICE_API_KEY}` },\n})\nconst result = await response.json()","import json\nimport os\nimport urllib.request\n\nrequest = urllib.request.Request(\n    \"https:\u002F\u002Fchartjuice.com\u002Fapi\u002Fv1\u002Fcharts?limit=2\",\n    headers={\"Authorization\": \"Bearer \" + os.environ[\"CHARTJUICE_API_KEY\"]},\n)\nwith urllib.request.urlopen(request) as response:\n    result = json.load(response)","{\n  \"charts\": [\n    {\n      \"id\": \"7b0c9f1e-6c1d-4c57-9a47-2f1f0a3b8e21\",\n      \"name\": \"Monthly sales\",\n      \"type\": \"bar\",\n      \"url\": \"https:\u002F\u002Fchartjuice.com\u002Fcharts\u002F7b0c9f1e-6c1d-4c57-9a47-2f1f0a3b8e21\",\n      \"created_at\": \"2026-10-10T14:03:12.481923+00:00\",\n      \"updated_at\": \"2026-10-10T14:05:40.118264+00:00\"\n    },\n    {\n      \"id\": \"f3a1d2c4-0b5e-4f6a-8c7d-9e0f1a2b3c4d\",\n      \"name\": \"Visitors by channel\",\n      \"type\": \"line\",\n      \"url\": \"https:\u002F\u002Fchartjuice.com\u002Fcharts\u002Ff3a1d2c4-0b5e-4f6a-8c7d-9e0f1a2b3c4d\",\n      \"created_at\": \"2026-10-10T14:03:12.481923+00:00\",\n      \"updated_at\": \"2026-10-09T09:12:44.530112+00:00\"\n    }\n  ],\n  \"next_cursor\": \"MjAyNi0xMC0wOVQwOToxMjo0NC41MzAxMTIrMDA6MDB8ZjNhMWQyYzQtMGI1ZS00ZjZhLThjN2QtOWUwZjFhMmIzYzRk\"\n}",{"name":48,"title":49,"description":50,"method":27,"path":51,"fields":52,"errors":62,"samples":66,"response":70},"get_chart","Get a chart","A chart as it is now, without its rows: its type and options, which column plays which role, the columns, the steps applied to the data, the main style settings and any warnings. Read this before editing a chart you did not make in this conversation, to get the column ids that ops use and to see what is already set. To see how the chart looks, call `render_chart`.","\u002Fcharts\u002F{id}",[53,58],{"name":54,"in":55,"type":39,"required":56,"description":57},"id","path",true,"The chart's id.",{"name":59,"in":32,"type":60,"required":34,"description":61},"include","\"spec\"","`spec` adds the whole chart spec, data included.",[63],{"code":64,"status":65},"not_found",404,{"curl":67,"javascript":68,"python":69},"curl \"https:\u002F\u002Fchartjuice.com\u002Fapi\u002Fv1\u002Fcharts\u002F7b0c9f1e-6c1d-4c57-9a47-2f1f0a3b8e21\" \\\n  -H \"Authorization: Bearer $CHARTJUICE_API_KEY\"","const response = await fetch('https:\u002F\u002Fchartjuice.com\u002Fapi\u002Fv1\u002Fcharts\u002F7b0c9f1e-6c1d-4c57-9a47-2f1f0a3b8e21', {\n  headers: { Authorization: `Bearer ${process.env.CHARTJUICE_API_KEY}` },\n})\nconst result = await response.json()","import json\nimport os\nimport urllib.request\n\nrequest = urllib.request.Request(\n    \"https:\u002F\u002Fchartjuice.com\u002Fapi\u002Fv1\u002Fcharts\u002F7b0c9f1e-6c1d-4c57-9a47-2f1f0a3b8e21\",\n    headers={\"Authorization\": \"Bearer \" + os.environ[\"CHARTJUICE_API_KEY\"]},\n)\nwith urllib.request.urlopen(request) as response:\n    result = json.load(response)","{\n  \"chart\": {\n    \"id\": \"7b0c9f1e-6c1d-4c57-9a47-2f1f0a3b8e21\",\n    \"name\": \"Monthly sales\",\n    \"type\": \"bar\",\n    \"url\": \"https:\u002F\u002Fchartjuice.com\u002Fcharts\u002F7b0c9f1e-6c1d-4c57-9a47-2f1f0a3b8e21\",\n    \"created_at\": \"2026-10-10T14:03:12.481923+00:00\",\n    \"updated_at\": \"2026-10-10T14:05:40.118264+00:00\"\n  },\n  \"state\": {\n    \"type\": \"bar\",\n    \"options\": {\n      \"orientation\": \"vertical\",\n      \"stack\": \"none\"\n    },\n    \"mapping\": {\n      \"category\": \"c1\",\n      \"values\": [\n        \"c2\"\n      ]\n    },\n    \"roles\": [\n      \"category: Category\",\n      \"values: Values, numbers\"\n    ],\n    \"columns\": [\n      {\n        \"id\": \"c1\",\n        \"name\": \"Month\",\n        \"kind\": \"text\"\n      },\n      {\n        \"id\": \"c2\",\n        \"name\": \"Sales\",\n        \"kind\": \"number\"\n      }\n    ],\n    \"columnCount\": 2,\n    \"rows\": 3,\n    \"steps\": [],\n    \"columnsAfterSteps\": [\n      {\n        \"id\": \"c1\",\n        \"name\": \"Month\",\n        \"kind\": \"text\"\n      },\n      {\n        \"id\": \"c2\",\n        \"name\": \"Sales\",\n        \"kind\": \"number\"\n      }\n    ],\n    \"rowsAfterSteps\": 3,\n    \"style\": {\n      \"title\": {\n        \"show\": true,\n        \"text\": \"Monthly sales\"\n      },\n      \"subtitle\": {\n        \"show\": false,\n        \"text\": \"\"\n      },\n      \"legend\": {\n        \"show\": \"auto\",\n        \"position\": {\n          \"x\": \"center\",\n          \"y\": \"bottom\"\n        }\n      },\n      \"labels\": {\n        \"show\": false\n      },\n      \"xAxisTitle\": null,\n      \"yAxisTitle\": null,\n      \"palette\": [\n        \"#0C008C\",\n        \"#2D1FF5\",\n        \"#5D55FA\",\n        \"#8888FC\",\n        \"#C4C6FF\"\n      ],\n      \"seriesColors\": {},\n      \"size\": \"800×500\"\n    },\n    \"warnings\": []\n  }\n}",{"name":72,"title":73,"description":74,"method":75,"path":28,"fields":76,"errors":100,"samples":109,"response":113},"create_chart","Create a chart","Save a new chart. Start from a chart type and your own data (`type` with `data`), from a chart type with sample data (`type` alone), or from a gallery example (`example`). `ops` are applied before it is saved, so one call can make and style a chart. Columns get the ids c1, c2, c3 and so on, in the order they appear in the data, so `ops` can name them in the same call. The answer has the chart's id to use from then on, its `url` to give the person, its columns with their ids, and its warnings, which are what `lint_chart` would report. Call `render_chart` next to look at the result, and `apply_ops` to change it. If you are not sure which type suits the data, `list_chart_types` says what each is for. On the Free plan this is refused with `chart_limit_reached` once the account has its limit of saved charts.","POST",[77,82,85,89,93,96],{"name":78,"in":79,"type":80,"required":34,"description":81},"type","body","\"bar\" | \"line\" | \"pie\" | \"scatter\" | \"histogram\" | \"boxplot\" | \"dotplot\" | \"sankey\" | \"radar\" | \"heatmap\"","The chart type. On its own, the chart starts as that type with sample data; with `data`, it charts your data.",{"name":83,"in":79,"type":39,"required":34,"description":84},"example","The id of a gallery example to start from (`list_examples`), instead of `type`.",{"name":86,"in":79,"type":87,"required":34,"description":88},"data","string or array","The data. CSV or TSV as one string with a header row, or JSON rows: an array of objects (`[{\"Month\":\"Jan\",\"Sales\":4200}]`) or an array of arrays whose first row is the header (`[[\"Month\",\"Sales\"],[\"Jan\",4200]]`).",{"name":90,"in":79,"type":91,"required":34,"description":92},"format","\"csv\" | \"tsv\" | \"json\"","How to read `data`. Left out, a string is read as CSV or TSV (the delimiter is detected) and an array as JSON rows. `json` also takes a string holding JSON.",{"name":94,"in":79,"type":39,"required":34,"description":95},"name","The chart's name in My charts. Left out, the chart's title is used.",{"name":97,"in":79,"type":98,"required":34,"description":99},"ops","array of objects","Ops to apply, in order. All apply or none do. See the op catalog (`get_op_catalog`).",[101,103,106],{"code":102,"status":9},"invalid_ops",{"code":104,"status":105},"chart_limit_reached",409,{"code":107,"status":108},"too_large",413,{"curl":110,"javascript":111,"python":112},"curl -X POST \"https:\u002F\u002Fchartjuice.com\u002Fapi\u002Fv1\u002Fcharts\" \\\n  -H \"Authorization: Bearer $CHARTJUICE_API_KEY\" \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -d '{\n  \"type\": \"bar\",\n  \"data\": \"Month,Sales\\nJan,4200\\nFeb,5100\\nMar,4800\",\n  \"ops\": [\n    {\n      \"op\": \"setTitle\",\n      \"title\": {\n        \"text\": \"Monthly sales\"\n      }\n    }\n  ]\n}'","const response = await fetch('https:\u002F\u002Fchartjuice.com\u002Fapi\u002Fv1\u002Fcharts', {\n  method: 'POST',\n  headers: { Authorization: `Bearer ${process.env.CHARTJUICE_API_KEY}`, 'Content-Type': 'application\u002Fjson' },\n  body: JSON.stringify({\n    \"type\": \"bar\",\n    \"data\": \"Month,Sales\\nJan,4200\\nFeb,5100\\nMar,4800\",\n    \"ops\": [\n      {\n        \"op\": \"setTitle\",\n        \"title\": {\n          \"text\": \"Monthly sales\"\n        }\n      }\n    ]\n  }),\n})\nconst result = await response.json()","import json\nimport os\nimport urllib.request\n\nrequest = urllib.request.Request(\n    \"https:\u002F\u002Fchartjuice.com\u002Fapi\u002Fv1\u002Fcharts\",\n    method=\"POST\",\n    headers={\"Authorization\": \"Bearer \" + os.environ[\"CHARTJUICE_API_KEY\"], \"Content-Type\": \"application\u002Fjson\"},\n    data=json.dumps({\n        \"type\": \"bar\",\n        \"data\": \"Month,Sales\\nJan,4200\\nFeb,5100\\nMar,4800\",\n        \"ops\": [{\"op\": \"setTitle\", \"title\": {\"text\": \"Monthly sales\"}}],\n    }).encode(),\n)\nwith urllib.request.urlopen(request) as response:\n    result = json.load(response)","{\n  \"chart\": {\n    \"id\": \"7b0c9f1e-6c1d-4c57-9a47-2f1f0a3b8e21\",\n    \"name\": \"Monthly sales\",\n    \"type\": \"bar\",\n    \"url\": \"https:\u002F\u002Fchartjuice.com\u002Fcharts\u002F7b0c9f1e-6c1d-4c57-9a47-2f1f0a3b8e21\",\n    \"created_at\": \"2026-10-10T14:03:12.481923+00:00\",\n    \"updated_at\": \"2026-10-10T14:03:12.481923+00:00\"\n  },\n  \"columns\": [\n    {\n      \"id\": \"c1\",\n      \"name\": \"Month\",\n      \"kind\": \"text\"\n    },\n    {\n      \"id\": \"c2\",\n      \"name\": \"Sales\",\n      \"kind\": \"number\"\n    }\n  ],\n  \"warnings\": [],\n  \"notices\": []\n}",{"name":115,"title":116,"description":117,"method":75,"path":118,"fields":119,"errors":125,"samples":131,"response":135},"apply_ops","Edit a chart","Change a chart with ops, the same edits the editor makes: its type, which columns it charts, steps such as sort and top N, titles, axes, colors, and the data itself. `get_op_catalog` lists every op and its fields: read it once before the first edit. The ops apply together or not at all; if one is wrong the answer is `invalid_ops` with what to fix, and the chart is unchanged. Returns the chart's warnings after the change, which are what `lint_chart` would report, so there is no need to call that as well. Use column ids (c1, c2), not column names: `create_chart` answers with them, and `get_chart` has them for any chart. Afterwards call `render_chart` to check how the chart looks.","\u002Fcharts\u002F{id}\u002Fops",[120,121,122],{"name":54,"in":55,"type":39,"required":56,"description":57},{"name":97,"in":79,"type":98,"required":56,"description":99},{"name":123,"in":79,"type":39,"required":34,"description":124},"expected_updated_at","The chart's `updated_at` as you last saw it. If the chart has changed since, nothing is applied and the answer is `conflict`.",[126,127,128,130],{"code":64,"status":65},{"code":102,"status":9},{"code":129,"status":105},"conflict",{"code":107,"status":108},{"curl":132,"javascript":133,"python":134},"curl -X POST \"https:\u002F\u002Fchartjuice.com\u002Fapi\u002Fv1\u002Fcharts\u002F7b0c9f1e-6c1d-4c57-9a47-2f1f0a3b8e21\u002Fops\" \\\n  -H \"Authorization: Bearer $CHARTJUICE_API_KEY\" \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -d '{\n  \"ops\": [\n    {\n      \"op\": \"setVariants\",\n      \"variants\": {\n        \"bar\": {\n          \"orientation\": \"horizontal\"\n        }\n      }\n    },\n    {\n      \"op\": \"addTransform\",\n      \"transform\": {\n        \"type\": \"sort\",\n        \"column\": \"c2\",\n        \"direction\": \"desc\"\n      }\n    }\n  ]\n}'","const response = await fetch('https:\u002F\u002Fchartjuice.com\u002Fapi\u002Fv1\u002Fcharts\u002F7b0c9f1e-6c1d-4c57-9a47-2f1f0a3b8e21\u002Fops', {\n  method: 'POST',\n  headers: { Authorization: `Bearer ${process.env.CHARTJUICE_API_KEY}`, 'Content-Type': 'application\u002Fjson' },\n  body: JSON.stringify({\n    \"ops\": [\n      {\n        \"op\": \"setVariants\",\n        \"variants\": {\n          \"bar\": {\n            \"orientation\": \"horizontal\"\n          }\n        }\n      },\n      {\n        \"op\": \"addTransform\",\n        \"transform\": {\n          \"type\": \"sort\",\n          \"column\": \"c2\",\n          \"direction\": \"desc\"\n        }\n      }\n    ]\n  }),\n})\nconst result = await response.json()","import json\nimport os\nimport urllib.request\n\nrequest = urllib.request.Request(\n    \"https:\u002F\u002Fchartjuice.com\u002Fapi\u002Fv1\u002Fcharts\u002F7b0c9f1e-6c1d-4c57-9a47-2f1f0a3b8e21\u002Fops\",\n    method=\"POST\",\n    headers={\"Authorization\": \"Bearer \" + os.environ[\"CHARTJUICE_API_KEY\"], \"Content-Type\": \"application\u002Fjson\"},\n    data=json.dumps({\n        \"ops\": [\n            {\"op\": \"setVariants\", \"variants\": {\"bar\": {\"orientation\": \"horizontal\"}}},\n            {\n                \"op\": \"addTransform\",\n                \"transform\": {\"type\": \"sort\", \"column\": \"c2\", \"direction\": \"desc\"},\n            },\n        ],\n    }).encode(),\n)\nwith urllib.request.urlopen(request) as response:\n    result = json.load(response)","{\n  \"chart\": {\n    \"id\": \"7b0c9f1e-6c1d-4c57-9a47-2f1f0a3b8e21\",\n    \"name\": \"Monthly sales\",\n    \"type\": \"bar\",\n    \"url\": \"https:\u002F\u002Fchartjuice.com\u002Fcharts\u002F7b0c9f1e-6c1d-4c57-9a47-2f1f0a3b8e21\",\n    \"created_at\": \"2026-10-10T14:03:12.481923+00:00\",\n    \"updated_at\": \"2026-10-10T14:05:40.118264+00:00\"\n  },\n  \"applied\": 2,\n  \"warnings\": []\n}",{"name":137,"title":138,"description":139,"method":140,"path":51,"fields":141,"errors":145,"samples":147,"response":151},"rename_chart","Rename a chart","Change a chart's name in My charts. The title drawn on the chart is separate: change that with the `setTitle` op.","PATCH",[142,143],{"name":54,"in":55,"type":39,"required":56,"description":57},{"name":94,"in":79,"type":39,"required":56,"description":144},"The new name.",[146],{"code":64,"status":65},{"curl":148,"javascript":149,"python":150},"curl -X PATCH \"https:\u002F\u002Fchartjuice.com\u002Fapi\u002Fv1\u002Fcharts\u002F7b0c9f1e-6c1d-4c57-9a47-2f1f0a3b8e21\" \\\n  -H \"Authorization: Bearer $CHARTJUICE_API_KEY\" \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -d '{\n  \"name\": \"Q1 sales\"\n}'","const response = await fetch('https:\u002F\u002Fchartjuice.com\u002Fapi\u002Fv1\u002Fcharts\u002F7b0c9f1e-6c1d-4c57-9a47-2f1f0a3b8e21', {\n  method: 'PATCH',\n  headers: { Authorization: `Bearer ${process.env.CHARTJUICE_API_KEY}`, 'Content-Type': 'application\u002Fjson' },\n  body: JSON.stringify({\n    \"name\": \"Q1 sales\"\n  }),\n})\nconst result = await response.json()","import json\nimport os\nimport urllib.request\n\nrequest = urllib.request.Request(\n    \"https:\u002F\u002Fchartjuice.com\u002Fapi\u002Fv1\u002Fcharts\u002F7b0c9f1e-6c1d-4c57-9a47-2f1f0a3b8e21\",\n    method=\"PATCH\",\n    headers={\"Authorization\": \"Bearer \" + os.environ[\"CHARTJUICE_API_KEY\"], \"Content-Type\": \"application\u002Fjson\"},\n    data=json.dumps({\"name\": \"Q1 sales\"}).encode(),\n)\nwith urllib.request.urlopen(request) as response:\n    result = json.load(response)","{\n  \"chart\": {\n    \"id\": \"7b0c9f1e-6c1d-4c57-9a47-2f1f0a3b8e21\",\n    \"name\": \"Q1 sales\",\n    \"type\": \"bar\",\n    \"url\": \"https:\u002F\u002Fchartjuice.com\u002Fcharts\u002F7b0c9f1e-6c1d-4c57-9a47-2f1f0a3b8e21\",\n    \"created_at\": \"2026-10-10T14:03:12.481923+00:00\",\n    \"updated_at\": \"2026-10-10T14:05:40.118264+00:00\"\n  }\n}",{"name":153,"title":154,"description":155,"method":75,"path":156,"fields":157,"errors":159,"samples":162,"response":166},"duplicate_chart","Duplicate a chart","Save a copy of a chart, named \"Copy of\" and the original's name. Use it to try another design without changing the original. The copy counts toward the Free plan's saved charts like any other chart.","\u002Fcharts\u002F{id}\u002Fduplicate",[158],{"name":54,"in":55,"type":39,"required":56,"description":57},[160,161],{"code":64,"status":65},{"code":104,"status":105},{"curl":163,"javascript":164,"python":165},"curl -X POST \"https:\u002F\u002Fchartjuice.com\u002Fapi\u002Fv1\u002Fcharts\u002F7b0c9f1e-6c1d-4c57-9a47-2f1f0a3b8e21\u002Fduplicate\" \\\n  -H \"Authorization: Bearer $CHARTJUICE_API_KEY\"","const response = await fetch('https:\u002F\u002Fchartjuice.com\u002Fapi\u002Fv1\u002Fcharts\u002F7b0c9f1e-6c1d-4c57-9a47-2f1f0a3b8e21\u002Fduplicate', {\n  method: 'POST',\n  headers: { Authorization: `Bearer ${process.env.CHARTJUICE_API_KEY}` },\n})\nconst result = await response.json()","import json\nimport os\nimport urllib.request\n\nrequest = urllib.request.Request(\n    \"https:\u002F\u002Fchartjuice.com\u002Fapi\u002Fv1\u002Fcharts\u002F7b0c9f1e-6c1d-4c57-9a47-2f1f0a3b8e21\u002Fduplicate\",\n    method=\"POST\",\n    headers={\"Authorization\": \"Bearer \" + os.environ[\"CHARTJUICE_API_KEY\"]},\n)\nwith urllib.request.urlopen(request) as response:\n    result = json.load(response)","{\n  \"chart\": {\n    \"id\": \"0d9e8f7a-6b5c-4d3e-9f2a-1b0c9d8e7f6a\",\n    \"name\": \"Copy of Monthly sales\",\n    \"type\": \"bar\",\n    \"url\": \"https:\u002F\u002Fchartjuice.com\u002Fcharts\u002F0d9e8f7a-6b5c-4d3e-9f2a-1b0c9d8e7f6a\",\n    \"created_at\": \"2026-10-10T14:09:02.640771+00:00\",\n    \"updated_at\": \"2026-10-10T14:09:02.640771+00:00\"\n  }\n}",{"name":168,"title":169,"description":170,"method":171,"path":51,"fields":172,"errors":174,"samples":176,"response":180},"delete_chart","Delete a chart","Delete a chart for good. There is no undo, so use it only when the person asked for that chart to be deleted.","DELETE",[173],{"name":54,"in":55,"type":39,"required":56,"description":57},[175],{"code":64,"status":65},{"curl":177,"javascript":178,"python":179},"curl -X DELETE \"https:\u002F\u002Fchartjuice.com\u002Fapi\u002Fv1\u002Fcharts\u002F7b0c9f1e-6c1d-4c57-9a47-2f1f0a3b8e21\" \\\n  -H \"Authorization: Bearer $CHARTJUICE_API_KEY\"","const response = await fetch('https:\u002F\u002Fchartjuice.com\u002Fapi\u002Fv1\u002Fcharts\u002F7b0c9f1e-6c1d-4c57-9a47-2f1f0a3b8e21', {\n  method: 'DELETE',\n  headers: { Authorization: `Bearer ${process.env.CHARTJUICE_API_KEY}` },\n})\nconst result = await response.json()","import json\nimport os\nimport urllib.request\n\nrequest = urllib.request.Request(\n    \"https:\u002F\u002Fchartjuice.com\u002Fapi\u002Fv1\u002Fcharts\u002F7b0c9f1e-6c1d-4c57-9a47-2f1f0a3b8e21\",\n    method=\"DELETE\",\n    headers={\"Authorization\": \"Bearer \" + os.environ[\"CHARTJUICE_API_KEY\"]},\n)\nwith urllib.request.urlopen(request) as response:\n    result = json.load(response)","{\n  \"deleted\": true,\n  \"id\": \"7b0c9f1e-6c1d-4c57-9a47-2f1f0a3b8e21\"\n}",{"name":182,"title":183,"description":184,"method":27,"path":185,"fields":186,"errors":188,"samples":190,"response":194},"lint_chart","Check a chart","Readability problems with a chart as it is now: too many slices, colors too faint to see, an axis that misleads. An empty list means none were found. `create_chart`, `apply_ops` and `set_data` already answer with the same list as `warnings`, so call this for a chart you have not just changed. Fix a `warn` with `apply_ops`. An `info` is a suggestion: leave it when it is about something the person asked for, such as a color they chose. A pie reads best with 6 slices or fewer: a `topN` step with `n` set to 5 keeps the five largest and adds the rest up as a sixth.","\u002Fcharts\u002F{id}\u002Flint",[187],{"name":54,"in":55,"type":39,"required":56,"description":57},[189],{"code":64,"status":65},{"curl":191,"javascript":192,"python":193},"curl \"https:\u002F\u002Fchartjuice.com\u002Fapi\u002Fv1\u002Fcharts\u002F7b0c9f1e-6c1d-4c57-9a47-2f1f0a3b8e21\u002Flint\" \\\n  -H \"Authorization: Bearer $CHARTJUICE_API_KEY\"","const response = await fetch('https:\u002F\u002Fchartjuice.com\u002Fapi\u002Fv1\u002Fcharts\u002F7b0c9f1e-6c1d-4c57-9a47-2f1f0a3b8e21\u002Flint', {\n  headers: { Authorization: `Bearer ${process.env.CHARTJUICE_API_KEY}` },\n})\nconst result = await response.json()","import json\nimport os\nimport urllib.request\n\nrequest = urllib.request.Request(\n    \"https:\u002F\u002Fchartjuice.com\u002Fapi\u002Fv1\u002Fcharts\u002F7b0c9f1e-6c1d-4c57-9a47-2f1f0a3b8e21\u002Flint\",\n    headers={\"Authorization\": \"Bearer \" + os.environ[\"CHARTJUICE_API_KEY\"]},\n)\nwith urllib.request.urlopen(request) as response:\n    result = json.load(response)","{\n  \"problems\": [\n    {\n      \"id\": \"pie-too-many-slices\",\n      \"level\": \"warn\",\n      \"message\": \"9 slices is hard to read; group small ones into \\\"Other\\\" or use a bar chart\"\n    }\n  ]\n}",{"name":196,"title":197,"description":198,"method":27,"path":199,"fields":200,"errors":216,"samples":222,"response":226},"render_chart","Render a chart","A saved chart as an image, as it is now, to look at or to hand on: PNG at 1, 2 or 4 times its size, or SVG. Look at the image after an edit to check the chart reads well. The warnings that `create_chart` and `apply_ops` answer with cover the problems that are easy to miss by eye; for a chart you have not just changed, `lint_chart` gives them. Counts toward the daily renders. To draw the chart with other data, use `render_template`. On the Free plan the image carries a small chartjuice.com mark, as downloads from the editor do.","\u002Fcharts\u002F{id}\u002Frender.{format}",[201,202,206,211],{"name":54,"in":55,"type":39,"required":56,"description":57},{"name":90,"in":55,"type":203,"required":56,"description":204,"default":205},"\"png\" | \"svg\"","The image format.","\"png\"",{"name":207,"in":32,"type":208,"required":34,"description":209,"default":210},"scale","1 | 2 | 4","PNG only: 1, 2 or 4 times the canvas size. The image can be up to 4,000 px on a side.","1",{"name":212,"in":32,"type":213,"required":34,"description":214,"default":215},"transparent","boolean","Leave out the background.","false",[217,218,220],{"code":64,"status":65},{"code":219,"status":15},"render_limit_reached",{"code":221,"status":15},"image_limit_reached",{"curl":223,"javascript":224,"python":225},"curl \"https:\u002F\u002Fchartjuice.com\u002Fapi\u002Fv1\u002Fcharts\u002F7b0c9f1e-6c1d-4c57-9a47-2f1f0a3b8e21\u002Frender.png?scale=2\" \\\n  -H \"Authorization: Bearer $CHARTJUICE_API_KEY\" \\\n  -o chart.png","const response = await fetch('https:\u002F\u002Fchartjuice.com\u002Fapi\u002Fv1\u002Fcharts\u002F7b0c9f1e-6c1d-4c57-9a47-2f1f0a3b8e21\u002Frender.png?scale=2', {\n  headers: { Authorization: `Bearer ${process.env.CHARTJUICE_API_KEY}` },\n})\nconst image = Buffer.from(await response.arrayBuffer())","import json\nimport os\nimport urllib.request\n\nrequest = urllib.request.Request(\n    \"https:\u002F\u002Fchartjuice.com\u002Fapi\u002Fv1\u002Fcharts\u002F7b0c9f1e-6c1d-4c57-9a47-2f1f0a3b8e21\u002Frender.png?scale=2\",\n    headers={\"Authorization\": \"Bearer \" + os.environ[\"CHARTJUICE_API_KEY\"]},\n)\nwith urllib.request.urlopen(request) as response:\n    image = response.read()",null,{"name":228,"operations":229},"Data",[230,249,263],{"name":231,"title":232,"description":233,"method":234,"path":235,"fields":236,"errors":240,"samples":244,"response":248},"set_data","Replace the data","Replace a chart's data with CSV, TSV or JSON rows, read the way a pasted or uploaded file is (header row, numbers and dates detected). Use it to show new numbers in a chart that is already designed. If the new data has the columns the chart had, by name, the chart keeps its roles, steps and colors. If the columns are different, roles are picked again: read the chart with `get_chart` to see what it charts now.","PUT","\u002Fcharts\u002F{id}\u002Fdata",[237,238,239],{"name":54,"in":55,"type":39,"required":56,"description":57},{"name":86,"in":79,"type":87,"required":56,"description":88},{"name":90,"in":79,"type":91,"required":34,"description":92},[241,242,243],{"code":64,"status":65},{"code":129,"status":105},{"code":107,"status":108},{"curl":245,"javascript":246,"python":247},"curl -X PUT \"https:\u002F\u002Fchartjuice.com\u002Fapi\u002Fv1\u002Fcharts\u002F7b0c9f1e-6c1d-4c57-9a47-2f1f0a3b8e21\u002Fdata\" \\\n  -H \"Authorization: Bearer $CHARTJUICE_API_KEY\" \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -d '{\n  \"data\": [\n    {\n      \"Month\": \"Apr\",\n      \"Sales\": 6300\n    },\n    {\n      \"Month\": \"May\",\n      \"Sales\": 7100\n    }\n  ]\n}'","const response = await fetch('https:\u002F\u002Fchartjuice.com\u002Fapi\u002Fv1\u002Fcharts\u002F7b0c9f1e-6c1d-4c57-9a47-2f1f0a3b8e21\u002Fdata', {\n  method: 'PUT',\n  headers: { Authorization: `Bearer ${process.env.CHARTJUICE_API_KEY}`, 'Content-Type': 'application\u002Fjson' },\n  body: JSON.stringify({\n    \"data\": [\n      {\n        \"Month\": \"Apr\",\n        \"Sales\": 6300\n      },\n      {\n        \"Month\": \"May\",\n        \"Sales\": 7100\n      }\n    ]\n  }),\n})\nconst result = await response.json()","import json\nimport os\nimport urllib.request\n\nrequest = urllib.request.Request(\n    \"https:\u002F\u002Fchartjuice.com\u002Fapi\u002Fv1\u002Fcharts\u002F7b0c9f1e-6c1d-4c57-9a47-2f1f0a3b8e21\u002Fdata\",\n    method=\"PUT\",\n    headers={\"Authorization\": \"Bearer \" + os.environ[\"CHARTJUICE_API_KEY\"], \"Content-Type\": \"application\u002Fjson\"},\n    data=json.dumps({\"data\": [{\"Month\": \"Apr\", \"Sales\": 6300}, {\"Month\": \"May\", \"Sales\": 7100}]}).encode(),\n)\nwith urllib.request.urlopen(request) as response:\n    result = json.load(response)","{\n  \"chart\": {\n    \"id\": \"7b0c9f1e-6c1d-4c57-9a47-2f1f0a3b8e21\",\n    \"name\": \"Monthly sales\",\n    \"type\": \"bar\",\n    \"url\": \"https:\u002F\u002Fchartjuice.com\u002Fcharts\u002F7b0c9f1e-6c1d-4c57-9a47-2f1f0a3b8e21\",\n    \"created_at\": \"2026-10-10T14:03:12.481923+00:00\",\n    \"updated_at\": \"2026-10-10T14:05:40.118264+00:00\"\n  },\n  \"columns\": [\n    {\n      \"id\": \"c1\",\n      \"name\": \"Month\",\n      \"kind\": \"text\"\n    },\n    {\n      \"id\": \"c2\",\n      \"name\": \"Sales\",\n      \"kind\": \"number\"\n    }\n  ],\n  \"rows\": 2,\n  \"mapping_kept\": true,\n  \"notices\": [],\n  \"warnings\": []\n}",{"name":250,"title":251,"description":252,"method":27,"path":253,"fields":254,"errors":256,"samples":258,"response":262},"describe_data","Describe the data","A summary of each column the chart is drawn from, after its steps: numbers get their lowest, highest and average; text and dates get their most common values. Use it to understand data you haven't seen. For the rows themselves, use `query_data`.","\u002Fcharts\u002F{id}\u002Fdata\u002Fsummary",[255],{"name":54,"in":55,"type":39,"required":56,"description":57},[257],{"code":64,"status":65},{"curl":259,"javascript":260,"python":261},"curl \"https:\u002F\u002Fchartjuice.com\u002Fapi\u002Fv1\u002Fcharts\u002F7b0c9f1e-6c1d-4c57-9a47-2f1f0a3b8e21\u002Fdata\u002Fsummary\" \\\n  -H \"Authorization: Bearer $CHARTJUICE_API_KEY\"","const response = await fetch('https:\u002F\u002Fchartjuice.com\u002Fapi\u002Fv1\u002Fcharts\u002F7b0c9f1e-6c1d-4c57-9a47-2f1f0a3b8e21\u002Fdata\u002Fsummary', {\n  headers: { Authorization: `Bearer ${process.env.CHARTJUICE_API_KEY}` },\n})\nconst result = await response.json()","import json\nimport os\nimport urllib.request\n\nrequest = urllib.request.Request(\n    \"https:\u002F\u002Fchartjuice.com\u002Fapi\u002Fv1\u002Fcharts\u002F7b0c9f1e-6c1d-4c57-9a47-2f1f0a3b8e21\u002Fdata\u002Fsummary\",\n    headers={\"Authorization\": \"Bearer \" + os.environ[\"CHARTJUICE_API_KEY\"]},\n)\nwith urllib.request.urlopen(request) as response:\n    result = json.load(response)","{\n  \"rows\": 3,\n  \"columns\": [\n    {\n      \"id\": \"c1\",\n      \"name\": \"Month\",\n      \"kind\": \"text\",\n      \"blanks\": 0,\n      \"distinct\": 3,\n      \"top\": [\n        {\n          \"value\": \"Jan\",\n          \"count\": 1\n        },\n        {\n          \"value\": \"Feb\",\n          \"count\": 1\n        },\n        {\n          \"value\": \"Mar\",\n          \"count\": 1\n        }\n      ]\n    },\n    {\n      \"id\": \"c2\",\n      \"name\": \"Sales\",\n      \"kind\": \"number\",\n      \"blanks\": 0,\n      \"min\": 4200,\n      \"max\": 5100,\n      \"mean\": 4700\n    }\n  ]\n}",{"name":264,"title":265,"description":266,"method":75,"path":267,"fields":268,"errors":277,"samples":279,"response":283},"query_data","Query the data","Rows of the chart's data after its steps, with extra steps of your own if you like (they are tried, not saved). Use it to check what a sort, filter or total would give before adding it with `apply_ops`.","\u002Fcharts\u002F{id}\u002Fdata\u002Fquery",[269,270,273],{"name":54,"in":55,"type":39,"required":56,"description":57},{"name":271,"in":79,"type":98,"required":34,"description":272},"steps","Extra steps to try, in the shape `addTransform` takes. They are not saved.",{"name":31,"in":79,"type":274,"required":34,"description":275,"default":276},"integer, 1 to 1,000","How many rows to return.","100",[278],{"code":64,"status":65},{"curl":280,"javascript":281,"python":282},"curl -X POST \"https:\u002F\u002Fchartjuice.com\u002Fapi\u002Fv1\u002Fcharts\u002F7b0c9f1e-6c1d-4c57-9a47-2f1f0a3b8e21\u002Fdata\u002Fquery\" \\\n  -H \"Authorization: Bearer $CHARTJUICE_API_KEY\" \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -d '{\n  \"steps\": [\n    {\n      \"type\": \"sort\",\n      \"column\": \"c2\",\n      \"direction\": \"desc\"\n    }\n  ],\n  \"limit\": 2\n}'","const response = await fetch('https:\u002F\u002Fchartjuice.com\u002Fapi\u002Fv1\u002Fcharts\u002F7b0c9f1e-6c1d-4c57-9a47-2f1f0a3b8e21\u002Fdata\u002Fquery', {\n  method: 'POST',\n  headers: { Authorization: `Bearer ${process.env.CHARTJUICE_API_KEY}`, 'Content-Type': 'application\u002Fjson' },\n  body: JSON.stringify({\n    \"steps\": [\n      {\n        \"type\": \"sort\",\n        \"column\": \"c2\",\n        \"direction\": \"desc\"\n      }\n    ],\n    \"limit\": 2\n  }),\n})\nconst result = await response.json()","import json\nimport os\nimport urllib.request\n\nrequest = urllib.request.Request(\n    \"https:\u002F\u002Fchartjuice.com\u002Fapi\u002Fv1\u002Fcharts\u002F7b0c9f1e-6c1d-4c57-9a47-2f1f0a3b8e21\u002Fdata\u002Fquery\",\n    method=\"POST\",\n    headers={\"Authorization\": \"Bearer \" + os.environ[\"CHARTJUICE_API_KEY\"], \"Content-Type\": \"application\u002Fjson\"},\n    data=json.dumps({\"steps\": [{\"type\": \"sort\", \"column\": \"c2\", \"direction\": \"desc\"}], \"limit\": 2}).encode(),\n)\nwith urllib.request.urlopen(request) as response:\n    result = json.load(response)","{\n  \"columns\": [\n    \"c1 (Month)\",\n    \"c2 (Sales)\"\n  ],\n  \"rows\": [\n    [\n      \"Feb\",\n      5100\n    ],\n    [\n      \"Mar\",\n      4800\n    ]\n  ],\n  \"total_rows\": 3,\n  \"errors\": []\n}",{"name":285,"operations":286},"Images",[287,323,349],{"name":288,"title":289,"description":290,"method":75,"path":291,"fields":292,"errors":315,"samples":319,"response":226},"render_image","Render a chart from data","An image of a chart you describe in the request, with nothing saved: a chart type and your data, or a whole chart spec. Use it for a picture you need once, in a report or a message, where there is no chart to keep. `ops` style it before it is drawn, as they do in `create_chart`. The answer is the image itself; send `Accept: application\u002Fjson` to get it base64-encoded in JSON instead. Counts toward the month's image renders: 100 on the Free plan and 1,000 on Pro (`image_limit_reached` after that). Each different picture counts once a month, so asking for the identical image again costs nothing more. On the Free plan the image carries a small chartjuice.com mark.","\u002Frender",[293,295,296,298,302,303,305,306,307,311,314],{"name":78,"in":79,"type":80,"required":34,"description":294},"The chart type, with `data`.",{"name":86,"in":79,"type":87,"required":34,"description":88},{"name":297,"in":79,"type":91,"required":34,"description":92},"data_format",{"name":299,"in":79,"type":300,"required":34,"description":301},"spec","object","A whole chart spec, in place of `type` and `data`: what `get_chart` returns with `include=spec`. Its `advanced` must be `null`.",{"name":97,"in":79,"type":98,"required":34,"description":99},{"name":94,"in":79,"type":39,"required":34,"description":304},"A name for the image file, used when the image is downloaded. Left out, it is `chart`.",{"name":90,"in":79,"type":203,"required":34,"description":204,"default":205},{"name":207,"in":79,"type":208,"required":34,"description":209,"default":210},{"name":308,"in":79,"type":309,"required":34,"description":310},"width","integer, 100 to 4,000","The canvas width in pixels, in place of the chart's own. The image is this times `scale`.",{"name":312,"in":79,"type":309,"required":34,"description":313},"height","The canvas height in pixels, in place of the chart's own. The image is this times `scale`.",{"name":212,"in":79,"type":213,"required":34,"description":214,"default":215},[316,317,318],{"code":102,"status":9},{"code":221,"status":15},{"code":107,"status":108},{"curl":320,"javascript":321,"python":322},"curl -X POST \"https:\u002F\u002Fchartjuice.com\u002Fapi\u002Fv1\u002Frender\" \\\n  -H \"Authorization: Bearer $CHARTJUICE_API_KEY\" \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -d '{\n  \"type\": \"bar\",\n  \"data\": \"Month,Sales\\nJan,4200\\nFeb,5100\\nMar,4800\",\n  \"ops\": [\n    {\n      \"op\": \"setTitle\",\n      \"title\": {\n        \"text\": \"Monthly sales\"\n      }\n    }\n  ],\n  \"scale\": 2\n}' \\\n  -o chart.png","const response = await fetch('https:\u002F\u002Fchartjuice.com\u002Fapi\u002Fv1\u002Frender', {\n  method: 'POST',\n  headers: { Authorization: `Bearer ${process.env.CHARTJUICE_API_KEY}`, 'Content-Type': 'application\u002Fjson' },\n  body: JSON.stringify({\n    \"type\": \"bar\",\n    \"data\": \"Month,Sales\\nJan,4200\\nFeb,5100\\nMar,4800\",\n    \"ops\": [\n      {\n        \"op\": \"setTitle\",\n        \"title\": {\n          \"text\": \"Monthly sales\"\n        }\n      }\n    ],\n    \"scale\": 2\n  }),\n})\nconst image = Buffer.from(await response.arrayBuffer())","import json\nimport os\nimport urllib.request\n\nrequest = urllib.request.Request(\n    \"https:\u002F\u002Fchartjuice.com\u002Fapi\u002Fv1\u002Frender\",\n    method=\"POST\",\n    headers={\"Authorization\": \"Bearer \" + os.environ[\"CHARTJUICE_API_KEY\"], \"Content-Type\": \"application\u002Fjson\"},\n    data=json.dumps({\n        \"type\": \"bar\",\n        \"data\": \"Month,Sales\\nJan,4200\\nFeb,5100\\nMar,4800\",\n        \"ops\": [{\"op\": \"setTitle\", \"title\": {\"text\": \"Monthly sales\"}}],\n        \"scale\": 2,\n    }).encode(),\n)\nwith urllib.request.urlopen(request) as response:\n    image = response.read()",{"name":324,"title":325,"description":326,"method":75,"path":327,"fields":328,"errors":341,"samples":345,"response":226},"render_template","Render a chart with new data","A saved chart drawn with data you send, in place of its own. Design the chart once in the editor, then send new numbers whenever you need the picture: it keeps its type, colors, titles and steps. The saved chart is not changed. The new data's columns are matched to the chart's by name, so it needs every column the chart is drawn from, under the same names; when one is missing the answer is `invalid_request` and names them. `ops` are applied for this image only. The answer is the image itself; send `Accept: application\u002Fjson` to get it base64-encoded in JSON instead. Counts toward the month's image renders, not the daily renders. Each different picture counts once a month: the same chart with the same data again costs nothing more.","\u002Fcharts\u002F{id}\u002Frender",[329,330,332,333,335,336,337,338,339,340],{"name":54,"in":55,"type":39,"required":56,"description":57},{"name":86,"in":79,"type":87,"required":56,"description":331},"The data to draw the chart with, in place of its own. Its columns are matched to the chart's by name. CSV or TSV as one string with a header row, or JSON rows: an array of objects (`[{\"Month\":\"Jan\",\"Sales\":4200}]`) or an array of arrays whose first row is the header.",{"name":297,"in":79,"type":91,"required":34,"description":92},{"name":97,"in":79,"type":98,"required":34,"description":334},"Ops to apply after the data is in, for this image only. All apply or none do. See the op catalog (`get_op_catalog`).",{"name":94,"in":79,"type":39,"required":34,"description":304},{"name":90,"in":79,"type":203,"required":34,"description":204,"default":205},{"name":207,"in":79,"type":208,"required":34,"description":209,"default":210},{"name":308,"in":79,"type":309,"required":34,"description":310},{"name":312,"in":79,"type":309,"required":34,"description":313},{"name":212,"in":79,"type":213,"required":34,"description":214,"default":215},[342,343,344],{"code":64,"status":65},{"code":102,"status":9},{"code":221,"status":15},{"curl":346,"javascript":347,"python":348},"curl -X POST \"https:\u002F\u002Fchartjuice.com\u002Fapi\u002Fv1\u002Fcharts\u002F7b0c9f1e-6c1d-4c57-9a47-2f1f0a3b8e21\u002Frender\" \\\n  -H \"Authorization: Bearer $CHARTJUICE_API_KEY\" \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -d '{\n  \"data\": [\n    {\n      \"Month\": \"Apr\",\n      \"Sales\": 6300\n    },\n    {\n      \"Month\": \"May\",\n      \"Sales\": 7100\n    }\n  ],\n  \"scale\": 2\n}' \\\n  -o chart.png","const response = await fetch('https:\u002F\u002Fchartjuice.com\u002Fapi\u002Fv1\u002Fcharts\u002F7b0c9f1e-6c1d-4c57-9a47-2f1f0a3b8e21\u002Frender', {\n  method: 'POST',\n  headers: { Authorization: `Bearer ${process.env.CHARTJUICE_API_KEY}`, 'Content-Type': 'application\u002Fjson' },\n  body: JSON.stringify({\n    \"data\": [\n      {\n        \"Month\": \"Apr\",\n        \"Sales\": 6300\n      },\n      {\n        \"Month\": \"May\",\n        \"Sales\": 7100\n      }\n    ],\n    \"scale\": 2\n  }),\n})\nconst image = Buffer.from(await response.arrayBuffer())","import json\nimport os\nimport urllib.request\n\nrequest = urllib.request.Request(\n    \"https:\u002F\u002Fchartjuice.com\u002Fapi\u002Fv1\u002Fcharts\u002F7b0c9f1e-6c1d-4c57-9a47-2f1f0a3b8e21\u002Frender\",\n    method=\"POST\",\n    headers={\"Authorization\": \"Bearer \" + os.environ[\"CHARTJUICE_API_KEY\"], \"Content-Type\": \"application\u002Fjson\"},\n    data=json.dumps({\"data\": [{\"Month\": \"Apr\", \"Sales\": 6300}, {\"Month\": \"May\", \"Sales\": 7100}], \"scale\": 2}).encode(),\n)\nwith urllib.request.urlopen(request) as response:\n    image = response.read()",{"name":350,"title":351,"description":352,"method":75,"path":353,"fields":354,"errors":368,"samples":370,"response":374},"create_image_url","Create an image link","A link that shows a saved chart as an image to anyone who has it, with no key and no sign-in: for an `\u003Cimg>` tag in an email, a doc, a dashboard or another site's page. The link is a live image. It shows the chart as it is now and changes when the chart is edited, so the picture in the email stays current. With `data`, the link draws the chart with that data in place of its own. The link is signed, so nobody can change it to show another chart. It works until its signing key is rotated or revoked on the account page, or for `expires_in` seconds if you give that. The link is for the site it was made on. Making a link costs nothing. Its picture counts toward the month's image renders once each time the chart changes, and once at the start of each month, however many people open it. On the Free plan the image carries a small chartjuice.com mark.","\u002Fimage-urls",[355,356,357,358,359,360,361,363,364],{"name":54,"in":79,"type":39,"required":56,"description":57},{"name":90,"in":79,"type":203,"required":34,"description":204,"default":205},{"name":207,"in":79,"type":208,"required":34,"description":209,"default":210},{"name":308,"in":79,"type":309,"required":34,"description":310},{"name":312,"in":79,"type":309,"required":34,"description":313},{"name":212,"in":79,"type":213,"required":34,"description":214,"default":215},{"name":86,"in":79,"type":87,"required":34,"description":362},"Data to draw the chart with in place of its own. It travels in the link, so it has to be small: up to 4,000 characters once encoded, about 3,000 characters of CSV. Its columns are matched to the chart's by name. Left out, the link is a live image of the chart: it shows the chart as it is now and changes when the chart is edited.",{"name":297,"in":79,"type":91,"required":34,"description":92},{"name":365,"in":79,"type":366,"required":34,"description":367},"expires_in","integer, 60 to 315,360,000","Seconds until the link stops working, from one minute to ten years. Left out, it works until its signing key is rotated or revoked.",[369],{"code":64,"status":65},{"curl":371,"javascript":372,"python":373},"curl -X POST \"https:\u002F\u002Fchartjuice.com\u002Fapi\u002Fv1\u002Fimage-urls\" \\\n  -H \"Authorization: Bearer $CHARTJUICE_API_KEY\" \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -d '{\n  \"id\": \"7b0c9f1e-6c1d-4c57-9a47-2f1f0a3b8e21\",\n  \"scale\": 2\n}'","const response = await fetch('https:\u002F\u002Fchartjuice.com\u002Fapi\u002Fv1\u002Fimage-urls', {\n  method: 'POST',\n  headers: { Authorization: `Bearer ${process.env.CHARTJUICE_API_KEY}`, 'Content-Type': 'application\u002Fjson' },\n  body: JSON.stringify({\n    \"id\": \"7b0c9f1e-6c1d-4c57-9a47-2f1f0a3b8e21\",\n    \"scale\": 2\n  }),\n})\nconst result = await response.json()","import json\nimport os\nimport urllib.request\n\nrequest = urllib.request.Request(\n    \"https:\u002F\u002Fchartjuice.com\u002Fapi\u002Fv1\u002Fimage-urls\",\n    method=\"POST\",\n    headers={\"Authorization\": \"Bearer \" + os.environ[\"CHARTJUICE_API_KEY\"], \"Content-Type\": \"application\u002Fjson\"},\n    data=json.dumps({\"id\": \"7b0c9f1e-6c1d-4c57-9a47-2f1f0a3b8e21\", \"scale\": 2}).encode(),\n)\nwith urllib.request.urlopen(request) as response:\n    result = json.load(response)","{\n  \"url\": \"https:\u002F\u002Fchartjuice.com\u002Fimg\u002F7b0c9f1e-6c1d-4c57-9a47-2f1f0a3b8e21.png?kid=3d2a1b0c-9e8f-4a7b-8c6d-5e4f3a2b1c0d&scale=2&sig=d2bd5b97a1f538c7cb8c860665879d38b7d5a75248202d534d21c3ed3cf0931f\",\n  \"expires_at\": null,\n  \"chart\": {\n    \"id\": \"7b0c9f1e-6c1d-4c57-9a47-2f1f0a3b8e21\",\n    \"name\": \"Monthly sales\",\n    \"type\": \"bar\",\n    \"url\": \"https:\u002F\u002Fchartjuice.com\u002Fcharts\u002F7b0c9f1e-6c1d-4c57-9a47-2f1f0a3b8e21\",\n    \"created_at\": \"2026-10-10T14:03:12.481923+00:00\",\n    \"updated_at\": \"2026-10-10T14:05:40.118264+00:00\"\n  }\n}",{"name":376,"operations":377},"Brand palette",[378,390,407],{"name":379,"title":380,"description":381,"method":27,"path":382,"fields":383,"errors":384,"samples":385,"response":389},"get_brand_palette","Get the brand palette","The account's saved brand palette: the colors it uses for its own charts. `null` when none is saved. Apply it to a chart with the `setPalette` op.","\u002Fbrand-palette",[],[],{"curl":386,"javascript":387,"python":388},"curl \"https:\u002F\u002Fchartjuice.com\u002Fapi\u002Fv1\u002Fbrand-palette\" \\\n  -H \"Authorization: Bearer $CHARTJUICE_API_KEY\"","const response = await fetch('https:\u002F\u002Fchartjuice.com\u002Fapi\u002Fv1\u002Fbrand-palette', {\n  headers: { Authorization: `Bearer ${process.env.CHARTJUICE_API_KEY}` },\n})\nconst result = await response.json()","import json\nimport os\nimport urllib.request\n\nrequest = urllib.request.Request(\n    \"https:\u002F\u002Fchartjuice.com\u002Fapi\u002Fv1\u002Fbrand-palette\",\n    headers={\"Authorization\": \"Bearer \" + os.environ[\"CHARTJUICE_API_KEY\"]},\n)\nwith urllib.request.urlopen(request) as response:\n    result = json.load(response)","{\n  \"colors\": [\n    \"#0F766E\",\n    \"#F59E0B\",\n    \"#E11D48\"\n  ]\n}",{"name":391,"title":392,"description":393,"method":234,"path":382,"fields":394,"errors":399,"samples":403,"response":389},"set_brand_palette","Set the brand palette","Save the account's brand palette, replacing the one it had, or clear it with `null`. Saving a palette needs the Pro plan (`forbidden_plan` otherwise).",[395],{"name":396,"in":79,"type":397,"required":56,"description":398},"colors","array of strings or null","1 to 12 colors as `#RRGGBB` or `#RGB`, or `null` to clear the palette.",[400],{"code":401,"status":402},"forbidden_plan",403,{"curl":404,"javascript":405,"python":406},"curl -X PUT \"https:\u002F\u002Fchartjuice.com\u002Fapi\u002Fv1\u002Fbrand-palette\" \\\n  -H \"Authorization: Bearer $CHARTJUICE_API_KEY\" \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -d '{\n  \"colors\": [\n    \"#0f766e\",\n    \"#F59E0B\",\n    \"#e11d48\"\n  ]\n}'","const response = await fetch('https:\u002F\u002Fchartjuice.com\u002Fapi\u002Fv1\u002Fbrand-palette', {\n  method: 'PUT',\n  headers: { Authorization: `Bearer ${process.env.CHARTJUICE_API_KEY}`, 'Content-Type': 'application\u002Fjson' },\n  body: JSON.stringify({\n    \"colors\": [\n      \"#0f766e\",\n      \"#F59E0B\",\n      \"#e11d48\"\n    ]\n  }),\n})\nconst result = await response.json()","import json\nimport os\nimport urllib.request\n\nrequest = urllib.request.Request(\n    \"https:\u002F\u002Fchartjuice.com\u002Fapi\u002Fv1\u002Fbrand-palette\",\n    method=\"PUT\",\n    headers={\"Authorization\": \"Bearer \" + os.environ[\"CHARTJUICE_API_KEY\"], \"Content-Type\": \"application\u002Fjson\"},\n    data=json.dumps({\"colors\": [\"#0f766e\", \"#F59E0B\", \"#e11d48\"]}).encode(),\n)\nwith urllib.request.urlopen(request) as response:\n    result = json.load(response)",{"name":408,"title":409,"description":410,"method":75,"path":411,"fields":412,"errors":416,"samples":418,"response":422},"extract_brand_palette","Get colors from a website","The brand colors a website uses, read from its page and stylesheets. Nothing is saved: look at the colors, then save the ones you want with `set_brand_palette`. Needs the Pro plan, and an account can look up 20 websites a day.","\u002Fbrand-palette\u002Fextract",[413],{"name":414,"in":79,"type":39,"required":56,"description":415},"url","A website address, like `example.com`.",[417],{"code":401,"status":402},{"curl":419,"javascript":420,"python":421},"curl -X POST \"https:\u002F\u002Fchartjuice.com\u002Fapi\u002Fv1\u002Fbrand-palette\u002Fextract\" \\\n  -H \"Authorization: Bearer $CHARTJUICE_API_KEY\" \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -d '{\n  \"url\": \"chartjuice.com\"\n}'","const response = await fetch('https:\u002F\u002Fchartjuice.com\u002Fapi\u002Fv1\u002Fbrand-palette\u002Fextract', {\n  method: 'POST',\n  headers: { Authorization: `Bearer ${process.env.CHARTJUICE_API_KEY}`, 'Content-Type': 'application\u002Fjson' },\n  body: JSON.stringify({\n    \"url\": \"chartjuice.com\"\n  }),\n})\nconst result = await response.json()","import json\nimport os\nimport urllib.request\n\nrequest = urllib.request.Request(\n    \"https:\u002F\u002Fchartjuice.com\u002Fapi\u002Fv1\u002Fbrand-palette\u002Fextract\",\n    method=\"POST\",\n    headers={\"Authorization\": \"Bearer \" + os.environ[\"CHARTJUICE_API_KEY\"], \"Content-Type\": \"application\u002Fjson\"},\n    data=json.dumps({\"url\": \"chartjuice.com\"}).encode(),\n)\nwith urllib.request.urlopen(request) as response:\n    result = json.load(response)","{\n  \"colors\": [\n    \"#5D55FA\",\n    \"#102A43\",\n    \"#0D009A\",\n    \"#9595FF\",\n    \"#4B42B9\",\n    \"#9D97E2\",\n    \"#C10007\",\n    \"#9FB3C8\"\n  ],\n  \"added\": 0\n}",{"name":424,"operations":425},"Account",[426],{"name":427,"title":428,"description":429,"method":27,"path":430,"fields":431,"errors":432,"samples":433,"response":437},"get_account","Get the account","The plan, how many charts are saved against the plan's limit, and what is left of the request, render and image allowances. Check it before making many charts or images, and to explain a `chart_limit_reached`, `render_limit_reached` or `image_limit_reached` refusal.","\u002Faccount",[],[],{"curl":434,"javascript":435,"python":436},"curl \"https:\u002F\u002Fchartjuice.com\u002Fapi\u002Fv1\u002Faccount\" \\\n  -H \"Authorization: Bearer $CHARTJUICE_API_KEY\"","const response = await fetch('https:\u002F\u002Fchartjuice.com\u002Fapi\u002Fv1\u002Faccount', {\n  headers: { Authorization: `Bearer ${process.env.CHARTJUICE_API_KEY}` },\n})\nconst result = await response.json()","import json\nimport os\nimport urllib.request\n\nrequest = urllib.request.Request(\n    \"https:\u002F\u002Fchartjuice.com\u002Fapi\u002Fv1\u002Faccount\",\n    headers={\"Authorization\": \"Bearer \" + os.environ[\"CHARTJUICE_API_KEY\"]},\n)\nwith urllib.request.urlopen(request) as response:\n    result = json.load(response)","{\n  \"plan\": \"free\",\n  \"saved_charts\": {\n    \"used\": 3,\n    \"limit\": 5\n  },\n  \"requests\": {\n    \"limit\": 60,\n    \"left\": 59,\n    \"resets_in_seconds\": 42\n  },\n  \"renders\": {\n    \"limit\": 100,\n    \"left\": 96,\n    \"resets_in_seconds\": 35700\n  },\n  \"image_renders\": {\n    \"limit\": 100,\n    \"left\": 88,\n    \"resets_in_seconds\": 1769700\n  }\n}",{"name":439,"operations":440},"Reference",[441,453,467,479,491],{"name":442,"title":443,"description":444,"method":27,"path":445,"fields":446,"errors":447,"samples":448,"response":452},"list_chart_types","List chart types","Every chart type: what it is for, the data it needs (one column per role), and a short guide to its options. Read it to choose a chart for some data, then make it with `create_chart`.","\u002Fchart-types",[],[],{"curl":449,"javascript":450,"python":451},"curl \"https:\u002F\u002Fchartjuice.com\u002Fapi\u002Fv1\u002Fchart-types\" \\\n  -H \"Authorization: Bearer $CHARTJUICE_API_KEY\"","const response = await fetch('https:\u002F\u002Fchartjuice.com\u002Fapi\u002Fv1\u002Fchart-types', {\n  headers: { Authorization: `Bearer ${process.env.CHARTJUICE_API_KEY}` },\n})\nconst result = await response.json()","import json\nimport os\nimport urllib.request\n\nrequest = urllib.request.Request(\n    \"https:\u002F\u002Fchartjuice.com\u002Fapi\u002Fv1\u002Fchart-types\",\n    headers={\"Authorization\": \"Bearer \" + os.environ[\"CHARTJUICE_API_KEY\"]},\n)\nwith urllib.request.urlopen(request) as response:\n    result = json.load(response)","{\n  \"chart_types\": [\n    {\n      \"type\": \"pie\",\n      \"label\": \"Pie chart\",\n      \"use_for\": \"Show parts of a whole\",\n      \"roles\": [\n        {\n          \"role\": \"category\",\n          \"label\": \"Slices\",\n          \"numeric\": false,\n          \"required\": true\n        },\n        {\n          \"role\": \"value\",\n          \"label\": \"Value\",\n          \"numeric\": true,\n          \"required\": true\n        }\n      ],\n      \"guide\": \"Show parts of a whole. Roles: category (slice names) + value (one number column).\"\n    }\n  ]\n}",{"name":454,"title":455,"description":456,"method":27,"path":457,"fields":458,"errors":461,"samples":462,"response":466},"list_examples","List examples","The gallery of example charts, each with sample data and a finished design. Pass an id as `example` to `create_chart` to start from one.","\u002Fexamples",[459],{"name":78,"in":32,"type":80,"required":34,"description":460},"Only examples of this chart type.",[],{"curl":463,"javascript":464,"python":465},"curl \"https:\u002F\u002Fchartjuice.com\u002Fapi\u002Fv1\u002Fexamples?type=bar\" \\\n  -H \"Authorization: Bearer $CHARTJUICE_API_KEY\"","const response = await fetch('https:\u002F\u002Fchartjuice.com\u002Fapi\u002Fv1\u002Fexamples?type=bar', {\n  headers: { Authorization: `Bearer ${process.env.CHARTJUICE_API_KEY}` },\n})\nconst result = await response.json()","import json\nimport os\nimport urllib.request\n\nrequest = urllib.request.Request(\n    \"https:\u002F\u002Fchartjuice.com\u002Fapi\u002Fv1\u002Fexamples?type=bar\",\n    headers={\"Authorization\": \"Bearer \" + os.environ[\"CHARTJUICE_API_KEY\"]},\n)\nwith urllib.request.urlopen(request) as response:\n    result = json.load(response)","{\n  \"examples\": [\n    {\n      \"id\": \"bar-grouped\",\n      \"type\": \"bar\",\n      \"label\": \"Double bar graph\",\n      \"description\": \"Compare two series side by side, like this year against last year.\"\n    }\n  ]\n}",{"name":468,"title":469,"description":470,"method":27,"path":471,"fields":472,"errors":473,"samples":474,"response":478},"list_palettes","List palettes","The preset color palettes. Apply one to a chart with the `setPalette` op and its colors.","\u002Fpalettes",[],[],{"curl":475,"javascript":476,"python":477},"curl \"https:\u002F\u002Fchartjuice.com\u002Fapi\u002Fv1\u002Fpalettes\" \\\n  -H \"Authorization: Bearer $CHARTJUICE_API_KEY\"","const response = await fetch('https:\u002F\u002Fchartjuice.com\u002Fapi\u002Fv1\u002Fpalettes', {\n  headers: { Authorization: `Bearer ${process.env.CHARTJUICE_API_KEY}` },\n})\nconst result = await response.json()","import json\nimport os\nimport urllib.request\n\nrequest = urllib.request.Request(\n    \"https:\u002F\u002Fchartjuice.com\u002Fapi\u002Fv1\u002Fpalettes\",\n    headers={\"Authorization\": \"Bearer \" + os.environ[\"CHARTJUICE_API_KEY\"]},\n)\nwith urllib.request.urlopen(request) as response:\n    result = json.load(response)","{\n  \"palettes\": [\n    {\n      \"id\": \"juice\",\n      \"name\": \"Juice\",\n      \"colors\": [\n        \"#0C008C\",\n        \"#2D1FF5\",\n        \"#5D55FA\",\n        \"#8888FC\",\n        \"#C4C6FF\"\n      ],\n      \"light\": false\n    }\n  ]\n}",{"name":480,"title":481,"description":482,"method":27,"path":483,"fields":484,"errors":485,"samples":486,"response":490},"get_op_catalog","Get the op catalog","Every op `apply_ops` takes, with its fields: as a compact text reference, and as a JSON Schema per op. Read it once before editing charts.","\u002Fops",[],[],{"curl":487,"javascript":488,"python":489},"curl \"https:\u002F\u002Fchartjuice.com\u002Fapi\u002Fv1\u002Fops\" \\\n  -H \"Authorization: Bearer $CHARTJUICE_API_KEY\"","const response = await fetch('https:\u002F\u002Fchartjuice.com\u002Fapi\u002Fv1\u002Fops', {\n  headers: { Authorization: `Bearer ${process.env.CHARTJUICE_API_KEY}` },\n})\nconst result = await response.json()","import json\nimport os\nimport urllib.request\n\nrequest = urllib.request.Request(\n    \"https:\u002F\u002Fchartjuice.com\u002Fapi\u002Fv1\u002Fops\",\n    headers={\"Authorization\": \"Bearer \" + os.environ[\"CHARTJUICE_API_KEY\"]},\n)\nwith urllib.request.urlopen(request) as response:\n    result = json.load(response)","{\n  \"catalog\": \"## Ops (pass a list to apply_ops; all must succeed or none apply)\\n\\nType and layout\\n- {\\\"op\\\":\\\"setType\\\",\\\"type\\\":\\\"bar|line|pie|...\\\"}: data, mapping and style carry over.\",\n  \"ops\": [\n    {\n      \"op\": \"setType\",\n      \"schema\": {\n        \"type\": \"object\",\n        \"properties\": {\n          \"op\": {\n            \"type\": \"string\",\n            \"const\": \"setType\"\n          },\n          \"type\": {\n            \"type\": \"string\",\n            \"enum\": [\n              \"bar\",\n              \"line\",\n              \"pie\"\n            ]\n          }\n        },\n        \"required\": [\n          \"op\",\n          \"type\"\n        ],\n        \"additionalProperties\": false\n      }\n    }\n  ]\n}",{"name":492,"title":493,"description":494,"method":27,"path":495,"fields":496,"errors":500,"samples":501,"response":505},"lookup_docs","Look up the docs","Search Chartjuice's reference: which chart suits what, how to shape data for each chart, palettes, number formats, plans and limits. Use it when unsure, before guessing.","\u002Fdocs\u002Fsearch",[497],{"name":498,"in":32,"type":39,"required":56,"description":499},"q","What to look up, like `stacked bar` or `number formats`.",[],{"curl":502,"javascript":503,"python":504},"curl \"https:\u002F\u002Fchartjuice.com\u002Fapi\u002Fv1\u002Fdocs\u002Fsearch?q=stacked+bar\" \\\n  -H \"Authorization: Bearer $CHARTJUICE_API_KEY\"","const response = await fetch('https:\u002F\u002Fchartjuice.com\u002Fapi\u002Fv1\u002Fdocs\u002Fsearch?q=stacked+bar', {\n  headers: { Authorization: `Bearer ${process.env.CHARTJUICE_API_KEY}` },\n})\nconst result = await response.json()","import json\nimport os\nimport urllib.request\n\nrequest = urllib.request.Request(\n    \"https:\u002F\u002Fchartjuice.com\u002Fapi\u002Fv1\u002Fdocs\u002Fsearch?q=stacked+bar\",\n    headers={\"Authorization\": \"Bearer \" + os.environ[\"CHARTJUICE_API_KEY\"]},\n)\nwith urllib.request.urlopen(request) as response:\n    result = json.load(response)","{\n  \"results\": [\n    {\n      \"title\": \"Bar charts\",\n      \"text\": \"Compare amounts across categories. Roles: category (labels) + values (one or more number columns; each becomes a series).\"\n    }\n  ]\n}",1791741570932]