# Management Operations

[← Back to the API Reference index](https://kaltura.github.io/intelligent-agents-sdk/reference/api-reference/index.md)


Endpoint and request reference for every `Management` operation: agents, avatars, intellects, tools, skills, threads, messages, knowledge, lifecycle and insight settings.

All operations use the **admin KS** (`createAdminToken`), except where a section says otherwise. Agents, Avatars, Lifecycle and Insight Settings call the management host (`https://api.avatar.us.kaltura.ai`). Everything else calls the conversation host (`https://genie.nvp1.ovp.kaltura.com`). Hosts for other regions: [Regions and base URLs](https://kaltura.github.io/intelligent-agents-sdk/reference/api/authentication/index.md#regions-and-base-urls).

## Agents

| Operation | Endpoint | Body |
|-----------|----------|------|
| Create | `POST /v1/agent/create` | `{"displayName":"...", "intellect":{...}, "avatarIds":["24-char-hex"], "adminTags"?:["..."]}` |
| List | `POST /v1/agent/list` | `{"filter":{},"pager":{"offset":0,"limit":30}}` |
| Get | `POST /v1/agent/get` | `{"agentId":"UUID"}` |
| Update | `POST /v1/agent/update` | `{"agentId":"UUID", ...fields}` |
| Delete | `POST /v1/agent/delete` | `{"agentId":"UUID"}` |

Filter keys: `agentId`, `adminTagsIn`, `adminTagsNotIn`, `searchValue` (case-insensitive substring match on `displayName`/`agentId`). An unrecognized key 400s.

The request also takes a top-level `orderBy` (`+createdAt`, `-createdAt`, `+updatedAt`, `-updatedAt`; anything else 400s). It sits next to `filter`, not inside it. Threads and Messages below take `orderBy` inside `filter`. SDK: `mgmt.agents.list(ks, opts)` passes `opts.filter` through as-is and does not take `orderBy`.

`mgmt.agents.delete` refuses to delete an agent whose `adminTags` match a production marker (`prod`, `production`, `keep`, `do-not-delete`, `live`; the exported `PROTECTED_TAGS`). Pass `{confirmPermanent:true, allowProtected:true}` to delete it anyway. This stops a cleanup-by-tag sweep from deleting an agent that is in use. The SDK reads the agent first. If that read fails (other than the agent not existing), the delete is refused with that error. `{skipProtectedCheck:true}` skips the read and the guard.

## Avatars

| Operation | Endpoint | Body |
|-----------|----------|------|
| Create | `POST /v1/avatar/create` | `{"voice":{"id":"...","speed"?:1.0}, "visual"?:{"id":"...","motionControl"?:{...}}, "face"?:{"id":"..."}, "background"?:{"type":"color"\|"visual","value"?:"..."}, "templateId"?:"...", "name"?:"...", "openingPhrase"?:"..."}` (leave `openingPhrase` unset. The intellect's `opening_phrase` sets the opening line, see [Start the Conversation](https://kaltura.github.io/intelligent-agents-sdk/guides/start-the-conversation/index.md#where-the-opening-phrase-lives).) Visual resolution rules: [Agent Components · Create an Avatar and an Agent § Three ways to get a visual](https://kaltura.github.io/intelligent-agents-sdk/reference/api/build/avatar-and-agent/index.md#three-ways-to-get-a-visual). |
| List | `POST /v1/avatar/list` | `{"pager":{"offset":0,"limit":30}}` |
| Get | `POST /v1/avatar/get` | `{"id":"24-char-hex"}`. A missing or unknown id throws `code:'api_exception'` with `title:'AVATAR_NOT_FOUND'`. Branch on `title`, not `code`. A malformed id throws `code:'bad_request'` |
| Update | `POST /v1/avatar/update` | `{"id":"24-char-hex", ...fields}`. Omitted fields are preserved. `templateId` is create-only (400 on update) |
| Delete | `POST /v1/avatar/delete` | `{"id":"24-char-hex"}` |
| List templates | `POST /v1/avatar-template/list` | `{"pager":{"offset":0,"limit":30}}`. Curated presets, each pairing a `voice` with either a ready `visual` or a `face`/`background` pair ([Agent Components · Create an Avatar and an Agent § Three ways to get a visual](https://kaltura.github.io/intelligent-agents-sdk/reference/api/build/avatar-and-agent/index.md#three-ways-to-get-a-visual)). SDK: `mgmt.avatars.listTemplates(ks, opts)`; `opts.idsIn` filters to specific template ids. |

**Changing the look on update.** On create, `face` and `background` travel together. On update:

- To change the background, send `background` alone. It applies to the avatar's current face.
- To change the face, send `face` and `background` together.

Avatars carry no `adminTags`. `avatars.create` and `avatars.update` throw `bad_request` before any network call if you pass it. Tag the parent **agent** instead.

## Intellects

| Operation | Endpoint | Body |
|-----------|----------|------|
| List | `POST /v1/intellect/list` | `{"filter":{},"pager":{"pageIndex":1,"pageSize":30}}` |
| Get | `POST /v1/intellect/get` | `{"id":1389}` |
| Update | `POST /v1/intellect/update` | See § Configure an Intellect |
| Delete | `POST /v1/intellect/delete` | `{"id":1389}` |

Create (`POST /v1/intellect/add`) isn't listed here. See [Agent Components · Create and Configure an Intellect](https://kaltura.github.io/intelligent-agents-sdk/reference/api/build/intellect/index.md) for creating an intellect with the SDK's default-applying `mgmt.intellects.create()`.

Deleting an agent does **not** delete its avatar or intellect.

`mgmt.setForcedLanguage({ configId, agentId, language, languageName?, asrProvider? }, ks)` forces the reply language and the speech-recognition language in one idempotent call. Usage and options: [Languages](https://kaltura.github.io/intelligent-agents-sdk/guides/languages/index.md).

Typed setters on `mgmt.intellectConfig` for the other single-purpose fields, all `(configId, value, ks)` and idempotent:

| Setter | Field | Clear with |
|---|---|---|
| `setModelConfiguration` | `model_configuration` (`model_id` in `MODEL_IDS`, `max_output_tokens`, `thinking_level` in `THINKING_LEVELS`, `temperature`) | `null` |
| `setOpeningPhrase` | `opening_phrase` (the opening line of every avatar session; a template over `requestVars` and `sys__*`; `SILENT_OPENING` for no spoken opening, see [Start the Conversation](https://kaltura.github.io/intelligent-agents-sdk/guides/start-the-conversation/index.md#personalize-the-opening)) | `null` |
| `setThreadStartTools` | `thread_start_tools`: unique tool ids run in order when a thread starts, before the first user turn[^1] | `[]` |
| `setAvatarSummaryConfig` | `avatar_summary_config` (`prompt`, `analysis`, `template`, `content_type` in `SUMMARY_CONTENT_TYPES`)[^2] | `null` |
| `setSkillIds` | `skill_ids` (`{ id, mode, condition? }`, `mode` in `SKILL_MODES`) | `[]` |

Each validates client-side and throws `bad_request` before any network call. See [Agent Components · Create and Configure an Intellect](https://kaltura.github.io/intelligent-agents-sdk/reference/api/build/intellect/index.md) for field semantics.

[^1]: Use `api` and `code` tools here. An `api` tool with `wait_for_response` is awaited. Every other tool runs without waiting. A failing tool does not fail the conversation. A thread-start tool never appears as a `tool` segment in the stream.

[^2]: `null` restores the defaults (`analysis: { summary }`, `template: '{{ summary }}'`, `content_type: 'text'`). Every `{{ key }}` in `template` must be an `analysis` key (or `summary` when `analysis` is unset). The SDK rejects a mismatch client-side. The summary is skipped entirely when the thread has no human messages.

## Tools

A standalone, partner-level entity, not embedded in an intellect. A name that is already in use returns 409. Skills below follow the same rule.

| Operation | Endpoint | Body |
|-----------|----------|------|
| List | `POST /v1/tool/list` | `{"filter":{"objectType":"ToolListFilter"},"pager":{"pageIndex":1,"pageSize":30}}` |
| Get | `POST /v1/tool/get` | `{"id":"TOOL_UUID"}` |
| Add | `POST /v1/tool/add` | `{"name":"...", "config":{...}}` |
| Update | `POST /v1/tool/update` | `{"id":"TOOL_UUID", "name"?, "config"?}` |
| Delete | `POST /v1/tool/delete` | `{"id":"TOOL_UUID"}` |

`mgmt.tools.delete` refuses by default with a typed `tool_in_use` error naming every intellect still listing the id in `tool_ids`. Pass `{confirmPermanent:true, force:true}` to delete anyway. Drop the id from each intellect's `tool_ids` first via `mgmt.intellectConfig.setToolIds`.

## Skills

A standalone, partner-level reusable-instruction entity: `{id (uuid), name, description, instructions}`. SDK: `mgmt.skills`. A name that is already in use returns 409. Tools above follow the same rule.

| Operation | Endpoint | Body |
|-----------|----------|------|
| List | `POST /v1/skill/list` | `{"filter":{"objectType":"SkillListFilter"},"pager":{"pageIndex":1,"pageSize":30}}` |
| Get | `POST /v1/skill/get` | `{"id":"SKILL_UUID"}` |
| Add | `POST /v1/skill/add` | `{"name":"...", "description":"...", "instructions"?}` |
| Update | `POST /v1/skill/update` | `{"id":"SKILL_UUID", "name"?, "description"?, "instructions"?}`. Idempotent. A rename to a name already in use returns 409 |
| Delete | `POST /v1/skill/delete` | `{"id":"SKILL_UUID"}`. Replies `{id}`. A follow-up get returns 404 |

**Shared skills.** A shared skill (`partner_id: 0`) appears in `skills.list` and can be attached with `setSkillIds`. `skills.get`, `skills.update` and `skills.delete` answer 404 `not_found` for it, so you cannot read, edit or delete it. `setSkillIds` rejects a skill id that does not exist or that you cannot use with 403 `forbidden`. `intellectConfig.audit` and `doctor` accept an attached shared skill.

Before deleting a Skill, `mgmt.skills.delete` lists every intellect and refuses with a typed `skill_in_use` error naming each one still referencing the id in `skill_ids`. Pass `{confirmPermanent:true, force:true}` to delete anyway. `mgmt.tools.delete` has the same guard with a `tool_in_use` error.

## Threads

Token rules per method: [Conversation & Analytics § Threads](https://kaltura.github.io/intelligent-agents-sdk/reference/api/operate/index.md#threads). `threads.push` needs an admin token. Which threads a token can reach: [Security & Compliance § Session type](https://kaltura.github.io/intelligent-agents-sdk/reference/security/index.md#session-type). SDK: `mgmt.threads.{list, get, rename, setAnalysis, clearAnalysis, push, delete, transcript}`.

| Operation | Endpoint | Body |
|-----------|----------|------|
| List | `POST /v1/thread/list` | `{"filter":{"objectType":"ListThreadFilter"},"pager":{"pageIndex":1,"pageSize":30}}` |
| Get | `POST /v1/thread/get` | `{"id":"UUID"}` |
| Rename | `POST /v1/thread/update` | `{"id":"UUID","title":"New name"}` |
| Set analysis | `POST /v1/thread/update` | `{"id":"UUID","thread_metadata":{"analysis":{...}}}`. Shallow merge one level under `analysis`. A key whose value changes fires `analysis_updated`. A patch that changes nothing fires no event. SDK: `mgmt.threads.setAnalysis(id, patch, ks)`. |
| Clear analysis | `POST /v1/thread/update` | `{"id":"UUID","thread_metadata":{}}`. Clears `analysis`. SDK: `mgmt.threads.clearAnalysis(id, ks)`. |
| Push | `POST /thread/push` (no `v1/` prefix on this route) | `{"id":"UUID","content":"...","request_vars"?:{...},"system_message"?:"..."}`. `delivered:false` in the reply means no live socket is attached. The message is still saved and appears in the Messages list. SDK: `mgmt.threads.push({id,content,request_vars?,system_message?}, ks)`. |
| Delete | `POST /v1/thread/delete` | `{"thread_ids":["UUID"]}`. See [Conversation & Analytics § Threads](https://kaltura.github.io/intelligent-agents-sdk/reference/api/operate/index.md#threads) for delete behavior |
| Transcript | `POST /v1/thread/get_transcripts` | `{"id":"UUID"}` |

**Filter fields (list):** `agentIdEquals`, `contextIdEqual`, `createdAtGreaterThanOrEqual`, `createdAtLessThanOrEqual`, `idEquals`, `idsIn`, `isEverywhere`, `orderBy`, `partnerIdEquals`, `statusEquals`, `statusIn`, `updatedAtGreaterThanOrEqual`, `updatedAtLessThanOrEqual`, `userIdEquals`.

Rules to know:

- Put `orderBy` inside `filter` (one of `+createdAt`, `-createdAt`, `+updatedAt`, `-updatedAt`).
- Send `statusEquals`/`statusIn` as numbers, `0` or `1`.
- Use only the filter fields listed above. `partnerIdIn` is not supported.
- Pager is `{pageIndex, pageSize}` (1-based). Use `pageIndex`/`pageSize`, not `{offset, limit}`.
- `pageSize` is at most 500. This applies to every list and report pager in this section (Threads, Messages, Feedback, Followups).

SDK: `mgmt.threads.list(ks, opts)` merges `opts.filter` under the fixed `objectType`, so it can't be overridden. `agentIdEquals` filters threads by agent. There is no "in" form: `agentIdIn` throws a `validation_error` before any network call.

`request_vars` on `push` goes through the same reserved-name check as `converse`, before any network call. See [Conversation & Analytics § Reserved Template Variables](https://kaltura.github.io/intelligent-agents-sdk/reference/api/operate/index.md#reserved-template-variables-sys__).

See [Conversation & Analytics § Threads](https://kaltura.github.io/intelligent-agents-sdk/reference/api/operate/index.md#threads) for response shapes and delete behavior.

## Messages, Feedback & Followups

SDK: `mgmt.messages`, `mgmt.feedback`, `mgmt.followups`. `messages.list`, `get` and `share` accept an admin, conversation or agent token (see [Conversation & Analytics § Threads](https://kaltura.github.io/intelligent-agents-sdk/reference/api/operate/index.md#threads)). `messages.report`, `messages.reportSummary`, `feedback.list` and `followups.list` need an admin token.

| Operation | Endpoint | Body |
|-----------|----------|------|
| List messages | `POST /message/list` | `{"filter":{"objectType":"GenieListMessageFilter"},"pager":{"pageIndex":1,"pageSize":50}}`. `opts.threadId` is sugar for `filter.threadIdEquals` and wins if both are given. |
| Share a message | `POST /message/share` | `{"id":"MSG_ID","newTitle":"..."}` → `{"status":"success","data":{"newMessageId":"..."}}`. SDK: `mgmt.messages.share(id, newTitle, ks)` unwraps this and returns `{newMessageId}`. It throws `server_error` if no id comes back. The clone is readable with `messages.get` and cannot be deleted. |
| Message report (CSV) | `POST /message/report` | `{"filter":{"objectType":"GenieListMessageFilter"}}`. ⚠️ SENSITIVE: contains end-user ids and names plus verbatim question and feedback text. SDK: `mgmt.messages.report(ks, opts)` (raw CSV) or `reportSummary(ks, opts)` (parsed, with a `_meta` provenance receipt). `reportSummary` uses `pageSize` 500 (the maximum) when you omit it. |
| Add feedback | `POST /feedback/add` | `{"schemaVersion":1,"data":{"message_id":"...","is_positive":true,"comment"?:"..."}}`. Idempotent for a given `(message_id, is_positive)` pair. Any KS (conversation or admin). Read ratings back with `mgmt.feedback.list` (below). |
| List feedback | *(built on `/message/list`, no dedicated endpoint)* | `mgmt.feedback.list(ks, opts)`. Details below. |
| Suggested followups | `POST /followup/get-suggested-questions?new_response=true` | `{}`. Starter questions for the partner or agent, not scoped to a thread. The set can differ between calls. Returns `[]` when none are configured. Distinct from per-answer followups (`capabilities.generate_followup_questions:on` on converse). SDK: `mgmt.followups.getSuggested(ks)`. |
| List followup records | `POST /followup/list` | `{"filter":{"objectType":"GenieListQuestionFilter"},"pager":{"pageIndex":1,"pageSize":30}}`. The raw partner-wide record listing, not the shortlist above. |

**List feedback in depth.** `mgmt.feedback.list(ks, opts)` reads feedback. It queries `POST /message/list` (and, for `filter.agentIdEquals`, `POST /v1/thread/list` first) and returns only the messages that carry a rating.

Filter: `messageIdEquals`, `messageIdsIn`, `threadIdEquals`, `agentIdEquals`, `isPositiveEquals`. `agentIdEquals` matches only threads opened with a token minted with that `agentId` (`createAgentToken`, or `createConversationToken` with `agentId`). It costs one thread query per matching thread. Set at least one of `messageIdEquals`, `messageIdsIn`, `threadIdEquals` or `agentIdEquals`. With none set, it reads every message for the partner.

Unlike every other `list()` in this SDK, `await`ing `feedback.list(...)` collects **every** matching row across all underlying pages, not just the first page. Use a narrow filter.

Row shape: `{message_id, thread_id, genie_id, user_id, is_positive, comment, created_at, updated_at}`. ⚠️ SENSITIVE: comments are end-user-entered text.

Messages filter fields: `createdAtGreaterThanOrEqual`, `createdAtLessThanOrEqual`, `genieIdEquals`, `idEquals`, `idsIn`, `isPositiveEquals`, `isPositiveIn`, `orderBy`, `threadIdEquals`, `updatedAtGreaterThanOrEqual`, `updatedAtLessThanOrEqual`, `userIdEquals`. Send only the keys listed. Sort with `filter.orderBy`.

`threads.list`, `messages.list` and `followups.list` merge `opts.filter` under a fixed `objectType` that you cannot override. `feedback.list` has its own filter shape (above).

## Knowledge records

Full record lifecycle. SDK: `mgmt.knowledge`. An intellect links to a record through `knowledge_ids`. See [Agent Components · Ground the Agent in Your Content (RAG) § Ground the Agent](https://kaltura.github.io/intelligent-agents-sdk/reference/api/build/knowledge-rag/index.md#ground-the-agent-in-your-content-rag).

| Operation | Endpoint | Body |
|-----------|----------|------|
| List | `POST /v1/knowledge/list` | `{"filter":{},"pager":{"pageIndex":1,"pageSize":30}}`. Finds records without knowing ids up front. SDK: `mgmt.knowledge.list(ks, opts)`. Distinct from `mgmt.knowledge.listCategoryEntries(categoryId, ks)`, which lists KMS entries inside one category, not Knowledge record containers. |
| Add | `POST /v1/knowledge/add` | `{"name":"..."}` |
| Get | `POST /v1/knowledge/get` | `{"id":2049}` |
| Update | `POST /v1/knowledge/update` | `{"id":2049, ...fields}`. When you send `config`, send the full config. To change sources, use `addSource`/`removeSource` below. |
| Delete | `POST /v1/knowledge/delete` | `{"id":2049}`. Returns HTTP 200 with body `null`. A follow-up get returns 404. |
| Per-entry status | `POST /v1/knowledge/entry_status` | `{"knowledge_id":2049, "entry_ids":["0_abc123"]}`. SDK: `mgmt.knowledge.entryStatus(id, entryIds, ks)`. |

`mgmt.knowledge.isIndexed(id, ks)` wraps Get and reads `status`/`config.sources[].indexers[].index_position`. `status` does not tell you that indexing is complete. For the completion check, see [Agent Components · Ground the Agent in Your Content (RAG) § Ground the Agent](https://kaltura.github.io/intelligent-agents-sdk/reference/api/build/knowledge-rag/index.md#ground-the-agent-in-your-content-rag).

`mgmt.knowledge.addSource(id, source, ks)` / `removeSource(id, source, ks)` read-merge-write one source into/out of `config.sources` without disturbing the others. Both skip the write (`applied:false`) when an identical source object is already present / already absent. Call them one at a time for the same record id. Two overlapping calls can lose one of the changes.

Before deleting a record, `mgmt.knowledge.deleteRecord` lists every intellect and refuses with a typed `knowledge_in_use` error naming each one still carrying the id in `knowledge_ids`. Pass `{confirmPermanent:true, force:true}` to delete anyway. `mgmt.tools.delete` and `mgmt.skills.delete` use the same guard.

## Lifecycle

An event-driven rule engine, not embedded in an intellect. SDK: `mgmt.lifecycle`. Full reference (rule shape, action types, CRUD + discovery methods) and a worked recipe: **[Lifecycle Rules](https://kaltura.github.io/intelligent-agents-sdk/reference/lifecycle/index.md)**. To check existing rules, and a partner's agents and intellects, for mistakes, use `mgmt.lifecycle.audit`, `mgmt.intellectConfig.audit` and `mgmt.doctor`. They only read. See [Audit your rules](https://kaltura.github.io/intelligent-agents-sdk/reference/lifecycle/index.md#audit-your-rules).

## Insight Settings

Reusable custom-insight definitions (`key`/`title`/`prompt`/`valueType`), referenced by id from a lifecycle rule's `triggerInsightSettingsKai` action. Not embedded in an intellect. SDK: `mgmt.insightSettings`. See [Lifecycle Rules](https://kaltura.github.io/intelligent-agents-sdk/reference/lifecycle/index.md).

| Operation | Endpoint | Body |
|-----------|----------|------|
| Create | `POST /v1/insight-settings/create` | `{"key":"NEXT_STEP","title":"Next step","prompt":"...","valueType":"string"}`. All 4 fields required |
| Get | `POST /v1/insight-settings/get` | `{"id":"<id>"}` |
| List | `POST /v1/insight-settings/list` | `{"filter":{"statusEqual":"active"},"pager":{"offset":0,"limit":30}}` |
| Update | `POST /v1/insight-settings/update` | `{"id":"<id>", ...fields}`. Any of `key`/`title`/`prompt`/`valueType`/`status` |
| Delete | `POST /v1/insight-settings/delete` | `{"id":"<id>"}`. Remove the id from every lifecycle rule that references it before you delete it |

Full reference and a worked recipe: **[Lifecycle Rules § InsightSettings](https://kaltura.github.io/intelligent-agents-sdk/reference/lifecycle/index.md#insightsettings-reusable-insight-definitions)**.

