Template gallery / slide-deck

slide-deck

16:9 presentation deck, one slide per PDF page at 13.333in x 7.5in. Each slide picks a layout — title, section, bullets, two-column, image, chart, quote, closing — and the deck carries a theme of one accent colour plus a font pairing. Speaker notes live in the schema and never render.

chromium default PDF 2 top-level fields 1 unit per page

Rendered preview of the slide-deck template
Rendered by Galley from the example payload below, at 1280px wide , scale 2.

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
deck object { title, subtitle, author, date, … } required Deck-level metadata: the cover credits, the running footer and the theme.
slides array of object { layout, title, subtitle, eyebrow, … } required One slide per PDF page, in order.

Default render options

Applied unless you override them. Options are part of the cache key.

margin "0"
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.

example.jsonjson
{
  "deck": {
    "title": "Galley Render",
    "subtitle": "Documents for agents. JSON in, PDF out.",
    "author": "galleyrender.com",
    "date": "September 2026",
    "footer": "Galley Render — the short version",
    "theme": {
      "accent": "#0f766e",
      "font_pairing": "sans"
    }
  },
  "slides": [
    {
      "layout": "title",
      "eyebrow": "Rendering API",
      "notes": "Thirty seconds on the one-liner, then straight to the problem. Do not demo yet."
    },
    {
      "layout": "section",
      "eyebrow": "01",
      "title": "Agents cannot hand you the file",
      "lead": "They will draft the invoice, the certificate and the report, then stop one step short of the thing you asked for.",
      "notes": "This is the whole wedge. Say it once, plainly, and move on."
    },
    {
      "layout": "bullets",
      "eyebrow": "What the job actually needs",
      "title": "Five things a render has to be",
      "lead": "Anything less and the agent is back to gluing a headless browser together.",
      "bullets": [
        {
          "text": "Deterministic",
          "detail": "The cache key hashes template version, data and options. Same request, same bytes."
        },
        {
          "text": "Schema-first",
          "detail": "A bad payload comes back as a field path, an expected type and an example value."
        },
        {
          "text": "Versioned",
          "detail": "Templates are code: create, diff, tag, roll back. Pin invoice@3 in anything you ship."
        },
        {
          "text": "Delivered",
          "detail": "Signed URLs with an expiry, push to R2, S3 or GCS, webhooks on completion."
        },
        {
          "text": "Cheap enough to call in a loop",
          "detail": "Priced per render, not per seat, under a spend cap the account owner sets."
        }
      ],
      "notes": "Land 'schema-first' — it is the one competitors have no answer to."
    },
    {
      "layout": "two-column",
      "eyebrow": "Architecture",
      "title": "Two engines, one API",
      "lead": "The template declares which path it takes. The call is identical either way.",
      "columns": [
        {
          "heading": "Chromium",
          "body": "A pooled headless browser for anything that has to paginate or print.",
          "bullets": [
            {
              "text": "Full HTML and CSS",
              "detail": "Print stylesheets, repeating table headers, controlled page breaks."
            },
            {
              "text": "PDF, PNG, JPG, WebP"
            },
            {
              "text": "Every subresource through an SSRF-safe fetcher"
            }
          ]
        },
        {
          "heading": "Satori fast path",
          "body": "A flexbox subset compiled straight to SVG, then to PNG. No browser process.",
          "bullets": [
            {
              "text": "Card-shaped templates",
              "detail": "OG images, quote cards, social slides, tickets, badges."
            },
            {
              "text": "Roughly two orders of magnitude cheaper"
            },
            {
              "text": "Bundled fonts, no network at render time"
            }
          ]
        }
      ],
      "notes": "If someone asks about PPTX: v2, gated on paying demand."
    },
    {
      "layout": "image",
      "eyebrow": "The request path",
      "title": "From tool call to signed URL",
      "image": "data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMTA0MCA0MjAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgZm9udC1mYW… [4,282 characters, shortened for display]",
      "image_fit": "contain",
      "alt": "An agent calls render; the payload is validated against the template schema, routed to the Chromium pool or the Satori fast path, and returned as a signed URL",
      "caption": "A cache hit skips the renderer entirely and is billed to nobody.",
      "notes": "Point at the validate box. That is the part that makes agents succeed on the first try."
    },
    {
      "layout": "chart",
      "eyebrow": "Pricing",
      "title": "The price floor is public now",
      "svg": "<svg viewBox=\"0 0 1000 330\" xmlns=\"http://www.w3.org/2000/svg\" font-family=\"Inter, Helvetica, Arial, sans-serif\"><line x… [1,976 characters, shortened for display]",
      "legend": [
        {
          "label": "Designer-first incumbents",
          "color": "#cbd5e1"
        },
        {
          "label": "Galley, Starter plan",
          "color": "#0f766e"
        },
        {
          "label": "Underlying compute",
          "color": "#5eead4"
        }
      ],
      "caption": "Incumbent list prices, Galley's $19/mo Starter plan at its included volume, and the measured compute cost of a render.",
      "notes": "Do not oversell the margin story. The point is that the floor is public now."
    },
    {
      "layout": "quote",
      "quote": "Documents for agents. JSON in, PDF out. Every render deterministic, cached, and signed.",
      "attribution": "Galley Render",
      "role": "The positioning line, and the whole product in one sentence",
      "notes": "Pause here. Let it sit before the close."
    },
    {
      "layout": "closing",
      "eyebrow": "Try it",
      "title": "50 renders. No key, no signup.",
      "lead": "The first render with no API key mints a trial account and returns its token. Upgrade in place when you outgrow it.",
      "links": [
        {
          "label": "Docs",
          "value": "galleyrender.com/docs"
        },
        {
          "label": "MCP",
          "value": "mcp.galleyrender.com"
        },
        {
          "label": "Claude skill",
          "value": "galleyrender.com/skill.md"
        }
      ],
      "notes": "End on the keyless trial. It is the thing people repeat to someone else."
    }
  ]
}

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

With an API keyshell
curl -sS https://api.galleyrender.com/v1/render \
  -H "Authorization: Bearer $GALLEY_API_KEY" \
  -H 'content-type: application/json' \
  -d '{
  "template": "slide-deck@1",
  "format": "pdf",
  "data": "… the example payload above …"
}'
With no API key, over MCPshell
# 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": "slide-deck",
        "format": "pdf",
        "data": { … see the example payload above … }
      }
    }
  }'

Pin the version — slide-deck@1 — in anything you ship. Publishing a new version never changes an old one. Render endpoint reference →

Try a free tool

Renders the example payload on the production service. No account, no key.

JSON Schema

schema.json (2 top-level properties)
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "title": "Slide deck",
  "description": "A 16:9 presentation. `deck` sets the running title, the cover credits and the theme; every entry in `slides` is one page of the PDF and picks its own layout.",
  "type": "object",
  "required": [
    "deck",
    "slides"
  ],
  "additionalProperties": true,
  "properties": {
    "deck": {
      "type": "object",
      "description": "Deck-level metadata: the cover credits, the running footer and the theme.",
      "required": [
        "title"
      ],
      "additionalProperties": true,
      "properties": {
        "title": {
          "type": "string",
          "minLength": 1,
          "maxLength": 120,
          "description": "Cover headline, and the running footer on every other slide unless `footer` overrides it.",
          "examples": [
            "Galley Render"
          ]
        },
        "subtitle": {
          "type": "string",
          "maxLength": 240,
          "description": "Standfirst under the cover headline.",
          "examples": [
            "Documents for agents. JSON in, PDF out."
          ]
        },
        "author": {
          "type": "string",
          "maxLength": 120,
          "description": "Credit line on the cover slide.",
          "examples": [
            "Galley Render"
          ]
        },
        "date": {
          "type": "string",
          "maxLength": 60,
          "description": "Shown next to the author on the cover. Free text, so \"Q4 2026\" is as valid as a date.",
          "examples": [
            "September 2026"
          ]
        },
        "footer": {
          "type": "string",
          "maxLength": 120,
          "description": "Running footer text. Defaults to `deck.title`.",
          "examples": [
            "Galley Render — investor update"
          ]
        },
        "theme": {
          "type": "object",
          "description": "Two knobs. Every tint in the deck is mixed from the accent, so one hex restyles the whole thing.",
          "additionalProperties": true,
          "properties": {
            "accent": {
              "type": "string",
              "description": "Accent colour as a CSS colour. Rules, bullet markers, section numbers and link labels are derived from it.",
              "default": "#0f766e",
              "examples": [
                "#0f766e",
                "#1d4ed8",
                "#b45309"
              ]
            },
            "font_pairing": {
              "type": "string",
              "description": "Display face for headings; body copy is always Inter. `sans` is Inter throughout, `serif` sets headings in an old-style serif, `mono` sets headings and labels in the system monospace.",
              "enum": [
                "sans",
                "serif",
                "mono"
              ],
              "default": "sans"
            }
          }
        }
      }
    },
    "slides": {
      "type": "array",
      "description": "One slide per PDF page, in order.",
      "minItems": 1,
      "maxItems": 200,
      "items": {
        "type": "object",
        "required": [
          "layout"
        ],
        "additionalProperties": true,
        "properties": {
          "layout": {
            "type": "string",
            "description": "Which layout renders this slide. `title`, `section` and `closing` are set on a dark ground; `quote` sits on an accent wash; the rest are on white.",
            "enum": [
              "title",
              "section",
              "bullets",
              "two-column",
              "image",
              "chart",
              "quote",
              "closing"
            ],
            "default": "bullets"
          },
          "title": {
            "type": "string",
            "maxLength": 200,
            "description": "Slide headline. On `title` it defaults to `deck.title`; on `image` it may be omitted for a clean full-bleed frame.",
            "examples": [
              "Two engines, one API"
            ]
          },
          "subtitle": {
            "type": "string",
            "maxLength": 240,
            "description": "`title` layout only: overrides `deck.subtitle` on the cover.",
            "examples": [
              "Documents for agents. JSON in, PDF out."
            ]
          },
          "eyebrow": {
            "type": "string",
            "maxLength": 60,
            "description": "Small label above the headline. On `section` it is set large as the part number, e.g. \"02\".",
            "examples": [
              "02",
              "The wedge"
            ]
          },
          "lead": {
            "type": "string",
            "maxLength": 400,
            "description": "One-sentence standfirst under the headline.",
            "examples": [
              "Every render is deterministic, cached and signed."
            ]
          },
          "bullets": {
            "type": "array",
            "description": "`bullets` layout. Plain strings, or objects with a supporting `detail` line. Six or more steps the type down a size so nothing falls off the slide.",
            "maxItems": 12,
            "items": {
              "type": [
                "string",
                "object"
              ],
              "description": "A bullet: either the string itself or `{ text, detail }`.",
              "additionalProperties": true,
              "properties": {
                "text": {
                  "type": "string",
                  "description": "The bullet.",
                  "examples": [
                    "Deterministic cache key"
                  ]
                },
                "detail": {
                  "type": "string",
                  "description": "Supporting line under the bullet, set smaller and muted.",
                  "examples": [
                    "Hash of template version + data + options. Cache hits are free."
                  ]
                }
              }
            }
          },
          "columns": {
            "type": "array",
            "description": "`two-column` layout: exactly two entries, left then right.",
            "maxItems": 2,
            "items": {
              "type": "object",
              "additionalProperties": true,
              "properties": {
                "heading": {
                  "type": "string",
                  "maxLength": 80,
                  "description": "Small accent label at the top of the column.",
                  "examples": [
                    "Chromium"
                  ]
                },
                "body": {
                  "type": "string",
                  "maxLength": 600,
                  "description": "Paragraph of body copy for the column.",
                  "examples": [
                    "Full HTML and CSS, print stylesheets, page breaks, PDF or raster."
                  ]
                },
                "bullets": {
                  "type": "array",
                  "description": "Points inside the column. Same shape as slide bullets.",
                  "maxItems": 8,
                  "items": {
                    "type": [
                      "string",
                      "object"
                    ],
                    "description": "A bullet: either the string itself or `{ text, detail }`.",
                    "additionalProperties": true,
                    "properties": {
                      "text": {
                        "type": "string",
                        "description": "The bullet.",
                        "examples": [
                          "Multi-page PDF"
                        ]
                      },
                      "detail": {
                        "type": "string",
                        "description": "Supporting line under the bullet.",
                        "examples": [
                          "Repeating table headers, controlled breaks."
                        ]
                      }
                    }
                  }
                }
              }
            }
          },
          "image": {
            "type": "string",
            "description": "`image` layout: an https URL fetched through the SSRF-safe fetcher, or an inline `data:` URI.",
            "examples": [
              "https://example.com/architecture.png",
              "data:image/svg+xml;base64,PHN2Zy8+"
            ]
          },
          "alt": {
            "type": "string",
            "maxLength": 200,
            "description": "Alternative text for the image. Defaults to the slide title.",
            "examples": [
              "Request path from MCP tool call to signed URL"
            ]
          },
          "image_fit": {
            "type": "string",
            "description": "How the image fills its frame.",
            "enum": [
              "cover",
              "contain"
            ],
            "default": "cover"
          },
          "full_bleed": {
            "type": "boolean",
            "description": "`image` layout: run the image to all four edges and set the title and caption over a scrim.",
            "default": false
          },
          "svg": {
            "type": "string",
            "description": "`chart` layout: a ready-made SVG string, dropped in unescaped and scaled to the plot area. Give it a `viewBox` and no fixed width or height.",
            "examples": [
              "<svg viewBox=\"0 0 800 360\" xmlns=\"http://www.w3.org/2000/svg\"><rect x=\"0\" y=\"300\" width=\"60\" height=\"60\" fill=\"#0f766e\"/></svg>"
            ]
          },
          "legend": {
            "type": "array",
            "description": "`chart` layout: swatch and label pairs under the plot.",
            "maxItems": 8,
            "items": {
              "type": "object",
              "additionalProperties": true,
              "properties": {
                "label": {
                  "type": "string",
                  "description": "Series name.",
                  "examples": [
                    "Chromium renders"
                  ]
                },
                "color": {
                  "type": "string",
                  "description": "Swatch colour. Defaults to the deck accent.",
                  "examples": [
                    "#0f766e"
                  ]
                }
              }
            }
          },
          "quote": {
            "type": "string",
            "maxLength": 400,
            "description": "`quote` layout: the pull quote itself, without surrounding quotation marks.",
            "examples": [
              "Every agent that can write a document should be able to hand you the file."
            ]
          },
          "attribution": {
            "type": "string",
            "maxLength": 120,
            "description": "`quote` layout: who said it.",
            "examples": [
              "Galley Render"
            ]
          },
          "role": {
            "type": "string",
            "maxLength": 160,
            "description": "`quote` layout: their title or the source, set under the attribution.",
            "examples": [
              "Product thesis, 2026"
            ]
          },
          "links": {
            "type": "array",
            "description": "`closing` layout: a row of label and value pairs — docs, install line, contact.",
            "maxItems": 4,
            "items": {
              "type": "object",
              "additionalProperties": true,
              "properties": {
                "label": {
                  "type": "string",
                  "maxLength": 40,
                  "description": "Small accent label.",
                  "examples": [
                    "Docs"
                  ]
                },
                "value": {
                  "type": "string",
                  "maxLength": 120,
                  "description": "The thing itself: a URL, an address, a command.",
                  "examples": [
                    "galleyrender.com/docs"
                  ]
                }
              }
            }
          },
          "caption": {
            "type": "string",
            "maxLength": 300,
            "description": "Small muted line under the image, chart or columns. Sources and footnotes go here.",
            "examples": [
              "Source: platform metrics, Oct 2025 – Sep 2026."
            ]
          },
          "notes": {
            "type": "string",
            "maxLength": 4000,
            "description": "Speaker notes. Kept with the deck, never rendered into the PDF.",
            "examples": [
              "Land the cost line here, then move on — the demo is the next slide."
            ]
          }
        }
      }
    }
  }
}