API reference
An API key is a password for programs: it lets a script or an AI assistant work with your charts without signing in as you. Create one on your account page, under API keys. The Chartjuice chart API is a REST API: with a key, a program can make a chart from CSV or JSON, edit it, and get it back as a PNG or SVG.
On this page
- Your first chart
- Authentication and requests
- When a request is refused
- Endpoints
- List charts
- Get a chart
- Create a chart
- Edit a chart
- Rename a chart
- Duplicate a chart
- Delete a chart
- Check a chart
- Render a chart
- Replace the data
- Describe the data
- Query the data
- Render a chart from data
- Render a chart with new data
- Create an image link
- Get the brand palette
- Set the brand palette
- Get colors from a website
- Get the account
- List chart types
- List examples
- List palettes
- Get the op catalog
- Look up the docs
Your first chart
You need a key first. On your account page, under API keys, name a key and choose Create key. Copy it when it appears, because it is shown once.
The examples read the key from an environment variable called CHARTJUICE_API_KEY, so it never has to be written into a file. In a terminal on macOS or Linux, set it like this, with your own key:
export CHARTJUICE_API_KEY="paste-your-key-here"Now make a chart. This sends three months of sales as CSV and asks for a bar chart with a title:
curl -X POST "https://chartjuice.com/api/v1/charts" \
-H "Authorization: Bearer $CHARTJUICE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"type": "bar",
"data": "Month,Sales\nJan,4200\nFeb,5100\nMar,4800",
"ops": [{ "op": "setTitle", "title": { "text": "Monthly sales" } }]
}'The answer is JSON. It has the chart's id, and a url you can open in a browser to see the chart in the editor. To download the chart as an image, put the id in place of $CHART_ID:
curl "https://chartjuice.com/api/v1/charts/$CHART_ID/render.png?scale=2" \
-H "Authorization: Bearer $CHARTJUICE_API_KEY" \
-o chart.pngThat saves chart.png, at twice the chart's size. The JavaScript and Python tabs do all of it in one short program, with one more step in the middle: an edit that sorts the bars.
Authentication and requests
Every address starts with https://chartjuice.com/api/v1.
Send your key in the Authorization header of every request, as the word Bearer, a space, and the key. Anyone who has the key can read, change and delete your charts, so keep it out of web pages and public code. If a key gets out, revoke it on your account page and make a new one.
An AI assistant that you connected by signing in sends an access token in the same header, in place of a key. It got the token when you chose Allow, through OAuth, and it works at every address here within the same limits. A token lasts a short while and the assistant renews it by itself. To end its access, disconnect the app on your account page. Connect an AI assistant has the steps, and what a connected app can and can't do.
Requests that send data send it as JSON, with a Content-Type: application/json header. Answers are JSON, except the endpoints that draw a chart, which answer with the image itself. Chart images covers those. A field the endpoint does not know is an error, so a misspelled field name is caught and not ignored.
Every chart in an answer has a url: the page where a person opens it in the editor. Hand that link to whoever asked for the chart.
Each answer also says how much of your request allowance is left, in three headers: X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset (the seconds until the count starts again). Limits and errors has the numbers.
The whole API is also described in one machine-readable file, in the OpenAPI 3.1 format, at https://chartjuice.com/api/v1/openapi.json. Tools that generate API clients can read it.
When a request is refused
A refused request gets an HTTP status of 400 or above and a JSON body like this:
{
"error": {
"code": "not_found",
"message": "There's no chart with that id in this account.",
"docs": "https://chartjuice.com/docs/limits/#not_found"
}
}Act on the code, which never changes. The message is written for a person and says what to do. docs links to the code's entry in Limits and errors, where every code is explained.
Any request can be refused with these codes: invalid_request, unauthorized, rate_limited, internal. Each endpoint below lists the others it can give.
Endpoints
This table lists every endpoint with its method and address. Each name leads to its entry further down, which has the fields, an example request and the answer.
| Endpoint | Method and address |
|---|---|
| List charts | GET /charts |
| Get a chart | GET /charts/{id} |
| Create a chart | POST /charts |
| Edit a chart | POST /charts/{id}/ops |
| Rename a chart | PATCH /charts/{id} |
| Duplicate a chart | POST /charts/{id}/duplicate |
| Delete a chart | DELETE /charts/{id} |
| Check a chart | GET /charts/{id}/lint |
| Render a chart | GET /charts/{id}/render.{format} |
| Replace the data | PUT /charts/{id}/data |
| Describe the data | GET /charts/{id}/data/summary |
| Query the data | POST /charts/{id}/data/query |
| Render a chart from data | POST /render |
| Render a chart with new data | POST /charts/{id}/render |
| Create an image link | POST /image-urls |
| Get the brand palette | GET /brand-palette |
| Set the brand palette | PUT /brand-palette |
| Get colors from a website | POST /brand-palette/extract |
| Get the account | GET /account |
| List chart types | GET /chart-types |
| List examples | GET /examples |
| List palettes | GET /palettes |
| Get the op catalog | GET /ops |
| Look up the docs | GET /docs/search |
An AI assistant uses these same operations as its tools, so the descriptions are written for an assistant as well as for you. Where one says "the person", it means whoever asked for the chart.
Charts
List charts
GET/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.
| Field | Type | What it is |
|---|---|---|
limitin the query, optional | integer, 1 to 100default 50 | How many charts to return. |
cursorin the query, optional | string | next_cursor from the previous page. |
curl "https://chartjuice.com/api/v1/charts?limit=2" \
-H "Authorization: Bearer $CHARTJUICE_API_KEY"Answer
{
"charts": [
{
"id": "7b0c9f1e-6c1d-4c57-9a47-2f1f0a3b8e21",
"name": "Monthly sales",
"type": "bar",
"url": "https://chartjuice.com/charts/7b0c9f1e-6c1d-4c57-9a47-2f1f0a3b8e21",
"created_at": "2026-10-10T14:03:12.481923+00:00",
"updated_at": "2026-10-10T14:05:40.118264+00:00"
},
{
"id": "f3a1d2c4-0b5e-4f6a-8c7d-9e0f1a2b3c4d",
"name": "Visitors by channel",
"type": "line",
"url": "https://chartjuice.com/charts/f3a1d2c4-0b5e-4f6a-8c7d-9e0f1a2b3c4d",
"created_at": "2026-10-10T14:03:12.481923+00:00",
"updated_at": "2026-10-09T09:12:44.530112+00:00"
}
],
"next_cursor": "MjAyNi0xMC0wOVQwOToxMjo0NC41MzAxMTIrMDA6MDB8ZjNhMWQyYzQtMGI1ZS00ZjZhLThjN2QtOWUwZjFhMmIzYzRk"
}Get a chart
GET/charts/{id}
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.
| Field | Type | What it is |
|---|---|---|
idin the path, required | string | The chart's id. |
includein the query, optional | "spec" | spec adds the whole chart spec, data included. |
curl "https://chartjuice.com/api/v1/charts/7b0c9f1e-6c1d-4c57-9a47-2f1f0a3b8e21" \
-H "Authorization: Bearer $CHARTJUICE_API_KEY"Answer
{
"chart": {
"id": "7b0c9f1e-6c1d-4c57-9a47-2f1f0a3b8e21",
"name": "Monthly sales",
"type": "bar",
"url": "https://chartjuice.com/charts/7b0c9f1e-6c1d-4c57-9a47-2f1f0a3b8e21",
"created_at": "2026-10-10T14:03:12.481923+00:00",
"updated_at": "2026-10-10T14:05:40.118264+00:00"
},
"state": {
"type": "bar",
"options": {
"orientation": "vertical",
"stack": "none"
},
"mapping": {
"category": "c1",
"values": [
"c2"
]
},
"roles": [
"category: Category",
"values: Values, numbers"
],
"columns": [
{
"id": "c1",
"name": "Month",
"kind": "text"
},
{
"id": "c2",
"name": "Sales",
"kind": "number"
}
],
"columnCount": 2,
"rows": 3,
"steps": [],
"columnsAfterSteps": [
{
"id": "c1",
"name": "Month",
"kind": "text"
},
{
"id": "c2",
"name": "Sales",
"kind": "number"
}
],
"rowsAfterSteps": 3,
"style": {
"title": {
"show": true,
"text": "Monthly sales"
},
"subtitle": {
"show": false,
"text": ""
},
"legend": {
"show": "auto",
"position": {
"x": "center",
"y": "bottom"
}
},
"labels": {
"show": false
},
"xAxisTitle": null,
"yAxisTitle": null,
"palette": [
"#0C008C",
"#2D1FF5",
"#5D55FA",
"#8888FC",
"#C4C6FF"
],
"seriesColors": {},
"size": "800×500"
},
"warnings": []
}
}Can also be refused with not_found.
Create a chart
POST/charts
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.
| Field | Type | What it is |
|---|---|---|
typein the body, optional | "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. |
examplein the body, optional | string | The id of a gallery example to start from (list_examples), instead of type. |
datain the body, optional | 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]]). |
formatin the body, optional | "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. |
namein the body, optional | string | The chart's name in My charts. Left out, the chart's title is used. |
opsin the body, optional | array of objects | Ops to apply, in order. All apply or none do. See the op catalog (get_op_catalog). |
curl -X POST "https://chartjuice.com/api/v1/charts" \
-H "Authorization: Bearer $CHARTJUICE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"type": "bar",
"data": "Month,Sales\nJan,4200\nFeb,5100\nMar,4800",
"ops": [
{
"op": "setTitle",
"title": {
"text": "Monthly sales"
}
}
]
}'Answer
{
"chart": {
"id": "7b0c9f1e-6c1d-4c57-9a47-2f1f0a3b8e21",
"name": "Monthly sales",
"type": "bar",
"url": "https://chartjuice.com/charts/7b0c9f1e-6c1d-4c57-9a47-2f1f0a3b8e21",
"created_at": "2026-10-10T14:03:12.481923+00:00",
"updated_at": "2026-10-10T14:03:12.481923+00:00"
},
"columns": [
{
"id": "c1",
"name": "Month",
"kind": "text"
},
{
"id": "c2",
"name": "Sales",
"kind": "number"
}
],
"warnings": [],
"notices": []
}Can also be refused with invalid_ops, chart_limit_reached or too_large.
Edit a chart
POST/charts/{id}/ops
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.
| Field | Type | What it is |
|---|---|---|
idin the path, required | string | The chart's id. |
opsin the body, required | array of objects | Ops to apply, in order. All apply or none do. See the op catalog (get_op_catalog). |
expected_updated_atin the body, optional | string | The chart's updated_at as you last saw it. If the chart has changed since, nothing is applied and the answer is conflict. |
curl -X POST "https://chartjuice.com/api/v1/charts/7b0c9f1e-6c1d-4c57-9a47-2f1f0a3b8e21/ops" \
-H "Authorization: Bearer $CHARTJUICE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"ops": [
{
"op": "setVariants",
"variants": {
"bar": {
"orientation": "horizontal"
}
}
},
{
"op": "addTransform",
"transform": {
"type": "sort",
"column": "c2",
"direction": "desc"
}
}
]
}'Answer
{
"chart": {
"id": "7b0c9f1e-6c1d-4c57-9a47-2f1f0a3b8e21",
"name": "Monthly sales",
"type": "bar",
"url": "https://chartjuice.com/charts/7b0c9f1e-6c1d-4c57-9a47-2f1f0a3b8e21",
"created_at": "2026-10-10T14:03:12.481923+00:00",
"updated_at": "2026-10-10T14:05:40.118264+00:00"
},
"applied": 2,
"warnings": []
}Can also be refused with not_found, invalid_ops, conflict or too_large.
Rename a chart
PATCH/charts/{id}
Change a chart's name in My charts. The title drawn on the chart is separate: change that with the setTitle op.
| Field | Type | What it is |
|---|---|---|
idin the path, required | string | The chart's id. |
namein the body, required | string | The new name. |
curl -X PATCH "https://chartjuice.com/api/v1/charts/7b0c9f1e-6c1d-4c57-9a47-2f1f0a3b8e21" \
-H "Authorization: Bearer $CHARTJUICE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Q1 sales"
}'Answer
{
"chart": {
"id": "7b0c9f1e-6c1d-4c57-9a47-2f1f0a3b8e21",
"name": "Q1 sales",
"type": "bar",
"url": "https://chartjuice.com/charts/7b0c9f1e-6c1d-4c57-9a47-2f1f0a3b8e21",
"created_at": "2026-10-10T14:03:12.481923+00:00",
"updated_at": "2026-10-10T14:05:40.118264+00:00"
}
}Can also be refused with not_found.
Duplicate a chart
POST/charts/{id}/duplicate
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.
| Field | Type | What it is |
|---|---|---|
idin the path, required | string | The chart's id. |
curl -X POST "https://chartjuice.com/api/v1/charts/7b0c9f1e-6c1d-4c57-9a47-2f1f0a3b8e21/duplicate" \
-H "Authorization: Bearer $CHARTJUICE_API_KEY"Answer
{
"chart": {
"id": "0d9e8f7a-6b5c-4d3e-9f2a-1b0c9d8e7f6a",
"name": "Copy of Monthly sales",
"type": "bar",
"url": "https://chartjuice.com/charts/0d9e8f7a-6b5c-4d3e-9f2a-1b0c9d8e7f6a",
"created_at": "2026-10-10T14:09:02.640771+00:00",
"updated_at": "2026-10-10T14:09:02.640771+00:00"
}
}Can also be refused with not_found or chart_limit_reached.
Delete a chart
DELETE/charts/{id}
Delete a chart for good. There is no undo, so use it only when the person asked for that chart to be deleted.
| Field | Type | What it is |
|---|---|---|
idin the path, required | string | The chart's id. |
curl -X DELETE "https://chartjuice.com/api/v1/charts/7b0c9f1e-6c1d-4c57-9a47-2f1f0a3b8e21" \
-H "Authorization: Bearer $CHARTJUICE_API_KEY"Answer
{
"deleted": true,
"id": "7b0c9f1e-6c1d-4c57-9a47-2f1f0a3b8e21"
}Can also be refused with not_found.
Check a chart
GET/charts/{id}/lint
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.
| Field | Type | What it is |
|---|---|---|
idin the path, required | string | The chart's id. |
curl "https://chartjuice.com/api/v1/charts/7b0c9f1e-6c1d-4c57-9a47-2f1f0a3b8e21/lint" \
-H "Authorization: Bearer $CHARTJUICE_API_KEY"Answer
{
"problems": [
{
"id": "pie-too-many-slices",
"level": "warn",
"message": "9 slices is hard to read; group small ones into \"Other\" or use a bar chart"
}
]
}Can also be refused with not_found.
Render a chart
GET/charts/{id}/render.{format}
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.
| Field | Type | What it is |
|---|---|---|
idin the path, required | string | The chart's id. |
formatin the path, required | "png" | "svg"default "png" | The image format. |
scalein the query, optional | 1 | 2 | 4default 1 | PNG only: 1, 2 or 4 times the canvas size. The image can be up to 4,000 px on a side. |
transparentin the query, optional | booleandefault false | Leave out the background. |
curl "https://chartjuice.com/api/v1/charts/7b0c9f1e-6c1d-4c57-9a47-2f1f0a3b8e21/render.png?scale=2" \
-H "Authorization: Bearer $CHARTJUICE_API_KEY" \
-o chart.pngAnswer
The image itself: a PNG file, or an SVG file from render.svg.
Can also be refused with not_found, render_limit_reached or image_limit_reached.
Data
Replace the data
PUT/charts/{id}/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.
| Field | Type | What it is |
|---|---|---|
idin the path, required | string | The chart's id. |
datain the body, required | 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]]). |
formatin the body, optional | "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. |
curl -X PUT "https://chartjuice.com/api/v1/charts/7b0c9f1e-6c1d-4c57-9a47-2f1f0a3b8e21/data" \
-H "Authorization: Bearer $CHARTJUICE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"data": [
{
"Month": "Apr",
"Sales": 6300
},
{
"Month": "May",
"Sales": 7100
}
]
}'Answer
{
"chart": {
"id": "7b0c9f1e-6c1d-4c57-9a47-2f1f0a3b8e21",
"name": "Monthly sales",
"type": "bar",
"url": "https://chartjuice.com/charts/7b0c9f1e-6c1d-4c57-9a47-2f1f0a3b8e21",
"created_at": "2026-10-10T14:03:12.481923+00:00",
"updated_at": "2026-10-10T14:05:40.118264+00:00"
},
"columns": [
{
"id": "c1",
"name": "Month",
"kind": "text"
},
{
"id": "c2",
"name": "Sales",
"kind": "number"
}
],
"rows": 2,
"mapping_kept": true,
"notices": [],
"warnings": []
}Describe the data
GET/charts/{id}/data/summary
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.
| Field | Type | What it is |
|---|---|---|
idin the path, required | string | The chart's id. |
curl "https://chartjuice.com/api/v1/charts/7b0c9f1e-6c1d-4c57-9a47-2f1f0a3b8e21/data/summary" \
-H "Authorization: Bearer $CHARTJUICE_API_KEY"Answer
{
"rows": 3,
"columns": [
{
"id": "c1",
"name": "Month",
"kind": "text",
"blanks": 0,
"distinct": 3,
"top": [
{
"value": "Jan",
"count": 1
},
{
"value": "Feb",
"count": 1
},
{
"value": "Mar",
"count": 1
}
]
},
{
"id": "c2",
"name": "Sales",
"kind": "number",
"blanks": 0,
"min": 4200,
"max": 5100,
"mean": 4700
}
]
}Can also be refused with not_found.
Query the data
POST/charts/{id}/data/query
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.
| Field | Type | What it is |
|---|---|---|
idin the path, required | string | The chart's id. |
stepsin the body, optional | array of objects | Extra steps to try, in the shape addTransform takes. They are not saved. |
limitin the body, optional | integer, 1 to 1,000default 100 | How many rows to return. |
curl -X POST "https://chartjuice.com/api/v1/charts/7b0c9f1e-6c1d-4c57-9a47-2f1f0a3b8e21/data/query" \
-H "Authorization: Bearer $CHARTJUICE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"steps": [
{
"type": "sort",
"column": "c2",
"direction": "desc"
}
],
"limit": 2
}'Answer
{
"columns": [
"c1 (Month)",
"c2 (Sales)"
],
"rows": [
[
"Feb",
5100
],
[
"Mar",
4800
]
],
"total_rows": 3,
"errors": []
}Can also be refused with not_found.
Images
Render a chart from data
POST/render
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/json 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.
| Field | Type | What it is |
|---|---|---|
typein the body, optional | "bar" | "line" | "pie" | "scatter" | "histogram" | "boxplot" | "dotplot" | "sankey" | "radar" | "heatmap" | The chart type, with data. |
datain the body, optional | 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]]). |
data_formatin the body, optional | "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. |
specin the body, optional | object | A whole chart spec, in place of type and data: what get_chart returns with include=spec. Its advanced must be null. |
opsin the body, optional | array of objects | Ops to apply, in order. All apply or none do. See the op catalog (get_op_catalog). |
namein the body, optional | string | A name for the image file, used when the image is downloaded. Left out, it is chart. |
formatin the body, optional | "png" | "svg"default "png" | The image format. |
scalein the body, optional | 1 | 2 | 4default 1 | PNG only: 1, 2 or 4 times the canvas size. The image can be up to 4,000 px on a side. |
widthin the body, optional | integer, 100 to 4,000 | The canvas width in pixels, in place of the chart's own. The image is this times scale. |
heightin the body, optional | integer, 100 to 4,000 | The canvas height in pixels, in place of the chart's own. The image is this times scale. |
transparentin the body, optional | booleandefault false | Leave out the background. |
curl -X POST "https://chartjuice.com/api/v1/render" \
-H "Authorization: Bearer $CHARTJUICE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"type": "bar",
"data": "Month,Sales\nJan,4200\nFeb,5100\nMar,4800",
"ops": [
{
"op": "setTitle",
"title": {
"text": "Monthly sales"
}
}
],
"scale": 2
}' \
-o chart.pngAnswer
The image itself: a PNG file, or an SVG file when format is svg. With the header Accept: application/json, the answer is JSON with the image base64-encoded, its type and its size.
Can also be refused with invalid_ops, image_limit_reached or too_large.
Render a chart with new data
POST/charts/{id}/render
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/json 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.
| Field | Type | What it is |
|---|---|---|
idin the path, required | string | The chart's id. |
datain the body, required | string or array | 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. |
data_formatin the body, optional | "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. |
opsin the body, optional | array of objects | Ops to apply after the data is in, for this image only. All apply or none do. See the op catalog (get_op_catalog). |
namein the body, optional | string | A name for the image file, used when the image is downloaded. Left out, it is chart. |
formatin the body, optional | "png" | "svg"default "png" | The image format. |
scalein the body, optional | 1 | 2 | 4default 1 | PNG only: 1, 2 or 4 times the canvas size. The image can be up to 4,000 px on a side. |
widthin the body, optional | integer, 100 to 4,000 | The canvas width in pixels, in place of the chart's own. The image is this times scale. |
heightin the body, optional | integer, 100 to 4,000 | The canvas height in pixels, in place of the chart's own. The image is this times scale. |
transparentin the body, optional | booleandefault false | Leave out the background. |
curl -X POST "https://chartjuice.com/api/v1/charts/7b0c9f1e-6c1d-4c57-9a47-2f1f0a3b8e21/render" \
-H "Authorization: Bearer $CHARTJUICE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"data": [
{
"Month": "Apr",
"Sales": 6300
},
{
"Month": "May",
"Sales": 7100
}
],
"scale": 2
}' \
-o chart.pngAnswer
The image itself: a PNG file, or an SVG file when format is svg. With the header Accept: application/json, the answer is JSON with the image base64-encoded, its type and its size.
Can also be refused with not_found, invalid_ops or image_limit_reached.
Create an image link
POST/image-urls
A link that shows a saved chart as an image to anyone who has it, with no key and no sign-in: for an <img> 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.
| Field | Type | What it is |
|---|---|---|
idin the body, required | string | The chart's id. |
formatin the body, optional | "png" | "svg"default "png" | The image format. |
scalein the body, optional | 1 | 2 | 4default 1 | PNG only: 1, 2 or 4 times the canvas size. The image can be up to 4,000 px on a side. |
widthin the body, optional | integer, 100 to 4,000 | The canvas width in pixels, in place of the chart's own. The image is this times scale. |
heightin the body, optional | integer, 100 to 4,000 | The canvas height in pixels, in place of the chart's own. The image is this times scale. |
transparentin the body, optional | booleandefault false | Leave out the background. |
datain the body, optional | string or array | 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. |
data_formatin the body, optional | "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. |
expires_inin the body, optional | 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. |
curl -X POST "https://chartjuice.com/api/v1/image-urls" \
-H "Authorization: Bearer $CHARTJUICE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"id": "7b0c9f1e-6c1d-4c57-9a47-2f1f0a3b8e21",
"scale": 2
}'Answer
{
"url": "https://chartjuice.com/img/7b0c9f1e-6c1d-4c57-9a47-2f1f0a3b8e21.png?kid=3d2a1b0c-9e8f-4a7b-8c6d-5e4f3a2b1c0d&scale=2&sig=d2bd5b97a1f538c7cb8c860665879d38b7d5a75248202d534d21c3ed3cf0931f",
"expires_at": null,
"chart": {
"id": "7b0c9f1e-6c1d-4c57-9a47-2f1f0a3b8e21",
"name": "Monthly sales",
"type": "bar",
"url": "https://chartjuice.com/charts/7b0c9f1e-6c1d-4c57-9a47-2f1f0a3b8e21",
"created_at": "2026-10-10T14:03:12.481923+00:00",
"updated_at": "2026-10-10T14:05:40.118264+00:00"
}
}Can also be refused with not_found.
Brand palette
Get the brand palette
GET/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.
curl "https://chartjuice.com/api/v1/brand-palette" \
-H "Authorization: Bearer $CHARTJUICE_API_KEY"Answer
{
"colors": [
"#0F766E",
"#F59E0B",
"#E11D48"
]
}Set the brand palette
PUT/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).
| Field | Type | What it is |
|---|---|---|
colorsin the body, required | array of strings or null | 1 to 12 colors as #RRGGBB or #RGB, or null to clear the palette. |
curl -X PUT "https://chartjuice.com/api/v1/brand-palette" \
-H "Authorization: Bearer $CHARTJUICE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"colors": [
"#0f766e",
"#F59E0B",
"#e11d48"
]
}'Answer
{
"colors": [
"#0F766E",
"#F59E0B",
"#E11D48"
]
}Can also be refused with forbidden_plan.
Get colors from a website
POST/brand-palette/extract
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.
| Field | Type | What it is |
|---|---|---|
urlin the body, required | string | A website address, like example.com. |
curl -X POST "https://chartjuice.com/api/v1/brand-palette/extract" \
-H "Authorization: Bearer $CHARTJUICE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "chartjuice.com"
}'Answer
{
"colors": [
"#5D55FA",
"#102A43",
"#0D009A",
"#9595FF",
"#4B42B9",
"#9D97E2",
"#C10007",
"#9FB3C8"
],
"added": 0
}Can also be refused with forbidden_plan.
Account
Get the account
GET/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.
curl "https://chartjuice.com/api/v1/account" \
-H "Authorization: Bearer $CHARTJUICE_API_KEY"Answer
{
"plan": "free",
"saved_charts": {
"used": 3,
"limit": 5
},
"requests": {
"limit": 60,
"left": 59,
"resets_in_seconds": 42
},
"renders": {
"limit": 100,
"left": 96,
"resets_in_seconds": 35700
},
"image_renders": {
"limit": 100,
"left": 88,
"resets_in_seconds": 1769700
}
}Reference
List chart types
GET/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.
curl "https://chartjuice.com/api/v1/chart-types" \
-H "Authorization: Bearer $CHARTJUICE_API_KEY"Answer
{
"chart_types": [
{
"type": "pie",
"label": "Pie chart",
"use_for": "Show parts of a whole",
"roles": [
{
"role": "category",
"label": "Slices",
"numeric": false,
"required": true
},
{
"role": "value",
"label": "Value",
"numeric": true,
"required": true
}
],
"guide": "Show parts of a whole. Roles: category (slice names) + value (one number column)."
}
]
}List examples
GET/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.
| Field | Type | What it is |
|---|---|---|
typein the query, optional | "bar" | "line" | "pie" | "scatter" | "histogram" | "boxplot" | "dotplot" | "sankey" | "radar" | "heatmap" | Only examples of this chart type. |
curl "https://chartjuice.com/api/v1/examples?type=bar" \
-H "Authorization: Bearer $CHARTJUICE_API_KEY"Answer
{
"examples": [
{
"id": "bar-grouped",
"type": "bar",
"label": "Double bar graph",
"description": "Compare two series side by side, like this year against last year."
}
]
}List palettes
GET/palettes
The preset color palettes. Apply one to a chart with the setPalette op and its colors.
curl "https://chartjuice.com/api/v1/palettes" \
-H "Authorization: Bearer $CHARTJUICE_API_KEY"Answer
{
"palettes": [
{
"id": "juice",
"name": "Juice",
"colors": [
"#0C008C",
"#2D1FF5",
"#5D55FA",
"#8888FC",
"#C4C6FF"
],
"light": false
}
]
}Get the op catalog
GET/ops
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.
curl "https://chartjuice.com/api/v1/ops" \
-H "Authorization: Bearer $CHARTJUICE_API_KEY"Answer
{
"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.",
"ops": [
{
"op": "setType",
"schema": {
"type": "object",
"properties": {
"op": {
"type": "string",
"const": "setType"
},
"type": {
"type": "string",
"enum": [
"bar",
"line",
"pie"
]
}
},
"required": [
"op",
"type"
],
"additionalProperties": false
}
}
]
}Look up the docs
GET/docs/search
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.
| Field | Type | What it is |
|---|---|---|
qin the query, required | string | What to look up, like stacked bar or number formats. |
curl "https://chartjuice.com/api/v1/docs/search?q=stacked+bar" \
-H "Authorization: Bearer $CHARTJUICE_API_KEY"Answer
{
"results": [
{
"title": "Bar charts",
"text": "Compare amounts across categories. Roles: category (labels) + values (one or more number columns; each becomes a series)."
}
]
}