The web server (node server.js or mdslides serve) exposes a small JSON
API used by the editor and suitable for direct agent integration. Base URL:
http://localhost:4210.
All responses are JSON. Error responses look like
{ "error": "message" } with an appropriate status code. Request bodies are
JSON (Content-Type: application/json), capped at 10 MB.
The API is unauthenticated and has no rate limits. It listens on all interfaces by default. Use it only on trusted networks / localhost.
| Method | Path | Body / query | What it does |
|---|---|---|---|
| GET | /api/health |
— | { ok, version } |
| GET | /api/decks |
— | list deck names |
| POST | /api/decks |
{ name?, content?, theme? } |
create deck |
| GET | /api/decks/:name |
— | fetch deck markdown |
| PUT | /api/decks/:name |
{ content } |
overwrite deck |
| DELETE | /api/decks/:name |
— | delete deck |
| POST | /api/generate |
{ topic, slides[], theme, author?, subtitle? } |
generate skeleton markdown |
| POST | /api/render |
{ markdown, theme?, forceTheme?, highlightTheme? } |
render slides for preview/embed |
| GET | /api/export/:name |
format=html|pdf, theme=, highlight= |
self-contained HTML or print page |
Deck names are slugified (My Deck! → my-deck); unknown names return
404.
curl -s localhost:4210/api/decks
# { "decks": ["api-deck", "cli-deck", "welcome"] }curl -s -X POST localhost:4210/api/decks -H 'Content-Type: application/json' \
-d '{"name":"spotify-wrapped","topic":"Spotify Wrapped","slides":["Data","Design","Next steps"],"theme":"dark"}'
# { "ok": true, "name": "spotify-wrapped", "path": "/…/decks/spotify-wrapped.md" }If content is omitted, a template is generated from topic + slides.
To store an exact deck, pass content (any valid markdown per
docs/format.md).
curl -s localhost:4210/api/decks/spotify-wrapped
# { "name": "spotify-wrapped", "content": "---\ntitle: \"Spotify Wrapped\"…" }Returns the deck DOM + a <style> block scoped for embedding. The editor
uses this on every keystroke; you can too.
curl -s -X POST localhost:4210/api/render -H 'Content-Type: application/json' \
-d '{"markdown":"# Hi\n\n---\n\n## Bye","highlightTheme":"dark"}'{
"meta": { "theme": "light" },
"theme": "light",
"style": ":root{…}\n…",
"body": "<div class=\"pv\"><div class=\"stage\"><section class=\"slide\" data-index=\"0\"><div class=\"slide-inner\"><h1>Hi</h1>…"
}curl -s "localhost:4210/api/export/spotify-wrapped?format=html&theme=dark" -o deck.html
open deck.html # or: xdg-open deck.htmlformat=html— single offline-ready.html.format=pdf— the same page with an autowindow.print(); save as PDF in the browser dialog. For a real PDF file, prefer the CLIpdfcommand (drives headless Chrome when available).theme=overrides the front-matter theme for this export only.
Same generator the UI uses; returns markdown only.
curl -s -X POST localhost:4210/api/generate -H 'Content-Type: application/json' \
-d '{"topic":"Web components","slides":["Intro","How","Demo"],"theme":"paper"}'
# { "markdown": "---\ntitle: \"Web components\"…" }Passing "llm": true invokes the MDSLIDES_LLM command (see
docs/cli.md); it must be configured, or the call 500s.
200success ·201deck created400malformed body / missing required field404unknown deck or path405wrong method on a known path500unexpected failure (badMDSLIDES_LLMexit, I/O errors)
# 1. author the deck content as markdown (docs/format.md)
# 2. store it
curl -s -X PUT localhost:4210/api/decks/demo -H 'Content-Type: application/json' \
-d '{"content":"---\ntitle: \"Demo\"\n---\n\n# Demo\n\n---\n\n## Two\n"}'
# 3. verify rendering returns the expected slide count
curl -s -X POST localhost:4210/api/render -H 'Content-Type: application/json' \
-d '{"markdown":"# Demo\n\n---\n\n## Two"}' | grep -o 'class="slide"' | wc -l # 2
# 4. ship it
curl -s "localhost:4210/api/export/demo?format=html" -o demo.html