The diagram APIbuilt for code & agents.
One POST turns Mermaid or PlantUML source into a presentation-ready SVG or PNG. Drop it into CI, commit the output next to your code, or wire it into agent pipelines — same engine that powers the editor.
- <2s
- render budget
- 4
- input formats
- SVG / PNG
- outputs
$ curl -X POST https://api.beauty-diagram.com/v1/beautify \
-H "authorization: Bearer bd_live_..." \
-d '{"source":"flowchart TD\nA-->B", "sourceFormat":"mermaid"}'
# → 200 OK application/json
{
"ok": true,
"diagramType": "flowchart",
"svg": "<svg xmlns=...>...</svg>",
"usage": { used: 7, limit: 100 }
}What you can build
The Beauty Diagram API takes diagram source (Mermaid, PlantUML, draw.io, or SVG), applies the same beautify pipeline as the editor, and returns a clean, deck-ready vector. Three things people typically wire it into:
Quick start
Authenticated request. Replace bd_live_... with your key from /account/api-keys. Or skip the header for a watermarked anonymous demo (rate limited by IP).
curl -X POST https://api.beauty-diagram.com/v1/beautify \
-H "authorization: Bearer bd_live_..." \
-H "content-type: application/json" \
-d '{
"source": "flowchart TD\nA-->B",
"sourceFormat": "mermaid",
"theme": "modern"
}'bd CLI to keep diagrams checked-in next to your code — see CLI section.Authentication
Three identities are accepted. Pick the smallest one that covers your use case.
Authorization: Bearer bd_live_..../v1/* directly using the user's Supabase session cookie. No extra setup.Authorization header — falls through to the demo bucket. Watermarked output, capped at 20 beautify requests / minute / IP and 1 export / 24h / IP. Denials include a hints block with sign-up / sign-in URLs so agents can self-onboard.Scopes
Tokens are issued with explicit scopes. Request only what you need.
| Scope | Capability |
|---|---|
render:write | Beautify diagrams |
export:write | Export SVG and PNG files |
share:write | Create public share links |
ai:write | Generate Mermaid via AI (Pro/Premium only) |
Endpoint matrix
Every /v1/* route at a glance — auth, plan-gated capabilities, monthly quota, and the limits applied to each.
| Endpoint | Auth | Scope | Quota | Limits |
|---|---|---|---|---|
POST /v1/beautify | Optional | render:write | Not metered | 120/min/keyIP-rate-limited (anon) |
POST /v1/export | Optional | export:write | Free 3 · Pro 100 · Premium ∞ /mo | 120/min/keyIP-rate-limited (anon)1 export / IP / 24h trial |
POST /v1/share | Required | share:write | Plan diagram cap (free 5 · pro 100 · premium ∞) | 120/min/key |
POST /v1/ai/generate | Required | ai:write | Pro 100 · Premium 500 /mo (free not allowed) | 30/min/key |
GET /v1/themes | None | — | — | 120/min/keyIP-rate-limited (anon) |
GET /v1/usage | Required | — | — | 120/min/key |
GET /v1/beautify.svg | None | — | — | 300/min/IP (anon)source ≤ 5 KB decoded |
GET /v1/share/<id>.svg | None (public shares) | — | — | ETag / 304 revalidations-maxage=300 |
PNG scaleis plan-gated separately: anonymous & free 1×, pro 2×, premium 4×. Higher requests are silently clamped — see X-BD-Scale-Clamped in the response headers reference below.
Endpoints
All endpoints return JSON (unless explicitly noted, like /v1/export which streams binary). Authenticate with a bearer token on every request.
https://api.beauty-diagram.comPrefix every path below with this origin. CORS is wide open — browser, server, and CLI clients all use the same host.
Authorization: Bearer bd_live_...Personal access token created at /account/api-keys. The same header accepts a Supabase session JWT for browser callers.
/v1/beautifyRender a diagram, return inline SVGBeautify and render a diagram. Returns the SVG inline so you can preview it immediately or persist it yourself. Anonymous calls are accepted but receive a watermarked SVG.
| Field | Type | Description |
|---|---|---|
sourcerequired | string | Diagram source code. UTF-8, max 100 KB. |
sourceFormatrequired | "mermaid" | "plantuml" | "drawio" | "svg" | Tells the parser how to interpret source. |
themeoptional | stringdefault "modern" | Theme id from GET /v1/themes. |
| Field | Type | Description |
|---|---|---|
okoptional | true | Success indicator. |
diagramTypeoptional | string | Detected type (e.g. "flowchart", "sequence"). |
svgoptional | string | Rendered SVG markup, ready to inline or save. |
metaoptional | object | { theme, width, height, hasWatermark } — render metadata. |
usageoptional | object | Export counter snapshot: { used, limit, resetsAt }. |
POST /v1/beautify
Authorization: Bearer bd_live_...
Content-Type: application/json
{
"source": "flowchart TD\nA-->B",
"sourceFormat": "mermaid",
"theme": "modern"
}
→ {
"ok": true,
"diagramType": "flowchart",
"svg": "<svg ...>",
"meta": { "theme": "modern", "width": 720, "height": 480, "hasWatermark": false },
"usage": { "used": 7, "limit": 100, "resetsAt": "2026-05-01T00:00:00Z" }
}/v1/exportBinary file download (SVG or PNG)Returns the rendered file as a binary download (Content-Type: image/svg+xml or image/png) so curl -o file.svg just works. Metadata travels in response headers so the body stays pristine. Pass Accept: application/json or ?response=json to opt into the legacy JSON wrapper.
| Field | Type | Description |
|---|---|---|
sourcerequired | string | Diagram source code, UTF-8, ≤ 100 KB. |
sourceFormatrequired | "mermaid" | "plantuml" | "drawio" | "svg" | Source language. |
formatoptional | "svg" | "png"default "svg" | Output format. |
scaleoptional | 1 | 2 | 4default 1 | PNG scale; clamped to plan cap (anon/free 1×, pro 2×, premium 4×). Reported via X-BD-Scale-Clamped. |
themeoptional | stringdefault "modern" | Theme id (see /v1/themes). |
Binary body. Read state from response headers (full reference): X-BD-Diagram-Type, X-BD-Theme, X-BD-Quota-Used, X-BD-Quota-Limit, X-BD-Quota-Resets-At, X-BD-Scale-Clamped, Content-Disposition.
POST /v1/export
Authorization: Bearer bd_live_...
Content-Type: application/json
{ "source": "...", "sourceFormat": "mermaid", "format": "svg" }
→ HTTP/1.1 200 OK
Content-Type: image/svg+xml; charset=utf-8
Content-Disposition: attachment; filename="diagram-flowchart.svg"
X-BD-Diagram-Type: flowchart
X-BD-Theme: modern
X-BD-Quota-Used: 7
X-BD-Quota-Limit: 100
X-BD-Quota-Resets-At: 2026-05-01T00:00:00Z
<svg xmlns="..."> ... </svg>More examples (filename auto-pick, PNG @ 4×)
Let the server pick the filename via curl's -OJ:
curl -OJ -X POST https://api.beauty-diagram.com/v1/export \
-H "authorization: Bearer bd_live_..." \
-H "content-type: application/json" \
-d '{ "source": "...", "sourceFormat": "mermaid", "format": "svg" }'
# saves ./diagram-flowchart-a3f9k2.svgPNG @ 4× for premium plan:
curl -OJ -X POST https://api.beauty-diagram.com/v1/export \
-H "authorization: Bearer bd_live_..." \
-H "content-type: application/json" \
-d '{ "source": "...", "sourceFormat": "mermaid", "format": "png", "scale": 4 }'Filenames default to diagram-<type>-<sourceHash6>.<ext> so two different sources never collide and the same source is idempotent. Override with ?filename=my-name.
/v1/ai/generateNatural language → diagram sourceGenerate a diagram from a plain-language prompt. Returns Mermaid source text, not an image — pipe the result into /v1/beautify or /v1/export to render. Paid-only (Pro / Premium); anonymous and free callers are rejected before any model call.
Output language is currently Mermaid. The endpoint name is intentionally generic so we can extend the output format without a versioned rename.
| Field | Type | Description |
|---|---|---|
promptrequired | string | Plain-language description of the diagram you want (e.g. “user signup with email verification”). Trimmed; ≤ 2000 chars. |
hintoptional | "flowchart" | "sequence" | "state" | "class" | "er" | Optional shape hint. Improves output for prompts that are ambiguous about the target diagram type. |
| Field | Type | Description |
|---|---|---|
okoptional | true | Success indicator. |
mermaidoptional | string | Generated diagram source — already validated by the parser before being returned. |
diagramTypeoptional | string | Detected diagram type from the generated source. |
requestIdoptional | string (uuid) | Tracing id; include when reporting issues. |
quotaoptional | object | Monthly AI bucket after this call: { limit, used, resetsAt }. Quota only increments on success. |
In addition to the generic codes (Errors), this endpoint can return prompt_injection (input looked like an injection attempt), parse_failed_after_retry (output unparseable after one retry — quota not consumed), safety_blocked, upstream_timeout, and upstream_error.
POST /v1/ai/generate
Authorization: Bearer bd_live_...
Content-Type: application/json
{
"prompt": "user signup with email verification",
"hint": "flowchart"
}
→ {
"ok": true,
"mermaid": "flowchart TD\n A[Sign up] --> B{Email valid?}\n ...",
"diagramType": "flowchart",
"requestId": "1f3e…",
"quota": { "limit": 100, "used": 23, "resetsAt": "2026-05-01T00:00:00Z" }
}/v1/themesList available themesBuild a theme picker that always reflects what the engine actually supports. Public — no auth needed.
No body, no query parameters.
| Field | Type | Description |
|---|---|---|
okoptional | true | Success indicator. |
themesoptional | Theme[] | Array of { id, name, tone, description }. id is what other endpoints accept as theme; tone is one of "light" / "dark" for UI grouping. |
GET /v1/themes
→ {
"ok": true,
"themes": [
{ "id": "modern", "name": "Modern", "tone": "light", "description": "Editor default." },
{ "id": "midnight", "name": "Midnight", "tone": "dark", "description": "Slide-deck dark." }
]
}/v1/usagePlan, export counter, AI counterReturns the actor's plan and per-feature counters. Use it before running expensive batches so you can pre-empt quota_exhausted. Authenticated only.
No body, no query parameters.
| Field | Type | Description |
|---|---|---|
okoptional | true | Success indicator. |
planoptional | "free" | "pro" | "premium" | Plan tier of the resolved actor. |
actoroptional | "user" | "api_key" | How the request was authenticated. |
exportsoptional | object | { plan, used, limit, resetsAt } — monthly export bucket. limit is null for unlimited (premium). |
aioptional | object | { enabled, limit, used, resetsAt } — monthly AI generation bucket. enabled is false on free plan (limit null); on Pro/Premium it reflects the current month's consumption. The bucket is keyed on the owner user, so multiple API keys share one counter. |
GET /v1/usage
Authorization: Bearer bd_live_...
→ {
"ok": true,
"plan": "pro",
"actor": "api_key",
"exports": { "plan": "pro", "used": 7, "limit": 100, "resetsAt": "2026-05-01T00:00:00Z" },
"ai": { "enabled": true, "used": 23, "limit": 100, "resetsAt": "2026-05-01T00:00:00Z" }
}/v1/beautify.svgAnonymous inline embed — returns SVG directlyRender a Mermaid diagram and return it as image/svg+xml, with no auth required — designed to be used as an <img src> URL for quick embeds in READMEs, Notion, and blog posts. A watermark is always applied. Any token passed in the query string is ignored; this endpoint is intentionally anonymous.
On parse failure the response is still HTTP 200 with a fallback SVG explaining the error — because <img> consumers cannot display diagnostic messages for 4xx responses. To get clean (watermark-free) output, save the diagram with POST /v1/share and embed using GET /v1/share/<id>.svg instead.
| Field | Type | Description |
|---|---|---|
sourcerequired | string | Base64url-encoded Mermaid source. Decoded payload must be ≤ 5 KB. Use base64url (URL-safe alphabet, no padding) or standard base64 — both are accepted. |
themeoptional | stringdefault "modern" | Theme id from GET /v1/themes. |
| Status | Meaning |
|---|---|
200 image/svg+xml | Successful render with watermark, OR fallback SVG on parse failure (HTTP 200 by design — <img> consumers cannot show 4xx diagnostics). |
413 | Decoded source exceeds the 5 KB limit. |
429 | Rate limit hit (300 req / min / IP). Retry-After header included. |
Cache-Control: public, max-age=3600, s-maxage=86400 — no immutable, because cross-deploy renders can differ when the engine is updated.
curl "https://api.beauty-diagram.com/v1/beautify.svg?source=$(echo -n 'graph TD; A-->B' | base64)" > diagram.svg
# Markdown / HTML embed (watermarked, no signup required):
# 
# <img src="https://api.beauty-diagram.com/v1/beautify.svg?source=Z3JhcGg..." />Limits, rate limiting & headers
The web app and the API share a single export counter — there is no separate "API quota". Rate limits are enforced cross-instance for API keys and IP-based for anonymous demo traffic.
120 requests / minute / key, fixed window. The counter is shared across the entire /v1/* namespace and persists across function instances.
Over-budget calls get 429 rate_limited with a Retry-After header and a rateLimit object describing window state.
Rate-limited per IP — exact ceiling for most anonymous routes is intentionally undocumented to discourage abuse. Sign in or use an API key for higher allowances.
Exception — GET /v1/beautify.svg: the anonymous cap is raised to 300 req / min / IP because image proxies (GitHub Camo, Notion, Medium) concentrate reader traffic onto a small number of egress IPs, making the standard 20/min threshold a false positive.
A 1-export-per-IP-per-24h trial budget on /v1/export lets agents and evaluators verify the toolchain end-to-end before registering. Denials carry a hints block with signUpUrl / signInUrl / apiDocsUrl.
HTTP/1.1 429 Too Many Requests
Retry-After: 47
Content-Type: application/json
{
"ok": false,
"error": "rate_limited",
"message": "API key rate limit (120 requests / 60s) reached. Retry after 2026-04-27T04:31:12Z.",
"retryAfterMs": 47000,
"rateLimit": {
"limit": 120,
"windowSeconds": 60,
"used": 121,
"resetsAt": "2026-04-27T04:31:12Z"
}
}Metadata that does not fit in the JSON body — useful for CLI / batch pipelines that need to read state without parsing the response.
| Header | Where | Meaning |
|---|---|---|
X-BD-Diagram-Type | /v1/export | Detected type — flowchart, sequence, etc. |
X-BD-Theme | /v1/export | Theme that produced the output. |
X-BD-Watermark | /v1/export | true when the badge is baked in. |
X-BD-Scale | /v1/export (PNG) | Effective scale (1, 2, or 4). |
X-BD-Scale-Clamped | /v1/export (PNG) | true when scale was lowered to plan cap. |
X-BD-Quota-Plan | /v1/export | Plan tier of the actor. |
X-BD-Quota-Used | /v1/export | Exports used in the current month. |
X-BD-Quota-Limit | /v1/export | Plan limit, or unlimited. |
X-BD-Quota-Resets-At | /v1/export | ISO timestamp when the counter resets. |
Retry-After | Any 429 | Seconds until the next attempt is safe. |
source on render endpoints: 100 KB (UTF-8 bytes). Oversize → source_too_large (HTTP 413).
UTF-8 only; CJK and emoji labels supported in SVG. PNG raster ships Latin glyphs only — CJK falls back to tofu boxes. Newlines must be JSON-escaped as \n.
POST routes carry maxDuration = 60s; render aims for <2s. PNG worst case (4× composite) is ~1.1s plus ~1.5s cold start.
Errors
Every error is JSON of the shape { ok: false, error, message }. Anonymous-actor denials additionally carry hints: { signUpUrl, signInUrl, apiDocsUrl } so CLIs and agents can guide the user to register without scraping these docs. Codes you should handle:
| Code | Meaning |
|---|---|
invalid_input | Malformed body or wrong types. |
not_authenticated | No key, no session. |
scope_missing | Key lacks the required scope. |
plan_not_allowed | Plan does not include this capability. |
parse_failed | Source did not parse as the declared format. |
quota_exhausted | Limit reached for this period. |
rate_limited | Per-key (120/min, 30/min for AI) or anonymous IP bucket is full. |
output_too_large | Rasterized PNG exceeds the 8192 px ceiling — lower scale or simplify. |
prompt_injection | AI input matched a prompt-injection pattern; rejected before any model call. |
instruction_rejected | AI: prompt did not describe a diagram (off-topic). Quota not consumed. |
parse_failed_after_retry | AI: model output unparseable after one retry. Quota not consumed. |
safety_blocked | AI: provider safety filter rejected the request. Rephrase the prompt. |
upstream_timeout | AI: provider took too long. Safe to retry after a moment. |
upstream_error | AI: provider failed for an unknown reason. |
Privacy
- We do not persist your
sourceor AIinstructionunless you explicitly call/v1/share. - Logs store a hash, length, format, and diagram type — never the raw input.
- You can revoke any API key from /account/api-keys. Revocation takes effect immediately.
CLI
The bd CLI wraps the API for repo-friendly use — same auth, same quotas, same engine, zero runtime dependencies. It runs single diagrams, parallel batches, and embeds Mermaid blocks straight back into your Markdown.
# zero-install
npx @beauty-diagram/cli --help
# global install
npm install -g @beauty-diagram/cliReady to ship?
Create a key, paste the curl from above, and you'll have your first rendered SVG inside a minute. Free plan includes 3 watermark-free exports a month — enough to wire up CI.