Skip to main content

API Reference

REST API endpoints for chart rendering and management.

OpenAPI 3.1 specification – Use with Swagger UI, Redoc, or code generators.

Postman collection – Import into Postman to test all endpoints. Set baseUrl, apiKey, and sessionToken variables.

POST /api/v1/render

Renders a chart from a JSON specification. Returns the image as binary (PNG, JPEG, SVG, WebP, or PDF) or JSON with a CDN URL when returnUrl: true.

Request Body

json
{ "type": "line" | "bar" | "pie" | "doughnut" | "radar" | "polarArea", "width": 800, "height": 400, "format": "png" | "jpeg" | "svg" | "webp" | "pdf", "data": { "labels": ["Jan", "Feb", "Mar"], "datasets": [{ "label": "Revenue", "data": [12000, 15000, 18000] }] }, "brandKitId": "uuid-or-preset", "devicePixelRatio": 1, "returnUrl": false, "options": {} }

See Chart Specifications and Card Composition for the full field reference. Authentication: Authorization: Bearer pk_live_... (optional — anonymous renders are allowed at starter plan limits).

Response Headers

  • Content-Typeimage/png, image/jpeg, image/svg+xml, image/webp, or application/pdf
  • X-Render-Time-Ms – Render latency in milliseconds
  • X-CacheHIT or MISS when Redis caching is enabled
  • X-Request-Id – Unique request ID for debugging and support
  • ETag – MD5 of the spec for client-side caching

GET /api/v1/render

Renders a chart from URL parameters. Ideal for <img src="..."> embeds in emails, Slack, Markdown, and forums.

Supports two formats: base64-encoded JSON (full spec) or simple query parameters (basic charts). URL length limit: 2000 characters — use POST for complex specs that exceed this.

Authentication

Browsers cannot send Authorization headers with image requests. Pass your API key as a query parameter instead:

  • key?key=pk_live_...
  • apiKey – Alias for key: ?apiKey=pk_live_...

Format 1: Base64-encoded JSON

Encode your full chart spec as base64url. Use chart or the alias c.

text
GET /api/v1/render?key=pk_live_YOUR_KEY&chart=eyJ0eXBlIjoibGluZSIsIndpZHRoIjo4MDAsImhlaWdodCI6NDAwLCJkYXRhIjp7ImxhYmVscyI6WyJKYW4iLCJGZWIiLCJNYXIiXSwiZGF0YXNldHMiOlt7ImxhYmVsIjoiUmV2ZW51ZSIsImRhdGEiOlsxMjAwMCwxNTAwMCwxODAwMF19XX19

Format 2: Query Parameters

Simple charts with comma-separated values. Best for quick embeds.

  • type or cht – line, bar, pie, doughnut, radar, polarArea
  • labels or l – Comma-separated labels
  • data or d – Comma-separated numbers
  • title or t – Chart title
  • width, height – Dimensions (100–4000 px)
  • format – png, jpeg, svg, webp, pdf
  • brandKitId – UUID or preset name (obsidian, linen, polar, studio, ember, harbor)
  • returnUrl – Return JSON with CDN URL instead of the image
text
GET /api/v1/render?key=pk_live_YOUR_KEY&type=bar&labels=Q1,Q2,Q3,Q4&data=100,150,120,180&title=Revenue&format=png&width=600&height=300

Email Embedding

Use the GET endpoint in HTML emails. PNG format recommended for best compatibility across Gmail, Outlook, and Apple Mail.

html
<img src="https://chart-output.com/api/v1/render?key=pk_live_YOUR_KEY&type=bar&labels=Jan,Feb,Mar&data=10,20,30&format=png" alt="Monthly stats" width="600" height="300" />

URL-encode special characters in labels (spaces → %20). Keep URLs under 2000 characters; use POST for complex charts.

GET /api/v1/templates/:templateId/render

Renders a built-in or custom template with optional query parameter overrides.

Query Parameters

  • labels – Comma-separated labels
  • data – Comma-separated values
  • title – Chart title
  • width, height
  • format – png, jpeg, svg, webp
  • brandKitId – UUID of brand kit or preset (obsidian, linen, polar, studio, ember, harbor)
  • scale / devicePixelRatio – 1–4; defaults to 2 on this route (retina output)
  • palette – Comma-separated hex colors (URL-encode # as %23)

Management APIs (Dashboard)

These endpoints require a session JWT (from the dashboard) or API key.

  • GET /api/v1/stats – Overview stats (renders this month, success rate, avg latency)
  • GET /api/v1/renders?limit=10 – Recent render history
  • GET /api/v1/usage – Usage data for current month
  • GET/POST/DELETE /api/v1/api-keys – API key management
  • GET/POST/PUT/DELETE /api/v1/brand-kits – Brand kit CRUD
  • GET/POST/DELETE /api/v1/webhooks – Webhook subscriptions
  • GET/POST/PUT/DELETE /api/v1/templates – Custom template CRUD
  • GET /api/v1/audit-logs – Audit log for account actions
  • GET/PUT /api/v1/settings/custom-domain – Custom CDN domain for returnUrl
  • POST /api/v1/jobs – Async render (returns 202 + jobId). Results arrive within ~60 seconds via render.complete webhook or GET /api/v1/jobs/:id polling. This is a known characteristic of the Vercel cron minimum interval.
  • GET /api/v1/jobs/:id – Poll async job status and result URL
  • POST /api/v1/ai/render – Natural-language chart generation (Pro/Business). Has a separate AI render quota; see the AI rendering guide.

Error Responses

400 Bad Request

Invalid chart specification or malformed JSON.

401 Unauthorized

An Authorization header was present but the key was invalid. Requests with no auth at all return 200 at anonymous limits, not 401.

403 Forbidden

Valid key, but the operation is not allowed for this plan (e.g. expired account, PDF on Pro tier, non-PNG on trial).

Subscription required

json
{ "error": "Subscription required. Please upgrade to continue.", "plan": "expired", "upgradeUrl": "/app/usage-billing" }

PDF / plan feature

json
{ "error": "PDF output requires the Business plan", "plan": "starter", "upgradeUrl": "/pricing" }

429 Too Many Requests

Rate limiting (100 requests / 15 min) or render quota (trial cap / billing period). Check the error body.

Billing-period quota

json
{ "error": "Render quota exceeded for your billing period. Upgrade or wait for renewal.", "currentUsage": 100000, "limit": 100000, "plan": "starter" }

Rate limit

json
{ "error": "Rate limit exceeded", "retryAfter": 120 }
  • Retry-After – Seconds until the window resets
  • X-RateLimit-Limit – Request limit per window (100)
  • X-RateLimit-Remaining – Requests remaining in current window
  • X-RateLimit-Reset – ISO timestamp of window reset

500 Internal Server Error

Server error during rendering. Include X-Request-Id when reporting issues.