Quickstart
Quickstart
Go from zero to a live, full-duplex conversation with a Casola avatar: get an API key, mint a session from your server, and connect the browser directly to the GPU edge. Under five minutes.
How it fits together (two planes — this shape matters for everything below):
- Control plane — your server calls
https://api.casola.aiwith your secret key to mint a session. The response names the GPU edge to talk to (connect_url) and a short-lived signed token for it (session_token). - Data plane — your client connects straight to that edge over two WebSockets (video down, microphone up). Your secret key never touches the client; media never proxies through your server.
1. Create an account and get an API key
Sign up at the dashboard and open the API Keys page. Click Create key, give it a name, and copy the key — it is shown only once and looks like:
avatar_<8-hex-chars>.<56-hex-chars>This is a secret key: keep it server-side only (env var, secret manager — never a client bundle or app binary).
export CASOLA_API_KEY="avatar_abc12345.xyz..."2. Verify the key
curl https://api.casola.ai/api/v1/tokens \ -H "Authorization: Bearer $CASOLA_API_KEY"A 200 with your token list confirms the key works.
3. Pick a stock avatar
The stock catalog is public — no auth:
curl https://api.casola.ai/api/gallery{ "avatars": [ { "id": "mei", "name": "Mei", "tagline": "…", "blurb": "…", "accent": "#e88", "voiceLang": "zh", "poster": "/api/gallery/mei/face", "hasIntro": true }, { "id": "david", "name": "David", "tagline": "…", "blurb": "…", "accent": "#88e", "voiceLang": "en", "poster": "/api/gallery/david/face", "hasIntro": true } ]}id is the persona key you pass when minting. Each persona also has a public
looping intro clip (/api/gallery/{id}/intro?lang=en|zh) you can show in your
picker UI while the user decides.
4. Start a session (server-side)
curl -X POST https://api.casola.ai/api/v1/sessions \ -H "Authorization: Bearer $CASOLA_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "persona": "mei" }'201 — a GPU seat is yours:
{ "status": "ready", "session_id": "019...", "connect_url": "https://box-1.casola.ai", "session_token": "eyJhbGciOiJFZERTQ...", "seat_token": "…", "expires_at": 1719000060}connect_url— the assigned edge’s https base URL; derive WebSocket URLs by swapping towss.session_token— a short-lived (≈60 s) EdDSA JWT the edge verifies offline. Connect promptly; if it expires, mint again. Once connected, the live session runs up to the server-set cap (default ≈5 minutes).
202 — fleet at capacity, you’re queued:
{ "status": "queued", "ticket": "q_...", "ahead": 3, "queue_ws": "/api/v1/sessions/queue?ticket=q_..." }Open the queue_ws WebSocket for live position updates, then re-mint when
promoted (see Sessions).
Hand connect_url + session_token to your client — that’s the only thing your
backend needs to produce.
5. Connect and talk (browser)
npm install @casola/avatar-clientimport { AvatarSession, connectViaToken } from '@casola/avatar-client'
// Your backend endpoint wrapping step 4:const { connect_url, session_token } = await fetch('/my-backend/start-session').then(r => r.json())
const session = new AvatarSession({ videoEl: document.querySelector('video'), connect: connectViaToken({ connectUrl: connect_url, sessionToken: session_token }), workletUrl: '/mic-worklet.js', // see "Worklet asset" below lang: 'en', callbacks: { onFirstFrame() { console.log('avatar is live') }, onPartial(text) { console.log('you (so far):', text) }, onTurn(t) { console.log('you said:', t.text, '→ avatar replies:', t.reply) }, onClose(reason) { console.log('ended:', reason) }, onError(err) { console.error(err) }, },})
// Must be called from a user gesture (mic permission + autoplay).await session.start()That’s the whole conversation loop: the SDK plays the avatar’s video+voice via
MSE and streams your microphone up; the avatar listens, thinks, and answers
by speaking — onPartial/onTurn are transcripts for your UI, not something
you need to respond to. Speak over the avatar to interrupt it (barge-in is
server-side).
The SDK handles ManagedMediaSource/MediaSource differences (iOS Safari), append
queueing, latency housekeeping, mic capture, 48 kHz → 16 kHz resampling, and
PCM16 framing. Microphone echoCancellation is always on — required, or the
avatar hears itself through your speakers.
Worklet asset. audioWorklet.addModule() needs a real URL — the worklet
can’t be inlined into your bundle. With Vite:
import workletUrl from '@casola/avatar-client/worklet?worker&url'// pass workletUrl to AvatarSession opts5b. Or connect without the SDK (server / native)
Two WebSockets against connect_url. Browsers must pass the token as
?token=<session_token> (no headers on WS upgrades); native/server clients
should prefer the Authorization: Bearer header.
| Socket | Path | Direction | Payload |
|---|---|---|---|
| Downlink | /mse | server → client | 1 text frame {"mime": "..."}, then binary fMP4 segments |
| Uplink | /mic_stream | client → server | 1 text frame {"op":"hello","lang":"en"}, then binary 16 kHz mono PCM16 frames (1600 samples = 100 ms); JSON partial / turn events come back |
See the API Reference → Data plane for the full wire protocol.
Next steps
- API Reference — concepts + every endpoint, including custom avatars (your own face + voice), voice design, and prebuild warm-up
- Browser SDK reference — full
AvatarSessionAPI - Authentication — scoped keys, publishable keys for browser-only embeds
- Need help? Email support@casola.ai