Render a Slide
Three deterministic render endpoints, each tailored to a different input shape — all $0.05 per slide, all sub-second. For multi-slide decks, see POST /v1/render/intent/deck.
Three render endpoints
POST /v1/render/auto — brief
Brief → SSG intent engine → deterministic render. ~<1s, $0.05. Bounded — never escalates. Unroutable briefs return a free intent_unroutable 422 (cost = 0).
POST /v1/render/intent — structured intent
The REST mirror of the MCP create_slide tool. Render a typed form, an exact catalog prior, or a full AuthorSSG document. $0.05 — or pass preview:true for a FREE ephemeral PNG.
POST /v1/render/code — python-pptx
Your python-pptx in a secure sandbox. Pixel-exact control. $0.05, ~0.5s. A free dry_run validates before you commit.
/v1/render/autoBrief → SSG intent engine → deterministic render. Bounded $0.05 — never escalates to a slower or more expensive engine. Charges only on a usable render; unroutable briefs return an intent_unroutable envelope at no cost.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| brief | string | required | Natural language description of the slide. The SSG intent engine routes it to a deterministic render pattern. |
| theme_id | string | optional | Theme id (default "slideforge_standard"). Built-ins via GET /v1/themes (slideforge_standard, consulting_graphite, dark_keynote, product_bold, technical_lab, education_warm, healthcare_calm, scientific_paper, sales_warm), or a saved custom theme id. |
| name | string | optional | Human-readable name for the slide. Auto-generated if omitted. |
| allow_fabrication | boolean | optional | Default false. A data brief (a form like kpi_metrics needing values) returns would_fabricate at cost 0 rather than invent numbers; set true to let the brief author them (fidelity=ai_completed). |
| allow_low_confidence | boolean | optional | Default false. A brief that doesn't match a form clearly returns needs_confirmation + candidates at cost 0; set true to render the top guess and bill it. |
| dry_run | boolean | optional | Default false. true returns a free cost:0 validation forecast (status / warnings / errors) with no job, PPTX, or billing — a pre-commit check. |
Response
{
"job_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"status": "complete",
"engine": "auto",
"cost": 0.05,
"form": "timeline_roadmap",
"fidelity": "mixed",
"latency_ms": 840
}Examples
curl -X POST https://api.slideforge.dev/v1/render/auto \
-H "Authorization: Bearer sf_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"brief": "Three priorities for Q2: stabilize cash by fixing AR aging, launch the partner onboarding flow, and hire two senior engineers.",
"theme_id": "slideforge_standard"
}'Downloading your file
Response bodies carry no download credentials. Fetch the file with GET /v1/jobs/{job_id}/pptx using your normal Bearer key (ownership-checked) — or mint a short-lived, single-use shareable link with POST /v1/jobs/{job_id}/download-url.
Brief-surface failure shape
When the brief does not ground a render pattern with confidence, /v1/render/auto returns a Problem+JSON 422 with code intent_unroutable. Nothing is charged, and remedy tells the agent what to add. A data-bearing brief (a form like kpi_metrics that needs values) returns status: "would_fabricate" (cost 0) rather than invent numbers — send the values as a typed intent (form + data) to render them verbatim, or set allow_fabrication: true to let the brief author them (fidelity: ai_completed).
{
"type": "https://docs.slideforge.dev/errors/intent_unroutable",
"title": "Intent could not be routed",
"status": 422,
"detail": "Brief is too thin to ground a form — name the metrics/comparison and the decision the slide should drive.",
"code": "intent_unroutable",
"actionable": true,
"remedy": "Supply the concrete data, or call browse_catalog(type=schema, family=<form>) for the form's data shape."
}/v1/render/intentDeterministic SSG render from a structured intent — the REST mirror of the MCP create_slide tool. Provide ONE of: form (+ typed content), prior_id (+ content) to render an exact catalog prior, author_ssg for a full document, or a prose brief. $0.05 per slide.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| form | string | optional | Intent form (e.g. kpi_metrics, comparison_matrix). Discover forms via GET /v1/catalog/forms and a form's typed-field JSON Schema via GET /v1/catalog/forms/{form}. |
| variant | string | optional | Optional variant within the form (e.g. delta_scoreboard) — pins the exact layout. See the form's contract. |
| data | object | optional | The form's typed payload (e.g. { metrics: [...] }), copied verbatim — never re-derived. Shape per GET /v1/catalog/forms/{form}. |
| headline | string | optional | Assertion-style slide title — plus context / takeaway / caution / source_note where the form binds them. |
| prior_id | string | optional | Power path: render an exact catalog prior verbatim (pair with content to fill its slots). Get prior_ids from GET /v1/catalog. |
| author_ssg | object | optional | Expert path: a full AuthorSSG scene-graph document — LLM-free, renders exactly what you specify. |
| brief | string | optional | Prose fallback. With only a brief, this behaves like /v1/render/auto. |
| theme_id | string | optional | Theme id (default "slideforge_standard"); see GET /v1/themes. |
| name | string | optional | Human-readable slide name. |
| preview | boolean | optional | Default false. true returns a FREE ephemeral PNG — no job, no charge, nothing downloadable. Eligible only for prior_id or author_ssg inputs; form/brief/image inputs return 400 (render them for $0.05). |
| dry_run | boolean | optional | Default false. true returns a free cost:0 validation forecast (status / fidelity_forecast / warnings / errors) with no job, PPTX, or billing. |
| allow_fabrication | boolean | optional | Brief mode only. Let a bare brief on a DATA form author the numbers (fidelity=ai_completed) instead of returning would_fabricate. |
| allow_low_confidence | boolean | optional | Brief mode only. Render the top route guess instead of returning needs_confirmation + candidates. |
| allow_truncation | boolean | optional | Default false. Render the capacity subset when you supply more items than a form holds (fidelity=verbatim_truncated) instead of a blocking error. |
Response
{
"job_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"status": "complete",
"engine": "auto",
"cost": 0.05,
"form": "timeline_roadmap",
"fidelity": "mixed",
"latency_ms": 840
}Examples
curl -X POST https://api.slideforge.dev/v1/render/intent \
-H "Authorization: Bearer sf_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"form": "kpi_metrics",
"variant": "delta_scoreboard",
"headline": "Q1 performance ahead of plan; AR aging needs action",
"context": "Exec committee — Q1 2026",
"data": { "metrics": [
{"label": "Revenue", "value": "$12.4M", "delta_value": "+18% YoY", "delta_tone": "good", "emphasis": "primary"},
{"label": "New clients", "value": "847", "delta_value": "+23%", "delta_tone": "good"},
{"label": "Days in AR", "value": "52", "delta_value": "+6", "delta_tone": "bad"}
]},
"theme_id": "slideforge_standard"
}'Free preview — preview: true
Pass preview: true with a verbatim input (prior_id or author_ssg) to get a free ephemeral PNG — no job is created, nothing is charged, and there is nothing to download. Use it to show quality before committing to a paid render. Briefs and images are not eligible (they need the paid engine) and return 400.
# Free ephemeral PNG — no job, no charge, nothing downloadable.
curl -X POST https://api.slideforge.dev/v1/render/intent \
-H "Authorization: Bearer sf_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"prior_id": "kpi_metrics_delta_scoreboard",
"theme_id": "slideforge_standard",
"preview": true
}'{
"preview": true,
"preview_url": "/v1/files/_ephemeral/preview-9f2a.png?sig=abc&exp=1711036800",
"engine": "intent",
"form": "kpi_metrics",
"latency_ms": 96
}Discovering forms + priors
GET /v1/catalog/forms lists every form (with its when-to-use + typed fields); GET /v1/catalog/forms/{form} returns one form's machine-readable JSON-Schema contract. GET /v1/catalog browses catalog priors (each carries a sample content and brief). The MCP browse_catalog tool is the agent-side equivalent.
/v1/render/codeRun python-pptx in a secure sandbox and get a PPTX + PNG preview. Define build(prs) — or build(prs, slide) when chrome is supplied. All python-pptx helpers plus the widget toolkit are available; dangerous imports are blocked; 30s timeout. $0.05 per render, ~0.5s.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| code | string | required | Python that defines build(prs) — or build(prs, slide) when chrome is supplied. All python-pptx helpers (add_text_box, add_box, add_icon, …) plus the widget toolkit are available. Dangerous imports are blocked; 30s timeout. Required unless job_id is given. |
| job_id | string | optional | A previous render/code job — loads its stored code so you can patch it with replacements. |
| replacements | array | optional | List of {old, new} string replacements to apply to the loaded code. Requires job_id. |
| theme_id | string | optional | Theme ID for chrome + colors. |
| chrome | object | optional | Chrome overlays: {title, subtitle, kicker, footer, source, page_number, classification}. |
| name | string | optional | Human-readable job name. |
| verify | string | optional | Verification tier: off | lint (default — static geometry linter + composer content validators, no LLM) | lint+vlm (adds a VLM second-look, ~+8s) | full. |
| dry_run | boolean | optional | Default false. When true, run the verify tier and return status:validated with warnings / errors at cost:0 and NO PPTX — a free pre-commit check. Fix errors, then render for real. |
| include_preview | string | optional | Embed preview inline: none (default), small (256px), default (512px), full. |
Response
{
"job_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"status": "complete",
"engine": "sandbox",
"warnings": [],
"cost": 0.05,
"latency_ms": 480
}Examples
curl -X POST https://api.slideforge.dev/v1/render/code \
-H "Authorization: Bearer sf_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"code": "def build(prs, slide):\n add_text_box(slide, 0.5, 0.5, 9, 1, \"Q1 Performance\", font_size=32, bold=True)\n add_box(slide, 0.5, 2, 4, 2, fill_color=\"#1E40AF\")",
"chrome": {"title": "Q1 2026 Performance", "footer": "Confidential"},
"theme_id": "slideforge_standard",
"verify": "lint"
}'Quality signal — status, warnings, errors
The verify tier returns the same diagnostic shape as the SSG path. errorsare structural bugs in your code — geometry overlaps/off-canvas and composer arithmetic (a waterfall that doesn't reconcile).warnings are cosmetic notes and any VLM visual read; they never block. A render with no errors is status: "complete" and bills $0.05; one with errors isstatus: "completed_with_errors" and is free — same usable-or-free promise as every path. Because the code is yours, we always return the rendered PPTX either way.
Free pre-commit check — dry_run: true
Pass dry_run: true to run the verify tier (static geometry linter + composer content validators) and get back status: "validated" with warnings / errors at cost: 0 and no PPTX. Fix any errors, then call again with dry_run: false to render for real.