DEVELOPER DOCS
Build with elevideo
Add captions and AI-powered overlays to any video with a single API call. Send a URL, pick a style, get back a polished MP4.
Welcome
elevideo turns raw videos into captioned and AI-edited content through a simple REST API, CLI, or MCP integration. Here's what you can do:
- Add captions — upload any video and get back styled, word-timed captions in 30+ visual styles
- Apply AI edits — let AI analyze your video's transcript and generate overlay graphics (property listings, product demos, podcast clips, and more)
- Re-style for free — once a video is transcribed, re-run it with any other style at no extra cost
New here? Start with the Quickstart below — you'll have a captioned video in under 5 minutes.
Quickstart
Get your first captioned video in under 5 minutes.
- Get an API key — create one below or on your account page
- Caption your video — call POST /api/v1/captions with any public video_url and optional style_id. You'll get back a run ID immediately while we process it in the background.
- Wait for it — call GET /api/v1/render/:id until status is "completed". Your captions are ready.
- Download your video — call POST /api/v1/render/:id/export, then poll until export_status is "completed" and grab the download_url.
Here's the complete flow:
# 1. Add captions to a video
curl -X POST https://api.elevideo.dev/v1/captions \
-H "X-API-Key: ck_your_key" \
-H "Content-Type: application/json" \
-d '{"video_url": "https://example.com/video.mp4", "style_id": "holographic"}'
# 2. Poll status (repeat until status = "completed")
curl https://api.elevideo.dev/v1/render/run_abc123 \
-H "X-API-Key: ck_your_key"
# 3. Trigger export
curl -X POST https://api.elevideo.dev/v1/render/run_abc123/export \
-H "X-API-Key: ck_your_key"
# 4. Poll again until export_status = "completed", then use download_url
# 5. Try a different style (free — no re-transcription)
curl -X POST https://api.elevideo.dev/v1/render/run_abc123/rerun \
-H "X-API-Key: ck_your_key" \
-H "Content-Type: application/json" \
-d '{"style_id": "beast"}'Once you have this working, try applying a different style — see Browse Styles for all 32 options.
How It Works
The pipeline
Upload Video ──▶ POST /captions ──▶ Transcription ──▶ Composition Built
or POST /ai-edits status: "completed"
│
▼
POST /render/:id/export
(async)
│
▼
Server-side Render
│
▼
Upload to CDN ──▶ download_url- You provide a video URL and optionally a style ID
- The API transcribes your video with word-level timing
- For caption styles: builds a composition with styled captions overlaid on your video
- For AI edit styles: also uses AI to extract highlights, quotes, or structured data from the transcript
- Once the composition is built, you trigger an export which renders a final MP4 on our servers
- The rendered MP4 is uploaded to CDN and a download URL is returned
What's a composition?
Every completed render produces a composition object — the full set of rendering instructions including captions, timing, styles, and overlays. You can retrieve any render's composition via GET /api/v1/render/:id. It contains:
- segments — video clips with timing, transitions, animations
- captions — word-level caption data with style configuration
- transcriptionWords — raw word timing from transcription
- audioUrl — extracted audio track
- styleParams — video effects (zoom, pan, blur)
- aiEditTemplate — AI-extracted overlay data (for AI edit styles)
Every video you render is effectively a reusable template. Process the same video with different styles and get different outputs — all from a single transcription.
Tracking progress
Both render and export operations are asynchronous. The API responds immediately and processes in the background. Poll the render endpoint to track progress.
Status transitions:
processing ──▶ completed ──▶ (trigger export) ──▶ rendering ──▶ uploading ──▶ completed
│ │
▼ ▼
failed failed- processing — transcription + composition in progress
- completed — composition ready, can view or export
- failed — processing error (check error_message)
- rendering — server-side export in progress
- uploading — rendered MP4 uploading to CDN
- export_status: "completed" — download_url available
Re-runs: change styles for free
Once a video is transcribed, you can re-run it with any other style at no cost using POST /render/:id/rerun. Caption re-runs complete instantly. AI edit re-runs only need a brief LLM step. No credits charged.
Now that you understand the flow, explore Add Captions or Apply AI Edits.
CLI
Prefer working from the terminal? The elevideo CLI handles uploads, rendering, and downloads in one command.
Install with npm:
npm install -g @elevideo/cli
Set your API key:
elevideo auth --key ck_your_key
Then render a video:
elevideo render ./video.mp4 --style bold --flow captions # ✓ Uploaded (12.4 MB) # ✓ Rendering … done # ✓ Exported → video-bold.mp4 elevideo styles captions # list available caption styles elevideo renders # list past renders elevideo status <run-id> # check render status
MCP Integration
Let AI agents render videos on your behalf. The elevideo MCP server connects to Claude Desktop, Cursor, or any MCP-compatible client — your agent calls the tools, we handle the rest.
Install the server:
npm install -g @elevideo/mcp-server
Claude Desktop — add to ~/Library/Application Support/Claude/claude_desktop_config.json
{
"mcpServers": {
"elevideo": {
"command": "elevideo-mcp",
"env": {
"ELEVIDEO_API_KEY": "ck_your_key"
}
}
}
}Cursor — add to .cursor/mcp.json in your project
{
"mcpServers": {
"elevideo": {
"command": "elevideo-mcp",
"env": {
"ELEVIDEO_API_KEY": "ck_your_key"
}
}
}
}Available tools:
- render_video — render a video with a template
- check_render_status — poll render progress
- export_render — trigger MP4 export
- list_templates — list all caption styles and AI templates
- get_account — check credit balance
Authentication
Every API request needs to be authenticated so we know who's making it and which credit balance to use. Pass your API key in the X-API-Key header:
curl -H "X-API-Key: ck_your_key_here" \ https://api.elevideo.dev/v1/account
Keep your key private — anyone with it can use your credits. If a key is compromised, revoke it immediately from the Account & Keys section below.
Bearer token authentication (Authorization: Bearer <token>) is also supported for browser-based integrations.
Your API Keys
Loading keys...
Add Captions
Turn any video into a captioned video. Send a URL and a style, and we'll transcribe the audio, generate word-timed captions, and build a composition you can export as MP4.
Send a video URL and get back styled, word-timed captions. The response comes back immediately with a run ID — check its status with GET /render/:id.
Request body
{
"video_url": "https://example.com/video.mp4", // required — public URL or R2 upload URL
"style_id": "holographic", // optional (default "classic") — see GET /styles/captions
"duration_seconds": 60, // optional (default 30) — for credit calc
"auto_render": true // optional — trigger export automatically after composition is built
}Response
{
"id": "run_abc123",
"status": "processing",
"flow_type": "captions",
"style_id": "holographic",
"created_on": "2026-03-25T12:00:00.000Z"
}Returns 402 if insufficient credits. Returns 400 for invalid style_id. Credits: 0.3 per 30-second chunk (minimum 0.3). When auto_render is true, poll GET /render/:id until export_status = "completed" for the download_url.
32 caption styles across 4 categories: minimal, bold, animated, and elegant. Each controls fonts, colors, animations, and effects. Call GET /api/v1/styles/captions for the full list.
Popular styles:
"classic" — Traditional subtitles with dark background (minimal) "holographic" — Cyan holographic glow with uppercase text (animated) "beast" — Impact font with yellow box on active word (bold) "elegance" — Serif script with alternating cursive words (elegant)
Want a different look? You can re-run with a new style for free after the first render.
Apply AI Edits
Transform a video with an AI-generated overlay. We transcribe the audio, then use AI to pull out the most relevant content — quotes, features, stats, or highlights — and build a styled overlay on top. Pick a style that matches your use case.
Transcribe a video, extract structured data with AI, and render a styled overlay. Returns immediately with a run ID — check status with GET /render/:id.
Request body
{
"video_url": "https://example.com/video.mp4", // required
"style_id": "property_showcase", // required — see GET /styles/ai-edits
"duration_seconds": 60, // optional (default 30)
"auto_render": true // optional — trigger export automatically after composition is built
}Response
{
"id": "run_abc123",
"status": "processing",
"flow_type": "ai_edit",
"style_id": "property_showcase",
"created_on": "2026-03-25T12:00:00.000Z"
}Returns 402 if insufficient credits. Returns 400 for invalid or missing style_id.
32 AI edit overlay styles organized by industry: real estate, SaaS, personal brand, trendy, podcast, news, reviews, local business, e-commerce, and finance. Each uses AI to extract relevant data from your video's transcript. Call GET /api/v1/styles/ai-edits for the full list.
Popular styles:
"property_showcase" — Property listing with price + features (real_estate) "product_demo" — SaaS product walkthrough (saas) "tiktok_title" — Trendy short-form content (trendy) "podcast_clip" — Interview clips with standout quote (podcast)
Browse Styles
Browse all available visual styles before starting a render. Each style has a unique ID you'll pass to the captions or AI edits endpoint.
List all 32 available caption styles. Use the style id as the style_id parameter in POST /captions.
Response
{
"styles": [
{
"id": "holographic",
"name": "Holographic",
"description": "Cyan holographic glow with uppercase text",
"category": "animated"
}
]
}List all 32 available AI edit styles. Use the style id as the style_id parameter in POST /ai-edits.
Response
{
"styles": [
{
"id": "property_showcase",
"label": "Property Showcase",
"description": "Elegant property listing with price, features, and CTA",
"category": "real_estate"
}
]
}Export & Download
Once your composition is ready, trigger an export to produce a downloadable MP4. The export runs on our servers and typically takes 1–8 minutes depending on video length.
Kick off the final MP4 render. Your composition must be ready (status = 'completed') before you can export. Poll GET /render/:id for export_status and download_url.
Parameters
:id — The render run ID
Response
{
"render_id": "run_abc123",
"export_status": "rendering"
}Returns 400 if render is not yet completed. Export takes 1-8 minutes depending on video length. Poll GET /render/:id for export_status.
Re-run a Style
Try a different style without re-processing your video. Since we've already transcribed the audio, switching styles is instant for captions and takes just a few seconds for AI edits. Best of all, re-runs are free — no credits charged.
Apply a new style to an existing render. Reuses the stored transcription — instant for captions, a few seconds for AI edits. Free, no credits charged.
Parameters
:id — The original render run ID (must be completed)
Request body
{
"style_id": "beast" // new style to apply (same flow type as original)
}Response
{
"id": "run_def456",
"status": "completed", // instant for captions
"flow_type": "captions",
"style_id": "beast",
"parent_run_id": "run_abc123", // links to original
"created_on": "2026-03-25T12:00:00.000Z"
}Returns 400 if original render is not completed or has no stored transcription. Style must match the same flow type (caption styles for captions, AI edit styles for AI edits).
Check Status
Track your render jobs and check where they are in the pipeline. Use these endpoints to poll for completion, view compositions, and list your render history.
Check where a render is in the pipeline. Returns the current status, the full composition (once ready), and the download URL (once exported).
Parameters
:id — The render run ID returned from POST /captions or POST /ai-edits
Response
{
"id": "run_abc123",
"status": "completed",
"flow_type": "captions",
"style_id": "holographic",
"parent_run_id": null, // set if this is a re-run
"composition": { ... }, // full composition when status = "completed"
"current_stage": null, // active processing stage: "transcribing" | "building" | "rendering" | "uploading" | null
"download_url": "https://cdn.elevideo.dev/renders/...",
"export_status": "completed", // null until export triggered
"export_progress": 1.0, // 0–1 float during rendering, null otherwise
"export_error": null,
"error_message": null,
"created_on": "2026-03-25T12:00:00.000Z"
}List all your render jobs, newest first. Includes both caption and AI edit renders.
Response
{
"renders": [
{
"id": "run_abc123",
"status": "completed",
"flow_type": "captions",
"style_id": "holographic",
"source_file_name": "video.mp4",
"created_on": "2026-03-25T12:00:00.000Z"
}
]
}Webhooks
Instead of polling for render status, have us notify you. Register a webhook URL and we'll send an HTTP POST whenever a render starts, completes, fails, or finishes exporting. This is especially useful for background automations, CI/CD pipelines, and AI agent workflows where you don't want to sit in a polling loop.
Webhook events:
"render.started" — job began processing "render.completed" — composition ready (status = "completed") "render.failed" — job failed "render.export_completed" — MP4 export done, download_url available "render.export_failed" — export failed
Payload example:
{
"event": "render.completed",
"data": {
"id": "run_abc123",
"status": "completed",
"flow_type": "captions",
"style_id": "holographic",
"created_on": "2026-03-25T12:00:00.000Z"
}
}List your registered webhooks and their current status.
Response
{
"webhooks": [
{
"id": "wh_abc123",
"url": "https://your-server.com/webhook",
"events": ["render.completed", "render.failed"],
"active": true,
"created_on": "2026-03-25T12:00:00.000Z"
}
]
}Register a webhook URL to receive render event notifications. You can have up to 5 webhooks per account.
Request body
{
"url": "https://your-server.com/webhook",
"events": ["render.completed", "render.export_completed", "render.failed"]
}Response
{
"id": "wh_abc123",
"url": "https://your-server.com/webhook",
"events": ["render.completed", "render.export_completed", "render.failed"],
"active": true,
"created_on": "2026-03-25T12:00:00.000Z"
}Returns 400 if URL is invalid or events list is empty. Returns 409 if you already have 5 webhooks.
Deactivate and remove a webhook. It will stop receiving events immediately.
Parameters
:id — The webhook ID
Response
{ "id": "wh_abc123", "active": false }Send a test payload to your webhook URL to verify it's reachable. Useful for debugging delivery issues.
Parameters
:id — The webhook ID
Response
{ "success": true, "status_code": 200 }Returns 200 even if your server returned an error — check status_code in the response.
View the last 20 delivery attempts for a webhook. Helpful for debugging failed deliveries or confirming events are arriving.
Parameters
:id — The webhook ID
Response
{
"deliveries": [
{
"id": "del_abc",
"event": "render.completed",
"success": true,
"status_code": 200,
"created_on": "2026-03-25T12:00:00.000Z"
}
]
}Account & Keys
Manage your API keys and check your credit balance. You can create multiple keys for different environments (development, staging, production) and revoke any key instantly.
Check how many credits you have left. Useful for showing a balance in your UI or gating renders before they fail with a 402.
Response
{
"user_id": "user_123",
"credits_remaining": 42.5
}Create a new API key. The full key is only returned once — store it securely. You won't be able to see the full key again.
Request body
{
"name": "My Production Key" // optional (default "Unnamed Key")
}Response
{
"id": "key_abc",
"key": "ck_live_abc123...",
"name": "My Production Key",
"created_on": "2026-03-25T12:00:00.000Z"
}List your API keys. Keys are masked for security — only the prefix is shown.
Response
{
"api_keys": [
{
"id": "key_abc",
"name": "My Production Key",
"key_prefix": "ck_live...",
"active": true,
"created_on": "2026-03-25T12:00:00.000Z"
}
]
}Revoke an API key immediately. Any requests using this key will start failing right away.
Parameters
:id — The API key ID
Response
{
"id": "key_abc",
"active": false
}View your credit purchase history, including amounts and dates.
Response
{
"purchases": [
{
"id": "purchase_abc",
"credits": 50,
"price_cents": 500,
"created_on": "2026-03-25T12:00:00.000Z"
}
]
}Buy Credits
Purchase credits programmatically via Stripe. This is useful if you're building a platform on top of elevideo and want to manage billing from your backend.
List available credit packages and their prices. Use these values when creating a checkout session.
Response
{
"packages": [
{ "price_cents": 500, "price_display": "$5.00", "credits": 50 },
{ "price_cents": 2000, "price_display": "$20.00", "credits": 250 },
{ "price_cents": 5000, "price_display": "$50.00", "credits": 700 },
{ "price_cents": 10000, "price_display": "$100.00", "credits": 1500 }
]
}Create a Stripe checkout session for purchasing credits. Redirect your user to the returned URL to complete payment.
Request body
{
"price_cents": 500,
"success_url": "https://elevideo.dev/account?checkout=success",
"cancel_url": "https://elevideo.dev/account?checkout=cancel"
}Response
{
"sessionId": "cs_live_...",
"url": "https://checkout.stripe.com/..."
}Returns 400 if price_cents does not match a valid package.
Error Codes
All errors return a JSON body with error (machine-readable code) and message (human-readable description). Here's what each code means and when you might see it:
| HTTP | Error Code | Meaning |
|---|---|---|
| 400 | missing_video_url | No video_url in request body |
| 400 | missing_template_id | No template_id in request body |
| 400 | invalid_template | Template ID not found |
| 400 | not_ready | Render not completed (cannot export yet) |
| 400 | missing_fields | Required fields missing (checkout) |
| 400 | file_too_large | File exceeds 500MB limit |
| 400 | checkout_failed | Stripe checkout session failed |
| 401 | missing_authorization | No auth header provided |
| 401 | invalid_token | Bearer token is invalid |
| 401 | missing_api_key | No X-API-Key header |
| 401 | invalid_api_key | API key not found or inactive |
| 402 | insufficient_credits | Not enough credits for this render |
| 404 | not_found | Resource not found or not owned by you |
| 429 | rate_limited | Rate limit exceeded (100/min) |
| 500 | lambda_error | Server-side rendering failed |
| 500 | internal_error | Unexpected server error |
Rate Limits
API requests are limited to 100 requests/minute per user. If you exceed this limit you'll receive a 429 response. Standard rate limit headers (RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset) are included in every response.
For error handling details, see Error Codes.