Template gallery / report-table
report-table
Multi-page report body: an intro block, then one or more sections of data tables. Column headers repeat on every page, rows never split across a break, and a section can be forced to start on a new page.
chromium default PDF 9 top-level fields 1 unit per page
Fields
The full JSON Schema is below. Required fields are marked; anything missing comes back as a 422 naming the path, the expected type and a value that would be accepted.
| Field | Type | Required | Description |
|---|---|---|---|
| title | string | required | |
| standfirst | string | optional | One paragraph under the title. |
| organization | string | required | Printed in the running head. |
| reference | string | optional | |
| period | string | optional | |
| issued_on | string (date) | optional | |
| accent | string | optional | |
| kpis | array of object { label, value, delta, direction } | optional | Headline figures across the top. Four fit comfortably. |
| sections | array of object { title, eyebrow, intro, start_on_new_page, … } | required |
Default render options
Applied unless you override them. Options are part of the cache key.
| page_size | "Letter" |
| margin | "0.6in" |
| print_background | true |
Example payload
This exact object renders the preview above. It is also what the API echoes back in a validation error, so an agent can repair a payload without a round trip to the docs.
{
"title": "Render Reliability Review",
"standfirst": "Across 14.2 million renders in Q3, p95 latency fell 31% while the failure rate held at 0.17%. The tail is now dominated by multi-page PDFs, and one region is inside its capacity margin.",
"organization": "Galley Render",
"reference": "ENG-RPT-0031",
"period": "Q3 2026",
"issued_on": "2026-09-16",
"accent": "#0f766e",
"kpis": [
{
"label": "Renders",
"value": "14.2M",
"delta": "+18% vs Q2",
"direction": "up"
},
{
"label": "p95 latency",
"value": "1.41s",
"delta": "−31% vs Q2",
"direction": "up"
},
{
"label": "Failure rate",
"value": "0.17%",
"delta": "−0.06pp vs Q2",
"direction": "up"
},
{
"label": "Cache hit rate",
"value": "41.8%",
"delta": "−2.1pp vs Q2",
"direction": "down"
}
],
"sections": [
{
"eyebrow": "Section 3",
"title": "Latency by template class",
"intro": "Wall time from job pickup to bytes written, excluding queue wait. Percentiles are computed per class over the full quarter.",
"columns": [
{
"label": "Template class",
"width": "2.1in"
},
{
"label": "Renders",
"align": "right"
},
{
"label": "p50",
"align": "right"
},
{
"label": "p95",
"align": "right"
},
{
"label": "p99",
"align": "right"
},
{
"label": "Δ p95 vs Q2",
"align": "right"
}
],
"rows": [
{
"group": "Chromium — PDF"
},
{
"cells": [
"Invoice",
"3,104,882",
"0.74s",
"1.61s",
"3.20s",
"−28%"
]
},
{
"cells": [
"Quote / estimate",
"902,441",
"0.81s",
"1.78s",
"3.55s",
"−24%"
]
},
{
"cells": [
"Statement (multi-page)",
"511,209",
"1.42s",
"3.90s",
"8.10s",
"−12%"
]
},
{
"cells": [
"Purchase order",
"388,020",
"0.77s",
"1.70s",
"3.31s",
"−26%"
]
},
{
"cells": [
"Report, cover + tables",
"166,904",
"1.88s",
"5.20s",
"11.40s",
"+4%"
],
"emphasis": "negative"
},
{
"cells": [
"Packing slip",
"240,118",
"0.62s",
"1.34s",
"2.70s",
"−31%"
]
},
{
"cells": [
"Letter on letterhead",
"198,655",
"0.58s",
"1.22s",
"2.41s",
"−33%"
]
},
{
"group": "Chromium — PNG"
},
{
"cells": [
"Event ticket",
"1,022,760",
"0.41s",
"0.92s",
"1.84s",
"−38%"
]
},
{
"cells": [
"Badge",
"744,318",
"0.38s",
"0.85s",
"1.70s",
"−40%"
]
},
{
"cells": [
"Shipping label",
"1,488,902",
"0.36s",
"0.79s",
"1.58s",
"−41%"
]
},
{
"group": "Satori — PNG fast path"
},
{
"cells": [
"OG card",
"4,010,552",
"0.021s",
"0.048s",
"0.092s",
"−9%"
]
},
{
"cells": [
"Social quote card",
"1,439,119",
"0.024s",
"0.055s",
"0.101s",
"−7%"
]
}
],
"total_row": [
"All classes",
"14,213,880",
"0.44s",
"1.41s",
"3.62s",
"−31%"
],
"caption": "Table 3.1 — Latency percentiles by template class, Q3 2026.",
"body": "Chromium PDF renders dominate the tail. The report template is the only class that moved the wrong way; the cause is the appendix tables, which now average 640 rows and force a full relayout on every page break."
},
{
"eyebrow": "Section 4",
"title": "Failure modes and their causes",
"start_on_new_page": true,
"intro": "24,681 failed renders out of 14.2 million. Every failure returns a structured error with the field path and an example value, so an agent can retry without a human.",
"columns": [
{
"label": "Failure mode",
"width": "2.3in"
},
{
"label": "Count",
"align": "right"
},
{
"label": "Share",
"align": "right"
},
{
"label": "Root cause"
},
{
"label": "Status",
"align": "right"
}
],
"rows": [
{
"cells": [
"Asset fetch blocked",
"9,411",
"38.2%",
"Template referenced a private-range host",
"Working as designed"
]
},
{
"cells": [
"Page timeout",
"6,022",
"24.4%",
"Webfont stall on a third-party CDN",
"Mitigated in 0.9.4"
]
},
{
"cells": [
"Liquid parse error",
"4,880",
"19.8%",
"Customer template pushed without validation",
"Open"
],
"emphasis": "negative"
},
{
"cells": [
"Satori unsupported CSS",
"2,104",
"8.5%",
"Grid or float used on the fast path",
"Doc fix shipped"
]
},
{
"cells": [
"Chromium OOM",
"1,190",
"4.8%",
"Single render with 2,400 table rows",
"Open"
],
"emphasis": "negative"
},
{
"cells": [
"Storage write failure",
"604",
"2.4%",
"R2 throttling during backfill",
"Closed"
]
},
{
"cells": [
"Schema validation reject",
"470",
"1.9%",
"Agent sent a string where a number was required",
"Working as designed"
]
}
],
"total_row": [
"All modes",
"24,681",
"100%",
"",
"0.17% of renders"
],
"caption": "Table 4.1 — Failure modes ranked by count.",
"body": "The two open items are both customer-authored template problems rather than platform faults. Parse errors drop to near z… [249 characters, shortened for display]"
},
{
"eyebrow": "Section 5",
"title": "Capacity headroom and scaling plan",
"start_on_new_page": true,
"intro": "Headroom is peak concurrency against pool size over a trailing 14-day window. Anything under 25% is inside the margin we hold for a regional failover.",
"columns": [
{
"label": "Region",
"width": "1.6in"
},
{
"label": "Pool size",
"align": "right"
},
{
"label": "Peak concurrency",
"align": "right"
},
{
"label": "Headroom",
"align": "right"
},
{
"label": "Action",
"width": "2.1in"
}
],
"rows": [
{
"cells": [
"us-east (Ohio)",
"24",
"19.4",
"19%",
"Add 8 workers before Nov 1"
],
"emphasis": "negative"
},
{
"cells": [
"us-west (Oregon)",
"12",
"6.1",
"49%",
"Hold"
]
},
{
"cells": [
"eu-central (Frankfurt)",
"16",
"11.8",
"26%",
"Add 4 workers in Q4"
]
},
{
"cells": [
"ap-southeast (Singapore)",
"8",
"3.2",
"60%",
"Hold"
]
},
{
"cells": [
"Cloudflare overflow",
"—",
"4.9",
"n/a",
"Keep as burst only"
]
}
],
"caption": "Table 5.1 — Pool utilisation and planned action by region.",
"body": "us-east is the binding constraint. Eight additional workers cover the projected Q4 load including the November invoice peak, and cost roughly $340 per month at current instance pricing."
}
]
}
Values longer than 240 characters — data URIs, inline SVG — are shortened here so the
shape of the payload stays readable, and the replacement says how much was left out.
get_template and GET /v1/templates/:ref return them in full.
Render it
curl -sS https://api.galleyrender.com/v1/render \
-H "Authorization: Bearer $GALLEY_API_KEY" \
-H 'content-type: application/json' \
-d '{
"template": "report-table@1",
"format": "pdf",
"data": "… the example payload above …"
}' # No API key. The first call mints a 50-render trial.
curl -sS https://mcp.galleyrender.com/mcp \
-H 'content-type: application/json' \
-H 'accept: application/json, text/event-stream' \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "render",
"arguments": {
"template": "report-table",
"format": "pdf",
"data": { … see the example payload above … }
}
}
}'
Pin the version — report-table@1 — in anything you ship. Publishing a new
version never changes an old one. Render endpoint reference →
Renders the example payload on the production service. No account, no key.
JSON Schema
schema.json (9 top-level properties)
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "Report table pages",
"type": "object",
"required": [
"title",
"organization",
"sections"
],
"additionalProperties": true,
"properties": {
"title": {
"type": "string",
"examples": [
"Render Reliability Review"
]
},
"standfirst": {
"type": "string",
"description": "One paragraph under the title.",
"examples": [
"Across 14.2 million renders in Q3, p95 latency fell 31% while the failure rate held under 0.2%."
]
},
"organization": {
"type": "string",
"description": "Printed in the running head.",
"examples": [
"Galley Render"
]
},
"reference": {
"type": "string",
"examples": [
"ENG-RPT-0031"
]
},
"period": {
"type": "string",
"examples": [
"Q3 2026"
]
},
"issued_on": {
"type": "string",
"format": "date",
"examples": [
"2026-09-16"
]
},
"accent": {
"type": "string",
"examples": [
"#0f766e"
]
},
"kpis": {
"type": "array",
"description": "Headline figures across the top. Four fit comfortably.",
"items": {
"type": "object",
"required": [
"label",
"value"
],
"properties": {
"label": {
"type": "string",
"examples": [
"Renders"
]
},
"value": {
"type": "string",
"examples": [
"14.2M"
]
},
"delta": {
"type": "string",
"examples": [
"+18% vs Q2"
]
},
"direction": {
"type": "string",
"enum": [
"up",
"down"
],
"default": "up",
"description": "Colours the delta green or red.",
"examples": [
"up"
]
}
}
}
},
"sections": {
"type": "array",
"minItems": 1,
"items": {
"type": "object",
"required": [
"title"
],
"properties": {
"title": {
"type": "string",
"examples": [
"Latency by template class"
]
},
"eyebrow": {
"type": "string",
"default": "Section",
"examples": [
"Section 3"
]
},
"intro": {
"type": "string",
"examples": [
"Wall time from job pickup to bytes written, excluding queue wait."
]
},
"start_on_new_page": {
"type": "boolean",
"default": false,
"description": "Force a page break before this section.",
"examples": [
true
]
},
"caption": {
"type": "string",
"examples": [
"Table 3.1 — Latency percentiles by template class, Q3 2026."
]
},
"body": {
"type": "string",
"examples": [
"Chromium PDF renders dominate the tail; the Satori path is effectively flat."
]
},
"columns": {
"type": "array",
"description": "Column definitions. `cells` in each row are positional and must line up with these.",
"items": {
"type": "object",
"required": [
"label"
],
"properties": {
"label": {
"type": "string",
"examples": [
"Template class"
]
},
"align": {
"type": "string",
"enum": [
"left",
"right"
],
"default": "left",
"examples": [
"right"
]
},
"width": {
"type": "string",
"description": "Any CSS width.",
"examples": [
"1.2in"
]
}
}
}
},
"rows": {
"type": "array",
"items": {
"type": "object",
"properties": {
"cells": {
"type": "array",
"description": "One string per column, in order.",
"items": {
"type": "string",
"examples": [
"Invoice"
]
},
"examples": [
[
"Invoice",
"412",
"0.9s"
]
]
},
"group": {
"type": "string",
"description": "Renders a full-width subheading row instead of cells.",
"examples": [
"Chromium — PDF"
]
},
"emphasis": {
"type": "string",
"enum": [
"positive",
"negative"
],
"description": "Colours the row's text.",
"examples": [
"negative"
]
}
}
}
},
"total_row": {
"type": "array",
"description": "Positional cells for a bold footer row.",
"items": {
"type": "string",
"examples": [
"All classes"
]
},
"examples": [
[
"All classes",
"14,213,880",
"1.4s"
]
]
}
}
}
}
}
}