Casola Avatar Interaction API

2. Choosing an avatar

A mint must name exactly one avatar. There are four ways to do it, and they differ in how much you pin: from “whatever this avatar currently publishes” to “this exact immutable version”.

The four selectors

Parameter Names Moves when the avatar is edited? Credential
avatar_id An avatar; resolves to its current published version Yes — you always get the latest publish Secret
avatar_ref A specific version id No Secret
avatar_version_id A specific version, as an explicit pin No Secret
persona A stock catalog avatar, by name ("mei") Yes — stock catalog is curated by Casola Any

Use avatar_id. It is the addressing form you want in almost every integration: you name the avatar, and whatever it currently publishes is what runs. You never have to learn or store version ids, and publishing a new version rolls out without a code change.

{ "avatar_id": "019fe463-fbd3-7000-80e8-85dad81d3fee" }

avatar_ref predates it and names a version, not an avatar — that is a historical quirk worth remembering when reading old integration code, because the name suggests otherwise. It still works and still means exactly what it always meant.

Mutual exclusivity

Combination Result
avatar_id + avatar_ref 400 avatar_ref_avatar_id_exclusive
avatar_ref + persona 400 avatar_ref_persona_exclusive
avatar_id with no published version 400 avatar_not_published
avatar_id that does not exist / is deleted 404 avatar_not_found

avatar_not_published is deliberate: an avatar whose wizard run never finished has draft assets, and resolving to a draft would put an unfinished face in front of a user.

Pinning a version

avatar_version_id pins the sealed assets to one immutable version, so a long-running integration can adopt new versions on its own schedule:

{
  "avatar_id": "019fe463-fbd3-…",
  "avatar_version_id": "019fe463-fc00-7000-806c-c9723f5f81cb"
}

Used together, the version must belong to that avatar. Used alone, the version names the avatar implicitly. The version must be published and sealed (400 version_not_published otherwise).

Pinning the assets is orthogonal to pinning the text: profile_id pins the prompt layer, and the two compose freely. See 4. Prompt, backstory & overrides.

Listing what you can choose from

Your workspace’s avatars

curl -sS https://api.casola.ai/api/v1/avatars \
  -H "Authorization: Bearer $CASOLA_SECRET_KEY"
{
  "data": [
    {
      "id": "019fe463-fbd3-7000-80e8-85dad81d3fee",
      "name": "Lyra",
      "slug": "lyra",
      "kind": "custom",
      "current_version_id": "019fe463-fc00-7000-806c-c9723f5f81cb",
      "default_profile_id": "019fe463-fc2a-7000-8093-1f0b2ac6e8d1",
      "assets_status": "ready",
      "created_at": 1786248112
    }
  ]
}

assets_status reports the avatar’s derived idle media (the loop clips it plays while listening):

Value Meaning
ready Idle media built and registered — full experience
building A background build is running; sessions work now and improve when it finishes
missing Not built yet, or a build failed. Sessions still work — the avatar simply holds a still frame while idle

Sessions never require derived assets, so missing is never a reason to hide an avatar from your users. It is a quality signal, not a gate.

One avatar

curl -sS https://api.casola.ai/api/v1/avatars/019fe463-fbd3-… \
  -H "Authorization: Bearer $CASOLA_SECRET_KEY"

Its versions

curl -sS https://api.casola.ai/api/v1/avatars/019fe463-fbd3-…/versions \
  -H "Authorization: Bearer $CASOLA_SECRET_KEY"

The public stock catalog

curl -sS https://api.casola.ai/api/gallery

No authentication. Returns the stock avatars available to persona, with display names, taglines and preview image URLs — this is what the public demo widget renders.

Entries carry a tier. That tier gates the consumer surfaces (the anonymous demo and signed-in consumer plans); API key traffic is deliberately not gated on a plan, because API access is granted by your workspace’s api_access feature rather than bought as a consumer subscription. A lapsed consumer plan can never silently break your integration.

Managing avatars

Route Method Purpose
/api/v1/avatars GET List
/api/v1/avatars POST Create ({"name": "Lyra"}) → 201
/api/v1/avatars/:avatarId GET Read
/api/v1/avatars/:avatarId PATCH Rename only ({"name": "…"})
/api/v1/avatars/:avatarId DELETE Soft-delete
/api/v1/avatars/:avatarId/versions GET / POST List / seal a new version
/api/v1/avatars/:avatarId/profiles GET / POST The text + config layer — see doc 4

PATCH takes a display name and nothing else. That is not an oversight: the persona fields are not mutable columns. Changing the face or voice publishes a new version; changing the prompt, backstory, tools or config appends a profile. Both are additive operations with their own identity, which is what makes “what exactly was this session running?” answerable after the fact.

Creating avatars

Creating an avatar with a face and voice is the job of the avatar creation wizard (/api/v1/design/drafts/*), which runs portrait generation, character-brief drafting and voice design on the GPU fleet and finalizes into an avatar + sealed version + default profile. That surface is documented separately; these docs cover interacting with avatars that already exist.

Stock avatars are read-only

Stock avatars (ws_stock) can be read, listed and used by anyone, but their profiles cannot be edited — 403 stock_read_only. To customize one, clone it: the wizard’s POST /api/v1/design/drafts/from-avatar/:avatarId copies its sealed face and voice into a draft you own, and finalizing gives you an avatar whose prompt you control.

Per-session overrides work fine against a stock avatar, since they change nothing stored:

{
  "persona": "mei",
  "extra_system_prompt": "The caller is asking about their order #4471."
}

Next: 3. Session lifecycle →