TwoMinuteHarvey Balls
Slide Deck Quality Comparison Matrices in 2 minutes or less

Harvey Ball Matrix HTTP API

POST a small JSON description and get back a deck-ready PNG (or SVG). The endpoint is open and CORS-enabled, so it works from browsers, scripts, CI and anywhere else you can make an HTTP call. The same JSON opens in the builder.

POST https://www.twominutetoolkit.com/api/render/harvey
Fair use: rate-limited to 20 requests a minute per IP (bursts capped at 5 a second), shared across every Two Minute tool, with a 64 KB body cap. No key or sign-up needed.

Try it

Open in builder

Code samples

Live preview

Click Render to call the API.

Request body

FieldTypeDescription
titlestringHeading shown top-left of the chart at 22px bold. Every chart has one title row; an empty string hides it.
max 140 chars · default "Comparison"
criteriarequiredstring[]Column headings, left to right: what each option is scored on, e.g. ["Cost", "Ease of use", "Integrations"]. 1–8 criteria, up to 40 characters each; long names wrap to two lines.
max 8 items
rowsrequiredobject[]The options being compared, top to bottom (2–12). Each has a name and one score per criterion, in the same order as `criteria`.
max 12 items
stylestringCell style for the whole grid: "harvey" (Harvey balls, scores 0–4 from empty to full), "check" (a tick for 1, nothing for 0) or "dots" (0–5 filled dots out of five). Default "harvey".
"harvey", "check", "dots" · default "harvey"
notesbooleanShow the Notes column on the right. true shows it even when no row has a note yet; false hides it (any row notes are kept but not drawn). When omitted, the column appears automatically as soon as any row has a note, so you can simply set rows[].notes.
legendbooleanShow a one-line legend under the grid explaining the scale. Default true.
default true
widthintegerChart width in pixels (640–2400, default 1280, which suits a 16:9 slide). PNG output renders at 2x. Height is always computed from the content.
640–2400 · default 1280
palettestring[]Hex colours applied in order to items that have no colour of their own. Pass the user's brand colours here when they name them. Default: indigo, sky, emerald, amber, red, gray.
max 12 items · default ["#4f46e5","#0ea5e9","#10b981","#f59e0b","#ef4444","#6b7280"]

rows[] item

FieldTypeDescription
namerequiredstringOption name shown in the left column (up to 40 characters; long names wrap to two lines).
max 40 chars
scores(number | null)[]One score per criterion, in criteria order. Range depends on `style`: harvey 0–4 (0 empty ring … 4 full ball), check 0/1 (1 draws a tick), dots 0–5 (filled dots). null leaves a cell blank (drawn as a muted dash). Values outside the style's range are clamped with a warning; a shorter array leaves the remaining cells blank, a longer one is truncated.
max 8 items · default []
highlightbooleanTint this row and tag it "Recommended". Use it on the option you are recommending (normally just one). Default false.
default false
notesstringOptional short comment shown in the Notes column on the right (wrapped to two lines, up to 160 characters). See the top-level `notes` field for when that column appears.
max 160 chars
colorstringOptional hex colour for this row's balls, ticks or dots, e.g. "#10b981". Default: the first palette colour (or dark slate if that colour is too light to read).
max 40 chars

Endpoints

  • POST /api/render/harvey returns image/png; add ?format=svg for SVG.
  • GET /harvey.png?d=<payload> and /harvey.svg?d=<payload> render a chart from a link. The payload is the JSON body, raw-deflated and base64url-encoded. Nothing is stored: links are permanent and cached for a year.
  • /harvey#d=<payload> opens the same chart in the builder for editing.
  • GET /api/render/harvey?demo=1 returns the demo chart.
  • GET /api/schema/harvey returns the JSON Schema, for code generators and AIs.

Errors and adjustments

Input is lenient where the intent is clear: numeric strings become numbers, out-of-range values are clamped, and unknown fields are ignored. Adjustments are listed in the X-Render-Warnings header. Anything unclear returns a 400 that says how to fix it:

{
  "error": "Invalid payload",
  "issues": [{ "path": "tasks", "message": "must be an array" }],
  "example": { … }
}

Calling from an AI assistant?

Use the hosted MCP server instead. It gives Claude, Cursor and other MCP clients a create_harvey_matrix tool that returns the image plus image, SVG and edit links. See the MCP page →