Zeli AvatarDeveloper docs

Get started / Authentication

Authentication

Use an API key from your Zeli Avatar account for server-side integrations. For browser streaming, your backend exchanges that key for a short-lived session token.

Get an API key

  1. Sign in to the developer portal.
  2. Open API keys, create a named key, and copy it when shown.
  3. Store it in your backend's secret manager or environment as ZELI_API_KEY. Do not commit it or include it in browser bundles.

Use this deployment's hosted base URL:

https://zeli-avatar.zelibot.xyz

The hosted service requires credentials for protected routes. Public visitor links use a separate consent and session flow; they do not expose your API key. See Share links.

Presenting a key

Send your key as X-Api-Key on routes that accept API keys. Streaming routes and token minting also accept Authorization: Bearer <key>; do not use that alternative for account-backed /auth/* API-key requests. The SDK sends the credential for you when you pass ZeliClient(api_key=...).

import os
from zeli import ZeliClient, AvatarConfig, ClientOptions
 
# The SDK forwards the key on signalling + the control WebSocket.
client = ZeliClient(
    api_key=os.environ["ZELI_API_KEY"],
    avatar_config=AvatarConfig(avatar_id=os.environ["ZELI_AVATAR_ID"]), # Copy ID from your library
    options=ClientOptions(server_url="https://zeli-avatar.zelibot.xyz"),
)

Full keys vs. session tokens

There are two credential kinds, with different scope:

CredentialScopeMinted byCan mutate?
API key (zsk_live_…)Authorized SDK and management routesYour signed-in account in the portalYes, for your resources
Session token (zsk_temp_…)Stream-only (tts)A full keyNo

A full key authorizes the SDK and management routes documented for API keys. It does not replace portal authentication on account-only routes. A session token is stream-only: it can drive an avatar stream but never mutate server state. This is what you hand to a browser, so a real key never leaves your backend.

Minting a session token

Your backend calls streaming.create_token with a full key and hands the short-lived token to the browser.

POST/v1/streaming.create_token
ttl_secondsintOptionaldefault: 300

Lifetime of the token in seconds. Clamped to the range 30 to 600.

// Request  (full-key gated, X-Api-Key: zsk_live_...)
{ "ttl_seconds": 300 }
 
// Response
{
  "data": {
    "token": "zsk_temp_...",
    "expires_at": 1770000000,
    "scope": "tts"
  }
}

The browser then passes the token on the /connect signalling request and on the control WebSocket as a ?session_token=... query parameter:

POST /connect?session_token=zsk_temp_...
WSS  <control-gateway>?session_token=zsk_temp_...
Never ship a full key to a browser

A leaked session token can drive a stream until it expires, but it can never mutate. A mutation attempt returns 401 insufficient_scope. Expiry is enforced server-side on every request.

Error envelope

Auth failures return 401 with a small JSON envelope:

{ "code": "missing_api_key", "message": "..." }
StatuscodeWhen
401missing_api_keyAuth is required but no key was sent
401invalid_api_keyThe key sent isn't recognized (or has expired)
401insufficient_scopeA session token was used on a mutating / management route

In the SDK, a rejected key or token surfaces as AuthenticationError.

Account and portal routes

Account management, API-key creation, and Persona owner routes require a signed-in account. An SDK API key does not grant access to every /auth/* endpoint. Each reference page identifies its accepted credential. Use X-Api-Key for the account-backed API routes that explicitly accept API keys; Authorization on those routes is reserved for the signed-in identity token.

Self-hosting

Operating your own server has a separate authentication configuration. Follow the operator authentication guide before exposing a self-hosted service. Hosted users do not need server environment variables or a database setup.

Zeli Avatar · real-time avatars over WebRTC · self-hostable · AU data residency · source