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

# Manage agents

> REST reference for creating and managing reusable voice agents. Endpoints, request and response schemas, the HTTP tool schema, and validation rules.

The Voice Agent API includes a REST API for creating and managing reusable voice agents. An agent stores its system prompt, greeting, voice, and tools server-side, so you can [deploy](/voice-agents/voice-agent-api/deploy) it across channels by referencing its `id`.

For a guided walkthrough, see [Create an agent](/voice-agents/voice-agent-api/create-agent).

**Base URL:** `https://agents.assemblyai.com`

## Authentication

Every request requires your AssemblyAI API key in the `Authorization` header. The raw key works directly; a `Bearer ` prefix is accepted and stripped:

```
Authorization: <YOUR_API_KEY>
```

| Response                                         | Meaning                                                   |
| ------------------------------------------------ | --------------------------------------------------------- |
| `401 {"detail": "Unauthorized"}`                 | Key missing, malformed, or not entitled for Voice Agents. |
| `401 {"detail": "Missing authorization header"}` | No `Authorization` header sent.                           |

## Endpoints

| Method   | Path              | Description        | Success |
| -------- | ----------------- | ------------------ | ------- |
| `POST`   | `/v1/agents`      | Create an agent    | `201`   |
| `GET`    | `/v1/agents`      | List your agents   | `200`   |
| `GET`    | `/v1/agents/{id}` | Retrieve one agent | `200`   |
| `PUT`    | `/v1/agents/{id}` | Update an agent    | `200`   |
| `DELETE` | `/v1/agents/{id}` | Delete an agent    | `204`   |

### Create an agent

`POST /v1/agents`

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://agents.assemblyai.com/v1/agents \
    -H "Authorization: $ASSEMBLYAI_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "name": "Support Assistant",
      "system_prompt": "You are a friendly support agent.",
      "greeting": "Hi, how can I help?",
      "voice": { "voice_id": "ivy" }
    }'
  ```

  ```python Python theme={null}
  # pip install requests
  import os
  import requests

  resp = requests.post(
      "https://agents.assemblyai.com/v1/agents",
      headers={"Authorization": os.environ["ASSEMBLYAI_API_KEY"]},
      json={
          "name": "Support Assistant",
          "system_prompt": "You are a friendly support agent.",
          "greeting": "Hi, how can I help?",
          "voice": {"voice_id": "ivy"},
      },
  )
  resp.raise_for_status()
  print(resp.json()["id"])
  ```

  ```javascript Node.js theme={null}
  // Node 18+ has fetch built in
  const res = await fetch("https://agents.assemblyai.com/v1/agents", {
    method: "POST",
    headers: {
      Authorization: process.env.ASSEMBLYAI_API_KEY,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      name: "Support Assistant",
      system_prompt: "You are a friendly support agent.",
      greeting: "Hi, how can I help?",
      voice: { voice_id: "ivy" },
    }),
  });
  const data = await res.json();
  console.log(data);
  ```
</CodeGroup>

Returns `201` with the full [agent record](#agent-object).

### List agents

`GET /v1/agents` returns a lightweight array of `id`, `name`, and timestamps, not full configurations.

<CodeGroup>
  ```bash cURL theme={null}
  curl https://agents.assemblyai.com/v1/agents \
    -H "Authorization: $ASSEMBLYAI_API_KEY"
  ```

  ```python Python theme={null}
  # pip install requests
  import os
  import requests

  resp = requests.get(
      "https://agents.assemblyai.com/v1/agents",
      headers={"Authorization": os.environ["ASSEMBLYAI_API_KEY"]},
  )
  resp.raise_for_status()
  print(resp.json())
  ```

  ```javascript Node.js theme={null}
  // Node 18+ has fetch built in
  const res = await fetch("https://agents.assemblyai.com/v1/agents", {
    method: "GET",
    headers: {
      Authorization: process.env.ASSEMBLYAI_API_KEY,
    },
  });
  const data = await res.json();
  console.log(data);
  ```
</CodeGroup>

### Retrieve an agent

`GET /v1/agents/{id}` returns the full [agent record](#agent-object). Tool header **values** are masked as `"***"` (see [HTTP tool config](#http-tool-config)).

### Update an agent

`PUT /v1/agents/{id}` accepts the same body as create, but **every field is optional**. Send only what changes. Returns `200` with the updated record.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X PUT https://agents.assemblyai.com/v1/agents/$AGENT_ID \
    -H "Authorization: $ASSEMBLYAI_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{ "greeting": "Thanks for calling Acme. What can I do for you?" }'
  ```

  ```python Python theme={null}
  # pip install requests
  import os
  import requests

  resp = requests.put(
      f"https://agents.assemblyai.com/v1/agents/{os.environ['AGENT_ID']}",
      headers={"Authorization": os.environ["ASSEMBLYAI_API_KEY"]},
      json={"greeting": "Thanks for calling Acme. What can I do for you?"},
  )
  resp.raise_for_status()
  print(resp.json())
  ```

  ```javascript Node.js theme={null}
  // Node 18+ has fetch built in
  const res = await fetch(`https://agents.assemblyai.com/v1/agents/${process.env.AGENT_ID}`, {
    method: "PUT",
    headers: {
      Authorization: process.env.ASSEMBLYAI_API_KEY,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ greeting: "Thanks for calling Acme. What can I do for you?" }),
  });
  const data = await res.json();
  console.log(data);
  ```
</CodeGroup>

### Delete an agent

`DELETE /v1/agents/{id}` returns `204` with no body.

## Request body

`POST /v1/agents` takes the agent as one JSON object; `PUT /v1/agents/{id}` takes the same body with every field optional (only `name`, `system_prompt`, and `voice` are required). For a copy-ready body with **every field populated**, see [A complete agent](/voice-agents/voice-agent-api/create-agent#a-complete-agent). For exact field types, defaults, and validation, see the [create-agent API reference](/api-reference/voice-agent-api/create-agent).

## Tool object

| Field             | Type                                  | Required | Default         | Notes                                                                                                                        |
| ----------------- | ------------------------------------- | -------- | --------------- | ---------------------------------------------------------------------------------------------------------------------------- |
| `name`            | string                                | Yes      | -               | Tool name the model calls.                                                                                                   |
| `description`     | string                                | Yes      | -               | When to call it. The model's main signal.                                                                                    |
| `parameters`      | [Parameters](#parameters-json-schema) | No       | `null`          | A JSON Schema describing the tool's arguments.                                                                               |
| `http`            | [`HttpToolConfig`](#http-tool-config) | No       | `null`          | The outbound request. Omit for a client-handled tool.                                                                        |
| `timeout_seconds` | integer                               | No       | `120`           | Range `1`–`300`.                                                                                                             |
| `execution_mode`  | `"interactive"` \| `"hold"`           | No       | `"interactive"` | How the agent behaves while the tool runs. See [tool calling](/voice-agents/voice-agent-api/tools/overview#execution-modes). |

### Parameters (JSON Schema)

`parameters` is a standard **JSON Schema** object describing the tool's arguments. The same shape for HTTP and client-side tools:

```json theme={null}
{
  "type": "object",
  "properties": {
    "order_id": {
      "type": "string",
      "description": "The customer's order ID.",
      "examples": ["AB-12345", "ZZ-90001"],
      "pattern": "[A-Z]{2}-\\d{5}"
    }
  },
  "required": ["order_id"]
}
```

Each property accepts standard JSON-Schema keywords. Beyond `type` and `description`, these sharpen tool-calling and turn-detection accuracy:

| Keyword    | Type      | Notes                                                          |
| ---------- | --------- | -------------------------------------------------------------- |
| `enum`     | string\[] | Restrict to a fixed set of allowed values.                     |
| `examples` | array     | Concrete example values. Improves recognition and turn-taking. |
| `pattern`  | string    | Regex the value must match to be accepted.                     |
| `format`   | string    | A named JSON-Schema format (`email`, `date-time`, …).          |

If you omit these, the agent infers the expected shape from each property's `description` at runtime. See [Parameter hints](/voice-agents/voice-agent-api/tools/overview#parameter-hints-improve-accuracy) for guidance and examples.

### HttpToolConfig

Write shape (create / update):

```json theme={null}
{
  "url": "https://api.example.com/orders",
  "http_method": "POST",
  "headers": [
    { "name": "Authorization", "value": "Bearer xyz" }
  ]
}
```

Read shape (get / list):

```json theme={null}
{
  "url": "https://api.example.com/orders",
  "http_method": "POST",
  "headers": [
    { "name": "Authorization", "last_set_at": "2026-06-20T10:00:00Z" }
  ]
}
```

| Field         | Type                      | Required | Default  | Notes                                                                |
| ------------- | ------------------------- | -------- | -------- | -------------------------------------------------------------------- |
| `url`         | string                    | Yes      | -        | Must be `https` and a public host. Max 2048 chars.                   |
| `http_method` | HTTP method               | No       | `"POST"` | `GET`, `POST`, `PUT`, `PATCH`, or `DELETE`.                          |
| `headers`     | HttpToolHeader\[] \| null | No       | `null`   | Sent on every call. Values are encrypted at rest and **write-only**. |

**HttpToolHeader (write):** `{ name, value?, remove? }`. Provide `value` to set or rotate the header. Provide name only (no `value`) to keep the stored value unchanged (useful for round-tripping on update). Set `remove: true` to delete it. Sending both `value` and `remove: true` is rejected.

**HttpToolHeader (read):** `{ name, last_set_at }`. Values are never returned.

**How arguments are sent:** `GET`/`DELETE` → query string (stringified, `null` dropped); `POST`/`PUT`/`PATCH` → JSON body. Query params already in `url` are merged with the model's arguments.

**Rotating a secret:** send `{ "name": "Authorization", "value": "Bearer <new>" }` in the headers list of a `PUT /v1/agents/{id}`. Any other headers you want to keep, round-trip as name-only entries.

<Note>
  **Server-side execution constraints.** AssemblyAI makes the request on your behalf and enforces: `https` only; public hosts only (private/loopback/link-local/CGNAT IPs blocked, including obfuscated literals); redirects not followed (a `3xx` is returned to the model as an error); response body capped at 8 KiB before being fed to the model; per-call timeout from `timeout_seconds`.
</Note>

## Agent object

The full record returned by create, get, and update:

```json expandable theme={null}
{
  "id": "7ad24396-b822-4dca-871a-be9cc4781cf9",
  "name": "Weather Buddy",
  "system_prompt": "You are Weather Buddy...",
  "greeting": "Hey there, which city would you like the weather for?",
  "tools": [
    {
      "id": "f29a0fd4-6f8b-4acb-8a74-e60f417f6dbb",
      "name": "get_weather",
      "description": "Fetch current weather for a geographic point...",
      "http": {
        "url": "https://api.open-meteo.com/v1/forecast?current=temperature_2m&temperature_unit=fahrenheit",
        "http_method": "GET",
        "headers": {}
      },
      "parameters": {
        "type": "object",
        "properties": {
          "latitude":  { "type": "number", "description": "Latitude in decimal degrees." },
          "longitude": { "type": "number", "description": "Longitude in decimal degrees." }
        },
        "required": ["latitude", "longitude"]
      },
      "timeout_seconds": 30,
      "execution_mode": "interactive"
    }
  ],
  "voice": { "voice_id": "ivy" },
  "input":  { "type": "audio", "format": { "encoding": "audio/pcm", "sample_rate": 24000 }, "keyterms": null, "turn_detection": null },
  "output": { "type": "audio", "voice": "ivy", "format": { "encoding": "audio/pcm", "sample_rate": 24000 }, "volume": null },
  "created_at": "2026-06-08T12:04:27.607110Z",
  "updated_at": "2026-06-08T12:04:27.607113Z"
}
```

Tools gain a generated `id`. Header values are masked as `"***"` (here the tool has no headers, so `headers` is `{}`).

## Validation errors

| Status | When                          | Example                                                                                                                                                  |
| ------ | ----------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `400`  | A field fails a domain rule   | `Invalid voice 'xyz'. Must be one of: ...`, `tools[0].http.url: webhook URL must use https://`, `'tools[0].timeout_seconds' must be between 1s and 300s` |
| `401`  | Auth failed                   | `{"detail": "Unauthorized"}`                                                                                                                             |
| `422`  | Malformed JSON or wrong types | Standard schema-validation body naming the offending field.                                                                                              |

## Deploy a stored agent

Once created, connect by `agent_id`. Over the WebSocket, bind to the agent in your first `session.update`:

```json theme={null}
{
  "type": "session.update",
  "session": { "agent_id": "7ad24396-b822-4dca-871a-be9cc4781cf9" }
}
```

`agent_id` is mutually exclusive with inline session fields (`system_prompt`, `greeting`, `tools`, `input`, `output`). See [Deploy your agent](/voice-agents/voice-agent-api/deploy).
