Unstill API · v1

One REST call → a narrated, explorable explainer

The same pipeline behind the Studio — reference-grounded briefing, generation, validation and auto-repair — exposed as a REST API. Send a topic; get back a complete .unstill file your product can play with the open player. No video files, no render farm.

Authentication

Every request carries a Bearer key. Keys are scoped to your account and the videos left on it.

http
Authorization: Bearer usk_YOUR_KEY

Keep keys server-side. Never ship them in client bundles — anyone with the key spends your videos.

API keys

Loading your keys…

Generate an explainer

POST /api/v1/generate

FieldTypeDescription
topicstringWhat to explain, in plain English. Required unless brief is sent.
dimension"3d" | "2d"Cinematic 3D scene (default) or flat animated diagram.
format"full" | "short"Full explainer (default) — length follows the concept, from ~40s to 10 minutes for a genuinely deep topic. "short" is a single idea in 20–40s, composed for a 9:16 crop and built to loop.
visualBriefstringOptional factual ground truth (shapes, ratios, conventions) the generator must follow.
briefobjectA full concept brief (as produced by the Studio) — skips the automatic briefing step.
critiquebooleanRun the closed-loop visual accuracy pass (slower, higher fidelity).
bash
curl https://gounstill.com/api/v1/generate \
  -X POST \
  -H "Authorization: Bearer usk_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "topic": "how DNS resolves a domain name",
    "dimension": "3d"
  }' -o dns.unstill.json

Sync generation takes 1–5 minutes — set your client timeout to 300s, or use async mode.

Async jobs & webhooks

Add "async": true and the call returns 202 immediately with a job id. Poll GET /api/v1/jobs/:id — status movesqueued → running → succeeded | failed; on success the job response carries the same fields as a sync response. Optionally pass an https webhookUrl and the full result is POSTed to it on completion.

bash
# 1) submit — returns immediately with a job id
curl https://gounstill.com/api/v1/generate \
  -X POST \
  -H "Authorization: Bearer usk_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "topic": "how DNS resolves a domain name",
    "async": true,
    "webhookUrl": "https://your-app.com/hooks/unstill"
  }'
# → 202 { "id": "9b2f…", "status": "queued", "poll": "/api/v1/jobs/9b2f…" }

# 2) poll until status is "succeeded" (or wait for the webhook)
curl https://gounstill.com/api/v1/jobs/9b2f… \
  -H "Authorization: Bearer usk_YOUR_KEY"

A video is counted at submission. Job records (and results) are queryable for later retrieval — treat the webhook as a convenience, not the only delivery.

The response

json
{
  "unstill":    { "unstill": "1.0", "format": "2.0", "meta": { … }, "three": { … }, "narrative": { … } },
  "brief":      { "concept": "…", "storyboard": [ … ] },
  "validation": { "valid": true, "warnings": [], "qualityWarnings": [] },
  "videosLeft": 3
}

unstill is the complete playable file. brief is the editorial plan the generator followed (useful for showing chapter lists). validation confirms the file passed the player's structural checks and quality lint.

Account & limits

API calls draw from the same account as the Studio — each generation uses one video. Check what’s left any time:

bash
curl https://gounstill.com/api/v1/account \
  -H "Authorization: Bearer usk_YOUR_KEY"

Up to 5 active keys per account. Need volume pricing or higher throughput? Talk to us.

Errors

StatusMeaning
400Malformed body — send JSON with topic or brief.
401Missing/invalid/revoked API key.
402No videos left — buy another at /account.
422The supplied brief is missing required fields.
429Rate limit exceeded (default 12 generations/hour per account) — honor the Retry-After header.
502The generator couldn't produce a valid file for this topic — retry or simplify the topic.

Error bodies are { "error": { "code": 402, "message": "…" } }.

Playing .unstill files

A .unstill file is self-contained JSON played by the open player (/player/unstill-player.js, three.js-based). Embed it in your product, or create a hosted share link from the Studio and iframe /v/<slug> — playback is free and unmetered either way.