Agent Integration Guide¶
How an LLM agent (Claude Code, Cursor, Codex, or any tool-using model) should use Deckrun.
Deckrun is designed for agents. The API is schema-driven, deterministic, and async-safe. This guide provides the decision logic an agent needs to use Deckrun correctly.
The agent loop¶
Discover → Build → Submit → Poll → Deliver
Each stage has a clear API call and a clear exit condition.
1. Discover¶
Before generating content, fetch the schemas and available resources.
Get the slide format schema (what markdown does Deckrun accept?):
GET /schema?category=slide
This returns the slide format description including layout tags, surface syntax, notes blocks, and supported attributes. Use it to understand what markdown to generate.
List available voices (if narration is needed):
GET /voices
Returns a list of voice resources (deckrun-voice.json). Pick a voice_id with status: "active" and the appropriate tier (system for included, premium for high-fidelity).
List available connectors (where should output go?):
GET /providers
Returns available output connector types. Use to select the right output_destination shape.
2. Build¶
Generate markdown following the slide format schema. Key conventions:
- Use
<!-- <title-slide /> -->for the title slide - Use
<!-- <slide-notes> --> ... <!-- </slide-notes> -->for presenter notes (used for TTS) - Use
---(horizontal rule) to separate slides - Use
<!-- <two-content /> -->and<!-- <right-side /> -->for two-column layouts - Speaker notes are the narration script — write them as complete sentences
Validate your markdown against the slide format schema before submitting.
3. Submit¶
POST /generate
Content-Type: application/json
Authorization: Bearer YOUR_API_KEY
{
"markdown": "...",
"theme_id": "deckrun-default",
"outputs": ["pdf", "mp4", "mp3"],
"voice_id": "deckrun://voices/system-default",
"output_destination": {
"type": "s3",
"bucket": "my-bucket",
"prefix": "decks/"
}
}
- Response may be
200(synchronous, PDF-only) or202(async, video/audio) - For
202, store thejob_idand proceed to Poll
4. Poll¶
GET /jobs/{job_id}
Authorization: Bearer YOUR_API_KEY
Poll until status is a terminal value:
| Status | Meaning | Action |
|---|---|---|
queued |
In queue | Wait, retry |
processing |
Generating | Wait, retry |
success |
Done | Retrieve artifacts |
failure |
Error | Read error_message, retry or escalate |
timeout |
Exceeded time limit | Retry or escalate |
cancelled |
Cancelled | Re-submit if needed |
Use queue_position and estimated_wait_seconds to set retry intervals. Do not poll faster than every 5 seconds.
5. Deliver¶
On status: "success", the response contains artifacts with URLs for each requested output:
{
"status": "success",
"artifacts": {
"pdf": "https://...",
"mp4": "https://...",
"mp3": "https://...",
"notes": "https://..."
}
}
If you configured an output_destination, artifacts are already delivered there. The URLs are also available for direct download.
Agent-safe conventions¶
- All heavy outputs (video, audio) are async — never block on the POST /generate response
- Schema
$idfields are permanent URLs — safe to cache and reference - Artifact filenames include timestamps — nothing is overwritten on re-runs
- The API is idempotent for read operations; re-submitting a generation creates a new job
- Error responses follow the job status schema — always check
error_messageon failure
Example: Claude Code integration¶
import httpx
API_KEY = "..."
BASE = "https://api.agenticdecks.com"
def generate_deck(markdown: str, theme_id: str = "deckrun-default") -> dict:
resp = httpx.post(
f"{BASE}/generate",
headers={"Authorization": f"Bearer {API_KEY}"},
json={"markdown": markdown, "theme_id": theme_id, "outputs": ["pdf"]},
)
resp.raise_for_status()
data = resp.json()
# Synchronous result (PDF-only)
if data.get("status") == "success":
return data["artifacts"]
# Async: poll for completion
job_id = data["job_id"]
import time
while True:
time.sleep(5)
r = httpx.get(
f"{BASE}/jobs/{job_id}",
headers={"Authorization": f"Bearer {API_KEY}"},
)
r.raise_for_status()
job = r.json()
if job["status"] == "success":
return job["artifacts"]
if job["status"] in ("failure", "timeout", "cancelled"):
raise RuntimeError(f"Job {job_id} failed: {job.get('error_message')}")
See also¶
- Quickstart — step-by-step first run
- Schemas — public schema index
- OpenAPI spec — machine-readable API definition