API Documentation

Chart API Documentation

Generate beautiful charts with a simple API. No dependencies, render charts server-side as images (PNG, JPEG, SVG).

Quick Start

Basic Example

bash
curl -X POST https://api.chartone.dev/v1/chart \
  -H "Content-Type: application/json" \
  -d '{
    "type": "bar",
    "data": {
      "labels": ["Q1", "Q2", "Q3", "Q4"],
      "datasets": [{
        "label": "Revenue",
        "data": [120, 190, 300, 500]
      }]
    }
  }' \
  --output bar-chart.png

URL Embedding

html
<img src="https://api.chartone.dev/v1/chart?type=bar&data={%22labels%22:[%22A%22,%22B%22,%22C%22],%22datasets%22:[{%22data%22:[10,20,30]}]}&theme=modern&width=600&height=400">

Authentication

🎉 No API key required to get started! The API works without authentication, but charts will include a small watermark. Sign up for a free account to remove the watermark and get higher limits—no credit card required.

Anonymous (No Signup)

Start using the API immediately without any signup. Perfect for testing and low-volume use.

  • No signup required
  • 20 requests per day per IP
  • Small watermark on charts
  • 2 themes (Modern, Minimal)
  • Max size: 800x600

Free Account

Sign up for a free account to remove the watermark and get tracked monthly limits.

  • No watermark
  • 2,000 requests/month
  • All chart types
  • 500 short URLs
  • No credit card required

Using Your API Key

Once you have an API key, you can authenticate your requests using either method:

Method 1: Authorization Header (Recommended for POST)

bash
curl -X POST https://api.chartone.dev/v1/chart \\
  -H "Authorization: Bearer YOUR_API_KEY" \\
  -H "Content-Type: application/json" \\
  -d '{"type": "bar", "data": {...}}'

Method 2: Query Parameter (For GET requests)

bash
curl "https://api.chartone.dev/v1/chart?apiKey=YOUR_API_KEY&type=bar&data=..."

Chart Types

We support all major chart types from Chart.js. Each type can be customized with themes, colors, and options.

Line Chart

Simple line chart with one or multiple series

json
{
  "type": "line",
  "data": {
    "labels": ["Jan", "Feb", "Mar", "Apr", "May"],
    "datasets": [{
      "label": "Sales",
      "data": [12, 19, 15, 25, 22]
    }]
  }
}

Bar Chart

Vertical bar chart for comparisons

json
{
  "type": "bar",
  "data": {
    "labels": ["Product A", "Product B", "Product C"],
    "datasets": [{
      "label": "Units Sold",
      "data": [65, 59, 80]
    }]
  }
}

Pie Chart

Circular pie chart for proportions

json
{
  "type": "pie",
  "data": {
    "labels": ["Desktop", "Mobile", "Tablet"],
    "datasets": [{
      "data": [55, 35, 10]
    }]
  }
}

Doughnut Chart

Pie chart with center hole

json
{
  "type": "doughnut",
  "data": {
    "labels": ["Chrome", "Firefox", "Safari", "Edge"],
    "datasets": [{
      "data": [45, 25, 20, 10]
    }]
  }
}

Area Chart

Line chart with filled area

json
{
  "type": "area",
  "data": {
    "labels": ["Mon", "Tue", "Wed", "Thu", "Fri"],
    "datasets": [{
      "label": "Page Views",
      "data": [1200, 1900, 1500, 2500, 2200]
    }]
  }
}

Radar Chart

Multi-axis radar/spider chart

json
{
  "type": "radar",
  "data": {
    "labels": ["Speed", "Power", "Accuracy", "Stamina", "Defense"],
    "datasets": [{
      "label": "Player Stats",
      "data": [85, 70, 90, 75, 80]
    }]
  }
}

Themes

Choose from 20+ professionally designed themes to match your brand or use case.

Modern

Free

Balanced neutral background, soft gridlines, fresh palette

Classic

Starter+

Traditional serif style with timeless color palette

Minimal

Free

Clean, distraction-free with transparent background

Dark

Starter+

High contrast dark mode with vibrant accent colors

Economist

Starter+

Data journalism style with authoritative serif font

Financial

Growth+

Bloomberg-inspired terminal style with monospace font

Scientific

Growth+

Academic research style with viridis-inspired palette

Presentation

Starter+

Bold colors and large fonts optimized for slides

Monochrome

Starter+

Grayscale only, perfect for print and accessibility

Material

Starter+

Google Material Design with bold primary colors

FiveThirtyEight

Starter+

Data-driven journalism style inspired by FiveThirtyEight

Pastel

Starter+

Soft muted colors perfect for lifestyle content

High Contrast

Starter+

Maximum accessibility with WCAG AAA compliant colors

Corporate

Growth+

Professional business blue tones for B2B and reports

Vibrant

Growth+

Bold energetic palette for social media and campaigns

Ocean

Growth+

Cool blue-green gradient inspired by the sea

Sunset

Growth+

Warm gradient from yellow to pink for engaging visuals

Nature

Growth+

Earth tones and organic greens for environmental data

Retro

Growth+

Vintage 1970s palette with muted warm tones

Neon

Growth+

Cyberpunk-inspired bright colors on dark background

Using Themes

json
{
  "type": "bar",
  "theme": "dark",
  "data": { ... }
}

API Endpoints

POST
/v1/chart

Generate a chart from JSON configuration.

Request Body

json
{
  "type": "bar",
  "theme": "modern",
  "data": {
    "labels": ["Q1", "Q2", "Q3"],
    "datasets": [{
      "label": "Revenue",
      "data": [100, 200, 300]
    }]
  },
  "options": {
    "title": "Quarterly Revenue"
  },
  "width": 800,
  "height": 400,
  "format": "png"
}

Parameters

ParameterTypeRequiredDescription
typestring
Yes
Chart type (line, bar, pie, etc.)
dataobject
Yes
Chart data with labels and datasets
themestring
No
Theme name (default: modern)
widthnumber
No
Chart width in pixels (100-4000)
heightnumber
No
Chart height in pixels (100-4000)
formatstring
No
Output format (png, jpeg, svg)
xAxisstring
No
X-axis label
yAxisstring
No
Y-axis label
targetLinenumber/object
No
Target line value or {value, label} (bar, line, area, stacked bar only)
averageLineboolean
No
Show average line (bar, line, area, stacked bar only)
highlightstring
No
Comma-separated 1-based indices to highlight (e.g., "1,3,6")
devicePixelRationumber
No
Pixel ratio for high-DPI (1-4, default: 2)
GET
/v1/chart

Generate a chart via URL parameters. Perfect for embedding charts in emails, Notion, or any platform that supports images.

Note: All parameters are the same as POST /v1/chart, but JSON values (like data) must be URL-encoded. Authentication via ?apiKey=YOUR_API_KEY query parameter.

⚠️ Security Warning: API Key in URLs

Including your API key in URLs (?apiKey=YOUR_KEY) exposes it in browser history, server logs, and referrer headers.

Safer alternatives:

  • • Use POST /v1/chart with Authorization header (recommended)
  • • Use POST /v1/short-url to create shareable URLs without exposing your key
  • • Only use GET with ?apiKey= in server-side contexts

Basic Example

html
<img src="https://api.chartone.dev/v1/chart?type=bar&data={"labels":["A","B","C"],"datasets":[{"data":[10,20,30]}]}&theme=modern&width=600&height=400">

Advanced Example (with axis labels and highlighting)

html
<img src="https://api.chartone.dev/v1/chart?apiKey=YOUR_API_KEY&type=bar&data={"labels":["Q1","Q2","Q3","Q4"],"datasets":[{"label":"Sales","data":[120,190,300,250]}]}&xAxis=Quarter&yAxis=Revenue ($)&highlight=3&theme=modern&width=800&height=400">
POST
/v1/short-url
Auth Required

Create a short URL for easy sharing and embedding. Short URLs are permanent (until expiry) and don't expose your chart configuration.

Request Body

json
{
  "chartConfig": {
    "type": "line",
    "data": {
      "labels": ["Jan", "Feb", "Mar"],
      "datasets": [{
        "label": "Revenue",
        "data": [100, 150, 200]
      }]
    }
  },
  "theme": "modern",
  "width": 800,
  "height": 400,
  "format": "png",
  "expiresInDays": 30
}

Response

json
{
  "id": "abc123xyz",
  "shortUrl": "/render/abc123xyz",
  "fullUrl": "https://api.chartone.dev/render/abc123xyz",
  "expiresInDays": 30
}

Plan Limits: Free accounts can create up to 500 short URLs with 7-day expiry. Paid plans get unlimited short URLs with 180-day expiry.

GET
/v1/usage
Auth Required

Get your current usage statistics and quota information.

bash
curl -H "Authorization: Bearer YOUR_API_KEY" \
  https://api.chartone.dev/v1/usage

Response

json
{
  "plan": "free",
  "period": "monthly",
  "quota": {
    "limit": 2000,
    "used": 456,
    "remaining": 1544,
    "exceeded": false
  }
}
GET
/v1/themes

List all available themes.

bash
curl https://api.chartone.dev/v1/themes

Batch API

Generate multiple charts in a single request for efficient report generation. Perfect for dashboards, PDFs, and multi-chart workflows.

POST
/v1/batch
NEW

Render up to 50 charts in parallel. Each chart in the batch counts toward your quota and must pass the same validation as individual requests.

Why use batch? Instead of making 15 separate HTTP requests for a PDF report, make 1 batch request and render all charts in parallel—faster and more efficient.

Request Body

json
{
  "charts": [
    {
      "type": "bar",
      "theme": "modern",
      "data": {
        "labels": ["Q1", "Q2", "Q3", "Q4"],
        "datasets": [{"label": "Revenue", "data": [100, 150, 200, 250]}]
      },
      "width": 800,
      "height": 400
    },
    {
      "type": "line",
      "theme": "dark",
      "data": {
        "labels": ["Jan", "Feb", "Mar", "Apr"],
        "datasets": [{"label": "Users", "data": [1200, 1900, 1500, 2200]}]
      },
      "width": 600,
      "height": 300
    }
  ]
}

Response Format

json
{
  "results": [
    {
      "success": true,
      "index": 0,
      "data": "iVBORw0KGgoAAAANSUhEUgAA...",  // Base64-encoded image
      "format": "png",
      "width": 800,
      "height": 400,
      "cacheHit": false
    },
    {
      "success": true,
      "index": 1,
      "data": "iVBORw0KGgoAAAANSUhEUgAA...",
      "format": "png",
      "width": 600,
      "height": 300,
      "cacheHit": true
    }
  ],
  "summary": {
    "total": 2,
    "succeeded": 2,
    "failed": 0,
    "totalTime": 234  // milliseconds
  }
}

Python Example

python
import requests
import base64

# Generate multiple charts at once
response = requests.post(
    'https://api.chartone.dev/v1/batch',
    headers={'Authorization': 'Bearer YOUR_API_KEY'},
    json={
        'charts': [
            {
                'type': 'bar',
                'data': {'labels': ['A', 'B', 'C'], 'datasets': [{'data': [10, 20, 30]}]},
                'theme': 'modern',
                'width': 800,
                'height': 400
            },
            {
                'type': 'line',
                'data': {'labels': ['Jan', 'Feb', 'Mar'], 'datasets': [{'data': [100, 200, 150]}]},
                'theme': 'dark',
                'width': 600,
                'height': 300
            }
        ]
    }
)

result = response.json()

# Save each chart
for chart in result['results']:
    if chart['success']:
        image_data = base64.b64decode(chart['data'])
        filename = f"chart_{chart['index']}.{chart['format']}"
        with open(filename, 'wb') as f:
            f.write(image_data)
        print(f"Saved {filename}")
    else:
        print(f"Chart {chart['index']} failed: {chart['error']}")

Limits

  • • Maximum 50 charts per batch request
  • • Each chart counts toward your monthly quota
  • • All charts must pass plan-based validation (theme access, dimensions, etc.)
  • • Quota check happens before rendering—if insufficient quota, entire batch fails

Email Client Best Practices

Email clients (Outlook, Gmail, Apple Mail) have unique rendering quirks. Follow these guidelines to ensure your charts display correctly across all email clients.

✅ Recommended Settings

  • Width:

    Max 600px (Outlook desktop clips wider images)

  • Format:

    PNG (best compatibility) or JPEG (smaller file size)

  • devicePixelRatio:

    2x for sharp rendering on mobile (default)

  • Theme:

    Use light themes (dark, minimal_dark) for dark mode email support

❌ Common Pitfalls

  • Images > 600px wide:

    Clipped in Outlook 365 desktop (WebKit bug)

  • SVG format:

    Not supported in most email clients (use PNG instead)

  • No alt text:

    Breaks accessibility and shows nothing when images blocked

  • Light charts only:

    Look bad in Apple Mail/Gmail dark mode

Email-Optimized HTML Template

html
<!-- Email-safe chart embedding -->
<table width="100%" cellpadding="0" cellspacing="0" border="0">
  <tr>
    <td align="center" style="padding: 20px;">
      <img
        src="https://api.chartone.dev/v1/chart?apiKey=YOUR_KEY&type=bar&data={...}&width=600&height=400&theme=modern"
        alt="Q4 Revenue Chart showing 25% growth compared to Q3"
        width="600"
        height="400"
        style="max-width: 100%; height: auto; display: block; border: 0;"
      />
    </td>
  </tr>
</table>

<!-- For dark mode support, use @media queries -->
<style>
  @media (prefers-color-scheme: dark) {
    .chart-light { display: none !important; }
    .chart-dark { display: block !important; }
  }
  @media (prefers-color-scheme: light) {
    .chart-light { display: block !important; }
    .chart-dark { display: none !important; }
  }
</style>

<!-- Light mode chart (default) -->
<img
  class="chart-light"
  src="https://api.chartone.dev/v1/chart?theme=modern&..."
  alt="Revenue chart"
  width="600"
  style="max-width: 100%; display: block;"
/>

<!-- Dark mode chart (hidden by default) -->
<img
  class="chart-dark"
  src="https://api.chartone.dev/v1/chart?theme=dark&..."
  alt="Revenue chart"
  width="600"
  style="max-width: 100%; display: none;"
/>

📧 Email Client Compatibility Matrix

Email ClientMax WidthFormat SupportDark Mode
Gmail (Web)650pxPNG, JPEG ✅CSS media queries ✅
Outlook 365 (Desktop)600px max ⚠️PNG, JPEG ✅Not supported ❌
Apple Mail (iOS/macOS)100% responsivePNG, JPEG ✅Native support ✅
Gmail (Android)100% responsivePNG, JPEG ✅Limited support ⚠️
Outlook (Web)700pxPNG, JPEG ✅Not supported ❌

💡 Pro Tips

  • Always include alt text:

    Describe the chart data in 1-2 sentences for accessibility and image-blocking scenarios.

  • Use inline styles:

    Email clients strip <style> tags—use inline CSS on <img> tags instead.

  • Test with Litmus or Email on Acid:

    Preview your emails across 90+ clients before sending to catch rendering issues.

  • Embed as <img>, not background images:

    Background images are disabled in many clients (especially Outlook)—always use <img> tags.

  • Use Short URLs for cleaner HTML:

    Create short URLs via POST /v1/short-url to avoid massive query strings in your email HTML.

Code Examples

Advanced Features (Axis Labels, Target Line, Highlighting)

javascript
// Using new parameters for enhanced charts
const response = await fetch('https://api.chartone.dev/v1/chart', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': 'Bearer YOUR_API_KEY'
  },
  body: JSON.stringify({
    type: 'bar',
    theme: 'modern',
    data: {
      labels: ['Q1', 'Q2', 'Q3', 'Q4'],
      datasets: [{
        label: 'Sales',
        data: [120, 190, 300, 250]
      }]
    },
    xAxis: 'Quarter',           // X-axis label
    yAxis: 'Revenue ($K)',       // Y-axis label
    targetLine: {                // Target line with label
      value: 200,
      label: 'Goal'
    },
    averageLine: true,           // Show average line
    highlight: '3',              // Highlight Q3 (1-based index)
    width: 800,
    height: 400
  })
});

JavaScript (Fetch)

javascript
async function generateChart() {
  const response = await fetch('https://api.chartone.dev/v1/chart', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'Authorization': 'Bearer YOUR_API_KEY'
    },
    body: JSON.stringify({
      type: 'bar',
      theme: 'modern',
      data: {
        labels: ['Q1', 'Q2', 'Q3', 'Q4'],
        datasets: [{
          label: 'Revenue',
          data: [120, 190, 300, 500]
        }]
      }
    })
  });

  const blob = await response.blob();
  const url = URL.createObjectURL(blob);
  document.getElementById('chart').src = url;
}

Python (Requests)

python
import requests

def generate_chart():
    response = requests.post(
        'https://api.chartone.dev/v1/chart',
        headers={
            'Authorization': 'Bearer YOUR_API_KEY',
            'Content-Type': 'application/json'
        },
        json={
            'type': 'bar',
            'theme': 'modern',
            'data': {
                'labels': ['Q1', 'Q2', 'Q3', 'Q4'],
                'datasets': [{
                    'label': 'Revenue',
                    'data': [120, 190, 300, 500]
                }]
            }
        }
    )

    with open('chart.png', 'wb') as f:
        f.write(response.content)

React Component

jsx
import React, { useEffect, useState } from 'react';

function ChartImage() {
  const [chartUrl, setChartUrl] = useState('');

  useEffect(() => {
    async function generateChart() {
      const response = await fetch('https://api.chartone.dev/v1/chart', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'Authorization': 'Bearer YOUR_API_KEY'
        },
        body: JSON.stringify({
          type: 'bar',
          theme: 'modern',
          data: {
            labels: ['Q1', 'Q2', 'Q3', 'Q4'],
            datasets: [{
              label: 'Revenue',
              data: [120, 190, 300, 500]
            }]
          }
        })
      });

      const blob = await response.blob();
      const url = URL.createObjectURL(blob);
      setChartUrl(url);
    }

    generateChart();
  }, []);

  return chartUrl ? <img src={chartUrl} alt="Chart" /> : <p>Loading...</p>;
}

Pricing

Anonymous
$0/forever

No signup needed

  • 20 charts/day
  • Watermark
  • 2 basic themes
  • PNG only
  • No AI assistant
Free Account
$0/forever

No watermark!

  • 2,000/mo
  • No watermark
  • 5 themes
  • PNG format
  • Signed URLs
  • 500 short URLs (7d)
  • No AI assistant
Starter
$15.83/mo

Billed annually ($190/yr)

  • 50,000/mo
  • 10 premium themes
  • PNG, JPEG, SVG
  • Signed URLs
  • Unlimited short URLs (180d)
  • 50 AI suggestions/mo
BEST VALUE
Growth
$32.50/mo

Billed annually ($390/yr)

  • 150,000 charts/mo
  • All 20+ chart types
  • All 20 themes
  • PNG, JPEG, SVG
  • Unlimited short URLs (180d)
  • 200 AI suggestions/mo
Pro
$65.83/mo

Billed annually ($790/yr)

  • 350,000 charts/mo
  • All features
  • Priority support
  • Custom palettes
  • 500 AI suggestions/mo
  • 99.9% SLA

Rate Limits

We enforce rate limits to prevent server abuse and ensure reliable service for all users. Limits scale with your plan to support both casual usage and high-volume integrations.

Anonymous Users (No API Key)

  • Per-minute: 20 requests
  • Daily: 20 requests per IP
  • Monthly: 600 requests per IP

Free Account

  • Per-minute: 500 requests
  • Monthly: 2,000 requests

Starter Plan

  • Per-minute: 1,000 requests
  • Monthly: 50,000 requests

Growth Plan

  • Per-minute: 2,000 requests
  • Monthly: 150,000 requests

Pro Plan

  • Per-minute: 3,000 requests
  • Monthly: 350,000 requests

Need higher limits? Contact us if you have legitimate use cases requiring higher throughput. We're happy to work with you on custom solutions.

Rate Limit Headers

http
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 856
X-Plan: free

Troubleshooting

400

Bad Request

Invalid data format or missing required fields

Solution: Ensure your data object includes all required fields

401

Unauthorized

Invalid or revoked API key

Solution: Check your API key is correct and active

403

Forbidden

Resource not available on your plan

Solution: Upgrade your plan or use an available resource

429

Too Many Requests

Rate limit exceeded

Solution: Wait for the rate limit to reset or upgrade your plan

Ready to Get Started?

Start creating beautiful charts today. No credit card required.