Skip to content
ChartDeck Developer API docs Account Get an API key

Chart pictures (PNG)

Strata charts as ready-made PNG pictures for bots - liquidation levels, the liquidation heatmap and the position heatmaps - with a Discord example.

GET /v1/charts/<kind>.png answers a PNG picture (1200 x 675, dark by default) of a Strata chart, ready for a bot to post. It needs the charts:read scope. The picture is drawn from exactly the data the matching /v1/strata route returns for the same query, and carries the coin, the chart, the window, the time of the data, the price axis, the current price and the attribution lines.

kinddrawn fromweight (7d / 30d)
liquidation-levels/v1/strata/levels: the modelled liquidation book per price, longs below the price, shorts above10 / 10
liquidation-heatmap/v1/strata/heatmap: the modelled liquidation field over the window, with the price path15 / 20
positions-heatmap/v1/strata/netpos: open interest parked by price (new positions park at the price they opened at, closes shrink it)15 / 20
net-longs-heatmap/v1/strata/netpos: the long share15 / 20
net-shorts-heatmap/v1/strata/netpos: the short share15 / 20
long-short-delta-heatmap/v1/strata/netpos: longs minus shorts per price and time15 / 20

Parameters: coin (BTC; or symbol=BTCUSDT), venue (default every venue of the model), window (7d; 30d from Developer), theme (dark or light).

  • The three split pictures need the long/short split some exchanges publish. Where the coin's venues (or the pinned venue) publish none, the answer is 404 split_unavailable, never an invented split: use positions-heatmap there.
  • Sandbox keys get a picture exactly where the sandbox has a recorded answer for the matching /v1/strata route, and the same 404 sandbox_not_recorded where it does not.
  • Errors are the usual JSON error body. A picture is drawn at most once per 45 seconds for the same kind, coin, venue, window and theme: Cache-Control: private, max-age=<seconds left> tells you how long it stays the same, and a repeated call still costs its weight. Under load the answer is 503 render_busy or render_timeout with Retry-After.
  • Attribution: the picture prints it, and the X-Attribution header carries the same lines (joined by |). Keep it with the picture when you post it.

#A Discord bot posting a picture

The key comes from the bot's environment (CHARTDECK_API_KEY), never from code or a URL. Node 18+ with discord.js:

JavaScript
import { Client, GatewayIntentBits, AttachmentBuilder } from 'discord.js';

const client = new Client({ intents: [GatewayIntentBits.Guilds] });

async function chartPicture(kind, coin) {
  const url = `https://api.chartdeck.trade/v1/charts/${kind}.png?coin=${encodeURIComponent(coin)}`;
  const res = await fetch(url, { headers: { Authorization: `Bearer ${process.env.CHARTDECK_API_KEY}` } });
  if (!res.ok) {
    const { error } = await res.json();          // errors are JSON: { error: { code, message } }
    throw new Error(`${error.code}: ${error.message}`);
  }
  return { png: Buffer.from(await res.arrayBuffer()), attribution: res.headers.get('x-attribution') ?? '' };
}

client.on('interactionCreate', async (i) => {
  if (!i.isChatInputCommand() || i.commandName !== 'heatmap') return;
  await i.deferReply();
  try {
    const { png, attribution } = await chartPicture('liquidation-heatmap', i.options.getString('coin') ?? 'BTC');
    await i.editReply({ content: attribution.replaceAll(' | ', ' ยท '), files: [new AttachmentBuilder(png, { name: 'heatmap.png' })] });
  } catch (e) {
    await i.editReply(`No picture: ${e.message}`);
  }
});

client.login(process.env.DISCORD_TOKEN);

With the SDKs: await cd.charts.picture('liquidation-heatmap', { coin: 'BTC' }) (JavaScript) and client.charts.picture('liquidation-heatmap', coin='BTC') (Python) return the image bytes as data, and the attribution lines in meta.attribution.

The Developer API documentation is in English.