AnkonAI Developer API

Generate narrated whiteboard explainer videos from a topic, script, or PDF — programmatically. 8+ languages, vertical or landscape, burned-in captions + SRT, from $0.85/min.

Auth
API key header
Rate limit
60 requests / min / key
Model
Async — poll for the MP4

Authentication

Create an API key in your dashboard. Send it in the X-Ankon-Api-Key header on every request. Keys start with anko_ and are shown in full only once at creation — store them securely. (The in-app frontend uses short-lived JWT sessions; API keys are for servers and scripts.)

curl https://ankonai.com/api/jobs/ \
  -H "X-Ankon-Api-Key: anko_your_key_here" \
  -H "Content-Type: application/json"

Quick start

Create a job → poll its status until completed → download the MP4 from output_url. A 2-minute video typically renders in a few minutes.

1 · Create a video job

curl -X POST https://ankonai.com/api/jobs/ \
  -H "X-Ankon-Api-Key: $ANKON_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "input_type": "topic",
    "payload": {
      "topic": "how photosynthesis works",
      "duration_min": 2,
      "language": "en-us",
      "orientation": "landscape",
      "fact_check": false,
      "captions": true
    }
  }'

Response: 201 with a job object — note the id and that status starts as pending. Credits are held immediately and refunded automatically if the render fails.

2 · Poll until complete

# Poll every ~5s until status == "completed"
curl https://ankonai.com/api/jobs/<id>/ \
  -H "X-Ankon-Api-Key: $ANKON_KEY"

3 · Use the result

When status is completed, the job object contains the finished artifacts:

{
  "id": "2f8566a0-8e9a-4c66-b73b-498c8b1f5fae",
  "status": "completed",
  "progress": "Completed",
  "output_url":      "https://.../final_video_captioned.mp4",
  "metadata_url":    "https://.../metadata.txt",
  "captions_url":    "https://.../captions.srt",
  "thumbnail_url":   "https://.../thumbnail.jpg",
  "meta_title":      "How Photosynthesis Works",
  "meta_description": "..."
}

Python

import requests, time

KEY = "anko_..."
H = {"X-Ankon-Api-Key": KEY, "Content-Type": "application/json"}

job = requests.post("https://ankonai.com/api/jobs/",
    headers=H, json={
        "input_type": "topic",
        "payload": {"topic": "how photosynthesis works", "duration_min": 2},
    }).json()

while True:
    j = requests.get(f"https://ankonai.com/api/jobs/{job['id']}/", headers=H).json()
    if j["status"] in ("completed", "failed"):
        break
    time.sleep(5)

print(j["output_url"] if j["status"] == "completed" else j["error"])

Node.js

const KEY = "anko_...";
const H = { "X-Ankon-Api-Key": KEY, "Content-Type": "application/json" };
const BASE = "https://ankonai.com";

const job = await fetch(BASE + "/api/jobs/", { method: "POST", headers: H,
  body: JSON.stringify({ input_type: "topic",
    payload: { topic: "how photosynthesis works", duration_min: 2 } }) })
  .then(r => r.json());

let j;
do { await new Promise(r => setTimeout(r, 5000));
  j = await fetch(BASE + "/api/jobs/" + job.id + "/", { headers: H }).then(r => r.json());
} while (j.status === "pending" || j.status === "running");

console.log(j.status === "completed" ? j.output_url : j.error);

Payload reference

POST /api/jobs/ body is { input_type, payload }. input_type is "topic" (AI writes the script) or "script" (you provide the words). All other keys live inside payload:

KeyTypeReq.Values / default
topicstringtopic modeThe video idea, e.g. "how photosynthesis works". AI writes the narration.
scriptstringscript modeThe exact narration words. duration_min is derived from word count (~150 wpm).
file_keysstring[]optionalStorage keys from POST /api/media/upload/. Max 3 files, 3 MB combined. The video explains the attached material.
duration_minnumberoptional0.5–10. Default 2. 1 credit = 1 min, 2-credit minimum.
languagestringoptionalOne of the 9 languages below. Default en-us.
voice_idstringoptionalFrom GET /api/voices/?lang=. Omit for the language default.
orientationstringoptional"horizontal" (16:9, default) | "vertical" (9:16, for Shorts/Reels).
resolutionstringoptional"1K" only — 2K/4K are ignored (1K is the supported resolution).
captionsbooleanoptionalBurned-in captions + SRT sidecar. Default false — the player auto-shows the soft subtitle track instead.
fact_checkbooleanoptionalIndependent fact-check pass (+1 flat credit per video). Default false.
is_longboolean|nulloptionalForce long/short. Default null → derived from duration (>90 s = long).
num_scenesnumber|nulloptionalOverride scene count. Default null → auto from duration.
publish_to_gallerybooleanoptionalList in the public gallery once completed. Default false.
logo_keystringoptionalStorage key of an uploaded logo (png/jpg/webp, max 1 MB). Adds a corner watermark.

Unrecognized keys are ignored. Prohibited content (sexual, terrorism, instructions-for-harm, hate) is rejected with 422 before any credits are held.

Sample request & response

Topic mode — full request

POST /api/jobs/
{
  "input_type": "topic",
  "payload": {
    "topic": "how photosynthesis works",
    "duration_min": 2,
    "language": "en-us",
    "voice_id": "af_heart",
    "orientation": "landscape",
    "resolution": "1K",
    "captions": true,
    "fact_check": false,
    "publish_to_gallery": false
  }
}

201 Created — response

{
  "id": "2f8566a0-8e9a-4c66-b73b-498c8b1f5fae",
  "input_type": "topic",
  "payload": { "topic": "how photosynthesis works", "duration_min": 2, "language": "en-us", "captions": true },
  "status": "pending",
  "progress": "Queued",
  "credits_held": 2,
  "credits_cost": 2,
  "real_cost_usd": 0.416,
  "output_url": "",
  "metadata_url": "",
  "captions_url": "",
  "thumbnail_url": "",
  "error": "",
  "attempts": 0,
  "is_public": false,
  "created_at": "2026-07-12T17:30:00Z",
  "started_at": null,
  "finished_at": null,
  "meta_title": "",
  "meta_description": ""
}

output_url, metadata_url, captions_url, thumbnail_url, and meta_title/meta_description are populated once the render completes — poll GET /api/jobs/{id}/ until status is completed.

Script mode — minimal request

POST /api/jobs/
{
  "input_type": "script",
  "payload": {
    "script": "The Sun is a star at the center of our solar system...",
    "language": "en-us"
  }
}

In script mode duration_min is derived from the word count (~150 wpm, capped at 10 min); you can still set it explicitly to override.

Attachments (docs & images)

To ground the video in your own material, upload files first and pass their storage keys in payload.file_keys. The video then explains the attached content (PDFs are extracted; images are described by a vision model). Limits: up to 3 files, 3 MB combined, types .pdf .txt .md .png .jpg .jpeg .webp.

# 1. upload (multipart) — returns a storage_key
curl -X POST https://ankonai.com/api/media/upload/ \
  -H "X-Ankon-Api-Key: $ANKON_KEY" \
  -F "[email protected]"
# -> { "storage_key": "uploads/abc123.png", "filename": "diagram.png", "size": 12345 }

# 2. create a video that explains it
curl -X POST https://ankonai.com/api/jobs/ \
  -H "X-Ankon-Api-Key: $ANKON_KEY" -H "Content-Type: application/json" \
  -d '{ "input_type": "topic",
        "payload": { "topic": "explain this diagram",
                     "file_keys": ["uploads/abc123.png"], "duration_min": 2 } }'

Languages & voices

9 narration languages. Query GET /api/voices/ (public) for the full list, or GET /api/voices/?lang=hi for one language. Pass the chosen voice_id in the payload.

en-usEnglish (US) — 7 voices
en-gbEnglish (UK) — 4 voices
esSpanish — 3 voices
frFrench — 1 voice
pt-brPortuguese (BR) — 3 voices
itItalian — 2 voices
hiHindi — 4 voices
jaJapanese — 4 voices
zhChinese — 4 voices

Endpoints

POST/api/jobs/

Create + enqueue a video job. Body: { input_type: 'topic'|'script', payload: { topic|script, duration_min, language, orientation, fact_check, captions, ... } }.

GET/api/jobs/{id}/

Status + output URLs for one job.

GET/api/jobs/

List your jobs (filters: q, lang, status, input_type, date_from, date_to; paginated).

GET/api/jobs/estimate/

Pre-flight cost estimate (no auth required). Query: duration_min, resolution, fact_check.

GET/api/voices/

Available languages + voices (no auth required).

POST/api/jobs/{id}/retry/

Re-run a failed job (credits re-held; refunded again if it re-fails).

POST/api/jobs/{id}/visibility/

Toggle public/private gallery visibility (completed jobs only).

GET/api/keys/

List your API keys (masked).

POST/api/keys/

Create a key — returns the full key exactly once.

DELETE/api/keys/{id}/

Revoke a key.

GET/api/keys/{id}/usage/

Aggregated call counts (total / 24h / 7d), top endpoints, and recent activity for a key.

POST/api/media/upload/

Upload an attachment (multipart) — returns a storage_key for payload.file_keys.

A full machine-readable OpenAPI spec (Swagger / Redoc) is available at /api/docs/ and /api/schema/.

The async model

Video generation is asynchronous — a POST /api/jobs/ returns immediately with status: "pending" and the job is rendered on a worker queue. Poll GET /api/jobs/{id}/ every 3–5 seconds; status moves through pending → running → completed (or failed). Use the progress field for a human-readable stage label.

Pricing & credits

1 credit = 1 minute of finished video, with a 2-credit minimum. Credits come from your balance (free credits on signup, or paid packs / plans). Failed renders are refunded automatically — you only pay for a finished video. Effective bulk rate from $0.85/min; see the pricing page for current packs.

What if my video comes out shorter than I requested?

You are billed on the requested length, not the final runtime — finished videos may run slightly shorter (narration pacing, voice rate). Small variance is accepted: if a finished video lands at ≥ 95% of the requested length, there's no refund. If it falls below that, the un-delivered minutes are automatically credited backto your balance at the same 1-credit-per-minute rate — you never pay for video time you didn't receive. The fact-check surcharge isn't refunded (that work ran regardless of length), and failed renders are refunded in full.

RequestNo refund if delivered ≥Example refund
2 min1:54none — the 2-credit minimum leaves nothing to refund (failed renders still refund in full)
3 min2:512:00 → 1 cr (max 1)
5 min4:454:00 → 1 · 3:00 → 2 · 2:00 → 3
10 min9:309:00 → 1 · 7:00 → 3 · 5:00 → 5

Enhance (2× credits) refunds at 2× the rate. Values are rounded; the exact credit-back is recomputed per job from the delivered minutes.

Errors & rate limits

Questions? Email [email protected] or start with 10 free credits — apply for the beta.