Venn Diagram API

Create diagrams with 2–6 circles using HTTP. No account or API key. The editor uses JavaScript; this documentation and the APIs do not.

Generate an SVG with one URL

GET /api/venn.svg accepts a (A only), b (B only), ab (A∩B), and optional colorA / colorB (#rrggbb). This friendly mode always uses two circles; other state fields use product defaults. Missing or empty text leaves the region blank; no query produces an empty diagram. Colors may be omitted but cannot be empty.

Open the example SVG

https://venn.applepig.net/api/venn.svg?a=%E8%97%A5%E5%93%81%E6%BF%AB%E7%94%A8&b=%E7%89%A9%E8%B3%AA%E6%BF%AB%E7%94%A8&ab=%E6%AF%92%E5%93%81&colorA=%23E76F51&colorB=%232A9D8F

Use URLSearchParams or a URL encoder. Encode # as %23 and + as %2B; unencoded # starts a fragment and never reaches the server. For full styles and shapes, use /api/venn.svg?s=<state>. Do not mix s with friendly parameters. Duplicate or unknown parameters return 400; the serialized query including ? is limited to 22156 characters. Success returns image/svg+xml; charset=utf-8 and X-Venn-Url for the same editable diagram. Fonts are not embedded: use PNG when identical glyph rendering across readers is required. SVG serialization does not use the PNG worker quota.

Generate a PNG in one request

POST /api/png accepts a complete VennState JSON body. Save the response as PNG. The X-Venn-Url response header gives an editable share link for the same diagram.

curl -sD headers.txt -o venn.png -H 'content-type: application/json' \
  --data '{
  "v": 1,
  "n": 2,
  "style": "translucent",
  "opacity": 0.6,
  "overlap": 1.2,
  "radius": 0.3,
  "colors": [
    "#2e9be6",
    "#e6a92e"
  ],
  "bg": "#fafafa",
  "size": 400,
  "texts": {
    "1": {
      "t": "Coffee"
    },
    "2": {
      "t": "Sleep"
    },
    "3": {
      "t": "Me at 3am"
    }
  }
}' \
  'https://venn.applepig.net/api/png'

Inspect headers.txt for X-Venn-Url. To fetch the diagram again, reuse its s parameter with GET.

Fetch a diagram by URL

GET /api/png?s=<state> returns a square PNG at state.size pixels. s is base64url without padding of raw DEFLATE of UTF-8 JSON, not gzip or zlib-wrapped DEFLATE. Copy it from an editor/share link, or generate it with Node:

import { deflateRawSync } from 'node:zlib';
const state = {
  "v": 1,
  "n": 2,
  "style": "translucent",
  "opacity": 0.6,
  "overlap": 1.2,
  "radius": 0.3,
  "colors": [
    "#2e9be6",
    "#e6a92e"
  ],
  "bg": "#fafafa",
  "size": 400,
  "texts": {
    "1": {
      "t": "Coffee"
    },
    "2": {
      "t": "Sleep"
    },
    "3": {
      "t": "Me at 3am"
    }
  }
};
const s = deflateRawSync(Buffer.from(JSON.stringify(state), 'utf8')).toString('base64url');
console.log(new URL('/api/png?s=' + s, "https://venn.applepig.net").href);

Fetch the example PNG

Complete state

Required: v, n, style, opacity, overlap, radius, colors, bg, size, texts. Missing required fields return 400; they do not receive defaults. arr defaults to ring. Colors must contain exactly n entries. Title and region text have a 80-Unicode-code-point limit; newlines wrap text. XML-invalid characters are rejected. fs and title_fs are canvas-width fractions (0.001–1). fill affects only flat regions. Unknown state fields are ignored for old-link compatibility.

Optional: arr, title, title_fill, title_fs, stroke_width, stroke. Title styling is kept only with a nonempty title; stroke defaults depend on style, and stroke color is ignored when the resolved width is zero.

Field types and constraints (also available in OpenAPI)
vinteger; must be 1
ninteger; 2–6
arrstring; ring / row
stylestring; translucent / flat / outline
opacitynumber; 0–1; Required for all styles; only translucent uses it.
overlapnumber; 0.6–1.6
radiusnumber; Canvas-width fraction; ring 0.2–0.35, row 0.1–0.35. See shape-specific constraints.
colorsarray; exactly n #rrggbb colors
bgstring; #rrggbb color
sizeinteger; 400–2000
textsobject; decimal region keys → {t, fs?, fill?}; see the region table below
titlestring; up to 80 code points
title_fillstring; #rrggbb color
title_fsnumber; 0.001–1
stroke_widthnumber; 0–0.03
strokestring; #rrggbb color

Region keys

texts maps decimal bitmasks to {"t":"words","fs":0.09,"fill":"#ffffff"}; fs and fill are optional. Circle i is bit i: 1 = A only, 2 = B only, 3 = A∩B, 7 = A∩B∩C. These describe exclusive regions, not whole-set membership. Empty texts: {} is valid. Legal keys are computed from the shape:

ring(2) 1 2 3
ring(3) 1 2 4 3 5 6 7
ring(4) 1 2 4 8 3 5 10 12 7 11 13 14 15
ring(5) 1 2 4 8 16 3 6 12 17 24 7 14 19 25 28 15 23 27 29 30 31
ring(6) 1 2 4 8 16 32 3 6 12 24 33 48 7 14 28 35 49 56
row(3)  1 2 4 3 6
row(4)  1 2 4 8 3 6 12
row(5)  1 2 4 8 16 3 6 12 24
row(6)  1 2 4 8 16 32 3 6 12 24 48

ring(2) and ring(3) support every combination. Other shapes may lack overlaps; for example row(3) has no 5 or 7. An unavailable slot is a 400. Rearrange circles or use fewer circles when necessary.

Social image

GET /api/og.png?v=6&s=<state>&lang=en returns a branded 1200 × 630 PNG, rather than the square diagram. Without s it renders a sample. Language uses only the query (zh-TW, en, ja); cookies and Accept-Language do not change a cached image. v is a layout cache buster, not the state version.

Errors and limits

Expected API errors are English JSON {"error":"..."} with Cache-Control: no-store. 400 means invalid/missing input; 413 means the POST body exceeds 32768 bytes. Encoded s is limited to 7300 characters, and decompressed JSON to 32768 bytes. PNG and OG share 3 concurrent rasterizers: 503 with Retry-After: 2 means wait and retry the same request. A missing OG base image returns 500.

Caching

GET PNG/OG and SVG s mode use public, max-age=31536000, immutable; POST PNG is no-store and renders on every call. Friendly SVG mode is no-cache because product defaults can change. Produce with POST, then reuse GET for repeat fetches. Renderer or watermark changes may leave previously cached images visible at unchanged URLs; deployments must account for cache invalidation.

Other interfaces

Use the agent guide for CLI and plugin instructions, or read the source and README.