Create Lumen5 videos from your content. Send a script or some source text, and Lumen5's agent turns it into a finished video in one of your workspaces. You can leave the style to the agent or pin down the template, voice, brand kit, aspect ratio and length yourself.
There are three ways to connect:
- HTTP: call the API directly from your own code. Most of this page documents it, starting with the quick start below.
- Automation platforms: use Lumen5's apps on platforms like Make, Zapier and n8n to create videos from your workflows, without writing code. See "Automation platforms" below.
- MCP: connect an AI assistant such as Claude, ChatGPT or Cursor, and it can create videos for you as a tool. See "MCP" below.
Quick start
-
Create an API key at
https://lumen5.com/dashboard/api/. It is shown once, so store it somewhere safe. -
Find the workspace to create the video in:
curl https://lumen5.com/api/v1/video-creation/workspaces/ \ -H "Authorization: Bearer $LUMEN5_API_KEY" -
Ask for a video:
curl -X POST https://lumen5.com/api/v1/video-creation/requests/ \ -H "Authorization: Bearer $LUMEN5_API_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: $(uuidgen)" \ -d '{ "workspace": "ws_123", "input_content": {"text": "Paste an article, notes or a brief here."}, "output_settings": {"aspect_ratio": "landscape", "target_duration_seconds": 60} }' -
Poll
GET /api/v1/video-creation/requests/{request_id}/untilstatusiscompletedorfailed, or register a webhook endpoint to be told. A completed request has avideo_urlthat opens the video in Lumen5.
Automation platforms
Lumen5 publishes apps on automation platforms, so you can create videos from your workflows without writing code: for example, turning each new blog post into a video.
| Platform | Status |
|---|---|
| Make | Coming soon |
| Zapier | Coming soon |
| n8n | Coming soon |
Each app connects to Lumen5 with OAuth: you sign in to Lumen5 and approve access when you add the connection, so there's no API key to create or paste. The apps are built on this API, so the options and behavior on this page apply to them too.
Until the app for your platform is available, you can use the platform's own HTTP step to call the API directly with an API key, as in the quick start above.
MCP
Lumen5 runs a Model Context Protocol (MCP) server, so AI assistants and agents can create videos as a tool. Its URL is:
https://lumen5.com/mcp
It speaks MCP's Streamable HTTP transport. Its tools work like the HTTP endpoints below, so the options, limits and errors on this page apply to it too.
Connect with OAuth
Most assistants (Claude, ChatGPT, Cursor, VS Code and others) only need the URL. Add https://lumen5.com/mcp as a custom connector or remote MCP server, and the assistant opens Lumen5 for you to sign in and approve access. Approve both permissions if you want it to create videos, not just look things up.
Lumen5 doesn't review the assistants that connect this way, so the approval screen marks them as unverified and shows where approving sends you. Only approve a connection you just started yourself.
Under the hood, the server follows the MCP authorization spec. A call without a credential gets a 401 whose WWW-Authenticate header points to https://lumen5.com/.well-known/oauth-protected-resource/mcp, which names Lumen5's authorization server (metadata at https://lumen5.com/.well-known/oauth-authorization-server). Clients register themselves, either with a client ID metadata document or through dynamic client registration at /oauth/register/, then sign the user in with the authorization-code flow and PKCE.
MCP tools
| Tool | What it does |
|---|---|
list_workspaces |
Lists the workspaces you can create videos in. |
list_recipes, list_templates, list_voices, list_blueprints, list_brand_kits |
List the style options, as the matching endpoints do. |
preview_video_request |
Checks a request without creating anything, like POST /resolve/. |
create_video |
Starts a video, like POST /requests/. Needs video:write. |
get_video_request |
Gets a request's status and, once it's done, its video_url. |
list_video_requests |
Lists a workspace's requests, newest first. |
preview_video_request and create_video take the same body as POST /requests/, and create_video also takes an optional idempotency_key in place of the header. Lists return up to 50 results per page. When a call fails, the tool's result says why, so the assistant can correct itself.
Authentication
Send a credential on every call as Authorization: Bearer <token>. Either works:
- API key: starts with
lm5_sk_. Create and delete keys athttps://lumen5.com/dashboard/api/. A key acts as the user who created it. - OAuth 2.0 access token: for apps acting on behalf of other Lumen5 users.
What a credential may do depends on its scopes:
| Scope | Allows |
|---|---|
basic:read |
Every GET, and POST /resolve/ (a dry run that changes nothing) |
video:write |
Creating video requests and managing webhook endpoints |
Workspace viewers and reviewers can read but not create videos, just as in the Lumen5 app.
Workspaces
Every call that reads or creates videos names the workspace it acts in: in the workspace query parameter for GET, and in the workspace body field for POST. There is no default workspace. Get workspace ids from GET /workspaces/.
IDs
Every id the API returns has a prefix that says what it is. Pass ids back exactly as you received them.
| Prefix | Names | Listed by |
|---|---|---|
ws_ |
Workspace | GET /workspaces/ |
tpl_ |
Template | GET /templates/ |
voice_ |
AI voice | GET /voices/ |
bp_ |
Blueprint (a workspace's saved video style) | GET /blueprints/ |
bk_ |
Brand kit | GET /brand-kits/ |
req_ |
Video creation request | GET /requests/ |
whep_ |
Webhook endpoint | GET /webhook-endpoints/ |
Recipe ids have no prefix (for example create-promo-ad); get them from GET /recipes/.
Pagination
List endpoints return 50 items per page:
{
"count": 120,
"next": "https://lumen5.com/api/v1/video-creation/templates/?page=2&workspace=ws_123",
"previous": null,
"results": []
}
Follow next until it is null.
Choosing a style
Everything in output_settings is optional. Anything you leave out (or send as null) is chosen by the agent.
There are two ways to set a style:
- A blueprint (
blueprint): a workspace's saved style. It decides the template, voice, recipe, brand kit, aspect ratio and duration, so it can't be combined with any of them.video_namecan still be set. - Individual settings: any combination of
template,voice,recipe,brand_kit,aspect_ratioandtarget_duration_seconds.
Every listing endpoint accepts search to narrow the list by keywords, and only returns options the named workspace can use.
Use POST /resolve/ to check a body before sending it: it validates exactly as POST /requests/ does and returns what would be stored, without creating anything.
Endpoints
All paths are relative to https://lumen5.com.
List workspaces
GET /api/v1/video-creation/workspaces/
The workspaces the caller can create videos in. Each result: id (ws_…), label.
List recipes
GET /api/v1/video-creation/recipes/?workspace=ws_123&search=promo
The kinds of video a request can ask for. Each result: id, label, description.
List voices
GET /api/v1/video-creation/voices/?workspace=ws_123
AI voices for narration. Each result: id (voice_…), label, attributes (for example accent and gender, each a list of strings), preview_url, is_paid.
List templates
GET /api/v1/video-creation/templates/?workspace=ws_123
Each result: id (tpl_…), label, description, aspect_ratios, preview_url.
List blueprints
GET /api/v1/video-creation/blueprints/?workspace=ws_123
Each result: id (bp_…), label, description, aspect_ratio.
List brand kits
GET /api/v1/video-creation/brand-kits/?workspace=ws_123
Each result: id (bk_…), label.
Validate a request (dry run)
POST /api/v1/video-creation/resolve/
Takes the same body as creating a request. Returns 200 with the request as it would be stored (workspace, input_content, output_settings, instructions, with null for anything left to the agent), or 400 explaining what's wrong. Needs only basic:read.
Create a video
POST /api/v1/video-creation/requests/
Body:
{
"workspace": "ws_123",
"input_content": {
"script": null,
"text": "Source material for the agent to write a script from."
},
"output_settings": {
"blueprint": null,
"template": "tpl_abc",
"voice": "voice_emma",
"recipe": "create-promo-ad",
"brand_kit": "bk_42",
"aspect_ratio": "vertical",
"target_duration_seconds": 45,
"video_name": "Q3 product update"
},
"instructions": "Upbeat tone. End on a call to action to book a demo."
}
| Field | Required | Description |
|---|---|---|
workspace |
Yes | A ws_ id. |
input_content.script |
See below | Narration, used word for word. |
input_content.text |
See below | Source material (an article, notes, a brief) for the agent to write a script from. |
output_settings.blueprint |
No | A bp_ id. Can't be combined with the settings below, apart from video_name. |
output_settings.template |
No | A tpl_ id. |
output_settings.voice |
No | A voice_ id. |
output_settings.recipe |
No | A recipe id. |
output_settings.brand_kit |
No | A bk_ id. |
output_settings.aspect_ratio |
No | landscape, square, vertical or fourfive (4:5). |
output_settings.target_duration_seconds |
No | 5 to 600. |
output_settings.video_name |
No | Up to 200 characters. |
instructions |
See below | Free-text direction for the agent. |
Send at least one of script, text and instructions, and never both script and text. With instructions alone, the agent writes the script from them.
Responses:
201: the new video request (see "The video request object" below).200: a retry of an earlier request with the sameIdempotency-Key; returns that request instead of making another video.400: the body is invalid. The response says which fields are wrong and why.409: theIdempotency-Keywas already used with a different body.429: too many requests (see "Limits" below).
Idempotency. Send an Idempotency-Key header (any unique string up to 255 characters, such as a UUID) so you can safely retry after a timeout or network error. Retrying with the same key and body returns the original request; the same key with a different body is refused with 409. Keys are scoped to the caller and workspace.
List video requests
GET /api/v1/video-creation/requests/?workspace=ws_123&status=running
The workspace's requests, newest first. status is optional: running, completed or failed.
Get a video request
GET /api/v1/video-creation/requests/{request_id}/
List webhook endpoints
GET /api/v1/video-creation/webhook-endpoints/
Add a webhook endpoint
POST /api/v1/video-creation/webhook-endpoints/
{
"url": "https://example.com/lumen5-webhook",
"events": ["request.completed", "request.failed"]
}
url must be a public https URL. Returns 201 with id (whep_…), url, events, created_at and secret (whsec_…). The secret is shown only this once; store it to verify deliveries.
An endpoint receives events for all of the caller's requests, in every workspace.
Delete a webhook endpoint
DELETE /api/v1/video-creation/webhook-endpoints/{endpoint_id}/
Returns 204.
Rotate a webhook secret
POST /api/v1/video-creation/webhook-endpoints/{endpoint_id}/rotate-secret/
Returns the endpoint with its new secret. The old secret keeps working for 24 hours, so you can update your receiver without dropping deliveries.
Get the OpenAPI schema
GET /api/v1/video-creation/schema/
No authentication needed. Use it to generate a client or to give an agent the full set of operations.
The video request object
{
"id": "req_9f1c2d3e-…",
"status": "completed",
"workspace": "ws_123",
"input_content": {"script": null, "text": "Source material…"},
"output_settings": {
"blueprint": null,
"template": "tpl_abc",
"voice": null,
"recipe": null,
"brand_kit": null,
"aspect_ratio": "vertical",
"target_duration_seconds": null,
"video_name": null
},
"instructions": null,
"video_url": "https://lumen5.com/app/?id=456",
"error": null,
"created_at": "2026-10-06T18:30:00Z",
"finished_at": "2026-10-06T18:34:10Z"
}
| Field | Description |
|---|---|
status |
running, then completed or failed. |
output_settings |
What you asked for. null means you left it to the agent. |
video_url |
Opens the video in Lumen5. null until there is a video. |
error |
Why the request failed, when status is failed. |
finished_at |
When the request completed or failed. |
Webhooks
Lumen5 sends a POST with a JSON body to each endpoint subscribed to the event:
| Event | Sent when |
|---|---|
request.completed |
A video request finished and its video is ready. |
request.failed |
A video request failed. |
{
"event": "request.completed",
"request_id": "req_9f1c2d3e-…",
"workspace": "ws_123",
"status": "completed",
"occurred_at": "2026-10-06T18:34:10+00:00",
"video_url": "https://lumen5.com/app/?id=456"
}
Payloads say what happened and, once there is a video, link to it in video_url (null otherwise, as for a failed request). Verify the signature before you act on a delivery or pass its video_url on. Fetch GET /requests/{request_id}/ with your own credentials for the rest of the details.
Respond with a 2xx status within 10 seconds. Redirects aren't followed. Respond with 410 Gone to unsubscribe: the endpoint is deleted and gets no further deliveries. Any other response, or no response, is retried up to 5 times over about half an hour, so the same event can arrive more than once: use request_id and event to ignore repeats.
Each delivery carries these headers:
| Header | Value |
|---|---|
X-Lumen5-Event |
The event name. |
X-Lumen5-Timestamp |
When the delivery was signed. |
X-Lumen5-Signature |
One or more comma-separated signatures, each v0= followed by a hex HMAC-SHA256 signature. |
To verify a delivery, compute HMAC-SHA256 over v0:{timestamp}:{raw request body} with the endpoint's secret, and accept the delivery if it matches any of the signatures in the header, comparing in constant time. Use the raw body bytes, before any JSON parsing.
The header usually holds one signature. For 24 hours after you rotate the secret, it holds one for the new secret and one for the old, so a receiver with either secret keeps verifying deliveries.
import hashlib
import hmac
def is_from_lumen5(secret: str, timestamp: str, raw_body: str, signature_header: str) -> bool:
expected = "v0=" + hmac.new(secret.encode(), f"v0:{timestamp}:{raw_body}".encode(), hashlib.sha256).hexdigest()
return any(hmac.compare_digest(expected, signature) for signature in signature_header.split(","))
Errors
Errors use standard HTTP status codes with a JSON body:
| Status | Meaning |
|---|---|
400 |
The body or parameters are invalid. The body maps each bad field to a list of messages, and detail sums them up in one readable string. |
401 |
The credential is missing, invalid, revoked or expired. |
403 |
The credential lacks the scope, or the user's role can't make that change. |
404 |
The workspace, request or endpoint doesn't exist or isn't visible to the caller. |
409 |
The Idempotency-Key was already used with a different body. |
429 |
Rate limited. Wait for the number of seconds in the Retry-After header. |
Limits
Each user can create up to 300 video requests an hour, on top of Lumen5's general API rate limits.
Notes for AI agents
- If you can use MCP tools, connect to
https://lumen5.com/mcpinstead of calling HTTP. See "MCP" above. - Fetch this page as Markdown from
https://lumen5.com/developers/api.md, and the machine-readable spec fromhttps://lumen5.com/api/v1/video-creation/schema/?format=json. - Start with
GET /workspaces/. If there is more than one workspace, ask the user which to use. - Only use ids returned by the listing endpoints. Don't guess them.
- Prefer leaving style settings out unless the user asked for them; the agent picks sensible defaults.
- Call
POST /resolve/beforePOST /requests/to catch mistakes without creating anything. - Always send an
Idempotency-Key, and reuse it when retrying the same request. - Creating a video takes minutes. Poll no more often than every 15 seconds, or use a webhook.