Fig. — Reference

API documentation

Base URL https://chart.hanif.app. Two endpoints, a handful of parameters, zero ceremony.

Overview

chart.hanif.app accepts a chart config (the Chart.js shape) and returns a rendered image. Two ways to call it:

  • POST with a JSON body — best for large or programmatic data.
  • GET with the config in the query string — best for dropping straight into an <img src>.

Every image carries a chart.hanif.app watermark in the bottom-right corner. It can be disabled with watermark: false.

POST /api/v1/chart

Send JSON, receive an image with Content-Type matching the requested format.

cURL
curl -X POST https://chart.hanif.app/api/v1/chart \
  -H "Content-Type: application/json" \
  -o chart.png \
  -d '{
    "type": "bar",
    "data": {
      "labels": ["Jan", "Feb", "Mar"],
      "datasets": [{ "label": "Sales", "data": [12, 19, 8] }]
    },
    "width": 800,
    "height": 500,
    "format": "png"
  }'

The body accepts either a flat shape (type, data, options at the root) or a nested one (wrapped in chart):

JSON · nested
{
  "chart": { "type": "line", "data": { }, "options": { } },
  "width": 800,
  "height": 500,
  "backgroundColor": "#ffffff",
  "format": "png",
  "watermark": true
}

GET /api/v1/chart

Pass the config through the c query parameter — either URL-encoded JSON or base64-encoded JSON. Perfect for embedding:

HTML
<img src="https://chart.hanif.app/api/v1/chart?c=
  {%22type%22:%22pie%22,%22data%22:{%22labels%22:[%22A%22,%22B%22],
  %22datasets%22:[{%22data%22:[60,40]}]}}&width=400" />

Extra options (width, height, format, backgroundColor, watermark) ride alongside as ordinary query params.

Use base64 for larger configs to keep the URL clean: ?c=<base64-json>.

Parameters

ParamTypeDefaultNotes
type / chart.typestringRequired. Chart type.
data / chart.dataobjectRequired. { labels, datasets }.
optionsobject{}Chart.js options (title, scales, legend…).
widthnumber800Pixels, 50–3000.
heightnumber600Pixels, 50–3000.
devicePixelRationumber2Crispness multiplier, 1–4.
backgroundColorstring#ffffffAny CSS color, or transparent.
formatstringpngpng · jpeg · webp.
watermarkbooleantrueShow the domain watermark.

Chart types

Native Chart.js types plus a few convenience aliases:

Type aliases

AliasBecomesEffect
arealineAll datasets get fill: true.
horizontalBarbarindexAxis: 'y'.
stackedBarbarx & y axes stacked: true.
mixedbarEach dataset may set its own type (bar/line).

Auto-theming

If you omit colors and labels, the renderer fills the gaps so output looks intentional out of the box:

  • Datasets without colors get a balanced brand palette (arc charts get per-segment colors).
  • A single unlabeled dataset hides its legend instead of printing undefined; multiple unlabeled datasets become Series 1, Series 2
  • Sensible line tension, point sizes, bar radius, fonts and grid colors are applied — all overridable via options.

Metadata endpoints

EndpointReturns
GET /api/v1/typesSupported types, formats and presets.
GET /api/v1/presetsAll preset configs.
GET /api/v1/presets/:keyOne preset config (e.g. bar).
GET /health · /livez · /readyzLiveness & readiness.

Limits

  • Effective canvas area is capped at 4,000,000 pixels (width × height × dpr²).
  • Up to 50 datasets, 5,000 points per dataset.
  • Request body capped at 512 KB.
  • Anonymous rate limit applies per IP; identical requests are served from cache (X-Cache: HIT).

Errors

Errors return JSON with an appropriate HTTP status (400 for validation, 429 rate-limited, 500 render). Server-side detail is never leaked on 5xx.

JSON · 400
{
  "error": "ValidationError",
  "message": "Field \"type\" wajib diisi."
}

Code examples

JavaScript (fetch)
const res = await fetch("https://chart.hanif.app/api/v1/chart", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    type: "line",
    data: {
      labels: ["Mon", "Tue", "Wed", "Thu", "Fri"],
      datasets: [{ label: "Visitors", data: [120, 190, 170, 220, 280] }]
    }
  })
});
const blob = await res.blob();
document.querySelector("img").src = URL.createObjectURL(blob);
Python (requests)
import requests

payload = {
    "type": "doughnut",
    "data": {
        "labels": ["Done", "Doing", "Pending"],
        "datasets": [{"data": [70, 20, 10]}]
    },
    "width": 600, "height": 600
}
r = requests.post("https://chart.hanif.app/api/v1/chart", json=payload)
open("chart.png", "wb").write(r.content)
Shell (base64 GET)
CFG=$(echo '{"type":"bar","data":{"labels":["A","B"],"datasets":[{"data":[5,9]}]}}' | base64)
curl "https://chart.hanif.app/api/v1/chart?c=$CFG&width=600" -o chart.png