UNITHdocs
Sign inarrow_forward

Realtime Avatars via the UNITH Platform API — Quickstart

warning_amber

This is an early soft launch of our new streaming solution, currently available only to API users. For this alpha release, several features have been temporarily removed — including the welcome message, alias, suggestions, image and link handling — to focus on the core real-time conversational experience. This is input into an upcoming full frontend and UX overhaul, scheduled for completion by the end of the year (2025).

This guide shows you how to create a streaming Digital Human (avatar) directly from the Unith API using your own account. It covers authentication, picking a head visual, choosing a TTS voice, creating the head, and deriving the stream URL.

info

Prerequisites:

  • API Access & your email address (registered on UNITH)
  • Your Secret Key (from Manage Account → Secret Key)
  • Base URL: https://platform-api.unith.ai
  • Tools: curl or any HTTP client

1) Authenticate → get a Bearer token

Bearer tokens authenticate all API requests and expire after 7 days.

Request

code
curl -X POST "https://platform-api.unith.ai/auth/token" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
    "email": "you@company.com",
    "secretKey": "sk_live_..."
  }'

Response (one of the shapes below):

{ "token": "eyJhbGciOi..." }

or

{ "data": { "bearer": "eyJhbGciOi..." } }

Use the returned token in Authorization: Bearer <token> for all subsequent requests.

2) Discover head visuals (faces)

List head visuals your org can use. You can filter and page; a practical pattern is to fetch a larger page (e.g., 50) and do client-side pagination in your UI.

warning_amber

For streaming avatars, you can only use Head Visuals that were created without gestures. Those that only contains a single silent idle.

Request (50 faces, optional gender filter)

code
# Gender can be MALE or FEMALE; omit it to fetch all.
curl -X GET "https://platform-api.unith.ai/head_visual/face/all?order=ASC&page=1&take=50&gender=FEMALE" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer <token>"

Response (excerpt)

{ "data": [ { "id": "ec4326ba-b06a-474d-bd08-ab96b42f06a3", "name": "aiko", "gender": "FEMALE", "avatar": "https://.../thumb.bmp", "videoUrl": "https://.../idle.mp4", "permissionType": "PRIVATE", "type": "TALK" } // ... ], "meta": { "page": 1, "take": 50, "itemCount": 1635, "pageCount": 33, "hasNextPage": true } }

info

Tip: display avatar (or fallback to posterImage or videoUrl) as the thumbnail in your UI.

3) Choose a TTS voice (provider: ElevenLabs)

Fetch the unified voice catalog filtered by provider. Use the voiceId (not the display name) when creating the avatar.

Request

code
curl -X GET "https://platform-api.unith.ai/voice/all?provider=elevenlabs" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer <token>"

Response (excerpt)

{ "data": { "voices": [ { "displayName": "Roger_eleven_v2_flash", "voiceId": "CwhRBWXzGAHq8TQ4Fs17_eleven_v2_flash", "locale": "en-US", "language": "English", "gender": "MALE", "provider": "elevenlabs" } // ... ] } }

error_outline

Currently, elevenlabs is the only support voice provider for streaming avatars.

4) Create a streaming Digital Human (Open Conversation)

To create a Digital Human, you must follow the same instructions as listed here Create a Digital Human but where the voice provider is elevenlabs, the greetings (welcome message) is an empty string "".

You must select:

  • headVisualId from step 2
  • ttsProvider and ttsVoice (voiceId) from step 3
  • operationMode can be any of UNITH's supported operations modes. Please see Configuration Parameters.
  • greetings must be an empty string

Request

code
curl -X POST "https://platform-api.unith.ai/head/create" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <token>" \
  -d '{
    "headVisualId": "ec4326ba-b06a-474d-bd08-ab96b42f06a3",
    "name": "Jester",
    "languageSpeechRecognition": "en-US",
    "language": "en-US",
    "operationMode": "oc",
    "ttsProvider": "elevenlabs",
    "ttsVoice": "CwhRBWXzGAHq8TQ4Fs17_eleven_v2_flash",
    "greetings": "",
    "promptConfig": { "system_prompt": "You are helpful and concise." }
  }'

Response (excerpt)

{ "id": "head_12345", "publicId": "head_12345", "publicUrl": "https://chat.unith.ai/<org-id>/<head-id>?api_key=<org-api-key>" }

error_outline

For elevenlabs, If you pass a voice name instead of a voiceId, you may get an error. Always send ttsVoice: <voiceId>.

5) Disable the splitter (required for streaming)

After the head is created, turn off the splitter so the head can stream conversationally:

code
curl -X PUT "https://platform-api.unith.ai/head/<head-id>/splitter?splitter=false" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer <token>"

Expect a 200 OK or equivalent confirmation.

6) Retrieve details → build your stream URL

Get the head to obtain publicUrl and derive the stream URL:

code
curl -X GET "https://platform-api.unith.ai/head/<head-id>" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer <token>"

Response (excerpt)

{ "publicId": "<head-id>", "publicUrl": "https://chat.unith.ai/<org-id>/<head-id>?api_key=<org-api-key>" }

Streaming URL format

Open that link in the browser to interact with your streaming avatar.

Keep this URL safe — it includes your org API key in the query string.

Example: minimal JS (fetch) flow

const BASE = 'https://platform-api.unith.ai';

async function api(path, { method='GET', token, body } = {}) { const res = await fetch(`${BASE}${path}`, { method, headers: { 'Accept': 'application/json', ...(method !== 'GET' ? { 'Content-Type': 'application/json' } : {}), ...(token ? { 'Authorization': `Bearer ${token}` } : {}), }, ...(body ? { body: JSON.stringify(body) } : {}) }); if (!res.ok) throw new Error(`HTTP ${res.status} — ${await res.text()}`); return res.json(); }

(async () => { // 1) Auth const a = await api('/auth/token', { method: 'POST', body: { email: 'you@company.com', secretKey: 'sk_live_...' } }); const token = a?.token || a?.data?.bearer;

// 2) Faces const faces = await api('/head_visual/face/all?order=ASC&page=1&take=50&gender=FEMALE', { token }); const headVisualId = faces.data[0].id;

// 3) Voices (ElevenLabs) const voices = await api('/voice/all?provider=elevenlabs', { token }); const voiceId = (voices?.data?.voices || [])[0].voiceId;

// 4) Create const created = await api('/head/create', { method: 'POST', token, body: { headVisualId, alias: 'My Assistant', name: 'My Assistant', languageSpeechRecognition: 'en-US', language: 'en-US', operationMode: 'oc', ttsProvider: 'elevenlabs', ttsVoice: voiceId, greetings: '', promptConfig: { system_prompt: 'You are helpful and concise.' } } }); const headId = created.id || created.publicId;

// 5) Disable splitter await api(`/head/${headId}/splitter?splitter=false`, { method: 'PUT', token });

// 6) Details → stream URL const details = await api(`/head/${headId}`, { token }); const u = new URL(details.publicUrl); const [ , org, head ] = u.pathname.split('/'); // ['', orgId, headId] const apiKey = u.searchParams.get('api_key'); const streamUrl = `https://stream.unith.ai/${org}/${head}?api_key=${apiKey}`;

console.log('Open:', streamUrl); })();

Troubleshooting

  • 403 Forbidden on faces/voices:
    • Your token may belong to a different org or lacks permissions. If you have multiple orgs, include "orgId": "<org-id>" when creating a head. Ensure your org is active and has the correct subscription.
  • 404 Voice not available:
    • You passed a voice name instead of a voiceId; fetch /voice/all?provider=elevenlabs and send ttsVoice: "<voiceId>".
  • Always getting page 1:
    • Use head_visual/face/all (not /head_visual/all). If server-side paging is inconsistent, fetch a larger take (e.g., 50) and paginate client-side.
  • No token returned:
    • The /auth/token response shape may be { data: { bearer: "..." } }; read both token and data.bearer. Also double-check your email + secret key.

Security best practices

  • Never store or hardcode your Secret Key in public repos.
  • The Bearer token expires in 7 days — refresh via /auth/token.
  • Treat the stream URL as sensitive (it contains your org API key in the querystring).

Optional: Other operation modes

  • Text-to-Video (operationMode: "ttt") generates an .mp4 from text.
  • doc_qa uses your uploaded knowledge base (requires additional document upload step).
  • plugin connects a custom conversational engine via webhook.
  • voiceflow integrates a Voiceflow conversation (requires voiceflowApiKey).

The core creation call is the same endpoint (/head/create), with mode-specific fields.

Reference endpoints

  • POST /auth/token — obtain bearer
  • GET /head_visual/face/all — list available head visuals (supports order, page, take, gender=MALE|FEMALE)
  • GET /voice/all?provider=elevenlabs — list voices for a provider
  • POST /head/create — create a Digital Human
  • PUT /head/{id}/splitter?splitter=false — enable streaming
  • GET /head/{id} — retrieve publicUrl → derive streaming URL
scheduleLast updated Oct 10, 2025