Skip to content

Authentication

The public API authenticates with workspace API keys. The dashboard and mobile app use short-lived session tokens instead.

API keys#

Keys belong to a workspace, not a person — they keep working when the person who created them leaves the team.

Send the key either way; both are equivalent:

Header
# Preferred
x-api-key: pk_live_1a2b3c4d…

# Also accepted
Authorization: Bearer pk_live_1a2b3c4d…

Keys are shown once

We store only a SHA-256 hash, so a key cannot be recovered — not by you, not by us. If you lose it, revoke it and create another. That also means a database leak on our side cannot be replayed as working credentials.

Live and test keys#

pk_live_pk_test_
Consumes creditsYesNo — always free
WatermarkFollows your planAlways watermarked
Rate limitPlan limitReduced
Rendering pathRealReal — identical code
Counts toward key quotaYesNo

Test mode is not a mock. It runs the same pipeline, returns the same shapes and produces a real file — so an integration built against it behaves identically when you swap the key.

Scopes#

Each key carries a set of scopes. Give a key only what it needs: a service that renders should not be able to delete templates.

ScopeGrants
renders:readList and retrieve renders, estimate cost
renders:writeCreate and cancel renders
templates:readList templates and read field schemas
templates:writeImport a design as a new template
assets:readList media library assets and transcriptions
assets:writeUpload and delete media, import from Drive, generate a voice-over, transcribe audio
webhooks:readList webhook endpoints
webhooks:writeRegister, edit, test and delete webhook endpoints
integrations:readList connections, browse and read connected accounts
integrations:writeCreate and modify data in connected accounts

A request missing the required scope returns 403 with INSUFFICIENT_SCOPE.

templates:write is narrower than it sounds. It grants exactly one thing — POST /v1/templates/import, which creates a private draft — and no endpoint behind it can edit, publish or delete a template you already have. Editing stays in the dashboard.

Restricting a key#

  • IP allowlist — plain addresses or CIDR blocks. A call from anywhere else returns 403 IP_NOT_ALLOWED. Worth setting for a key used only by your own servers.
  • Expiry — set a date and the key stops working then. Useful for contractors and short-lived integrations.
  • Revocation — immediate, from the dashboard. There is no grace period.

If a key leaks

Revoke it first, then rotate. A live key can spend your credits, so the order matters — creating the replacement before revoking the old one leaves a window where both work.

Session authentication#

The dashboard and mobile app use JWT session tokens rather than API keys. You do not normally interact with these directly, but they are documented because a few endpoints — credits history, billing — accept only session auth.

# Phone (WhatsApp OTP) — the only sign-in method.
POST /api/auth/send-otp     { "phone": "+919876543210" }
POST /api/auth/verify-otp   { "phone": "+919876543210", "otp": "123456" }

# verify-otp returns: { token, refreshToken, user, organization, plan, credits }

Access tokens last 12 hours; refresh tokens 60 days. Exchange an expired one at POST /api/auth/refresh — the dashboard does this automatically. Signing out revokes every token the account holds, on every device, immediately.

Authentication errors#

StatusCodeFix
401NO_API_KEYSend the x-api-key header
401INVALID_API_KEYKey unknown, revoked, inactive or expired — check which environment you are using
403INSUFFICIENT_SCOPEAdd the scope to the key, or use a different key
403IP_NOT_ALLOWEDAdd the calling IP to the key’s allowlist
403ORG_SUSPENDEDContact support — the workspace is suspended
401TOKEN_EXPIREDSession auth: refresh the token