# Create an Avatar and an Agent

[← Back to Agent Components](https://kaltura.github.io/intelligent-agents-sdk/reference/api/build/index.md)


## Create an Avatar

```
POST https://api.avatar.us.kaltura.ai/v1/avatar/create
```

```json
{
  "voice": { "id": "KbakCphLGyrStJ2sp8mp", "speed": 1.0 },
  "visual": {
    "id": "f5a6b7c8-d9e0-4f1a-2b3c-4d5e6f7a8b9c",
    "motionControl": { "speaking": 0.7, "nonSpeaking": 0.2 }
  },
  "name": "Support rep"
}
```

Allowed ranges: `voice.speed` 0.5 to 1.5; `motionControl.speaking` and `motionControl.nonSpeaking` each 0.1 to 1.0 (keep `nonSpeaking` below `speaking`); `name` up to 255 characters. A value outside these ranges is a 400.

`voice.id` and `visual.id` come from the catalog ([Catalog & Assets § Browse the Catalog](https://kaltura.github.io/intelligent-agents-sdk/reference/api/design/index.md#browse-the-catalog)). For your own portrait, upload it first and use the returned `itemId` as `visual.id` ([§ Upload a Custom Visual](https://kaltura.github.io/intelligent-agents-sdk/reference/api/design/index.md#upload-a-custom-visual-portrait--animated-avatar), which also covers how to prepare the photo). Returns `id` (24-char hex). **No `adminTags`** on avatars: tag the parent agent instead ([Management Operations § Avatars](https://kaltura.github.io/intelligent-agents-sdk/reference/api/management-operations/index.md#avatars)).

Leave `openingPhrase` unset. The intellect's `opening_phrase` sets the first, uninterruptible turn of every session ([Configure an Intellect](https://kaltura.github.io/intelligent-agents-sdk/reference/api/build/intellect/index.md#configure-an-intellect)). `provision()` writes it there and creates the avatar without a phrase. An avatar-level `openingPhrase` is spoken only for a session whose intellect has none. Clear one with `avatars.update({ id, openingPhrase: null }, ks)`. Where the phrase lives, how to personalize it with a template, and the silent-opening and `kickoff` pattern: [Start the Conversation](https://kaltura.github.io/intelligent-agents-sdk/guides/start-the-conversation/index.md).

### Three ways to get a visual

`avatar/create` needs exactly one of these to resolve a visual:

| Way | Body | When |
|---|---|---|
| An existing Visual | `visual: { id }` | Fastest. A catalog preset, or your own upload via `catalog.createVisual`. Do not send just one of `face`/`background` alongside `visual`. Send both as a complete pair or neither. |
| Compose a new Visual from a Face + Background | `face: { id }` + `background: { type: 'color', value?: '#hex' }` (`value` optional, defaults to white) or `{ type: 'visual', value: <Background catalog itemId> }` (`value` required) | You want a specific face (a `catalog.createFace` upload, or a preset Face item) over a specific backdrop. Send `face` and `background` together at create time. `avatars.create` throws `bad_request` before any network call if you send only one, even when `visual` is also sent. With `templateId`, one half is enough: a template can carry its own `face` or `background`. |
| A curated template + whatever it's missing | `templateId` + whichever of `face`/`background`/`visual` the template doesn't already supply | Fastest good-looking result. See below. `templateId` alone works only when the template already includes a complete `visual`. |

You cannot create an avatar from a face alone and add the background afterwards: a face and a background are required together at create time. Once the avatar exists, `avatars.update` accepts a `background` on its own ([Management Operations § Avatars](https://kaltura.github.io/intelligent-agents-sdk/reference/api/management-operations/index.md#avatars)).

For `background.type: 'color'`, `value` must be a plain 6-digit hex string (`#RRGGBB`) with **no alpha channel**. An 8-digit hex (`#RRGGBBAA`), `rgba(...)` or a CSS4 `rgb(... / ...%)` throws `bad_request` before any network call.

Whichever way you pick, the composed result is reflected in the created avatar's `visual.composition` and a fresh `previewImageUrl`/`loadingVideoUrl` (asset URLs, not the rendered live-session composite). Inspect those to see what was built. Changing the composition after create follows different rules: [Management Operations § Avatars](https://kaltura.github.io/intelligent-agents-sdk/reference/api/management-operations/index.md#avatars).

**Faster path: pick a curated preset instead of assembling voice and visual by hand.** `mgmt.avatars.listTemplates(ks, opts)` lists curated bundles, each pairing a `voice` with either a ready `visual` or a `face`/`background` pair. Pass the template's own `id` as `templateId`; if the template's `face`/`background` is not already a complete pair, add whichever half it is missing:

```js
const templates = await mgmt.avatars.listTemplates(ks, { pageSize: 10 });
const t = templates[0]; // { id, name, voice: { id }, face: { id, imageUrl } }
await mgmt.avatars.create(
  { voice: t.voice, templateId: t.id, background: { type: 'color', value: '#ffffff' } },
  ks,
);
```

## Compose from a custom Face and Background

Upload the two halves first ([Catalog & Assets § Upload a custom Face or Background](https://kaltura.github.io/intelligent-agents-sdk/reference/api/design/index.md#upload-a-custom-face-or-background-compose-a-visual-path)), then pass their ids as `face.id` and `background.value`:

```js
const face = await mgmt.catalog.createFace(portraitBlob, { name: 'Support rep', genderPresentation: 'Feminine' }, ks);
const bg = await mgmt.catalog.createBackground(backdropBlob, { name: 'Office', genderPresentation: 'Feminine' }, ks);
await mgmt.avatars.create(
  { voice: { id: voiceItemId }, face: { id: face.itemId }, background: { type: 'visual', value: bg.itemId } },
  ks,
);
```

Unlike `createVisual` (a photo used directly, already a full custom digital twin), a Face/Background is only usable through the `face` and `background` composition. You cannot pass it as `visual.id` on its own.

---

## Create an Agent

```
POST https://api.avatar.us.kaltura.ai/v1/agent/create
```

```json
{
  "displayName": "StreamBot Support Agent",
  "intellect": {
    "intellectType": "genie",
    "id": 1389
  },
  "avatarIds": ["6a07d63d8ccd85cbfafc5416"],
  "adminTags": ["support"],
  "maxConversationLength": 900
}
```

| Field | Notes |
|-------|-------|
| `intellect.intellectType` | `"genie"`. The value `mgmt.intellects.create()` produces. The field also accepts `"external"`, for an intellect created and managed outside this SDK. |
| `intellect.id` | The intellect's configId, from intellect create. Pass it straight in, no discovery step |
| `avatarIds` | Optional. Omit for a headless text-only agent |
| `maxConversationLength` | Seconds. Omit to use the default |
| `widgetConfig` / `embedConfig` | Optional config objects for the hosted widget and embed. Omit them unless you customize widget or embed behavior |
| `screenShare` | Optional `{enabled, prompt}`. Set `enabled: true` and a `prompt` that says how to describe the shared screen to let an avatar session share its screen. `mgmt.agents.update` changes it later. The `sys__avatar_share_screen_enabled` variable is true only while a share runs |

Returns `agentId` (UUID). **Save this.**

## Screen share

The agent can look at the user's screen and help with what it sees. Two steps:

1. Turn it on for the agent. The `prompt` tells the vision step what to report.

```js
await mgmt.agents.update({ agentId, screenShare: { enabled: true, prompt: 'Describe code, errors and UI state.' } }, ks);
```

2. In the browser, call `session.startScreenShare()` from a click. The browser shows its screen picker.

```js
shareButton.addEventListener('click', () => {
  if (session.screenSharing) session.stopScreenShare();
  else session.startScreenShare().catch((e) => { if (e.code !== 'screen_share_denied') throw e; });
});
session.on('screenShareChanged', ({ active }) => shareButton.setAttribute('aria-pressed', String(active)));
```

`KalturaAgentSession` has the same `startScreenShare()`, `stopScreenShare()`, `screenSharing` and `screenShareChanged`. In chat mode `startScreenShare()` throws `screen_share_unsupported`. A `switchMode()` ends a running share.

The SDK sends a JPEG still every 2 seconds until `stopScreenShare()`, `disconnect()` or the user's own "stop sharing" control. The agent reads the stills as text, so answers can lag by a few seconds.

| Option (`startScreenShare(opts)`) | Default | Meaning |
|---|---|---|
| `intervalMs` | `2000` | Time between stills |
| `maxWidth` | `1500` | Wider stills (px) are scaled down |
| `quality` | `0.5` | JPEG quality, 0 to 1 |
| `stream` | none | A display stream you already hold. The SDK then skips the picker and does not stop its tracks |

| Error code | When |
|---|---|
| `capability_disabled` | The agent's `screenShare` setting is off |
| `screen_share_denied` | The user cancelled the picker or blocked access |
| `screen_share_unsupported` | The browser has no `getDisplayMedia` |
| `screen_share_failed` | The browser could not start the capture |

A failed capture during a share arrives as a `warning` event with code `screen_share_capture_failed`, and the share continues. `session.sendScreenShot(data)` sends one still you captured yourself. Full app: [examples/screen-share-agent.html](https://github.com/kaltura/intelligent-agents-sdk/blob/main/examples/screen-share-agent.html).

---

## Related docs

| Doc | What it adds |
|---|---|
| [Agent Components · Create and Configure an Intellect](https://kaltura.github.io/intelligent-agents-sdk/reference/api/build/intellect/index.md) | The intellect an agent's `intellect.id` points at |
| [Agent Components](https://kaltura.github.io/intelligent-agents-sdk/reference/api/build/index.md) | The Agent Components index |

