Vidu S1
Concept | Description |
|---|---|
Live (Session) | A complete digital character interaction; obtain live_id |
RTC Channel | audio and video transmission channel carrying microphone, camera, and digital character audio and video |
WebSocket Signaling | Control-command channel for starting, text, interruption, and hang-up |
Persona | Digital character personality, speaking style, and other settings |
POST https://{host}/live/v1/lives Authorization: Token vda_xxx Content-Type: application/json
{ "call_mode": "video", "avatar": { "persona": "You are a friendly customer service representative. Interact naturally with the user in real time.", "image_uri": "https://your-digital-character-image-url.png", "voice": "" } }
wss://{host}/live/ws/live/connect?live_id={live_id} Authorization: Token vda_xxx
{ "type": 1, "live_id": "123456789", "seq_id": 1, "payload": { "conn_init": { "version": 1 } } }
await aliRtc.joinChannel(rtc.token, rtc.user_id); await aliRtc.publishLocalAudioStream(true); if (callMode === 'video') { await aliRtc.publishLocalVideoStream(true); }
Mode | App Publishing / Subscription |
|---|---|
audio | Join live-audio-{liveID}, publish microphone audio, and subscribe to digital character audio at live-bot-.... |
video | Join live-user-{liveID}, publish microphone and camera streams, and subscribe to digital character audio and video at live-video-push-.... |
Method | Path | Purpose |
|---|---|---|
POST | /live/v1/lives | Create a Live session (core entry point; returns RTC join and WS initialization information) |
GET | /live/v1/lives/{live_id} | Query the status and billing of a single Live session |
GET | /live/v1/lives | List Live Sessions |
WebSocket | /live/ws/live/connect | App control signaling (start / text / interrupt / hang up) |
— | AliRTC joinChannel | Real-time media streams (microphone / camera / digital character audio and video); requires AliRTC SDK integration |
POST | /live/v1/voices/clone | Clone a voice to create a custom voice |
GET | /live/v1/voices | Query the custom voice list |
POST / PUT | /tools/v2/files/uploads | Upload an image and obtain a URI usable as avatar.image_uri |
Item | Convention |
|---|---|
{host} | {host} is the domain name without a protocol. The China environment uses api.vidu.cn, and the international environment uses api.vidu.com. Use https://{host} for HTTP requests and wss://{host} for WebSocket. |
Authentication | All app-side HTTP and WebSocket interfaces require Authorization: Token vda_xxx。The API key is available in the Console |
JSON Fields | Request and response fields use snake_case,for example call_mode、live_id、token_expire_at。 |
IDs and Time | live_id、character_id、created_at、token_expire_at and other int64 fields should be handled as strings on the frontend to avoid JavaScript number precision issues. |
Media Transmission | App WebSocket carries control signaling only; the microphone, camera, and digital character audio and videoare all transmitted through AliRTC. |
{ "code": 400, "reason": "BAD_REQUEST", "message": "FieldInvalid", "metadata": {} }
POST https://{host}/live/v1/lives Authorization: Token vda_xxx Content-Type: application/json
{ "call_mode": "video", "character_id": "1", "avatar": { "persona": "You are Sweet Tina. My voice is like warm milk tea—sweet and comforting—but I am always clear and capable when solving problems!", "image_uri": "https://scene.cf.vidu.studio/media-asset/070302-ZFkgvJxBTM0ZQJoO.png", "voice": "Tina" }, "moderation": "disabled", "extra_motion": true, "audio": { "enable_transcription": true }, "vad": { "type": "semantic", "threshold": 0.5, "silence_duration_ms": 200, "idle_timeout_ms": 500 }, "llm": { "temperature": 0.7, "top_p": 0.8, "top_k": 20, "frequency_penalty": 1, "presence_penalty": 0.3, "seed": -1, "max_tokens": 50 }, "idle_timeout_seconds": 7200, "memory_retrieval": { "enabled": true, "endpoint": "https://api.example.com/memory/search", "authorization": "Bearer memory-api-token", "timeout_ms": 3000 }, "knowledge_retrieval": { "enabled": true, "endpoint": "https://api.example.com/knowledge/search", "authorization": "Bearer knowledge-api-token", "timeout_ms": 3000 } }
Field | Type | Required | Description |
|---|---|---|---|
call_mode | String | Yes | Interaction mode: audio for audio only; video for audio and video |
avatar.persona | String | Yes | Digital character persona, up to 50,000 Chinese characters. |
avatar.image_uri | String | Yes | digital character image image URL. Supports an image URL, Base64, or image_uri (see the Image Upload section). Formats: PNG / JPG / JPEG / WEBP; image size ≤ 50 MB; byte length after Base64 decoding < 20 MB |
avatar.voice | String | No | Voice; default: Tina |
avatar.greeting_instruction | string | No | Opening greeting prompt, ≤ 200 characters |
Field | Type | Default | Description |
|---|---|---|---|
audio.enable_transcription | bool | false | When true, returns user speech-to-text and digital character output audio-to-text results through WebSocket. |
Field | Type | Default | Description |
|---|---|---|---|
vad.type | String | server | server:filters backchannel responses / background noise; semantic: interrupts the current response as soon as the user starts speaking |
vad.threshold | float | 0.5 | Noise suppression strength, range [0, 1.0],lower values apply less suppression |
vad.silence_duration_ms | int | 400 | Amount of silence after speech ends before triggering a response; range [200, 6000]ms。 |
vad.idle_timeout_ms | int | 0 | The model proactively starts a conversation; 0 or [500, 30000] ms; 0 means no proactive conversation |
Field | Type | Default | Description |
|---|---|---|---|
llm.temperature | float | 0.7 | Creativity, range [0.0, 2.0) |
llm.top_p | float | 0.8 | Quality threshold, range (0.0, 1.0] |
llm.top_k | int | 20 | range [0, 100] |
llm.frequency_penalty | float | 1.0 | Content repetition; default 1.0 means no penalty;< 1 encourages repetition;> 1 penalizes repetition |
llm.presence_penalty | float | 0.3 | Topic breadth, range [0, 2] |
llm.seed | int | -1 | Range: -1 or [0–2³¹]; default -1 means random |
llm.max_tokens | int | 50 | Maximum model output length,range 1 ~ 64000 |
Field | Type | Default | Description |
|---|---|---|---|
idle_timeout_seconds | int | 7200 | Automatic disconnection time when there is no input. Default: 7200 s; range [10 ~ 7200]s |
Field | Type | Default | Description |
|---|---|---|---|
*.enabled | bool | None | Required; whether to enable this capability |
*.endpoint | String | None | Required when enabled; retrieval API URL |
*.authorization | String | None | Required when enabled; forwarded as the external API Authorization header and validated as non-empty |
*.timeout_ms | int | 30000 | Request timeout; maximum 30000ms |
{ "live": { "id": "123456789", "status": "waiting", "live_duration": 600, "call_mode": "video" }, "rtc": { "app_id": "xxxx", "channel_id": "live-user-123456789", "user_id": "live-user-1001-123456789", "token": "base64-token...", "token_expire_at": "1750003600" } }
Field | Type | Description |
|---|---|---|
live.id | String | Room ID |
live.status | String | waiting means the digital character is not ready |
live.live_duration | Int | Maximum duration of this session; automatically disconnects on timeout; maximum 600 seconds |
rtc.token | String | Credential for joining the video room; valid for 1 hour |
rtc.user_id | String | Your username in the RTC channel |
rtc.token_expire_at | String | Token expiration time |
GET https://{host}/live/v1/lives/{live_id} Authorization: Token vda_xxx
Parameter | Type | Description |
|---|---|---|
live_id | String | Required; live_id must belong to the account associated with the current API key |
Response Fields | Description |
|---|---|
live.status | Session status:waiting、prepared、on_live、ending、ended |
live.created_at | Creation time in Unix seconds. |
live.start_time | Actual Start Time |
live.end_time | End Time |
live.trace_id | Trace ID |
live.billed_seconds | Billable Seconds |
live.credits_cost | Credits consumed by this session. |
GET https://{host}/live/v1/lives?pager.page=0&pager.pagesz=10 Authorization: Token vda_xxx
Query Parameters | Type | Default | Description |
|---|---|---|---|
pager.page | Int | 0 | Page number, starting from 0 |
pager.pagesz | Int | 10 | Items per page; maximum 100. |
pager.page_token | String | - | next_page_token returned by the server |
{ "total": 12, "lives": [ { "id": "1234567890", "status": "ended", "call_mode": "video", "billed_seconds": 120, "credits_cost": 20 } ], "next_page_token": "" }
wss://{host}/live/ws/live/connect?live_id={live_id}&conn_id={conn_id} Authorization: Token vda_xxx
Query Parameters | Type | Default | Description |
|---|---|---|---|
live_id | String | None | Required; live.id returned when creating the Live session |
conn_id | String | None | Optional,Client connection ID; generated automatically by the server if omitted |
{ "type": 1, "live_id": "1234567890", "user_id": "10000", "conn_id": "app-conn-1", "seq_id": 1, "payload": {} }
type | Name | Direction | Description |
|---|---|---|---|
1 | conn_init | App → live | Connection initialization; must be sent after the WS opens. |
2 | conn_init_ack | live → App | Initialization result; success=true indicates that the real-time control connection is ready. |
5 | call_hangup | App → live | Active Hang-Up |
6 | force_hangup | live → App | Server-Forced Hang-Up |
7 | audio_interrupted | App → live | User interrupts the current digital character output |
99 | text_msg | App → live | Send a Text Message |
{ "type": 1, "live_id": "1234567890", "conn_id": "app-conn-1", "seq_id": 1, "payload": { "conn_init": { "version": 1 } } }
{ "type": 2, "live_id": "1234567890", "conn_id": "app-conn-1", "seq_id": 2, "payload": { "conn_init_ack": { "success": true, "error_code": "", "error_msg": "", "server_timestamp": 1710000000 } } }
{ "type": 2, "live_id": "1234567890", "conn_id": "app-conn-1", "seq_id": 2, "payload": { "conn_init_ack": { "success": false, "error_code": "NOT_READY", "error_msg": "live sip endpoint not ready", "server_timestamp": 1710000000 } } }
{ "type": 99, "live_id": "1234567890", "conn_id": "app-conn-1", "seq_id": 10, "payload": { "text_msg": { "msg_id": "client-msg-1", "content": "Hello, please introduce yourself.", "timestamp": 1710000000000 } } }
Field | Type | Default | Description |
|---|---|---|---|
msg_id | string | None | Optional,Optional message ID generated by the client for log correlation. |
content | string | None | Required; text content sent to the digital character. |
timestamp | int64 | 0 | Optional,Client send time in milliseconds. |
{ "type": 7, "live_id": "1234567890", "conn_id": "app-conn-1", "seq_id": 11, "payload": {} }
{ "type": 5, "live_id": "1234567890", "conn_id": "app-conn-1", "seq_id": 12, "payload": { "hangup": { "hangup_reason": "user_end" } } }
{ "type": 6, "live_id": "1234567890", "conn_id": "app-conn-1", "payload": { "hangup": { "hangup_reason": "timeout" } } }
hangup_reason | Common Scenario |
|---|---|
user_end | The user actively ends the session. |
timeout | The session reaches its maximum duration. |
audit_violation | A content-safety or risk-control policy is triggered. |
credit_insufficient | Insufficient credits. |
sip_closed / provider_closed | The service or digital character rendering service closes. |
| The disconnection exceeds the reconnection grace period. |
external | Closed by the backend or external control. |
Connection | Content Carried | Typical Action |
|---|---|---|
App WebSocket | Control Signaling | conn_init starts, text_msg provides text interaction, audio_interrupted interrupts, and call_hangup hangs up. |
AliRTC | Real-Time Media Streams | Subscribe to digital character audio and video. |
flowchart LR CreateLive["Create Live"] --> WsInit["App WS conn_init"] CreateLive --> RtcJoin["AliRTC joinChannel"] WsInit --> ControlReady["Control Ready"] RtcJoin --> MediaReady["Media Ready"] ControlReady --> Interact["Live Interaction"] MediaReady --> Interact
await aliRtc.setDefaultSubscribeAllRemoteAudioStreams(true); await aliRtc.setDefaultSubscribeAllRemoteVideoStreams(true); await aliRtc.joinChannel(rtc.token, rtc.user_id); await aliRtc.publishLocalAudioStream(true); if (callMode === 'video') { await aliRtc.publishLocalVideoStream(true); }
Mode | channel_id | App Responsibilities |
|---|---|---|
audio | live-audio-{live_id} | Publish microphone audio and subscribe to digital character audio. |
video | live-user-{live_id} | Publish microphone and camera streams and subscribe to the digital character video stream. |
<video id="remoteVideo" autoplay playsinline></video>
const remoteVideoElement = document.getElementById('remoteVideo'); aliRtc.on('remoteUserOnLineNotify', (userId) => { console.log('remote user online', userId); }); aliRtc.on('videoSubscribeStateChanged', (userId, oldState, newState) => { if (newState === 'subscribed') { // streamType=1 indicates the remote camera stream. In video mode, digital character video generally uses this callback. aliRtc.setRemoteViewConfig(remoteVideoElement, userId, 1); remoteVideoElement.play().catch(() => { console.warn('remote video autoplay failed'); }); } }); aliRtc.on('screenShareSubscribeStateChanged', (userId, oldState, newState) => { if (newState === 'subscribed') { // streamType=2 indicates the remote screen stream. If the server uses this stream type, the view must also be bound. aliRtc.setRemoteViewConfig(remoteVideoElement, userId, 2); } });
Role | User ID Format |
|---|---|
User | live-user-{creatorID}-{liveID} |
Digital Character Audio | live-bot-{creatorID}-{liveID} |
Digital Character Video Stream | |
POST https://{host}/live/v1/voices/clone Authorization: Token vda_xxx Content-Type: application/json
{ "audio_url": "https://example.com/reference.wav", "voice": "my_custom_voice", "text": "This is the transcript corresponding to the reference audio.", "language": "zh" }
Field | Type | Default | Description |
|---|---|---|---|
audio_url | String | None | Required; reference audio; supports a URL or data URI with a length of 1–2048. Formats: WAV (16-bit), MP3, M4A. Recommended duration: 10–20 seconds; maximum: 60 seconds. File size < 10 MB. |
voice | String | None | Required; voice name, 1–64 characters; only digits, uppercase/lowercase letters, and underscores are allowed. |
text | String | Empty | Reference audio transcript; maximum length 4096 |
language | String | Empty | Reference audio language; maximum length 16 |
{ "id": "your_resource_id", "put_url": "put_url_example", "expires_at": "2024-09-05T04:20:29.589251952Z" }
curl -v -H "Content-Type: image/png" -X PUT --data-binary '@upload.png' '{put_url_example}' # Response header example: < HTTP/2 200 < etag: "d035e206b3243107372249559495346c"
{ "uri": "ssupload:?id=your_resource_id" }
POST <memory_retrieval.endpoint> Content-Type: application/json Accept: application/json Authorization: <memory_retrieval.authorization>
{ "live_id": "1234567890", "query": "The user’s preferred coding style, programming language, and script output style", "reason": "The user asked for a script in their previously preferred coding style, but the current context contains no relevant preference information.", "memory_types": ["preference", "style"], "time_hint": "Long-term preferences", "max_results": 5 }
Field | Type | Default | Description |
|---|---|---|---|
live_id | string | None | Required; current session ID |
query | string | None | Required; natural-language retrieval intent generated by the model |
reason | string | None | Required; the model’s explanation of why memory retrieval is needed for the current response |
memory_types | string[] | Empty | Desired memory types, including preference/profile/history/project/constraint/relationship/style/other |
time_hint | string | Empty | Time-range hint |
max_results | integer | 5 | Maximum number of results,range[1-10] |
{ "memories": [ { "id": "mem_101", "summary": "The user prefers concise code, avoids excessive abstraction, and uses clear variable names.", "type": "style", "confidence": 0.94, "updated_at": "2026-06-01T09:00:00+08:00", "source": "long_term_memory" }, { "id": "mem_102", "summary": "The user generally prefers Go examples; Python may be used when explicitly requested.", "type": "preference", "confidence": 0.86, "updated_at": "2026-05-20T13:00:00+08:00", "source": "long_term_memory" } ] }
POST <knowledge_retrieval.endpoint> Content-Type: application/json Accept: application/json Authorization: <knowledge_retrieval.authorization>
{ "live_id": "1234567890", "query": "Troubleshooting steps when Vidu real-time digital character creation fails", "reason": "The user asked for a specific troubleshooting process, but the current context contains no product documentation.", "knowledge_types": ["procedure", "troubleshooting"], "time_hint": "Latest version", "max_results": 5 }
Field | Type | Default | Description |
|---|---|---|---|
live_id | string | None | Required; conversation Live ID |
query | string | None | Required; natural-language retrieval intent generated by the model |
reason | string | None | Required; reason knowledge retrieval is needed |
knowledge_types | string[] | Empty | Desired knowledge types |
time_hint | string | Empty | Time or version hint |
max_results | integer | 5 | Maximum number of results,[1-10] |
{ "knowledge": [ { "id": "doc_001_chunk_03", "title": "Real-Time Digital Character Creation Troubleshooting Guide", "content": "If CreateLive returns a SIP creation failure, first check call_mode, avatar.image_uri, the SIP provider return code, and trace_id in the Live logs.", "type": "troubleshooting", "source": "ops_runbook", "updated_at": "2026-07-01T10:00:00+08:00", "confidence": 0.92, "url": "https://kb.example.com/docs/live-troubleshooting" } ] }
{ "code": 400, "reason": "BAD_REQUEST", "message": "Invalid parameter", "metadata": {} }
Source | Status / Error Code | Typical Cause | Recommended Client Handling |
|---|---|---|---|
HTTP | 400 | Invalid parameters, missing fields, invalid call_mode, text exceeding the length limit, or a session state that does not permit further operations. | Correct the request according to the field descriptions. If the Live session has ended, create a new session. |
HTTP | 401 | The API key is missing, incorrectly formatted, or invalid. | Check Authorization: Token vda_xxx and confirm that the API key belongs to the current environment. |
HTTP | 403 | The requested Live session does not belong to the current API key/account. | Use the same API key that created the Live session; do not reuse live_id across accounts. |
HTTP | 404 | The session does not exist, has expired, or live_id is incorrect. | Confirm live_id; if recovery is impossible, create a new session. |
HTTP | 500 | An internal service dependency failed, such as the database, SIP/video provider, or AliRTC token service. | Retry after a short delay. If the failure persists, provide live_id, trace_id, and the request time for investigation. |
Source | Status / Error Code | Typical Cause | Recommended Client Handling |
|---|---|---|---|
WS | NOT_READY | In video mode, the digital character rendering service has not completed its callback connection, so conn_init cannot succeed yet. | Do not reload the page immediately. Wait 2–3 seconds and retry conn_init; exponential backoff may be used. |
WS | LIVE_CONN_INIT_FAILED | Initialization failed, possibly due to an abnormal session state or a server-side dependency failure. | Close the current WS and create a new Live session. If it still fails, provide live_id and logs for investigation. |