Get started

Errors & rate limits

Every response is wrapped in a consistent envelope:

Success
{
  "success": true,
  "data": { /* ... */ }
}
Error
{
  "success": false,
  "statusCode": 403,
  "code": "INSUFFICIENT_SCOPE",
  "message": "This credential is missing the render:write scope",
  "path": "/v1/embed/emb_123/render",
  "timestamp": "2026-09-08T12:00:00.000Z"
}

Authentication and authorization — thrown before your request reaches any handler:

ParamTypeNotes
401 NO_SESSIONNo credential was sent at all.
403 INVALID_API_KEYAn fl_live_… key is unknown or revoked.
403 SUBSCRIPTION_SUSPENDEDThe key's workspace subscription is suspended.
403 WORKSPACE_MISMATCHThe request targets a workspace other than the key's own.
403 INSUFFICIENT_SCOPEAn embed session or MCP connection is not allowed to use this endpoint. API keys have full access and never get this.
403 RLS_DENIEDA database policy blocked the query — surfaced only if a guard check is ever bypassed; treat as a bug report.

Credits and plan limits:

ParamTypeNotes
402 INSUFFICIENT_CREDITSThe workspace's subscription has run out of render credits.
402 WORKSPACE_CREDIT_LIMITThe workspace's own per-workspace credit limit was hit, ahead of the shared subscription pool.
403 PLAN_FEATURE_NOT_INCLUDEDThe current plan doesn't include the feature being used (e.g. social publishing, embeds).

Rendering:

ParamTypeNotes
422 RENDER_TOO_LARGEThe rendered output exceeds the maximum file size.
422 VIDEO_TOO_LONGThe computed animation duration exceeds the maximum allowed video length.
400 INVALID_VIDEO_OPTIONSAn fps, scale or quality value for an animated render is out of range.
400 INVALID_MODIFICATIONSA modification value is not a string.
503 QUEUE_UNAVAILABLEThe render queue is unreachable — retry shortly.
504 RENDER_TIMEOUTThe render job exceeded its wait timeout.

Render editing / embed sessions:

ParamTypeNotes
403 EDIT_SESSION_REQUIREDA render-mode route was called without an edit session token.
409 EDIT_SESSION_NOT_OPENEDA draft or save was requested before the edit session was opened.
409 EDIT_SESSION_ALREADY_OPENEDAn editor link was used twice — create a new edit session.
403 EMBED_MISMATCHAn embed session token was used against a different embed id.
403 DOMAIN_NOT_ALLOWEDAn edit session's origin is not on the embed's allowed domains.
400 PAGE_CHANGES_NOT_ALLOWED / LOCKED_LAYER_CHANGEDAn editor save broke the session's allowPageChanges / allowUnlock option. Full list under Render editing → Errors.

Validation and Postgres conflicts:

ParamTypeNotes
400 (no code)Request body failed validation — unknown fields are rejected outright, and message is an array of every failed field, not a single string.
429 (no code)Rate limit exceeded — see below.
409 (unique constraint)Postgres conflict — code is the violated constraint's name.
A code field is only present when the thrown error explicitly set one. Plain validation failures and rate-limit responses carry a message but no code — match on statusCode for those.

Rate limits scale with your plan (requests/minute) and are reported back on GET /v1/me under plan.limits.rate_per_minute. Exceeding it returns 429 with no code field:

429 Too Many Requests
{
  "success": false,
  "statusCode": 429,
  "message": "ThrottlerException: Too Many Requests",
  "path": "/v1/templates/tpl_123/render",
  "timestamp": "2026-09-08T12:00:00.000Z"
}
The rate-limit bucket depends on how the request is authenticated: per workspace for an API key or MCP connection, per user for a dashboard session, and per IP address for an embed session. One noisy integration can't exhaust a teammate's allowance.

Was this page helpful?