Chartlink Assets API
The Assets API from Chartlink — 18 operation(s) for assets.
The Assets API from Chartlink — 18 operation(s) for assets.
Every API here is available over the APIs.io API and to AI agents over MCP.
One button, every client — Claude, Cursor, VS Code and the rest.
https://apis.io/mcp
find_apisBrowse and filter every API in the catalog.get_api_artifactsOne API's artifacts, grouped by type.get_openapiThe primary OpenAPI for this API.find_similar_apisAPIs that look like this one.apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.resolveTurn a domain, URL or GitHub org into the provider it belongs to.find_cohortsEvery scored population of providers in the catalog.curl "https://apis.io/api/v1/apis/chartlink-app:chartlink-app-assets-api"
curl "https://apis.io/api/v1/apis?limit=25"
Calls without X-API-Key need no key. Calls with it need a paid plan — get a key.
Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.
A second provider on the same verified email joins the account you already have.
openapi: 3.2.0
info:
title: chartlink Assets API
version: 0.1.0
description: 'chartlink — a platform for charts and maps, made in your brand, with live-updating embed links. NOT CONNECTED YET? In an AI app that takes MCP connectors (Claude and others): your human adds https://chartlink.app/mcp as a
connector, signs in and picks a workspace — no key, nothing pasted into the chat. In Claude Code or a script:
an API key from their studio (Workspace → API keys for Claude Code and scripts), sent as Authorization: Bearer. Either way you work in their workspace — their brands and charts. Every chart carries urls.studio, where they
fine-tune it. A share URL is one published chart. Credits are GET
/api/billing-info and a checkout link from POST /api/checkout-link, which you hand to your human. WHAT AN ASSET IS
CHART TYPES: line, bar, area, scatter, dumbbell, slope, heatmap, choropleth, symbol-map, pie, treemap, waterfall, candlestick
(GET /api/asset-types describes each; GET /api/asset-types/{type}/schema is the contract — read it before the first create.)
An asset = type + data + config (+ brand). data holds typed columns and row-arrays; config holds
everything about presentation (title and the other text elements, encoding, chart options). They are updated independently:
PUT /assets/{id}/data replaces the numbers; PATCH /assets/{id} deep-merges config. Never resend
what you are not changing. There is no table type (removed): a ranking is a sorted "bar" chart with
value labels, a row-by-row comparison a "dumbbell" (one point per row = a dot plot) with row labels. KICKER AND TITLE MARKER: kicker {text, font, align, box} is a short line above the title (a section or topic
that ties charts together; default a small bold line in the emphasis colour). title.marker {position: "top" |
"left" | "end" | "none", shape: "bar" | "dot" | "square", hang, color, length, thickness, gap} draws one mark
above the title, beside it (a bar spans the title, a dot or square sits at its first line; hang: true puts it
in the margin instead of pushing the text right) or after the last word ("end"; skipped when the title already
ends in . ? ! … : ; so never type a mark into the title). gap is the space to the text everywhere. Both are
brand-settable (kicker''s style, the marker); the kicker''s words are per chart. kicker.show: false (usually on
a brand) hides kickers whatever their text; description.show: false does the same for descriptions. POINTS (line, area): chart.points is the one way to put dots on series — a list of rules {series?, at, label?,
labelPosition?, align?, font?, fill?, ring?, radius?}. A label uses the brand''s data-label style; font overrides it
key by key, and font.color "series" (here or in the brand''s data-label colour) takes the series'' colour. A note in
words with the annotation look is an annotation, not a point label. at: "all" | "first" | "last" | "max" | "min" | [x values]. label fills in
{value}, {series}, {x}: [{at: "max", label: "Peak {value}"}], [{at: [2008, 2020], label: "{x}"}]. markers
("none" | "end" | "all") is the end dot, the brand''s house style (default "end"): a chart''s own points are added to it,
so set markers "none" to drop it; points: [] draws no points at all. LINE BREAKS: "
" breaks a line in the words you write — title, kicker, description, source, annotations,
reference-line and highlight labels, point labels, and series names in line/area end labels (which then take
the room of their lines). A multi-line point label aligns by its side (centred above/below) unless
points[].align says "left" | "center" | "right"; annotations and free text have align too. Legends and
tooltips show a series name on one line. AXES: a value axis takes min/max, ticks {count | values: [0, 50, 100] — ticks and gridlines exactly there}, ticks.format,
ticks.labels.text: the words at those values, one per value (["", "50", "100%"]; "" leaves a tick unlabelled, its
gridline stays) — omit it for each value formatted.'
servers:
- url: https://chartlink.app
tags:
- name: Assets
paths:
/api/assets:
get:
operationId: listAssets
summary: List assets (data/config elided; use GET /assets/{id} for full bodies)
parameters:
- schema:
type: string
enum:
- line
- bar
- area
- scatter
- dumbbell
- slope
- heatmap
- choropleth
- symbol-map
- pie
- treemap
- waterfall
- candlestick
required: false
name: type
in: query
- schema:
type: string
enum:
- draft
- published
- archived
required: false
name: status
in: query
- schema:
type: string
description: Case-insensitive title substring
required: false
description: Case-insensitive title substring
name: search
in: query
- schema:
type: string
description: Only charts in this brand (id or slug); for the workspace's default brand, charts made without a brand too
required: false
description: Only charts in this brand (id or slug); for the workspace's default brand, charts made without a brand too
name: brand
in: query
- schema:
type: string
description: 'Comma list: "config" and/or "data" to include each chart''s settings and rows (a chart over 5,000 rows comes without them, marked dataOmitted: GET /assets/{id} has them); "published" to add, on published charts, changesNotLive (saved since publishing: the live chart is behind) and published: {versionNumber, title, config (its own settings), data, updateAvailable} — updateAvailable: the brand changed since it was published (POST /assets/{id}/restyle applies it)'
required: false
description: 'Comma list: "config" and/or "data" to include each chart''s settings and rows (a chart over 5,000 rows comes without them, marked dataOmitted: GET /assets/{id} has them); "published" to add, on published charts, changesNotLive (saved since publishing: the live chart is behind) and published: {versionNumber, title, config (its own settings), data, updateAvailable} — updateAvailable: the brand changed since it was published (POST /assets/{id}/restyle applies it)'
name: include
in: query
- schema:
type: integer
minimum: 1
maximum: 200
default: 50
required: false
name: limit
in: query
- schema:
type: integer
nullable: true
minimum: 0
default: 0
required: false
name: offset
in: query
responses:
'200':
description: Assets with total count
tags:
- Assets
post:
operationId: createAsset
summary: Create a draft asset
description: 'Validates config against the type schema and test-renders it, so a 200 means the asset is renderable. Creates a draft by default — iterate with PATCH + the preview URL, then POST /assets/{id}/publish. Send publish: true to do it in one call when the chart is already final.'
requestBody:
content:
application/json:
schema:
type: object
properties:
type:
type: string
enum:
- line
- bar
- area
- scatter
- dumbbell
- slope
- heatmap
- choropleth
- symbol-map
- pie
- treemap
- waterfall
- candlestick
title:
type: string
description: 'Convenience: sets config.title.text'
config:
type: object
additionalProperties:
nullable: true
data:
type: object
properties:
columns:
type: array
items:
type: object
properties:
id:
type: string
minLength: 1
description: Column identifier referenced by encodings
type:
type: string
enum:
- string
- number
- date
- boolean
description: 'date columns parse ISO-ish strings on their own: "2024", "2024-03", "2024-03-15", "2024-Q2", full ISO timestamps, or epoch numbers; a column of fiscal years ("2012/13", "2012–13", "2012/2013") is drawn at each first year and labelled as written. Anything else needs dateFormat.'
label:
type: string
description: Display label; defaults to id
dateFormat:
type: string
description: 'For date columns whose strings are NOT ISO-ish: a strftime-style parse hint tried first — tokens %Y %m %d %b %B %q %H %M %S, e.g. "%d/%m/%Y" for "15/03/2024", "%b %Y" for "Mar 2024". Removes the day/month guess; ISO-ish strings never need it.'
required:
- id
- type
additionalProperties: false
minItems: 1
rows:
type: array
items:
type: array
items:
anyOf:
- type: string
- type: number
- type: boolean
- nullable: true
description: Row-major values, one array per row, order matching columns
required:
- columns
- rows
additionalProperties: false
brand:
type: string
description: Brand id (brd_...) or slug
publish:
type: boolean
default: false
description: Publish immediately instead of leaving a draft, so the returned url/pngUrl/embedUrl are live. Skip it while you are still iterating — publishing a draft you intend to keep editing just means republishing later.
note:
type: string
description: Publish note, when publish is true
howMade:
type: string
maxLength: 4000
description: 'How the chart was made, for the person who reviews it: where the numbers come from and anything done to them (filtered, summed, converted, rounded, estimated, rows left out). Plain sentences. Shown on the chart''s page in the studio, never on the chart.'
required:
- type
- data
additionalProperties: false
responses:
'201':
description: The created asset with ready-to-paste urls
tags:
- Assets
/api/assets/{id}/restyle:
post:
operationId: restyleAsset
summary: Re-apply the brand as it is now to the published chart (its published settings…
description: 'Published charts keep the look they were published with. When the brand changes, GET /assets?include=published shows updateAvailable; this publishes a new version with the current brand, from what is published — unpublished draft edits are NOT published. updated: false when nothing would change.'
parameters:
- schema:
type: string
pattern: ^ast_
required: true
name: id
in: path
responses:
'200':
description: Restyled, or nothing to do
tags:
- Assets
/api/assets/{id}/premium:
post:
operationId: upgradeAssetToPremium
summary: 'Spend one credit: the chart becomes premium — its own footer, no badge, SVG…'
parameters:
- schema:
type: string
pattern: ^ast_
required: true
name: id
in: path
responses:
'200':
description: Upgraded
tags:
- Assets
/api/assets/{id}:
get:
operationId: getAsset
summary: Get one asset (draft state)
parameters:
- schema:
type: string
pattern: ^ast_
required: true
name: id
in: path
- schema:
type: string
enum:
- 'true'
- 'false'
default: 'true'
required: false
name: includeData
in: query
responses:
'200':
description: Full asset
tags:
- Assets
patch:
operationId: updateAsset
summary: Update config (deep-merge) / title / brand
description: 'configPatch is DEEP-MERGED: objects merge recursively, arrays replace wholesale, explicit null clears a key — send only what changes. To REMOVE keys (drop an aspect, delete a free text) send `config`: it REPLACES the whole config. Requires expectedVersion; a 409 returns the current row to re-merge onto.'
parameters:
- schema:
type: string
pattern: ^ast_
required: true
name: id
in: path
requestBody:
content:
application/json:
schema:
type: object
properties:
expectedVersion:
type: integer
minimum: 1
configPatch:
type: object
additionalProperties:
nullable: true
description: 'Deep-merged into config: objects merge, arrays replace, null clears a key'
config:
type: object
additionalProperties:
nullable: true
description: 'REPLACES the whole config. Use this when a key must go away: a deep-merge cannot express removal except by sending an explicit null, so an editor that holds the full config sends it here.'
title:
type: string
brand:
type: string
nullable: true
description: Brand id/slug, or null to use the default brand
howMade:
type: string
nullable: true
maxLength: 4000
description: 'How the chart was made, for the person who reviews it: where the numbers come from and anything done to them (filtered, summed, converted, rounded, estimated, rows left out). Plain sentences. Shown on the chart''s page in the studio, never on the chart. null clears it.'
required:
- expectedVersion
additionalProperties: false
responses:
'200':
description: Updated asset
'409':
description: Version conflict
tags:
- Assets
delete:
operationId: deleteAsset
summary: Soft-delete (embeds go dark; restorable)
parameters:
- schema:
type: string
pattern: ^ast_
required: true
name: id
in: path
responses:
'200':
description: Deleted
tags:
- Assets
/api/assets/{id}/data:
put:
operationId: replaceAssetData
summary: 'Replace the data rows (THE core flow: update numbers, embeds update)'
description: Replaces data wholesale. ?publish=auto (default) republishes when the asset is already published, so every embed/PNG serves the new numbers immediately. publish=false stages the data on the draft; publish=true force-publishes even a draft.
parameters:
- schema:
type: string
pattern: ^ast_
required: true
name: id
in: path
- schema:
type: string
enum:
- auto
- 'true'
- 'false'
default: auto
required: false
name: publish
in: query
requestBody:
content:
application/json:
schema:
type: object
properties:
data:
type: object
properties:
columns:
type: array
items:
type: object
properties:
id:
type: string
minLength: 1
description: Column identifier referenced by encodings
type:
type: string
enum:
- string
- number
- date
- boolean
description: 'date columns parse ISO-ish strings on their own: "2024", "2024-03", "2024-03-15", "2024-Q2", full ISO timestamps, or epoch numbers; a column of fiscal years ("2012/13", "2012–13", "2012/2013") is drawn at each first year and labelled as written. Anything else needs dateFormat.'
label:
type: string
description: Display label; defaults to id
dateFormat:
type: string
description: 'For date columns whose strings are NOT ISO-ish: a strftime-style parse hint tried first — tokens %Y %m %d %b %B %q %H %M %S, e.g. "%d/%m/%Y" for "15/03/2024", "%b %Y" for "Mar 2024". Removes the day/month guess; ISO-ish strings never need it.'
required:
- id
- type
additionalProperties: false
minItems: 1
rows:
type: array
items:
type: array
items:
anyOf:
- type: string
- type: number
- type: boolean
- nullable: true
description: Row-major values, one array per row, order matching columns
required:
- columns
- rows
additionalProperties: false
mode:
type: string
enum:
- replace
- append
default: replace
description: append adds the body's rows after the existing ones (columns must match the asset's column ids) — the chunked path for datasets too big for one call. Send publish=false on every chunk but the last.
note:
type: string
description: Publish note when this triggers a republish
config:
type: object
additionalProperties:
nullable: true
description: The full settings to store WITH the data, for when the new columns differ from what the current config's encoding names — a rename, or a switch from a number to a class column. Data alone is checked against the current config and rejected if it no longer fits; sent together, both are checked as a pair.
type:
type: string
enum:
- line
- bar
- area
- scatter
- dumbbell
- slope
- heatmap
- choropleth
- symbol-map
- pie
- treemap
- waterfall
- candlestick
description: 'Draw the data as another chart type (a bar chart becomes a line chart): needs `config` for that type. The chart keeps its id, link and embeds.'
expectedVersion:
type: integer
minimum: 1
required:
- data
additionalProperties: false
responses:
'200':
description: Updated asset (+ publish info when republished)
tags:
- Assets
/api/assets/{id}/source:
put:
operationId: setAssetDataSource
summary: Attach a data source URL — the chart refetches and republishes itself on…
description: 'Sets {url, format, refresh} and fetches ONCE immediately so you see the parse result now. The scheduled fetcher then keeps the chart current: rows are replaced from the URL (the asset''s columns stay authoritative — CSV headers / JSON keys must match column ids or labels), and a published asset republishes after every successful fetch. Refreshes are free — updates are never metered.'
parameters:
- schema:
type: string
pattern: ^ast_
required: true
name: id
in: path
requestBody:
content:
application/json:
schema:
type: object
properties:
url:
type: string
maxLength: 2000
format: uri
description: Public http(s) URL serving CSV or JSON. Fetched on schedule; rows replace the asset's data (columns are fixed by the asset).
format:
type: string
enum:
- auto
- csv
- json
default: auto
description: '"auto" sniffs: JSON when the body parses as JSON, else CSV'
refresh:
type: string
enum:
- hourly
- daily
- weekly
default: daily
description: Fetch cadence. Published assets republish automatically after a successful fetch.
required:
- url
additionalProperties: false
responses:
'200':
description: Source saved + first fetch outcome (check `fetch.ok`)
tags:
- Assets
delete:
operationId: clearAssetDataSource
summary: Detach the data source (the chart keeps its current data)
parameters:
- schema:
type: string
pattern: ^ast_
required: true
name: id
in: path
responses:
'200':
description: Source removed
tags:
- Assets
/api/assets/{id}/source/fetch:
post:
operationId: fetchAssetDataSource
summary: Fetch the data source now (on top of the schedule)
parameters:
- schema:
type: string
pattern: ^ast_
required: true
name: id
in: path
responses:
'200':
description: Fetch outcome (check `ok`; `error` is the teachable failure)
tags:
- Assets
/api/assets/{id}/edit-link:
post:
operationId: createEditLink
summary: 'Retired: your human edits charts in the studio'
description: 'Edit links opened a no-login tweak panel; charts are edited in the studio now, by the people in the workspace. Invite your human to the workspace (or they sign in: it is theirs) and hand them the chart. Existing links can still be listed and revoked.'
parameters:
- schema:
type: string
pattern: ^ast_
required: true
name: id
in: path
responses:
'410':
description: Where editing happens now
tags:
- Assets
/api/assets/{id}/data-upload:
post:
operationId: createDataUploadLink
summary: A link to send this chart's whole dataset to as a file (CSV or JSON, gzip…
description: 'For data too large to pass through tool calls: up to 10 MB of data (as stored), sent as a file. PUT the file to the url (no key needed: the link is the permission) — CSV with a header row, or JSON (an array of objects, or {rows: [[...]]}), mapped onto the chart''s columns by id or label, exactly like a data source. Gzip it for anything over a few MB (the request itself is capped near 4.5 MB). The rows replace the chart''s; a published chart republishes. Make the chart first with a few sample rows in the same columns.'
parameters:
- schema:
type: string
pattern: ^ast_
required: true
name: id
in: path
responses:
'200':
description: The link, its expiry, and the command
tags:
- Assets
/api/assets/{id}/preview-links/stop:
post:
operationId: stopPreviewLinks
summary: Stop every preview link given out for this chart; new ones come with the next…
description: 'Every asset response carries urls.preview: the current draft for anyone with the link, no account, for 14 days (and urls.previewImage, its PNG). This makes every link handed out so far stop working at once; the answer carries the new ones.'
parameters:
- schema:
type: string
pattern: ^ast_
required: true
name: id
in: path
responses:
'200':
description: Stopped; the new links
tags:
- Assets
/api/assets/{id}/edit-links:
get:
operationId: listEditLinks
summary: List this asset's edit links (prefixes only — secrets are never stored)
parameters:
- schema:
type: string
pattern: ^ast_
required: true
name: id
in: path
responses:
'200':
description: Active and revoked links
tags:
- Assets
/api/assets/{id}/edit-links/{tokenId}:
delete:
operationId: revokeEditLink
summary: Revoke one edit link (the URL stops working immediately)
parameters:
- schema:
type: string
pattern: ^ast_
required: true
name: id
in: path
- schema:
type: string
pattern: ^etk_
required: true
name: tokenId
in: path
responses:
'200':
description: Revoked
tags:
- Assets
/api/assets/{id}/publish:
post:
operationId: publishAsset
summary: Publish the draft — snapshots an immutable version and updates every embed
parameters:
- schema:
type: string
pattern: ^ast_
required: true
name: id
in: path
requestBody:
required: false
content:
application/json:
schema:
type: object
properties:
note:
type: string
description: Publish note for the version history
premium:
type: boolean
description: Spend one credit and pin the premium tier in the same call
responses:
'200':
description: Publish result with embed snippet
tags:
- Assets
/api/assets/{id}/unpublish:
post:
operationId: unpublishAsset
summary: Take the asset offline (embeds return 410)
parameters:
- schema:
type: string
pattern: ^ast_
required: true
name: id
in: path
responses:
'200':
description: Unpublished
tags:
- Assets
/api/assets/{id}/duplicate:
post:
operationId: duplicateAsset
summary: Copy an asset into a new draft (new id, new embed URLs)
parameters:
- schema:
type: string
pattern: ^ast_
required: true
name: id
in: path
requestBody:
required: false
content:
application/json:
schema:
type: object
properties:
title:
type: string
brand:
type: string
responses:
'201':
description: The new draft
tags:
- Assets
/api/assets/{id}/restore:
post:
operationId: restoreAsset
summary: Restore a soft-deleted asset
parameters:
- schema:
type: string
pattern: ^ast_
required: true
name: id
in: path
responses:
'200':
description: Restored
tags:
- Assets
/api/assets/{id}/versions:
get:
operationId: listAssetVersions
summary: Publish history
parameters:
- schema:
type: string
pattern: ^ast_
required: true
name: id
in: path
responses:
'200':
description: Version list (newest first)
tags:
- Assets
/api/assets/{id}/versions/{versionNumber}/restore:
post:
operationId: restoreAssetVersion
summary: Bring back a published version as the draft
description: Replaces the draft's config, data and type with those of published version N (GET /assets/{id}/versions). The live chart is unchanged until you publish, which makes it a new version — so going back is always undoable. Requires expectedVersion (the draft's version).
parameters:
- schema:
type: string
pattern: ^ast_
required: true
name: id
in: path
- schema:
type: integer
minimum: 1
required: true
name: versionNumber
in: path
requestBody:
content:
application/json:
schema:
type: object
properties:
expectedVersion:
type: integer
minimum: 1
required:
- expectedVersion
additionalProperties: false
responses:
'200':
description: The asset with the version as its draft
'409':
description: Version conflict
tags:
- Assets