Route inbound calls to an agent

Updated

Assign an agent to answer calls to a phone number, and set limits and behavior for those calls.

Preview documentation

You're reading the Conversational AI Platform (Preview) docs. Switch to Main.

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:

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. You can set both when you import the number, or later by updating the number.

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.

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)

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.

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 });

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.

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)
}

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, and pass its ETag from your last create or retrieve request in the If-Match header:

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.

saved_agent.unassign_number("92e68758-3d3a-4f27-8b93-3fd8d834467c")
await savedAgent.unassignNumber('92e68758-3d3a-4f27-8b93-3fd8d834467c');
_, err = savedAgent.UnassignNumber(ctx, "92e68758-3d3a-4f27-8b93-3fd8d834467c")
if err != nil {
	log.Fatal(err)
}

Set inbound.agent to null in a request to Update a phone number.

Set limits and behavior for inbound calls

The call policy sets limits and behavior for inbound calls:

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

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},
        },
    },
)

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

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 },
    },
  },
});

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.

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)
}

Set call_policy in the number's inbound object:

"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
    }
  }
}
FieldDescription
max_call_duration_secondsThe maximum length of a call in seconds, from when it's answered.
max_silence_duration_msHang up when nobody on the call has spoken for this many milliseconds.
end_callThe 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:

API reference