Official TypeScript SDK for szum, a chart image API.
Turn a JSON config into an SVG, PNG or interactive embed. Use it in transactional emails, weekly digests, PDF reports, Slack messages, dashboards – anywhere an <img> tag works. No headless browser, no canvas, no client-side JavaScript.
npm install @szum-io/sdkServer-side only. The SDK sends your API key on every request. Never import it into browser code – save charts server-side and pass the URLs to the client.
import { Szum } from "@szum-io/sdk";
const szum = new Szum({ apiKey: process.env.SZUM_KEY! });
const png = await szum.render({
format: "png",
theme: "editorial",
title: "Quarterly Revenue",
subtitle: "By region, FY 2025",
marks: [
{
type: "barY",
data: [
{ x: "Q1", y: 4.2, region: "Americas" },
{ x: "Q2", y: 5.1, region: "Americas" },
{ x: "Q1", y: 2.1, region: "EMEA" },
{ x: "Q2", y: 2.8, region: "EMEA" },
],
fill: "region",
},
],
});Save a config server-side and embed the returned short URL in an <img> tag, or drop the embed URL into an <iframe> for an interactive version (Pro plan):
const chart = await szum.charts.create({
format: "svg",
theme: "editorial",
marks: [
{
type: "barY",
data: [
{ x: "Q1", y: 42 },
{ x: "Q2", y: 58 },
],
},
],
});
// Static image: <img src={chart.imageUrl} />
// Interactive embed: <iframe src={chart.embedUrl} />
// Revoke later: await szum.charts.delete(chart.id);create returns a chart object – { id, source, title, createdAt, updatedAt, sizeBytes, imageUrl, embedUrl, configUrl } – and the same shape comes back from get, update, and each item of list. imageUrl (https://szum.io/c/<id>) renders the same image on every fetch; append .png/.svg to force a format. embedUrl (https://szum.io/e/<id>) serves an interactive HTML page with tooltips, legend toggle, and responsive resize.
Beyond create and delete, the charts resource lets you enumerate and edit:
// List your charts, newest first; page via nextCursor
const { items, nextCursor } = await szum.charts.list({ source: "api" });
// Read one chart's metadata, or its config
const chart = await szum.charts.get(id);
const config = await szum.charts.getConfig(id);
// Read many configs in one request (max 100 ids)
const { configs, missing } = await szum.charts.getConfigs([id1, id2]);
// Replace a config in place – same id, same /c/ and /e/ URLs
await szum.charts.update(id, {
format: "svg",
marks: [
/* … */
],
});list pages via nextCursor (pass it back as cursor; null on the last page). getConfigs returns { configs, missing }; each missing entry carries a reason – an open set (today "not_found" or "unavailable"), so match the values you handle and treat anything unfamiliar as a non-fatal skip.
const szum = new Szum({
apiKey: process.env.SZUM_KEY!,
timeout: 30_000, // ms, default 30s
maxRetries: 2, // default 2; retries 429, 502, 503, 504, and network errors
});Every method accepts an optional second argument for per-call overrides:
const controller = new AbortController();
await szum.render(config, {
timeout: 60_000, // override client timeout
signal: controller.signal, // caller-initiated cancellation
});Set SZUM_DEBUG=true in your environment to log every request, response status, timing, and retry attempt to stderr.
Errors are typed by category. Match by subclass instead of status codes:
import {
Szum,
SzumError,
SzumAuthenticationError,
SzumRateLimitError,
SzumInvalidRequestError,
SzumConnectionError,
} from "@szum-io/sdk";
try {
await szum.render(config);
} catch (err) {
if (err instanceof SzumAuthenticationError) {
// 401 – bad or missing API key
} else if (err instanceof SzumRateLimitError) {
// 429 – wait err.retryAfter seconds
} else if (err instanceof SzumInvalidRequestError) {
// 400 / 413 – bad config
} else if (err instanceof SzumConnectionError) {
// timeout or network error
} else if (err instanceof SzumError) {
console.error(err.code); // "api_error", "invalid_request", etc.
console.error(err.message);
console.error(err.status); // HTTP status
console.error(err.retryAfter); // seconds (on 429)
console.error(err.requestId); // from x-vercel-id – include in support tickets
}
}All errors serialize cleanly via JSON.stringify(err) (they implement toJSON), so they work with Sentry, Datadog, and standard loggers.
| Export | Description |
|---|---|
Szum |
Client class (render; charts.create/list/get/getConfig/getConfigs/update/delete) |
SzumOptions |
Constructor options (apiKey, timeout, maxRetries, …) |
RequestOptions |
Per-call options (timeout, signal) |
SzumError |
Base error (code, status, message, retryAfter, requestId) |
SzumAuthenticationError |
401 |
SzumPermissionError |
403 |
SzumInvalidRequestError |
400 / 413 |
SzumRateLimitError |
429 |
SzumAPIError |
5xx |
SzumConnectionError |
Timeout / network |
ChartConfig |
Config type for SDK methods (version optional) |
ChartConfigInput |
Full config type including required version |
SavedChart |
Saved-chart object from charts.create/get/update/list |
SavedChartSource |
Open union of chart origins ("api", "figma", "app", "mcp", …) |
SavedChartPage |
charts.list result (items, nextCursor) |
SavedChartConfigs |
charts.getConfigs result (configs, missing) |
ConfigMissingReason |
Open union: why a config was missing ("not_found", "unavailable", …) |
SCHEMA_VERSION |
Schema version this SDK was built against |
Full reference at szum.io/docs.
