Errors and Limitations

Errors

Failures carry a JSON body of the shape { "message": "..." }. Validation failures on the newer
endpoints may add an errors array naming the offending fields.

401 is the exception: it has no body at all. A missing, unknown or revoked token all produce
the same bare 401 — and so does a workspace on the Unlimited plan, which cannot use the API at
all. If a freshly generated token returns 401 on every endpoint, check the plan before debugging
the token.

CodeMeaning
200Success. On the render endpoints this means queued, not finished
206Partial content. Only on POST /videos/from-presentation: conversion outlived the request timeout and is still running. Not a failure — poll GET /videos rather than retrying
400The request was rejected. The message names the reason
401Not authorised. No body
403The resource belongs to another workspace
404Not found
429Either a rate limit or a quota — see below, they are not the same thing
500Internal error

Telling the two kinds of 429 apart

Both return 429, and the remedy is different. Read the message.

A rate limit means "you are going too fast". Wait and retry.

{ "message": "Too many requests per minute, please try again later.", "retryAfter": 42 }

These responses carry a Retry-After header with the same number of seconds. Use it instead of a
fixed backoff.

A quota means "you have created too many of something". Retrying will not help until the window
rolls or you upgrade.

{ "message": "You have reached the limit of 1000 videos per last 8 hours, please try again later" }

Rate limits

Only a few endpoints are rate limited, and the headers ship on every response from them — not
just the rejections — so you can see how much headroom is left before you are throttled.

EndpointPer minutePer hourApplies to
POST /videos/voice/{videoId}/{slideId}20200Every caller
POST /outline/{outlineId}/generate-chapters560API callers only, per workspace
POST /outline/{outlineId}/generate-script560API callers only, per workspace
HeaderOn
X-RateLimit-Limit-Min / X-RateLimit-Limit-HourYour ceiling for each window
X-RateLimit-Remaining-Min / X-RateLimit-Remaining-HourRequests left in each window
X-RateLimit-Reset-Min / X-RateLimit-Reset-HourUnix time (seconds) when each window resets
Retry-AfterOnly on a 429 — seconds to wait

The outline limits count public-API traffic only: the same workspace working in the Elai app does
not consume them.

Entity creation limits

A rolling 8-hour window per workspace. Exceeding one returns 429.

The buckets are Free versus paid-per-plan. A trial granted by an admin shares the paid
limits, not the Free ones — so a trialling Enterprise workspace gets 6000 videos, not 50.

EntityFreeCreatorTeamEnterprise
Videos (templates included)50100010006000
Folders10100100100
Uploaded media200100010001000
Custom fonts10100100100

The Free column applies when the workspace's status is Free. Every other status — trial, active,
cancelled — reads the paid column for its plan. Two legacy plans, Corporate and Platinum, have no
entry and are therefore unlimited.

Absolute caps

These are not windows — they do not roll. You are at the limit until you delete something or
upgrade.

LimitFreeCreatorTeamEnterprise
Upload folders5520Unlimited
{ "message": "You have reached the limit of 20 upload folders for your team plan. Please upgrade your plan or delete some folders." }

Per-request limits

LimitValue
Rows in one templateData batch (POST /videos/renderTemplate/{videoId})200
Slides per video100
Slides rendered on a Free plan3
Webhook response deadline10 seconds, single attempt, no retry

Failures that are not HTTP errors

Rendering is fire-and-forget. POST /videos/render/{videoId} and
POST /videos/renderTemplate/{videoId} both validate after responding, so no render failure
reaches you as a status code. Those arrive as a video_error
webhook, or as status: "error" on
GET /videos/{videoId}.

Webhook deliveries are single-attempt with a 10-second deadline and no retry, so a missed
video_error is not resent. If you cannot afford to lose one, reconcile with
GET /videos as well.