HTTP API

Validate documents, render images, and manage saved charts.

The API accepts the same chart document shape as Studio, Figma, MCP, and the TypeScript SDK. All JSON endpoints use UTF-8 and support CORS.

POST /validate

Validate a ChartDocument or supported 2026-03-20 config without rendering or saving. Validation is public, free, read-only, and does not consume a monthly render allowance.

curl 'https://szum.io/validate' \
  --fail-with-body \
  --max-time 30 \
  -H 'Content-Type: application/json' \
  -d '{
  "version": "2026-09-26",
  "config": {
    "version": "2026-09-26",
    "type": "column",
    "category": { "field": "quarter" },
    "values": { "type": "long", "field": "revenue" }
  },
  "data": [
    { "quarter": "Q1", "revenue": 42 },
    { "quarter": "Q2", "revenue": 58 }
  ],
  "output": { "format": "svg" }
}'

Success and chart-invalid responses use the validation contract:

{
  "valid": true,
  "diagnostics": []
}

When a deterministic fix exists, the response may include one complete, validated suggestedDocument. Review the proposed changes before using it; validate again only if you modify it. When an older config is converted, the response also includes compatibility with its classification and stable codes. See Validation and compatibility.

POST /chart

Render a current ChartDocument or supported 2026-03-20 config. New integrations should use a document. Authenticate with an API key or dashboard session. The response body is the selected image format.

curl 'https://szum.io/chart' \
  --fail \
  --max-time 30 \
  -H 'Authorization: Bearer YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{
  "version": "2026-09-26",
  "config": {
    "version": "2026-09-26",
    "type": "column",
    "category": { "field": "quarter" },
    "values": { "type": "long", "field": "revenue" }
  },
  "data": [
    { "quarter": "Q1", "revenue": 42 },
    { "quarter": "Q2", "revenue": 58 }
  ],
  "output": { "format": "svg" }
}' \
  --output 'chart.svg'

Successful responses include the image Content-Type, Content-Length, and usage headers for authenticated callers. They use private, no-store because usage is account-specific.

Theme overrides require Creator or Pro. Free output uses built-in themes and includes attribution. A semantic error, plan rejection, or render failure occurs before successful usage is finalized.

GET /chart

For small public images, URL-encode the complete document into the historical config query parameter:

https://szum.io/chart?config={URL_ENCODED_RENDER_REQUEST}

No API key is required. Keyless output uses the anonymous monthly allowance and includes attribution. Theme overrides are rejected. Successful responses are publicly cacheable by the exact URL; cache hits do not reach origin and do not consume another render.

Do not put private data or credentials in this URL. Query strings can appear in browser history, proxy logs, analytics, and referrer metadata.

Response formats

Set output.format to "svg" or "png". PNG scale accepts 1, 2, 3, or 4 and defaults to 2. The format belongs inside the request rather than an Accept header so cache identity and validation remain explicit.

SVG responses are UTF-8 XML bytes. PNG responses are binary. Treat both as bytes; do not parse successful image bodies as JSON.

Saved charts

Saved-chart endpoints use a durable ChartDocument and stable chart identity:

  • POST /api/charts creates and publishes { document, title?, source? }.
  • GET /api/charts lists owner-scoped metadata with source, sort, search, limit, and opaque cursor filters.
  • GET /api/charts/:id reads metadata.
  • PATCH /api/charts/:id renames metadata.
  • GET /api/charts/:id/document reads the published document plus optional newer draft.
  • PUT /api/charts/:id/document replaces and publishes the document in place.
  • GET /api/charts/documents?ids=... reads up to 100 documents in one owner-scoped batch.
  • DELETE /api/charts/:id permanently deletes the chart.

Create supports Idempotency-Key. The key identifies one intended HTTP create and is reused across retries; deduplication is by key, not by comparing the body. Use a fresh key for a different chart. A concurrent request with the same key returns 409 with Retry-After. Document replacement keeps /c/{id} and /e/{id} stable and refuses to overwrite unpublished Studio work for Bearer callers.

See Saved charts for request bodies, response objects, drafts, storage, public URLs, and lifecycle behavior.

Rate limits

  • Ordinary API traffic is limited to 10 requests per second per IP at the edge.
  • API-key traffic also has a 30 requests-per-second credential bucket.
  • Keyless GET /chart has a 100 image monthly allowance per IP.
  • Authenticated renders consume the account's monthly plan allowance; validation and saved-chart metadata reads do not.

On 429, honor Retry-After and retry with backoff. CDN hits for successful public image and embed URLs do not reach these origin limits.

Errors

Handled HTTP failures return an error object with code, message, and retryable. Chart input failures add a single diagnostics array. /validate returns its completed validation result separately; see Errors for the distinction and transport exceptions.

{
  "error": {
    "code": "validation_failed",
    "message": "Field \"revenue\" is missing from the data.",
    "retryable": false
  },
  "diagnostics": [
    {
      "code": "incompatible_data",
      "path": "/config/values/field",
      "severity": "error",
      "message": "Field \"revenue\" is missing from 1 of 1 data row. Every referenced field must exist on every row.",
      "details": {
        "reason": "data_field_missing",
        "affectedRows": 1,
        "field": "revenue",
        "roles": ["value"],
        "rowCount": 1,
        "samplePaths": ["/data/0/revenue"]
      }
    }
  ]
}

Common statuses:

  • 400 invalid JSON, contract shape, semantic input, or cursor;
  • 401 missing or invalid credentials;
  • 403 plan or presentation policy rejection;
  • 404 missing or unavailable opaque chart id;
  • 409 idempotency or concurrent draft/publication conflict;
  • 413 document or account storage limit;
  • 429 burst or monthly allowance exceeded;
  • 500 render or application failure;
  • 503 temporary credential or storage dependency failure.

See Errors for retry guidance and stable diagnostic handling.

Common mistakes

  • Sending only ChartConfig to /chart instead of a complete document with data.
  • Omitting version in raw HTTP JSON. The SDK may add its current version; HTTP does not.
  • Sending null for optional config properties instead of omitting them.
  • Putting output, size, or presentation inside semantic config.
  • Omitting the document version or using a different nested config version.
  • Retrying a create with a new idempotency key and accidentally creating duplicates.
  • Parsing an image success response as JSON.

Compatibility and versioning

New integrations should use 2026-09-26. The API also accepts the documented subset of 2026-03-20 configs for validation, rendering, save, and update operations. exact and normalized conversions may be rendered and saved. lossy durable writes require explicit acceptance of every returned loss code. unsupported input returns a stable compatibility error and is not written.

The version identifies a compatibility generation, not a product release. See older config compatibility.

Language examples

See Language examples for TypeScript, Python, Go, Ruby, curl, and HTML.

For agents

Agents should prefer the MCP server, which exposes chart-type discovery, examples, validation, previews, and saved-chart operations with machine-readable tool schemas. Direct HTTP remains available when an MCP client is not appropriate.

On this page