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

# Agents

> Phone voice agents: build an agent, attach a phone line, place calls, and follow them to the end

## Overview

An **agent** is a phone voice assistant. You give it a script, a 60db voice and, optionally, tools that call your backend. You attach a phone line, then place a call. The agent speaks with the caller, follows its script, and leaves a recording, a transcript and a result you can read through the API or dashboard.

> [!NOTE]
>
> **Access.** If Agents is not enabled for your workspace yet, requests return `403 AGENTS_BETA_ONLY`. Contact 60db support to turn it on.
>
> **Outbound only for now.** Agents place calls. Inbound calls (an agent answering a number you own) are coming soon. Phone lines show `inbound_available: false` until then.

> [card] Agents
>
> Script, voice, languages, tools and call defaults in one object

> [card] Phone lines
>
> Call from a 60db Dialer number or your own SIP trunk

> [card] Calls
>
> Status, duration, transcript and recording for every call

> [card] Tools and events
>
> Let the agent call your API mid-call, and get signed call events

## Quickstart

### Dashboard

**1. Open Agents**

Sidebar → **Agents**

**2. Pick a template**

Start from **Receptionist**, **Lead qualifier** or **Appointment booking**, then edit the script

**3. Pick a voice**

Choose a 60db voice. See [Voices](https://docs.60db.ai/features/voices.md)

**4. Add a phone line**

**Phone lines** → **Add a phone line**. Use a 60db number ([get one in Dialer](https://docs.60db.ai/features/dialer.md)) or your own SIP trunk

**5. Run a test call**

Choose **Test call**, enter the number to ring, and start the call

### API

**1. Create the agent**

`POST /agents`. The response includes `webhook_secret`, shown only once. Store it now

**2. Find a number**

`GET /agents/phone-lines/available-numbers` lists your 60db Dialer numbers. `in_use: false` means it is free

**3. Add the phone line**

`POST /agents/phone-lines` with `kind: "sixtydb"` and the number. Copy the line `id`

**4. Place a call**

`POST /agents/{agentId}/calls` with `to` and `phone_line_id`. Returns `202` with the call

**5. Follow the call**

Poll `GET /agents/calls/{callId}` until `status` is `completed` or `failed`. Or set `event_webhook_url` and handle `call.completed`

```bash theme={null}
# 1. Create an agent
curl -X POST https://api.60db.ai/agents \
  -H "Authorization: Bearer $SIXTYDB_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Front desk",
    "script": "You are the receptionist for Juniper Kitchen. Keep replies short.",
    "voice_id": "YOUR_VOICE_ID",
    "greeting": "Hello, Juniper Kitchen. How can I help?",
    "listen_languages": ["hi", "en"],
    "call_defaults": { "max_duration_secs": 300, "record": true }
  }'

# 2. Add a 60db number as a phone line
curl -X POST https://api.60db.ai/agents/phone-lines \
  -H "Authorization: Bearer $SIXTYDB_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "kind": "sixtydb", "number": "+919876543210", "agent_id": "AGENT_ID" }'

# 3. Place a call
curl -X POST https://api.60db.ai/agents/AGENT_ID/calls \
  -H "Authorization: Bearer $SIXTYDB_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "to": "+919999999999", "phone_line_id": "LINE_ID" }'
```

> [tab] JavaScript
>
> ```javascript theme={null}
> import { SixtyDBClient } from '60db-service';
>
> const client = new SixtyDBClient('your-api-key');
>
> const call = await client.agents.call(agentId, { to: '+919999999999', phoneLineId: lineId });
> const done = await client.agents.calls.waitForCompletion(call.id);
> console.log(done.status, done.duration_secs);
> ```

> [tab] Python
>
> ```python theme={null}
> from sixtydb import SixtyDBClient
>
> client = SixtyDBClient('your-api-key')
>
> call = client.agents.call(agent_id, to='+919999999999', phone_line_id=line_id)
> done = client.agents.calls.wait_for_completion(call['id'])
> print(done['status'], done['duration_secs'])
> ```

## API keys and accounts

You only need **your own 60db API key** — the same `sk_…` key you use for text-to-speech or speech-to-text. There is nothing else to sign up for and no separate phone-agent account or token.

* **Create a key** in **Developers → API keys** and send it as `Authorization: Bearer sk_…`. New keys include the `agents` scope; if you narrowed a key's scopes, turn `agents` on for it.
* **Your workspace only.** A key is tied to one workspace. Everything it creates — agents, phone lines, calls, recordings — belongs to that workspace, and no other account can see or use it.
* **Billed to you.** Calls bill the workspace of the key: speech, LLM and knowledge-base use come from your AI credits, and line minutes on a 60db number from your Dialer balance.
* **You stay in control.** Deleting or narrowing your key stops your own API access at once. Calls that are already running finish normally.

> [!NOTE]
>
> 60db runs the phone-call side for you. Behind the scenes each workspace has its own internal key for call usage, so usage is always attributed to the right account — it never appears in your API keys list and you never handle it.

## Concepts

| Term | What it is |
| - | - |
| **Agent** | Script, voice, languages, tools, webhook URLs and call defaults. Identified by `id` (UUID) |
| **Phone line** | A number an agent calls from. `kind` is `sixtydb` (a 60db Dialer number) or `byo` (your own SIP trunk) |
| **Call** | One outbound call made by an agent. Has a status, a result, a duration and a cost |
| **Tools** | Functions the agent can call during a call. Your endpoint answers them |
| **Knowledge base** | A workspace Smart Memory collection the agent can search during calls |
| **Events** | `call.completed`, `call.failed` and `recording.ready`, sent to your `event_webhook_url` |

### Call lifecycle

| Status | Meaning |
| - | - |
| `queued` | Saved. The dialer has not confirmed the call yet |
| `dialing` | Accepted. The phone is ringing |
| `in_progress` | Connected |
| `completed` | Ended normally |
| `failed` | Did not connect, or ended with an error |

When a call ends, `reason` gives a short code. 60db uses `dial_unconfirmed` (the dialer never confirmed the call), `stale` (no final state in time) and `lost` (the call could not be found on the call runtime). Other values are passed through from the runtime, so treat `reason` as informational, not a fixed list.

`duration_secs` is the connected time. It is set once the call ends.

## Talk to your agent in the browser

Test an agent without a phone line. Open the agent, go to **Test call**, and choose **Talk in browser**. Allow microphone access, wait for **Connected**, and speak. The dialog shows a timer, a **Mute** toggle and **Hang up**. Closing the dialog or the tab ends the call.

* It uses the agent's saved settings, voice, tools and knowledge base, like a phone call. Audio has phone-call quality.
* Call transfer and the keypad (DTMF) are not available in the browser.
* A browser call lasts up to 5 minutes. Up to 3 browser calls can run at once in a workspace.
* It appears in **Calls** with the label **Web**. It uses no phone line and no Dialer balance. AI credits and the agent runtime fee apply as for any call.
* Use a recent Chrome, Edge, Safari or Firefox. If it will not connect, check that your network or firewall allows real-time calls (UDP).

To add this to your own app, see [Start browser call](https://docs.60db.ai/api-reference/agents/start-web-call.md). The browser offer must go through your server, so your API key never reaches the browser.

## Tools and knowledge base

* **Tools** let the agent fetch or change data during a call, such as checking availability or booking a table. Each tool call goes to your `tool_webhook_url`. See [Tools and webhooks](https://docs.60db.ai/features/agents-tools-and-webhooks.md).
* **Knowledge base** is set with `knowledge_collection_id`, a workspace Smart Memory collection. See [Memory](https://docs.60db.ai/features/memory.md) and [Collections](https://docs.60db.ai/api-reference/memory/collections.md). Personal collections are not supported yet and return `422 KNOWLEDGE_COLLECTION_UNSUPPORTED`.

## Languages and code-switching

| Field | Meaning |
| - | - |
| `listen_languages` | Languages the agent understands. Callers may mix them in one call |
| `speak_languages` | Languages the agent may reply in |

Use two- or three-letter lowercase codes with no dialect tag: `en`, `hi`. `en-IN` is rejected with `400 VALIDATION_ERROR`. Each list holds up to 20 codes.

For code-switching (a caller who mixes Hindi and English), set `"listen_languages": ["hi", "en"]`.

## Emotion

`emotion` (boolean, default `true`) controls expressive speech. Set it to `false` for plainer delivery.

## Recording and consent

* Turn recording on with `call_defaults.record`, or per call with `overrides.record`.
* A recorded call keeps a stereo WAV (caller on the left, agent on the right) and a transcript. `GET /agents/calls/{callId}/recording?mix=1` returns one mixed channel.
* Delete a recording and its transcript with `DELETE /agents/calls/{callId}/recording`.
* Tell callers that the call is recorded, and get consent where your local law requires it. The API does not add a consent message. Put one in the script or greeting if you need it.

## Call settings

Set defaults on the agent in `call_defaults`. Override any of them for one call in `overrides`. A setting you leave unset uses the call runtime's default.

| Setting | Allowed values |
| - | - |
| `speaks_first` | `agent` or `caller` |
| `start_delay_ms` | 0 to 10000 |
| `idle_ms` | 1000 to 60000, or `null` |
| `idle_checkins` | 0 to 5 |
| `max_duration_secs` | 10 to 900 |
| `record` | `true` or `false` |
| `voice_speed` | 0.5 to 2, or `null` |
| `voice_stability` | 0 to 100, or `null` |
| `voice_similarity` | 0 to 100, or `null` |
| `speech_terms` | Up to 100 words or names, each up to 80 characters |

## Limits

| Item | Limit |
| - | - |
| Agent `name` | 1 to 64 characters, unique in the workspace (case-insensitive) |
| `script` | Up to 8,000 characters |
| `greeting` | Up to 500 characters |
| `listen_languages` / `speak_languages` | Up to 20 codes each |
| `tools` | Up to 16 per agent. See [tool rules](https://docs.60db.ai/features/agents-tools-and-webhooks.md#define-tools) |
| `metadata` on a call | Up to 4 KB of JSON |
| Concurrent calls per workspace | 2. A new call beyond this returns `429 CONCURRENCY_LIMIT` |
| Browser calls | 3 at once, up to 5 minutes each |
| Call length | 10 to 900 seconds (`max_duration_secs`) |
| Tool-call log | 50 most recent per agent through the API. Kept 30 days |
| List pages | `limit` 1 to 100 (default 50) |

## Pricing

| Item | Price | Billed from |
| - | - | - |
| Speech-to-text, text-to-speech, LLM and memory during a call | Standard AI credit rates | AI credits |
| Agent runtime fee | **\$0** | AI credits, per connected minute, in 6-second steps |
| Line minutes on a 60db number | ₹0.30/min (\$0.003/min) | Dialer balance |
| 60db number rental | ₹600/month (\$6.00/month) | Dialer balance |
| Line minutes on your own SIP trunk (BYO) | Your carrier's rate | Your carrier |

* Line minutes are billed per completed call, the same way as other Dialer calls. A 60db number needs a Dialer balance above zero, or the call returns `402 DIALER_BALANCE_EMPTY`.
* Each call returns `cost.runtime_usd` and `cost.runtime_billing_status`.

## Errors

| Status | Code | Meaning |
| - | - | - |
| 400 | `VALIDATION_ERROR` | A field is invalid. The response names it in `field` |
| 403 | `AGENTS_BETA_ONLY` | Your workspace is not on the beta list |
| 403 | `POLICY_DENY` | The API key lacks the `agents` scope, or placing calls needs an active plan |
| 404 | `AGENTS_DISABLED` | Agents are not enabled on this environment |
| 402 | `INSUFFICIENT_CREDITS` | Not enough AI credits to place a call |
| 402 | `DIALER_BALANCE_EMPTY` | The Dialer balance for a 60db number is empty |
| 429 | `CONCURRENCY_LIMIT` | Too many calls are running at once |

Endpoint pages list the codes that apply to each call. See [Troubleshooting](https://docs.60db.ai/api-reference/troubleshooting.md) for the general error format.

## Related

* [Tools and webhooks](https://docs.60db.ai/features/agents-tools-and-webhooks.md): tool calls, signed events, retries
* [Dialer](https://docs.60db.ai/features/dialer.md): 60db numbers, balance and call billing
* [Agents API reference](https://docs.60db.ai/api-reference/agents/list-agents.md)
* [MCP tools](https://docs.60db.ai/mcp-server/agents.md): run agents from Claude or another MCP client
* [JavaScript SDK](https://docs.60db.ai/sdks/javascript.md#agents) and [Python SDK](https://docs.60db.ai/sdks/python.md#agents)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.