Video Project Management - Avatar Videos
Video Project Management
A video project is the central object — it holds the avatar assignment, an ordered list of scenes (each with narration text and an optional layout), and tracks the generation status. You create a project, populate its scenes (manually or via AI composition), then generate the final video.
Create a Video Project
The video/add endpoint creates a new project. You must provide a name and an avatarId (from section 5). Scenes can be included at creation time or added later via video/update.
VIDEO_RESULT=$(curl -s -X POST "$AVATAR_API/video/add" \
-H "Authorization: Bearer $KS" \
-H "Content-Type: application/json" \
-d "{
\"name\": \"Q1 Training Overview\",
\"avatarId\": \"$AVATAR_ID\",
\"scenes\": [
{
\"layoutType\": \"full-screen\",
\"narration\": { \"text\": \"Welcome to the Q1 training overview.\" }
},
{
\"layoutType\": \"broll\",
\"narration\": { \"text\": \"Here we see the key metrics from last quarter.\" },
\"broll\": {
\"entryId\": \"$BROLL_ENTRY_ID\",
\"startTime\": 30
}
}
]
}")
VIDEO_ID=$(echo "$VIDEO_RESULT" | python3 -c "import sys,json; print(json.load(sys.stdin)['id'])")
echo "Video ID: $VIDEO_ID"
Top-Level Request Fields
| Field | Type | Required | Description |
|---|---|---|---|
name | string | yes | Display name for the video project |
avatarId | string | yes | The avatar ID returned by avatar/upsert — determines which AI presenter appears in the video |
scenes | array of scene objects | no | Ordered list of scenes. Can be empty at creation and populated later via video/update or video/compose |
Scene Object
Each element in the scenes array represents one segment of the video.
| Field | Type | Required | Description |
|---|---|---|---|
layoutType | string enum | no | How the scene is displayed. Default: "full-screen" |
narration | object | no | The spoken content for this scene (see narration fields below) |
broll | object | no | Background video configuration (see broll fields below). The broll data is stored regardless of layoutType — you can set it up front and switch layoutType to "broll" later |
layoutType enum:
| Value | Visual | Description |
|---|---|---|
"full-screen" | Avatar fills the frame | The avatar character is rendered full-screen with its configured background. Use for introductions, conclusions, and talking-head segments |
"broll" | Avatar overlaid on video | The avatar is composited as a smaller overlay on top of a background video clip. Use when referencing visual content like charts, demos, or slides |
Narration Object
| Field | Type | Required | Description |
|---|---|---|---|
text | string | yes (if narration provided) | The script text the avatar will speak. This is converted to audio via text-to-speech during generation |
avatarId | string | no | Override the video-level avatar for this specific scene. Omit to use the project's default avatarId. Useful for multi-presenter videos where different scenes feature different characters |
Broll Object
| Field | Type | Required | Description |
|---|---|---|---|
entryId | string | yes (if broll provided) | Kaltura entry ID of the background video to display behind the avatar |
startTime | number | yes (if broll provided) | Start time in seconds within the background video. The clip plays from this point for the duration of the scene's narration |
B-roll constraints:
- The same entry can be reused across multiple scenes with different
startTimevalues — each reuse does not count as an additional source - B-roll entries require a standard frame rate (25 or 30 fps). Re-encode PowerPoint exports and other non-standard-rate sources to 25 fps before uploading (e.g.,
ffmpeg -i input.mp4 -r 25 -c:v libx264 -profile:v main -c:a aac output.mp4) - Kaltura's transcoding pipeline adds an audio track to video-only uploads, so entries uploaded through the standard upload workflow (uploadToken → media.add → media.addContent) are always compatible with the Avatar renderer
- The
brollobject is stored on the scene regardless oflayoutType— you can pre-configure B-roll data and switchlayoutTypeto"broll"later viavideo/updatewithout re-specifying the entry
Narration constraints:
- Provide narration text as a non-empty string — the API validates this at
video/addtime. Omitting thenarrationobject entirely is accepted, but scenes with narration are required for generation - Each scene's narration must produce at least ~1.5 seconds of audio after text-to-speech conversion. Use at least one complete sentence per scene (~4+ words) to meet this threshold
TTS speaking rate:
- The text-to-speech engine speaks at approximately 2.4 words/second (measured average across varying sentence lengths). When writing narration for B-roll scenes, calculate the maximum safe word count as:
available_clip_duration × 2.1(using a 15% safety buffer) - Use
video/previewAudioto verify the actual TTS duration for critical scenes before generating
Response Fields
The response returns the full video object. Key fields:
| Field | Type | Description |
|---|---|---|
id | string | The video project ID — use as $VIDEO_ID in all subsequent calls |
partnerId | number | Your Kaltura partner ID |
userId | string | The KS user who created the project |
status | string enum | Current status — starts as "draft" (see status lifecycle in section 3) |
name | string | The project name |
avatarId | string | The assigned avatar ID |
scenes | array | The scenes array as submitted |
entryId | string or null | Kaltura media entry ID of the generated video — populated only when status is "ready" |
composeParams | object or null | The compose parameters if AI composition was used (see section 7) |
createdAt | string | ISO 8601 creation timestamp |
updatedAt | string | ISO 8601 last update timestamp |
Scene Examples
Full-screen scene — avatar talks directly to camera:
{ "layoutType": "full-screen", "narration": { "text": "Let me introduce the agenda." } }
B-roll scene — avatar overlaid on a video clip starting at the 45-second mark:
{ "layoutType": "broll", "narration": { "text": "As you can see in this demo..." }, "broll": { "entryId": "1_xyz789", "startTime": 45 } }
Scene with per-scene avatar override — different presenter for this scene:
{ "layoutType": "full-screen", "narration": { "text": "Hi, I am Adam.", "avatarId": "ADAM_AVATAR_ID" } }
Minimal scene — layout defaults to "full-screen":
{ "narration": { "text": "This scene uses the default full-screen layout." } }
Get a Video Project
curl -s -X POST "$AVATAR_API/video/get" \
-H "Authorization: Bearer $KS" \
-H "Content-Type: application/json" \
-d "{ \"id\": \"$VIDEO_ID\" }"
Returns the full VideoDto including status, entryId (if generated), and all scenes.
Update a Video Project
curl -s -X POST "$AVATAR_API/video/update" \
-H "Authorization: Bearer $KS" \
-H "Content-Type: application/json" \
-d "{
\"id\": \"$VIDEO_ID\",
\"name\": \"Q1 Training — Updated\",
\"scenes\": [
{
\"layoutType\": \"full-screen\",
\"narration\": { \"text\": \"Updated welcome message for Q1 training.\" }
}
]
}"
Request fields:
| Field | Type | Required | Description |
|---|---|---|---|
id | string | yes | Video project ID |
name | string | no | Updated name |
avatarId | string | no | Updated avatar ID |
scenes | array | no | Replaces all scenes (removed trailing scenes are cleaned up) |
Scenes are editable only when status is draft or composed — the API returns VIDEO_IS_PROCESSING during active operations.
List Video Projects
curl -s -X POST "$AVATAR_API/video/list" \
-H "Authorization: Bearer $KS" \
-H "Content-Type: application/json" \
-d '{
"filter": { "orderBy": "-createdAt" },
"pager": { "offset": 0, "limit": 10 }
}'
Filter options:
| Field | Type | Values |
|---|---|---|
orderBy | string | "-createdAt", "createdAt", "-updatedAt", "updatedAt" (default: "-createdAt") |
Pager options:
| Field | Type | Description |
|---|---|---|
offset | number | Number of results to skip (0-based) |
limit | number | Maximum number of results to return |
Response:
{
"objects": [ ... ],
"totalCount": 42
}
Delete a Video Project
curl -s -X POST "$AVATAR_API/video/delete" \
-H "Authorization: Bearer $KS" \
-H "Content-Type: application/json" \
-d "{ \"id\": \"$VIDEO_ID\" }"