Template gallery / slide
slide
A single 1920x1080 slide for social posts, thumbnails and carousels. Same layouts as slide-deck minus chart — title, section, bullets, two-column, image, quote, closing — on the Satori fast path: flexbox subset, inline styles, bundled Inter, no network at render time.
satori default PNG 20 top-level fields 1 unit
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 |
|---|---|---|---|
| layout | "title" | "section" | "bullets" | "two-column" | "image" | "quote" | "closing" | required | Which layout renders the slide. `chart` is not available on the Satori fast path — use `slide-deck`, or pass a pre-rendered chart to the `image` layout. |
| title | string | optional | The headline. |
| subtitle | string | optional | `title` layout: the standfirst under the headline. |
| eyebrow | string | optional | Small label next to the accent tick at the top of the slide. |
| number | string | optional | `section` layout: the oversized part number behind the headline. |
| lead | string | optional | One-sentence standfirst under the headline. |
| bullets | array of string | object | optional | `bullets` layout. Plain strings, or objects with a supporting `detail` line. The list steps down a size as it gets heavier so it always lands inside the frame. |
| columns | array of object { heading, body, bullets } | optional | `two-column` layout: exactly two entries, left then right. |
| image | string | optional | `image` layout: an https URL inlined through the SSRF-safe fetcher, or a `data:` URI. Satori cannot fetch at render time, so the image is resolved before the slide is drawn. |
| image_fit | "cover" | "contain" | optional | How the image fills its frame. |
| full_bleed | boolean | optional | `image` layout: run the image to all four edges and set the eyebrow, title and caption over a scrim at the bottom. |
| caption | string | optional | `image` layout: the small muted line under the frame, or inside the scrim when full bleed. |
| quote | string | optional | `quote` layout: the pull quote itself, without surrounding quotation marks. |
| attribution | string | optional | `quote` layout: who said it. |
| role | string | optional | `quote` layout: their title or the source. |
| links | array of object { label, value } | optional | `closing` layout: a row of label and value pairs. |
| footer | string | optional | Bottom-left running line. |
| badge | string | optional | Bottom-right line, set in the accent colour. Carousel position, a date, a hashtag. |
| theme | object { mode, accent, background, font_pairing } | optional | Satori ships Inter only, so `font_pairing` changes weight and letterspacing rather than the family. |
| notes | string | optional | Speaker notes. Kept with the slide, never rendered into the image. |
Default render options
Applied unless you override them. Options are part of the cache key.
| width | 1920 |
| height | 1080 |
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.
{
"layout": "bullets",
"eyebrow": "Galley Render",
"title": "Five things a render has to be",
"lead": "Anything less and your 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 you set."
}
],
"footer": "galleyrender.com",
"badge": "1 / 5",
"theme": {
"mode": "dark",
"accent": "#2dd4bf",
"font_pairing": "sans"
},
"notes": "Opening card of the launch carousel. The next four cards each expand one line."
} Render it
curl -sS https://api.galleyrender.com/v1/render \
-H "Authorization: Bearer $GALLEY_API_KEY" \
-H 'content-type: application/json' \
-d '{
"template": "slide@1",
"format": "png",
"data": {
"layout": "bullets",
"eyebrow": "Galley Render",
"title": "Five things a render has to be",
"lead": "Anything less and your 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 you set."
}
],
"footer": "galleyrender.com",
"badge": "1 / 5",
"theme": {
"mode": "dark",
"accent": "#2dd4bf",
"font_pairing": "sans"
},
"notes": "Opening card of the launch carousel. The next four cards each expand one line."
}
}' # 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",
"format": "png",
"data": { … see the example payload above … }
}
}
}'
Pin the version — slide@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 (20 top-level properties)
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "Slide",
"description": "One 16:9 slide as a 1920x1080 PNG. The fields match a single entry of `slide-deck`'s `slides` array, so a slide can be lifted straight out of a deck and posted on its own.",
"type": "object",
"required": [
"layout"
],
"additionalProperties": true,
"properties": {
"layout": {
"type": "string",
"description": "Which layout renders the slide. `chart` is not available on the Satori fast path — use `slide-deck`, or pass a pre-rendered chart to the `image` layout.",
"enum": [
"title",
"section",
"bullets",
"two-column",
"image",
"quote",
"closing"
],
"default": "bullets"
},
"title": {
"type": "string",
"maxLength": 200,
"description": "The headline.",
"examples": [
"Five things a render has to be"
]
},
"subtitle": {
"type": "string",
"maxLength": 240,
"description": "`title` layout: the standfirst under the headline.",
"examples": [
"Documents for agents. JSON in, PDF out."
]
},
"eyebrow": {
"type": "string",
"maxLength": 60,
"description": "Small label next to the accent tick at the top of the slide.",
"examples": [
"Galley Render"
]
},
"number": {
"type": "string",
"maxLength": 8,
"description": "`section` layout: the oversized part number behind the headline.",
"examples": [
"02"
]
},
"lead": {
"type": "string",
"maxLength": 400,
"description": "One-sentence standfirst under the headline.",
"examples": [
"Anything less and the agent is back to gluing a headless browser together."
]
},
"bullets": {
"type": "array",
"description": "`bullets` layout. Plain strings, or objects with a supporting `detail` line. The list steps down a size as it gets heavier so it always lands inside the frame.",
"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": [
"Deterministic"
]
},
"detail": {
"type": "string",
"description": "Supporting line under the bullet, set smaller and muted.",
"examples": [
"The cache key hashes template version, data and options."
]
}
}
}
},
"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": 400,
"description": "Paragraph of body copy for the column.",
"examples": [
"A pooled headless browser for anything that has to paginate or print."
]
},
"bullets": {
"type": "array",
"description": "Points inside the column. Detail lines are not shown in the column layout.",
"maxItems": 5,
"items": {
"type": [
"string",
"object"
],
"description": "A bullet: either the string itself or `{ text }`.",
"additionalProperties": true,
"properties": {
"text": {
"type": "string",
"description": "The bullet.",
"examples": [
"PDF, PNG, JPG, WebP"
]
}
}
}
}
}
}
},
"image": {
"type": "string",
"description": "`image` layout: an https URL inlined through the SSRF-safe fetcher, or a `data:` URI. Satori cannot fetch at render time, so the image is resolved before the slide is drawn.",
"examples": [
"https://example.com/screenshot.png",
"data:image/svg+xml;base64,PHN2Zy8+"
]
},
"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 eyebrow, title and caption over a scrim at the bottom.",
"default": false
},
"caption": {
"type": "string",
"maxLength": 300,
"description": "`image` layout: the small muted line under the frame, or inside the scrim when full bleed.",
"examples": [
"Rendered by Galley, 1920x1080, in about 40 ms."
]
},
"quote": {
"type": "string",
"maxLength": 300,
"description": "`quote` layout: the pull quote itself, without surrounding quotation marks.",
"examples": [
"Documents for agents. JSON in, PDF out."
]
},
"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.",
"examples": [
"Product thesis, 2026"
]
},
"links": {
"type": "array",
"description": "`closing` layout: a row of label and value pairs.",
"maxItems": 3,
"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"
]
}
}
}
},
"footer": {
"type": "string",
"maxLength": 80,
"description": "Bottom-left running line.",
"default": "galleyrender.com"
},
"badge": {
"type": "string",
"maxLength": 40,
"description": "Bottom-right line, set in the accent colour. Carousel position, a date, a hashtag.",
"examples": [
"1 / 5"
]
},
"theme": {
"type": "object",
"description": "Satori ships Inter only, so `font_pairing` changes weight and letterspacing rather than the family.",
"additionalProperties": true,
"properties": {
"mode": {
"type": "string",
"description": "Dark ground or light ground. The default accent changes with it.",
"enum": [
"dark",
"light"
],
"default": "dark"
},
"accent": {
"type": "string",
"description": "Accent colour as a CSS colour. Defaults to #2dd4bf on dark, #0f766e on light.",
"examples": [
"#2dd4bf",
"#0f766e",
"#f59e0b"
]
},
"background": {
"type": "string",
"description": "Overrides the ground colour for the chosen mode.",
"examples": [
"#0b0f14",
"#ffffff"
]
},
"font_pairing": {
"type": "string",
"description": "Headline treatment: `sans` is bold and tightly tracked, `serif` is light and airy, `mono` is semibold with neutral tracking.",
"enum": [
"sans",
"serif",
"mono"
],
"default": "sans"
}
}
},
"notes": {
"type": "string",
"maxLength": 4000,
"description": "Speaker notes. Kept with the slide, never rendered into the image.",
"examples": [
"Post this one first — it is the hook for the thread."
]
}
}
}