kitegraph
API access is included on the Professional and Business plans

The charts API

Create, update, publish, and export charts from code. A chart made through the API is a chart in your account.

A chart is a resource in your account. Create it, load data into it, publish it as a live embed, and export it as a file. A chart created through the API appears in My charts, opens in the editor, and records version history like any other. On a team plan, charts are workspace-scoped: the list includes the team's shared charts, and a teammate's key can update or delete them.

Creating a chart

Send a JSON body to POST /v1/charts. Supply data either as series references to library statistics or as a CSV data body of your own.

FieldTypeDescription
kindstringThe chart type (see chart kinds). Defaults to line.
seriesarrayReferences to library data: { "statistic": <id> } using an id from the data API, or { "source": <id>, "select": {…} } for an exact selection.
datastringA CSV of your own data, as an alternative to series (also settable later with PUT /v1/charts/{id}/data). It follows the table shapes in Data shapes for every chart.
metaobjectChart settings (see the meta object).
# create a chart on library data (scope: chart:write) curl -X POST "https://api.kitegraph.com/v1/charts" \ -H "Authorization: Bearer kg_live_…" \ -H "Content-Type: application/json" \ -d '{ "kind": "line", "series": [{ "statistic": 4821 }], "meta": { "title": "World GDP" } }' # → 201 { "id": "9f2c41d05b7a83e6", "name": "World GDP", "kind": "line", "hasData": true, "folderId": null, "published": null } # …or bring your own data as a CSV body curl -X PUT "https://api.kitegraph.com/v1/charts/9f2c41d05b7a83e6/data" \ -H "Authorization: Bearer kg_live_…" \ -H "Content-Type: text/csv" \ --data-binary @data.csv

A body that is not a JSON object returns 422 invalid_body; an unparseable CSV returns 422 invalid_data.

Chart kinds

The kind field takes one of:

kindFamily
lineLine, area, stacked and 100% area (the default)
horizontal-barBar, column, stacked, grouped, 100%, bar race
piePie, donut, half-pie
scatterScatter, bubble, connected
themeriverStreamgraph
multiplesSmall multiples
mapChoropleth (world, US states)
dot, range, arrowDot plot, range plot, arrow plot
candlestickOHLC candles
heatmapHeatmap, calendar
treemapTreemap
sankeySankey flows
boxplotBox plot
radarRadar
tableData table

The meta object

meta carries every editor setting. The common fields:

FieldTypeDescription
titlestringThe chart title.
subtitlestringThe description shown under the title.
sourceTextstringThe source line in the footer.
themestringA built-in theme id, or one of your theme ids from GET /v1/themes.
modestring"light" or "dark".
w, hnumberThe chart width and height, in pixels.
seriesTransformobjectPer-series transforms (see transforming a series).

To find any other setting, style a chart in the editor and read its meta back with GET /v1/charts/{id}.

Transforming a series

A transform reshapes one series without changing its data: rescale it, smooth it, index it, accumulate it, or hide it. Set meta.seriesTransform to an object keyed by series name, each value a config of an optional hidden flag and an ops pipeline.

{ "seriesTransform": { "United States": { "hidden": false, "ops": [ { "fn": "rollsum", "args": [12] } ] } } }

ops is an ordered pipeline; each entry names a function and its arguments:

fnargsEffect
divide[n]Divide every value by n (e.g. [1000000000] to read in billions).
multiply[n]Multiply every value by n.
rollsum[n]Rolling sum over the last n periods (a trailing-n total).
rollmean[n]Rolling average over the last n periods.
index100noneRebase to 100 at the first non-null period.
cumulativenoneRunning total across periods.

Set "hidden": true to keep a series in the data but off the chart, which is what a total charted beside its own parts needs.

The key is the resolved series name, which is not the statistic id or its title. It comes from the data: US GDP resolves to United States, Apple revenue to AAPL. Read the exact names from a chart's series array with GET /v1/charts/{id} before setting a transform.

Worked example

Create a chart from a statistic, read its resolved series name, then key a rolling sum to it:

# 1. create the chart from a library statistic POST /v1/charts { "kind": "line", "series": [ { "statistic": 4821 } ] } → { "id": "9f2c41d05b7a83e6", … } # 2. read the resolved series name (US GDP resolves to "United States", not its title) GET /v1/charts/9f2c41d05b7a83e6 → { "id": "9f2c41d05b7a83e6", "series": [ "United States" ], … } # 3. apply a 12-period rolling sum, keyed by that name PATCH /v1/charts/9f2c41d05b7a83e6 { "meta": { "seriesTransform": { "United States": { "ops": [ { "fn": "rollsum", "args": [12] } ] } } } }

A transform is a chart view, so GET /v1/charts/{id}/export/csv returns the original series and the transformed one side by side.

The chart resource

curl "https://api.kitegraph.com/v1/charts/9f2c41d05b7a83e6" \ -H "Authorization: Bearer kg_live_…" { "id": "9f2c41d05b7a83e6", "name": "US GDP since 1960", "kind": "line", "series": [ "United States" ], "meta": { …the editor's settings… }, "hasData": true, "folderId": null, "published": { "embedUrl": "https://app.kitegraph.com/embed/…" } }
FieldDescription
idThe chart id.
nameThe chart name (its title).
kindThe chart type.
seriesThe resolved series names, in order. These are the keys for meta.seriesTransform.
metaThe full settings object.
hasDataWhether data has been loaded.
folderIdThe folder the chart is filed in, or null.
publishedThe live embed once published ({ embedUrl }), or null.

Listing, updating, deleting

RequestScopeEffect
GET /v1/chartschart:readList your charts (workspace-scoped, unpaginated). Each item is { id, name, kind, updatedAt, folderId, published }.
PATCH /v1/charts/{id}chart:writeUpdate kind, series, or meta; pass folderId to file it into a folder.
DELETE /v1/charts/{id}chart:writeDelete the chart. Returns { "deleted": true }.
# rename and retheme in one PATCH curl -X PATCH "https://api.kitegraph.com/v1/charts/9f2c41d05b7a83e6" \ -H "Authorization: Bearer kg_live_…" \ -H "Content-Type: application/json" \ -d '{ "meta": { "title": "World GDP, 1960 to 2023", "theme": "kite" } }'

Publishing

Publishing creates the hosted live embed, or updates it in place. The URL is stable: republish, and every page embedding it shows the new version. Scope: chart:write.

curl -X POST "https://api.kitegraph.com/v1/charts/9f2c41d05b7a83e6/publish" \ -H "Authorization: Bearer kg_live_…" { "embedUrl": "https://app.kitegraph.com/embed/…", "iframe": "<iframe src=\"…\" width=\"100%\" height=\"420\"></iframe>" }

See the Embedding page for the responsive snippet.

Exporting

Export returns a one-time file of the chart as it stands. Rendering is synchronous. Scope: chart:read.

RequestReturns
GET /v1/charts/{id}/export/pngA raster PNG image.
GET /v1/charts/{id}/export/svgA vector SVG image.
GET /v1/charts/{id}/export/pdfA print-ready PDF.
GET /v1/charts/{id}/export/csvThe chart's data, with both the raw and transformed columns.
curl "https://api.kitegraph.com/v1/charts/9f2c41d05b7a83e6/export/png" \ -H "Authorization: Bearer kg_live_…" -o chart.png

At most two exports render at once. A busy renderer returns 503 export_busy with Retry-After: 5; a format other than png, svg, pdf, or csv returns 422 invalid_format.

Folders

Folders organize charts within a workspace, and nest one under another. File a chart into one with folderId on PATCH /v1/charts/{id}. Deleting a folder keeps its charts and moves them up a level.

RequestEffect
GET /v1/foldersList your folders (workspace-scoped).
POST /v1/foldersCreate a folder (name, optional parentId).
GET /v1/folders/{id}One folder.
PATCH /v1/folders/{id}Rename or move a folder.
DELETE /v1/folders/{id}Delete a folder; its charts move up a level.

A folder is { id, name, parentId, workspaceId }. A new folder inherits its parent's workspace; a bad parentId returns 422 invalid_parent. Scopes: folder:read to list and read, folder:write to change.

Themes

Themes are authored in the editor (Visualize → Layout → Custom theme) and referenced by id. Set one on a chart with meta.theme, which takes a built-in theme id or one of your theme ids. Scope: theme:read.

curl "https://api.kitegraph.com/v1/themes" -H "Authorization: Bearer kg_live_…" { "themes": [ { "id": "a3f8c21e9b04d576", "name": "Newsroom", "is_default": true } ] }
The charts API — Kitegraph docs