Image API

Validate a shared chart definition or render it as a publication-ready PNG or SVG image.

Validate a chart definition for free, then send it to the image endpoint for an SVG or PNG.

Need stable URLs without exposing your API key in the markup? See Saved charts for the production embed primitive.

POST /validate

Send a chart config directly as the JSON request body. Validation is public, free, and read-only: it does not require an API key, consume a render, or save anything.

curl -X POST https://szum.io/validate \
  -H "Content-Type: application/json" \
  -d '{
    "version": "2026-03-20",
    "format": "svg",
    "data": [{ "category": "A", "value": 42 }],
    "marks": [
      { "type": "barY", "x": "category", "y": "value" },
      { "type": "text", "x": "category", "y": "value", "text": "value" }
    ]
  }'

The response contains valid, an error-only errors array, and the complete diagnostics array. When Szum can verify a deterministic repair for either a blocking error or a non-blocking suggestion, it also returns one complete suggestedConfig:

{
  "valid": true,
  "message": "Valid chart config with 1 non-blocking diagnostic. A canonical replacement is available in suggestedConfig; validate that complete config again before rendering, saving, or updating.",
  "errors": [],
  "diagnostics": [
    {
      "code": "prefer_mark_label",
      "severity": "suggestion",
      "path": ["marks", 1],
      "relatedPaths": [["marks", 0, "label"]],
      "message": "This text mark duplicates labels supported by barY. Use the mark's label property so labels participate in responsive placement and interaction.",
      "details": { "chartMarkIndex": 0, "textMarkIndex": 1 }
    }
  ],
  "suggestedConfig": {
    "version": "2026-03-20",
    "format": "svg",
    "data": [{ "category": "A", "value": 42 }],
    "marks": [
      {
        "type": "barY",
        "x": "category",
        "y": "value",
        "label": { "show": ["value"], "position": "auto" }
      }
    ]
  }
}

Use suggestedConfig as a whole replacement and validate it again. A blocking response remains HTTP 400 with valid: false, even when it contains a repair. One verified replacement is returned at a time, so repeat until the config is valid or no replacement is present. Szum never changes the submitted config automatically.

See Validation and Review for the distinction between structural errors, semantic errors, recoverable warnings, and canonical-authoring suggestions.

POST /chart

POST requests require an API key. Include it in the Authorization header:

curl -X POST https://szum.io/chart \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "version": "2026-03-20",
    "format": "svg",
    "theme": "editorial",
    "marks": [{
      "type": "barY",
      "data": [
        { "x": "Q1", "y": 42 },
        { "x": "Q2", "y": 58 },
        { "x": "Q3", "y": 65 }
      ]
    }]
  }'

The response body is the rendered image.

GET /chart

Pass the config as a query parameter. This is what makes <img> embeds work – no JavaScript required:

<img
  src='https://szum.io/chart?config={"version":"2026-03-20","format":"svg","marks":[{"type":"barY","data":[{"x":"Q1","y":42},{"x":"Q2","y":58}]}]}'
/>

GET requests are keyless – no API key, no sign-up. Limited to 100 renders per month per IP.

GET URLs must be percent-encoded in production. We show them unencoded here for readability. Your HTTP client or browser will typically handle this for you.

Both methods accept up to 50 KB of JSON.

Response

HeaderValue
Content-Typeimage/svg+xml or image/png (depends on format)
Cache-ControlGET success: public, max-age=86400, s-maxage=604800, stale-while-revalidate=86400 · GET errors and POST success: private, no-store
Access-Control-Allow-Origin*

format is required – set it to "svg" or "png" in your config. CORS is fully open – you can call the API from any browser origin.

Successful GET responses are cached on the CDN edge; handled GET errors and successful POST responses are never cached (POST success carries your per-account usage headers). See Caching & CDN for the full picture.

POST responses include usage headers:

HeaderDescription
X-Usage-UsedRenders consumed this month
X-Usage-LimitMonthly render allowance for the plan
X-Usage-RemainingRenders left before the included limit
X-Usage-Overage"true" when rendering beyond the included quota (overage billing enabled)

Rate limits

Unauthenticated requests are limited to 10 requests per second per IP. Authenticated POST requests are limited to 30 requests per second per key. Beyond that, each plan has a monthly render allowance.

PlanMonthly renders
Free500
Creator5,000
Pro25,000 included

Pro users can opt in to overage billing ($1 per 5,000 additional renders). When you exceed your limit without overage billing, the API returns 429 Too Many Requests:

{
  "error": "Monthly render limit exceeded (25000/25000). Enable overage billing at https://szum.io/account/billing."
}

Limits reset on the 1st of each month (UTC). See Plans & Limits for full details.

Errors

/chart returns the standard Szum error envelope on any failure: { "error": "..." } with a meaningful HTTP status. See Errors for the full status table and response shape. The error message contains a JSON path like marks.0.type so you can jump straight to the offending field.

Common mistakes

Missing version – Every config needs "version": "2026-03-20". Without it you'll get a 400.

Missing formatformat is required. Set it to "svg" or "png".

Wrong mark type – Valid types are barY, barX, line, dot, areaY, areaX, pie, text, ruleX, ruleY. Typos like "bar" or "Bar" will fail.

Mismatched field names – If your data has { "month": "Jan", "revenue": 42 } but your mark uses "x": "date", semantic validation reports the missing field. A mark with no usable rows is rejected; a chart with other usable rows can render with a warning that identifies what was skipped.

Mixing sizing modes – You cannot set both width/height and plotWidth/plotHeight. Pick one. See Sizing.

Unquoted JSON in GET – The config query parameter must be valid JSON with double-quoted keys. Single quotes or unquoted keys will return a 400.

Versioning

version is required. The current version is "2026-03-20". It identifies the chart config's compatibility generation, so backwards-compatible features and fixes do not require a new version. Configs with older versions are automatically migrated forward. See the changelog for config version history.

Language examples

For Node and TypeScript, the @szum-io/sdk package provides typed configs, error handling, and timeouts out of the box. Any language that can make an HTTP request also works – see Language Examples for copy-paste examples in Node, Python, Go, Ruby, and curl.

For agents

Building an integration or tool that generates charts? Three resources:

  • MCP endpointhttps://szum.io/mcp – connect agents directly, no API key required.
  • szum.io/schema.json – JSON Schema for chart configs. Use it in tool definitions or for validation.
  • szum.io/llms.txt – Compact API reference designed for LLM context windows.

On this page