# Start a session (/en/api-reference/api-ref/conversational-ai/platform/start-session)

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

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


Starts a session that runs a saved agent in an RTC channel or over the phone.

- OpenAPI: /openapi/conversational-ai/rest-api-platform.en.yaml
- Operation ID: start-session
- Method: POST
- Path: /v1/projects/{appid}/sessions
- Endpoint: https://preview.ai.agora.io/conversational-ai/v1/projects/{appid}/sessions

## Servers

- https://preview.ai.agora.io/conversational-ai

The session uses the agent's configuration as saved when the session starts. To run a configuration without saving an agent first, use [Start an ephemeral session](/en/api-reference/api-ref/conversational-ai/platform/start-ephemeral-session).

A `200` response confirms that the session exists. It doesn't confirm that the agent has joined the RTC channel or that an outbound call was answered. To follow the session, [retrieve it](/en/api-reference/api-ref/conversational-ai/platform/retrieve-session). The session ends when you [stop it](/en/api-reference/api-ref/conversational-ai/platform/stop-session), or when it reaches a limit in `lifecycle`.


## Authorization

This endpoint requires authentication.

- `tokenAuth`
- `basicAuth`

## Parameters

- `appid` (path, required, string) - The App ID of your project.
- `Idempotency-Key` (header, optional, string) - A unique key, so that retrying the request can't start a second session. If a session was already started with this key, the request fails with `409` and reason `IdempotencyKeyConflict`, and no new session starts. The API doesn't return the original response. To find the session, [list sessions](/en/api-reference/api-ref/conversational-ai/platform/list-sessions). Keep the same key when you retry; never switch keys.
  - Min length: `1`
  - Max length: `256`
  - Pattern: `^[\x21-\x7E]+$`

## Request body

- `agent_id` (string, required) - The ID of the saved agent to run.
  - Format: `uuid`
- `transport` (object, required) - How the agent connects to the participant. Pass the fields of one transport type only.
  - `transport.type` (string, required) - `rtc`: The agent joins an RTC channel.
  - `transport.from` (string, required) - The `number_id` of the number in the project to call from. Phone numbers aren't accepted. [Import the number](/en/api-reference/api-ref/conversational-ai/platform/create-number) first.
    - Format: `uuid`
  - `transport.to` (string, required) - The phone number to call, in E.164 format, for example `+14155550100`.
    - Pattern: `^\+[1-9][0-9]{1,14}$`
  - `transport.call_policy` (object) - Limits and behavior for outbound phone calls. Each limit you omit adds no limit.
    - `transport.call_policy.max_ring_duration_ms` (integer) - The maximum time in milliseconds from starting the dial until the call is answered. If the call isn't answered in time, the dial attempt ends.
      - Minimum: `1`
    - `transport.call_policy.max_call_duration_seconds` (integer) - The maximum length of the call in seconds, measured from when it's answered. The session's `lifecycle` limits can end the call earlier.
      - Minimum: `1`
    - `transport.call_policy.max_silence_duration_ms` (integer) - Hang up when nobody on the call has spoken for this many milliseconds. This is separate from `pipeline.silence_config`, which only prompts the user.
      - Minimum: `1`
    - `transport.call_policy.end_call` (object) - Conditions under which the agent can end the call itself. Every condition is off unless you set it to `true`.
      - `transport.call_policy.end_call.on_user_request` (boolean) - End the call when the caller clearly says goodbye or asks to hang up.
        - Default: `false`
      - `transport.call_policy.end_call.on_voicemail` (boolean) - End the call when the agent reaches voicemail, such as a "please leave a message after the tone" announcement.
        - Default: `false`
      - `transport.call_policy.end_call.on_ai_assistant` (boolean) - End the call when the call is answered by an AI assistant, a voice secretary, or another automated answering system.
        - Default: `false`
  - `transport.channel` (string, required) - The name of the RTC channel to join, 1 to 256 characters.
    - Min length: `1`
    - Max length: `256`
  - `transport.token` (string) - The RTC token the agent uses to join the channel. Required when the project has an App Certificate enabled. To renew it, [update the session](/en/api-reference/api-ref/conversational-ai/platform/update-session).
  - `transport.uid` (string) - The user ID the agent uses in the channel. Pass a string of up to 255 characters, such as `"1002"` or `"agent-bot"`, or an integer from 0 to 4294967295, such as `1002`. Omit it, or pass `0`, to let Agora assign a user ID that differs from `subscribe_uids`.
    - Default: `0`
    - Range: `[0, 4294967295]`
    - Min length: `1`
    - Max length: `255`
  - `transport.subscribe_uids` (array, required) - The user ID of the participant the agent talks to, as a string or an integer. Pass exactly one user ID.
    - Min items: `1`
    - Max items: `1`
    - `transport.subscribe_uids.items` (string)
      - Range: `[1, 4294967295]`
      - Min length: `1`
      - Max length: `255`
  - `transport.audio_scenario` (string) - The audio scenario of the agent in the channel:

- `aiserver`: Optimized for latency and network resilience in conversations with an
  agent.
- `chorus`: For participants with good network conditions who need ultra-low latency.
    - Allowed: `aiserver` | `chorus`
    - Default: `aiserver`
  - `transport.encryption` (object) - Media encryption for the RTC channel. These values are never returned.
    - `transport.encryption.mode` (string, required) - The encryption mode. Agora recommends `aes_128_gcm2` or `aes_256_gcm2`, which use a salt.
      - Allowed: `aes_128_xts` | `aes_128_ecb` | `aes_256_xts` | `sm4_128_ecb` | `aes_128_gcm` | `aes_256_gcm` | `aes_128_gcm2` | `aes_256_gcm2`
    - `transport.encryption.key` (string, required) - The encryption key.
      - Min length: `1`
    - `transport.encryption.salt` (string) - A Base64-encoded salt that is 32 bytes long after decoding. Required when `mode` is `aes_128_gcm2` or `aes_256_gcm2`.
      - Pattern: `^[A-Za-z0-9+/]{43}=$`
- `values` (object) - Values for the agent's variables, keyed by variable name, for this session only. Each key must be a variable the agent declares, and each value must match its `type` and `options`. Pass a value for every `required` variable. `null` values are rejected.
  - Example: `{"customer_name":"Ada"}`
- `lifecycle` (object) - When the session ends on its own.
  - `lifecycle.idle_timeout_ms` (integer) - How long in milliseconds the session continues with no participant present: after the subscribed user leaves the RTC channel, or after the other side of a phone call hangs up. It isn't silence detection. Set to `0` to turn off the idle timer. Can't be greater than `max_duration_ms`.
    - Default: `30000`
    - Range: `[0, 3600000]`
  - `lifecycle.max_duration_ms` (integer) - The maximum length of the session in milliseconds, measured from `start_ts`. Defaults to 5 minutes. The maximum is 1 hour.
    - Default: `300000`
    - Range: `[1000, 3600000]`
  - `lifecycle.graceful_stop` (object) - How the agent finishes when you stop the session, or when the idle timer expires. It doesn't extend `max_duration_ms`, and it doesn't add a farewell message.
    - `lifecycle.graceful_stop.enabled` (boolean) - Whether the agent finishes what it's saying before it leaves.
      - Default: `false`
    - `lifecycle.graceful_stop.timeout_ms` (integer) - The longest time in milliseconds the agent can take to finish.
      - Default: `30000`
      - Range: `[0, 120000]`
- `data_policy` (object) - How Agora handles the session's data. You set it when the session starts and can't change it afterward.
  - `data_policy.retention` (string) - How long Agora keeps the conversation data:

- `30_days`: Agora keeps the data for 30 days.
- `none`: Agora doesn't keep the data, and variable extraction doesn't run. Use it, for
  example, when a caller declines recording.
    - Allowed: `30_days` | `none`
    - Default: `30_days`
- `labels` (object) - Key-value labels for this session, such as a team or customer ID. They're included in the `payload` of [notification events](/en/ai/reference/event-types).

### Request body example

```json
{
  "agent_id": "3f6c2a9e-8d1b-4e7a-9c55-0b2f7d1e4a10",
  "values": {
    "customer_name": "Ada"
  },
  "labels": {
    "team": "support"
  },
  "transport": {
    "type": "rtc",
    "channel": "support-4821",
    "token": "<your_rtc_token>",
    "uid": "1002",
    "subscribe_uids": [
      "1001"
    ]
  },
  "lifecycle": {
    "idle_timeout_ms": 30000,
    "max_duration_ms": 3600000
  }
}
```

## Responses

### 200

The session was created.

- `agent_session_id` (string, required) - The ID of the session.
  - Pattern: `^[a-z0-9]{32}$`
- `create_ts` (integer, required) - The time the session was created, as a Unix timestamp in seconds.
- `status` (string, required) - The status of the session when it starts. For a phone call, `RUNNING` doesn't mean the call was answered.
  - Allowed: `STARTING` | `RUNNING`
### 400

The request was rejected and no session was created. For example, `InvalidModuleParameter` when the agent's pipeline is invalid, `MissingRequiredField` when a required variable has no value, or `InvalidFieldValue` when a telephony session uses an agent that is deployed for inbound calls.

- `detail` (string, required) - A human-readable description of the error. It names the field or resource involved, when there is one. Don't parse it; branch on `reason` instead.
- `reason` (string, required) - A machine-readable error reason, such as `InvalidFieldValue` or `ResourceNotFound`. For all reasons, see [Status codes](/en/api-reference/api-ref/conversational-ai/platform/status-codes).
### 401

Authentication is missing or invalid. The reason is `InvalidPermission`.

- `detail` (string, required) - A human-readable description of the error. It names the field or resource involved, when there is one. Don't parse it; branch on `reason` instead.
- `reason` (string, required) - A machine-readable error reason, such as `InvalidFieldValue` or `ResourceNotFound`. For all reasons, see [Status codes](/en/api-reference/api-ref/conversational-ai/platform/status-codes).
### 404

The resource in the path doesn't exist. The reason is `ResourceNotFound`.

- `detail` (string, required) - A human-readable description of the error. It names the field or resource involved, when there is one. Don't parse it; branch on `reason` instead.
- `reason` (string, required) - A machine-readable error reason, such as `InvalidFieldValue` or `ResourceNotFound`. For all reasons, see [Status codes](/en/api-reference/api-ref/conversational-ai/platform/status-codes).
### 409

`TaskConflict`: An agent is already running with the same RTC channel and UID. `IdempotencyKeyConflict`: A session was already started with this `Idempotency-Key`.

- `detail` (string, required) - A human-readable description of the error. It names the field or resource involved, when there is one. Don't parse it; branch on `reason` instead.
- `reason` (string, required) - A machine-readable error reason, such as `InvalidFieldValue` or `ResourceNotFound`. For all reasons, see [Status codes](/en/api-reference/api-ref/conversational-ai/platform/status-codes).
### 422

The request failed. The response body contains the `reason` and `detail` of the failure. For possible reasons, see [Status codes](/en/api-reference/api-ref/conversational-ai/platform/status-codes).

- `detail` (string, required) - A human-readable description of the error. It names the field or resource involved, when there is one. Don't parse it; branch on `reason` instead.
- `reason` (string, required) - A machine-readable error reason, such as `InvalidFieldValue` or `ResourceNotFound`. For all reasons, see [Status codes](/en/api-reference/api-ref/conversational-ai/platform/status-codes).
### 429

`ConcurrencyLimitExceeded`: The project has reached its concurrent session limit. Stop a session, or retry later with exponential backoff.

- `detail` (string, required) - A human-readable description of the error. It names the field or resource involved, when there is one. Don't parse it; branch on `reason` instead.
- `reason` (string, required) - A machine-readable error reason, such as `InvalidFieldValue` or `ResourceNotFound`. For all reasons, see [Status codes](/en/api-reference/api-ref/conversational-ai/platform/status-codes).
### 503

The request failed. The response body contains the `reason` and `detail` of the failure. For possible reasons, see [Status codes](/en/api-reference/api-ref/conversational-ai/platform/status-codes).

- `detail` (string, required) - A human-readable description of the error. It names the field or resource involved, when there is one. Don't parse it; branch on `reason` instead.
- `reason` (string, required) - A machine-readable error reason, such as `InvalidFieldValue` or `ResourceNotFound`. For all reasons, see [Status codes](/en/api-reference/api-ref/conversational-ai/platform/status-codes).
### 504

The request failed. The response body contains the `reason` and `detail` of the failure. For possible reasons, see [Status codes](/en/api-reference/api-ref/conversational-ai/platform/status-codes).

- `detail` (string, required) - A human-readable description of the error. It names the field or resource involved, when there is one. Don't parse it; branch on `reason` instead.
- `reason` (string, required) - A machine-readable error reason, such as `InvalidFieldValue` or `ResourceNotFound`. For all reasons, see [Status codes](/en/api-reference/api-ref/conversational-ai/platform/status-codes).
### default

The request failed. The response body contains the `reason` and `detail` of the failure. For possible reasons, see [Status codes](/en/api-reference/api-ref/conversational-ai/platform/status-codes).

- `detail` (string, required) - A human-readable description of the error. It names the field or resource involved, when there is one. Don't parse it; branch on `reason` instead.
- `reason` (string, required) - A machine-readable error reason, such as `InvalidFieldValue` or `ResourceNotFound`. For all reasons, see [Status codes](/en/api-reference/api-ref/conversational-ai/platform/status-codes).

## Response examples

### 200

```json
{
  "agent_session_id": "a42ac95tp25py49fc37hp94vm67ht52h",
  "create_ts": 1737111452,
  "status": "RUNNING"
}
```
