# Route inbound calls to an agent (/en/ai/platform/build/phone-calls/route-inbound-calls)

> For AI agents: see the complete documentation index at [llms.txt](/llms.txt).

> Documentation: Conversational AI.
> Documentation version: Preview.
> This document describes only this version. [Version index](/llms/doc-versions-convoai-guides-v2.txt).


When someone calls one of your phone numbers, the Platform starts a session with the agent you route the number to, and the agent answers the call. You assign an agent to each number, and set limits and behavior for its calls.

## Prerequisites

Before you begin, make sure that you have:

- An agent to answer the calls. For details, see [Create an agent and start a session](/en/ai/platform/get-started/start-stop-agent).
- A phone number in your project. For details, see [Import phone numbers](/en/ai/platform/build/phone-calls/import-phone-numbers).

## Route a number to an agent

Assign the agent that answers calls to the number, and set a call policy. A call policy is required whenever you assign an agent. For its fields, see [Set limits and behavior for inbound calls](#set-limits-and-behavior-for-inbound-calls). You can set both when you [import the number](/en/ai/platform/build/phone-calls/import-phone-numbers#import-a-number), or later by updating the number.

**Python SDK**

Load the agent and call `assign_number()` with the number's ID or its E.164 number. The SDK reads the number's ETag for you, and retries once if the number changed in the meantime.

```python
from agora_agent import SavedAgent

saved_agent = SavedAgent.get(client, "c8a1e5d2-6f3b-4a9c-b7e0-2d4f6a8c1e3b")
saved_agent.assign_number("92e68758-3d3a-4f27-8b93-3fd8d834467c", max_call_duration_seconds=1800)
```

**TypeScript SDK**

Load the agent and call `assignNumber()` with the number's ID or its E.164 number. The SDK reads the number's ETag for you, and retries once if the number changed in the meantime.

```ts
import { SavedAgent } from 'agora-agents';

const savedAgent = await SavedAgent.get(client, 'c8a1e5d2-6f3b-4a9c-b7e0-2d4f6a8c1e3b');
await savedAgent.assignNumber('92e68758-3d3a-4f27-8b93-3fd8d834467c', { maxCallDurationSeconds: 1800 });
```

**Go SDK**

Load the agent and call `AssignNumber()` with the number's ID or its E.164 number. The SDK reads the number's ETag for you, and retries once if the number changed in the meantime.

```go
savedAgent, err := agentkit.GetSavedAgent(ctx, client, "c8a1e5d2-6f3b-4a9c-b7e0-2d4f6a8c1e3b")
if err != nil {
	log.Fatal(err)
}
maxCallDuration := 1800
_, err = savedAgent.AssignNumber(ctx, "92e68758-3d3a-4f27-8b93-3fd8d834467c", agentkit.AssignNumberOptions{
	MaxCallDurationSeconds: &maxCallDuration,
})
if err != nil {
	log.Fatal(err)
}
```

**REST API**

In the number's `inbound` object, set `agent` to the agent ID, and set a `call_policy`. To update a number, send a request to [Update a phone number](/en/api-reference/api-ref/conversational-ai/platform/update-number), and pass its `ETag` from your last create or retrieve request in the `If-Match` header:

```bash
curl --request PATCH \
  --url https://preview.ai.agora.io/conversational-ai/v1/projects/<your_app_id>/numbers/<number_id> \
  --header 'Authorization: Basic <your_base64_encoded_credentials>' \
  --header 'Content-Type: application/json' \
  --header 'If-Match: <etag>' \
  --data '
{
  "inbound": {
    "agent": "c8a1e5d2-6f3b-4a9c-b7e0-2d4f6a8c1e3b",
    "call_policy": {
      "max_call_duration_seconds": 1800
    }
  }
}'
```

If the number has changed since you read its `ETag`, the request fails with `412 PreconditionFailed`. Retrieve the number again, and retry with its current `ETag`.

The `inbound` object you pass replaces the saved one as a whole, so include the complete `call_policy` each time. The same applies to `sip_trunk`: if you update it, pass every field you want to keep, including `auth`.

To reject inbound calls to a number, remove its agent. A number without inbound routing also rejects inbound calls.

**Python SDK**

```python
saved_agent.unassign_number("92e68758-3d3a-4f27-8b93-3fd8d834467c")
```

**TypeScript SDK**

```ts
await savedAgent.unassignNumber('92e68758-3d3a-4f27-8b93-3fd8d834467c');
```

**Go SDK**

```go
_, err = savedAgent.UnassignNumber(ctx, "92e68758-3d3a-4f27-8b93-3fd8d834467c")
if err != nil {
	log.Fatal(err)
}
```

**REST API**

Set `inbound.agent` to `null` in a request to [Update a phone number](/en/api-reference/api-ref/conversational-ai/platform/update-number).

## Set limits and behavior for inbound calls

The call policy sets limits and behavior for inbound calls:

**Python SDK**

`assign_number()` sets only the duration limits. To set `end_call`, update the number with the low-level API, and pass its current ETag:

```python
current = client.v3.numbers.with_raw_response.get(number_id="92e68758-3d3a-4f27-8b93-3fd8d834467c")
client.v3.numbers.update(
    number_id="92e68758-3d3a-4f27-8b93-3fd8d834467c",
    if_match=current.etag,
    inbound={
        "agent": "3f6c2a9e-8d1b-4e7a-9c55-0b2f7d1e4a10",
        "call_policy": {
            "max_call_duration_seconds": 1800,
            "max_silence_duration_ms": 60000,
            "end_call": {"on_user_request": True},
        },
    },
)
```

**TypeScript SDK**

`assignNumber()` sets only the duration limits. To set `end_call`, update the number with the low-level API, and pass its current ETag:

```ts
const { rawResponse } = await client.v3.numbers.get({ id: '92e68758-3d3a-4f27-8b93-3fd8d834467c' }).withRawResponse();
await client.v3.numbers.update({
  id: '92e68758-3d3a-4f27-8b93-3fd8d834467c',
  ifMatch: rawResponse.headers.get('etag') ?? '',
  inbound: {
    agent: '3f6c2a9e-8d1b-4e7a-9c55-0b2f7d1e4a10',
    call_policy: {
      max_call_duration_seconds: 1800,
      max_silence_duration_ms: 60000,
      end_call: { on_user_request: true },
    },
  },
});
```

**Go SDK**

`AssignNumber()` sets only the duration limits. To set `end_call`, update the number with the low-level API, and pass its current ETag. This example also imports `github.com/AgoraIO/agora-agents-go/v2/v3`.

```go
callPolicy := map[string]any{
	"max_call_duration_seconds": 1800,
	"max_silence_duration_ms":   60000,
	"end_call": map[string]any{
		"on_user_request": true,
	},
}

current, err := client.V3.Numbers.Get(ctx, "92e68758-3d3a-4f27-8b93-3fd8d834467c")
if err != nil {
	log.Fatal(err)
}
_, err = client.V3.Numbers.Update(ctx, "92e68758-3d3a-4f27-8b93-3fd8d834467c", current.ETag, v3.NumberPatch{
	"inbound": map[string]any{
		"agent":       "3f6c2a9e-8d1b-4e7a-9c55-0b2f7d1e4a10",
		"call_policy": callPolicy,
	},
})
if err != nil {
	log.Fatal(err)
}
```

**REST API**

Set `call_policy` in the number's `inbound` object:

```json
"inbound": {
  "agent": "3f6c2a9e-8d1b-4e7a-9c55-0b2f7d1e4a10",
  "call_policy": {
    "max_call_duration_seconds": 1800,
    "max_silence_duration_ms": 60000,
    "end_call": {
      "on_user_request": true
    }
  }
}
```

| Field                       | Description                                                                                                                                                                                                                                                                                                 |
| --------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `max_call_duration_seconds` | The maximum length of a call in seconds, from when it's answered.                                                                                                                                                                                                                                           |
| `max_silence_duration_ms`   | Hang up when nobody on the call has spoken for this many milliseconds.                                                                                                                                                                                                                                      |
| `end_call`                  | The conditions under which the agent can end the call itself. Each condition is off unless you set it to `true`. `on_user_request`: the caller clearly says goodbye or asks to hang up. `on_voicemail`: the call reaches voicemail. `on_ai_assistant`: an AI assistant or another automated system answers. |

If you omit a limit, it doesn't apply.

## Reference

For more information, see the following pages:

- [Import phone numbers](/en/ai/platform/build/phone-calls/import-phone-numbers)
- [Make outbound calls and run campaigns](/en/ai/platform/build/phone-calls/outbound-calls-campaigns)

### API reference

- [Update a phone number](/en/api-reference/api-ref/conversational-ai/platform/update-number)
- [Retrieve a phone number](/en/api-reference/api-ref/conversational-ai/platform/retrieve-number)
