Quantumplations has an API.
Post a prompt, get back a narrated film. It's the same renderer the website runs on, with a key instead of a login.
Base URL https://quantumplations.ai/api/v1. Everything speaks JSON, a render costs 1.5 credits a second, and your key is the only credential.
Quickstart
Mint a key
Further down this page, on your own account. It's shown once, so keep it on a server: a secret key in a browser is a leaked key.
Order a film
Only prompt is required.
curl -X POST https://quantumplations.ai/api/v1/videos \
-H "Authorization: Bearer $QP_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"prompt": "Explain how a Kalman filter works.", "duration_seconds": 60}'
You get 202 and a render:
{
"id": "425e4bbe-5d63-4343-b0ad-8d90dc5805b4",
"status": "queued",
"cost_credits": 60,
"duration_seconds": 60,
"credits_remaining": 940,
"video": null
}
The Idempotency-Key is optional but worth sending. If the reply never reaches you, repeating the call with the same key hands back the render you already bought instead of ordering a second one.
Collect it
Poll the render, or give callback_url on step 2 and let a webhook tell you.
curl https://quantumplations.ai/api/v1/videos/$RENDER_ID \ -H "Authorization: Bearer $QP_API_KEY"
status runs queued to processing to one of succeeded, failed or canceled. On success video arrives, and its URLs are signed and expire in an hour, so fetch rather than store them:
"video": {
"url": "https://…/425e4bbe….mp4?token=…",
"poster_url": "https://…/425e4bbe….jpg?token=…",
"duration_seconds": 59.8,
"expires_in": 3600
}
Endpoints
| Method | Path | What it does |
|---|---|---|
| POST | /videos | Order a film. Charges at once, refunds if it fails. |
| GET | /videos/{id} | One render, with signed URLs once it's done. |
| GET | /videos | Your renders, newest first. ?limit= 1–100, ?before= a timestamp. |
| DELETE | /videos/{id} | Cancel one that hasn't started, and refund it. |
| GET | /options | Every voice, language and look you can ask for. |
| GET | /credits | Your balance and plan. |
Render options
Everything but prompt has a default. Anything else you send is ignored.
| Field | Default | Accepts |
|---|---|---|
| prompt required | – | Up to 8,000 characters. |
| duration_seconds | 45 | A whole number, 10 to 1800. This is what you're charged. |
| look | whiteboard | whiteboard, technical, sketch. |
| voice | Finn | A voice id from /options, or "none" for a silent film. |
| language | en | 74 languages, listed in /options. |
| scope | standard | standard, or socratic for a two-voice dialogue. |
| captions | false | Burns the narration into the frames. Not with "none". |
| aspect_ratio | 16:9 | 16:9 or 9:16. |
| callback_url | null | An https URL on a public host. |
Errors
Every failure is {"error": "<code>", "message": "…"} with a matching status.
| Code | HTTP | When |
|---|---|---|
| auth_required | 401 | No key. |
| invalid_api_key | 401 | The key isn't ours, or it's been revoked. |
| insufficient_credits | 402 | The film costs more than you hold. |
| forbidden | 403 | A browser tried to use a key. |
| invalid_request | 400 | A field is missing or out of range. The message names it. |
| render_not_found | 404 | No render with that id on your account. |
| render_not_cancelable | 409 | It already started, or it started once and is queued for another try. |
| rate_limited | 429 | Past 60 calls a minute on one key, or 240 from one address. Carries Retry-After. |
| upstream_error | 502 | Our side. Safe to repeat everywhere except POST /videos, which is what Idempotency-Key is for. |
Webhooks
Give callback_url and we post once, when the render settles: { event, id, status, error, completed_at }, with X-Quantumplations-Signature: t=<unix>,v1=<hex>. There's no retry, so keep polling as your fallback.
The signature is an HMAC-SHA256 of "<t>.<raw body>" keyed with the webhook secret shown beside your key. Verify against the raw bytes, before parsing:
import { createHmac, timingSafeEqual } from 'node:crypto';
export function verifyWebhook(rawBody, header, secret,
nowS = Math.floor(Date.now() / 1000)) {
const parts = Object.fromEntries(String(header || '').split(',').map((p) => {
const i = p.indexOf('=');
return i < 0 ? ['', ''] : [p.slice(0, i).trim(), p.slice(i + 1).trim()];
}));
// Reject a replay of anything older than five minutes.
const t = Number(parts.t);
if (!/^[0-9]+$/.test(parts.t || '') || Math.abs(nowS - t) > 300) return false;
const expected = createHmac('sha256', secret).update(`${parts.t}.${rawBody}`).digest();
const given = Buffer.from(String(parts.v1 || ''), 'hex');
// timingSafeEqual throws on a length mismatch, so check length first.
return given.length === expected.length && timingSafeEqual(given, expected);
}
Answer with a 2xx quickly. Nothing you return is read.
Use it from an agent
There's an MCP server at https://quantumplations.ai/api/mcp, so Claude Code, Cursor and anything else that speaks MCP can order a film without leaving the conversation. It's the same API and the same key.
claude mcp add --transport http quantumplations https://quantumplations.ai/api/mcp \ --header "Authorization: Bearer $QP_API_KEY"
Or, in a client that takes JSON:
{
"mcpServers": {
"quantumplations": {
"type": "http",
"url": "https://quantumplations.ai/api/mcp",
"headers": { "Authorization": "Bearer qp_live_…" }
}
}
}
Five tools: generate_video, answer_questions, get_video, list_videos and get_credits. The one worth knowing about is answer_questions: the agent making your film stops and asks when a brief is ambiguous, and get_video reports awaiting_answers with the questions and how long is left to answer. Only generate_video spends anything, and it's annotated so your client asks before it does. There's deliberately no cancel tool — an agent that can cancel renders it didn't order is a footgun, and cancelling stays on the REST surface where a person presses the button.
A key in an MCP config is still a secret key. It sits on the machine running the client, which is a server-side place, but treat the config file the way you'd treat any file holding a credential.
Your API keys
Keys belong to your Quantumplations account and carry your credits, your plan and your beta access. Mint one per application, so you can revoke one without breaking the rest. Twenty live keys is the ceiling; revoke one to make room for another.
Sign in to mint a key
Your keys live on your account, so we need to know who you are. Sign in on the home page, then come back to this one.
Mint a key
Name it after the thing that will use it. You'll see the key itself once, right after minting, and never again.
Copy your key now
This is the only time you'll see it. We store a hash, not the key, so nobody can show it to you again. If you lose it, revoke it and mint another.
Live keys
No live keys yet.
| Name | Key | Created | Last used | Webhook secret | Revoke |
|---|
Revoking is immediate and can't be undone. Renders already queued with that key still finish, and their webhooks still arrive.
Credits
A render ordered through the API costs 1.5 credits per second of film, rounded up — so a 60-second film is 90 credits. The same film ordered from the website costs 60. cost_credits on the render always says exactly what was charged, so you never have to work it out. API and website renders draw on the same balance, every plan includes the API, and a render that fails or is cancelled refunds itself. See the plans.
