Create an avatar
Upload a zip with a manifest, an image and a voice sample, and get back a fully built, ready-to-chat avatar.
Everything a person can do in Studio → Create avatar — upload a face, a voice sample, write a
persona, attach knowledge files — is also one API call. The avatar that comes back is identical to
one built in the UI: it shows up in Manage and can be used with POST /v1/session the same way.
Create a key with the right scope
Avatar management needs a key with the avatars:write scope; the default sessions scope is
not enough. Add billing:write too if the manifest will carry a sponsor block. The key must be
account-wide — an avatar-scoped key can update the one avatar it is scoped to, but never create
or delete. See API keys.
Build the zip
my-avatar.zip
├── avatar.json # manifest (required)
├── image/portrait.jpg # exactly one image (jpg/png/webp ≤10 MB)
├── voice/sample.wav # exactly one sample (mp3/wav/m4a/aac/ogg/flac/opus/webm, 10–60 s, ≤12 MB)
├── prompt/prompt.txt # the scenario, free text (≤10,000 chars) -- or use persona.scenario
└── knowledge/ # optional, ≤20 files: pdf/docx/doc/txt/md/html/csv ≤50 MB eachThe image should show the whole head with some margin around it; a face that fills the frame edge to edge fails the preview stage. The voice sample is checked server-side for clean, audible speech — not silence or a pure tone.
avatar.json:
{
"schemaVersion": 1,
"name": "Grand Valley Concierge",
"description": "Friendly resort concierge",
"language": "en",
"visibility": "private",
"persona": {
"preferredAlias": "Val",
"personality": "A warm, endlessly patient concierge who knows the resort inside out and keeps every answer practical.",
"greeting": "Hi, I'm Val — how can I help?",
"selfIntroduction": "I'm Val, the concierge for Grand Valley resort...",
"guardrails": ["Never quote prices that aren't in the knowledge base"],
"conversationalHabits": {
"CONVERSATIONAL_HABIT_ENGAGEMENT": "CONVERSATIONAL_HABIT_SCALE_MEDIUM"
}
},
"knowledge": { "descriptions": { "pricing.pdf": "2026 rate card" } },
"previewMessage": "Hello!"
}| Field | Required | Notes |
|---|---|---|
name | yes | The project name shown in Studio (1–100 chars). |
visibility | no | private or unlisted at create time. public requires a PATCH once the avatar is ready. |
language | no | en, zh-TW or ja. |
persona.preferredAlias | no | The name the avatar goes by in conversation. |
persona.personality | no | The main character description — who the avatar is. Up to 10,000 chars. |
persona.scenario | no | What the avatar is doing with the visitor. JSON alternative to prompt/prompt.txt — providing both is rejected. |
persona.selfIntroduction | no | 51–2000 chars, used verbatim; derived from personality when absent. |
persona.greeting | no | The avatar's opening line, ≤500 chars. |
persona.guardrails | no | Up to 20 entries, ≤500 chars each, used verbatim. |
knowledge.descriptions | no | Maps a filename in knowledge/ to a short description. Up to 20 files. |
sponsor | no | { microcredits, maxPerSession } — funds the avatar's budget at creation. Needs billing:write. See Sponsored access. |
Upload it
curl -X POST "https://api.atmanity.us/v1/avatars" \
-H "X-Api-Key: $ATMEE_API_KEY" \
-F "file=@my-avatar.zip"{
"avatarId": "56cc8fdd-ba78-4d48-a210-16cf80c3f5f5",
"status": "building",
"statusUrl": "/v1/avatars/56cc8fdd-ba78-4d48-a210-16cf80c3f5f5"
}A 202 means the build has started. A malformed zip or manifest answers 400 with an error of
invalid_zip or invalid_manifest and a message naming the problem; the full list of codes is
in the Reference.
Use https://staging.atmanity.us with a staging key while you develop — keys are not
interchangeable between environments, same as /v1/session.
Poll until it's ready
curl "https://api.atmanity.us/v1/avatars/56cc8fdd-ba78-4d48-a210-16cf80c3f5f5" \
-H "X-Api-Key: $ATMEE_API_KEY"{
"id": "56cc8fdd-ba78-4d48-a210-16cf80c3f5f5",
"name": "Grand Valley Concierge",
"status": "ready",
"readyToChat": true,
"moderationState": "clean",
"visibility": "private",
"stages": {
"appearance": { "status": "completed" },
"voice": { "status": "completed" },
"persona": { "status": "completed" },
"knowledge": { "status": "completed" },
"previews": { "status": "completed" }
}
}status is building → ready (or failed / moderation_hold). Each stage under stages is
independently waiting → pending → processing → completed (or failed, with a
userFeedback message you can show verbatim). A clean build typically finishes in under a
minute; poll every few seconds rather than long-polling.
Once readyToChat is true, start a session with
POST /v1/session using the id as avatarId, exactly
as in the Quickstart.
Update it afterwards
Text changes — name, description, visibility, language, preview message and every persona field —
go through PATCH /v1/avatars/{avatarId}. A new
image, voice sample or knowledge set is a PUT to
/appearance,
/voice or
/knowledge; only the affected build stages
re-run, and the avatar answers building again until they finish.
DELETE /v1/avatars/{avatarId} removes it.
Next steps
