Quantumplations
Developers

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

1

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.

2

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.

3

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

MethodPathWhat it does
POST/videosOrder a film. Charges at once, refunds if it fails.
GET/videos/{id}One render, with signed URLs once it's done.
GET/videosYour renders, newest first. ?limit= 1–100, ?before= a timestamp.
DELETE/videos/{id}Cancel one that hasn't started, and refund it.
GET/optionsEvery voice, language and look you can ask for.
GET/creditsYour balance and plan.

Render options

Everything but prompt has a default. Anything else you send is ignored.

FieldDefaultAccepts
prompt requiredUp to 8,000 characters.
duration_seconds45A whole number, 10 to 1800. This is what you're charged.
lookwhiteboardwhiteboard, technical, sketch.
voiceFinnA voice id from /options, or "none" for a silent film.
languageen74 languages, listed in /options.
scopestandardstandard, or socratic for a two-voice dialogue.
captionsfalseBurns the narration into the frames. Not with "none".
aspect_ratio16:916:9 or 9:16.
callback_urlnullAn https URL on a public host.

Errors

Every failure is {"error": "<code>", "message": "…"} with a matching status.

CodeHTTPWhen
auth_required401No key.
invalid_api_key401The key isn't ours, or it's been revoked.
insufficient_credits402The film costs more than you hold.
forbidden403A browser tried to use a key.
invalid_request400A field is missing or out of range. The message names it.
render_not_found404No render with that id on your account.
render_not_cancelable409It already started, or it started once and is queued for another try.
rate_limited429Past 60 calls a minute on one key, or 240 from one address. Carries Retry-After.
upstream_error502Our 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.

Checking your account…

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.