Authentication
Every request to https://faceless.so/api/v1 is authenticated with an API key. Keys are created in the dashboard, in your team settings at https://faceless.so/team, and look like fl_live_....
Sending the key
Two headers are accepted; use whichever fits your HTTP client:
curl -s https://faceless.so/api/v1/me \
-H "Authorization: Bearer $FACELESS_API_KEY"
curl -s https://faceless.so/api/v1/me \
-H "X-API-Key: $FACELESS_API_KEY"
Keys are accepted in headers only. Never put a key in a URL or query string; URLs end up in logs.
A missing or invalid key returns 401 with error type unauthorized.
Scopes
Each key carries a set of scopes chosen at creation. Calling an endpoint the key is not scoped for returns 403 with error type forbidden_scope.
credits:read: credit balance and ledger (GET /credits)videos:read: list and read videos, poll generation status and renders (GET /videos, GET /videos/{id}, GET /videos/{id}/status, GET /renders/{id})videos:write: create, caption, update, render and delete videos (POST /videos, POST /videos/captions, PATCH /videos/{id}, POST /videos/{id}/render, DELETE /videos/{id})series:read: list and read series and their episodes (GET /series, GET /series/{id}, GET /series/{id}/episodes)series:write: create, update and delete series, force the next episode (POST /series, PATCH /series/{id}, DELETE /series/{id}, POST /series/{id}/generate)posts:read: the posting calendar (GET /calendar)posts:write: publish, schedule and cancel posts (POST /posts, POST /posts/schedule, DELETE /posts/{id})accounts:read: list connected social accounts (GET /accounts)assets:read/assets:write: read and register media assets (POST /assets)analytics:read: cross-platform performance (GET /analytics)catalog:read: voices and option catalogs (GET /voices, GET /options)
GET /me works with any valid key regardless of scopes; use it to check which scopes a key has (data.auth.scopes).
Legacy team keys
Teams created before scoped keys have a legacy team API key (a UUID). It still works in the same headers and is treated as having every scope. Prefer creating a scoped fl_live_ key: it can be revoked on its own and limits the blast radius of a leak. GET /me reports data.auth.legacy: true when a legacy key is used.
Managing keys
Everything happens in team settings at https://faceless.so/team:
- Create a key with a name and the scopes it needs
- The full key is shown once, at creation; only a prefix (like
fl_live_a1b2c3d4) is visible afterwards - Revoke a key at any time; revoked keys stop working immediately
Security notes
- Store keys in environment variables or a secret manager, never in source control
- Give each integration its own key with the minimum scopes it needs, so one leak has a small blast radius and revocation does not break everything else
- If a key leaks, revoke it in the dashboard and create a new one
- Keys act on behalf of your team; treat them like passwords