> ## Documentation Index
> Fetch the complete documentation index at: https://docs.rumik.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# manage agents

> create, configure, deploy, roll back and delete agents.

an agent is a prompt, a greeting, a voice and a language, plus a little call
behaviour. `/v1/agents` is the same thing the dashboard's agent editor edits.

## create

`POST /v1/agents` creates an agent as a draft.

<ParamField body="name" type="string" required>
  up to 120 characters. applies immediately when changed later.
</ParamField>

<ParamField body="systemInstruction" type="string" required>
  the persona — who the agent is and how it behaves, up to 8000 characters.
  write only the persona: the rules for the chosen language and voice are
  appended server-side. `{name}` reads a [variable](/variables-and-tools),
  `{{tool_name}}` attaches a tool.
</ParamField>

<ParamField body="greeting" type="string" required>
  the first thing the agent says, up to 1000 characters. may use `{name}`.
</ParamField>

<ParamField body="ttsConfig" type="object">
  the voice. `model` is `muga`, `mulberry` or `spider`; mulberry also takes a
  named `voice` and a style `description`. see [voices](/voices). defaults to
  `{ "model": "muga" }`.
</ParamField>

<ParamField body="language" type="string">
  `english`, `hinglish` or `hindi`, as the voice engine allows. unset = the
  engine's default.
</ParamField>

<ParamField body="callSettings" type="object">
  `background_noise` and `idle_ladder`, both off by default. see
  [call behaviour](#call-behaviour).
</ParamField>

<ParamField body="versionName" type="string">
  a name for the first version, shown in the history. optional.
</ParamField>

<ParamField body="source" type="string">
  `scratch` (default) or `template`, with `templateSlug` naming the template
  from `GET /v1/agents/templates`.
</ParamField>

```bash curl theme={null}
curl -X POST https://silk-api.rumik.ai/v1/agents \
  -H "Authorization: Bearer rk_live_•••••••••" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "support",
    "systemInstruction": "You are the support agent for {company}. Be brief and warm. When the caller asks for a human, {{transfer_call}}.",
    "greeting": "Hi, this is {company} support. How can I help?",
    "ttsConfig": { "model": "mulberry", "voice": "Emma" },
    "language": "english",
    "callSettings": { "idle_ladder": { "enabled": true } },
    "versionName": "first cut"
  }'
```

returns `201` with the agent:

```json theme={null}
{
  "id": "019f6a2e-7c1d-7b3a-9e4f-1a2b3c4d5e6f",
  "handle": "ua_fe3277d8",
  "name": "support",
  "systemInstruction": "You are the support agent for {company}. …",
  "greeting": "Hi, this is {company} support. How can I help?",
  "ttsConfig": { "model": "mulberry", "voice": "Emma" },
  "callSettings": { "idle_ladder": { "enabled": true, "nudge_after_seconds": 5, "presence_after_seconds": 7, "hangup_after_seconds": 5 } },
  "language": "english",
  "source": "scratch",
  "templateSlug": null,
  "inboundPhoneNumber": null,
  "deployed": false,
  "ownerUserId": "019f0000-0000-7000-8000-000000000001",
  "createdAt": "2026-09-11T10:00:00Z",
  "updatedAt": "2026-09-11T10:00:00Z"
}
```

<ResponseField name="handle" type="string">
  the short id (`ua_…`). use it or the UUID wherever an agent is named.
</ResponseField>

<ResponseField name="deployed" type="boolean">
  false until the first deploy. an undeployed agent answers no calls.
</ResponseField>

<ResponseField name="inboundPhoneNumber" type="string | null">
  the number this agent answers, once a [rented number](/phone-numbers) or
  [SIP trunk](/sip-trunks) is connected to it.
</ResponseField>

<ResponseField name="systemInstruction, greeting, ttsConfig, language, callSettings">
  the **live** configuration. after a `PATCH`, the pending edit is on the
  draft, not here, until you deploy.
</ResponseField>

<Note>
  typing `{company}` into the prompt declares an account-wide variable named
  `company` (with a blank default) if none exists yet. set its value with
  [`/v1/variables`](/variables-and-tools).
</Note>

up to 25 agents per account (`409 limit_exceeded` past that).

## deploy

`POST /v1/agents/{agent_ref}/deploy` promotes the pending draft to the next
version and puts it live. it returns that version.

```bash curl theme={null}
curl -X POST https://silk-api.rumik.ai/v1/agents/ua_fe3277d8/deploy \
  -H "Authorization: Bearer rk_live_•••••••••"
```

```json theme={null}
{
  "id": "019f6b3f-8d2e-7c4b-af50-2b3c4d5e6f70",
  "versionNumber": 1,
  "name": "first cut",
  "status": "active",
  "systemInstruction": "…",
  "greeting": "…",
  "ttsConfig": { "model": "mulberry", "voice": "Emma" },
  "callSettings": { … },
  "language": "english",
  "activatedAt": "2026-09-11T10:05:00Z",
  "createdAt": "2026-09-11T10:00:00Z",
  "updatedAt": "2026-09-11T10:05:00Z"
}
```

with nothing pending you get `409 agent_version_no_draft` — the agent already
serves its latest edits.

## update

`PATCH /v1/agents/{agent_ref}` takes any subset of the create fields.

* `name` renames the agent at once.
* `systemInstruction`, `greeting`, `ttsConfig`, `language` and `callSettings`
  go to the **draft**. the live version keeps answering until you deploy.
* `versionName` names the draft this edit writes. omit it to leave the name
  alone, send `null` to clear it. sent on its own it renames the existing
  draft (`409 agent_version_no_draft_to_name` when there is none).

```bash curl theme={null}
curl -X PATCH https://silk-api.rumik.ai/v1/agents/ua_fe3277d8 \
  -H "Authorization: Bearer rk_live_•••••••••" \
  -H "Content-Type: application/json" \
  -d '{ "systemInstruction": "You are the support agent for {company}. Be brief.", "versionName": "shorter prompt" }'
```

the response is the agent with its **live** fields; read the draft with
`GET /v1/agents/{agent_ref}/versions/draft`, then deploy.

## versions

| method | path                                           | what                                                                          |
| ------ | ---------------------------------------------- | ----------------------------------------------------------------------------- |
| GET    | `/v1/agents/{agent_ref}/versions`              | history, newest first: the `draft`, the `active` version, the `archived` ones |
| GET    | `/v1/agents/{agent_ref}/versions/draft`        | the pending draft (`404 agent_version_not_found` when none)                   |
| DELETE | `/v1/agents/{agent_ref}/versions/draft`        | discard the pending edits                                                     |
| GET    | `/v1/agents/{agent_ref}/versions/{n}`          | one version's full snapshot                                                   |
| POST   | `/v1/agents/{agent_ref}/versions/{n}/activate` | roll back: that version goes live, the current one is archived                |
| DELETE | `/v1/agents/{agent_ref}/versions/{n}`          | remove an archived version (`409` for the active one)                         |

a version carries the whole snapshot, not a diff, so any two can be compared
without walking the chain.

## call behaviour

`callSettings` is versioned with the rest of the config and sent to the bot on
every call. both features are off unless enabled.

```json theme={null}
{
  "background_noise": { "enabled": true, "volume": 30 },
  "idle_ladder": {
    "enabled": true,
    "nudge_after_seconds": 5,
    "presence_after_seconds": 7,
    "hangup_after_seconds": 5
  }
}
```

<ResponseField name="background_noise" type="object">
  mixes a quiet room tone under the voice. `volume` is 0–100 (default 30).
</ResponseField>

<ResponseField name="idle_ladder" type="object">
  when the caller stays silent after the agent stops speaking: after
  `nudge_after_seconds` the agent says one short line to bring them back,
  `presence_after_seconds` later it asks whether they are still there, and
  `hangup_after_seconds` after that it says goodbye and ends the call
  (`endReason: "customer_ended"`). any reply restarts the ladder. each timing
  is 1–120 seconds.
</ResponseField>

on [outbound calls](/outbound-calls) you can override `callSettings` for one
call without touching the agent.

## list, get, delete

```bash curl theme={null}
curl https://silk-api.rumik.ai/v1/agents -H "Authorization: Bearer rk_live_•••••••••"
curl https://silk-api.rumik.ai/v1/agents/ua_fe3277d8 -H "Authorization: Bearer rk_live_•••••••••"
curl -X DELETE https://silk-api.rumik.ai/v1/agents/ua_fe3277d8 -H "Authorization: Bearer rk_live_•••••••••"
```

`GET /v1/agents` returns `{ "items": [...], "count": n }`, newest first.
`DELETE` answers `204`; the agent's calls stay in history and a number
connected to it is detached.

## this agent's calls

read the account's call history with
[`GET /v1/calls`](/outbound-calls#call-history) and keep the ones whose
`agentSlug` is this agent's handle. every call carries its transcript and a
short-lived recording url.

## templates

`GET /v1/agents/templates` lists the starter templates the dashboard offers.
to create from one, copy its `systemInstruction`, `greeting` and `ttsConfig`
into `POST /v1/agents` with `"source": "template"` and its `slug` as
`templateSlug`.

next: [voices](/voices).
