TypeScript SDK
Updated
API reference for the Conversational AI Platform (Preview) features of the Agora agents TypeScript SDK, including saved agents, sessions, secrets, numbers, and campaigns.
Preview documentation
The agora-agents TypeScript SDK supports the Conversational AI Platform (Preview) alongside the Voice Agent API. This page covers the Platform features: saved agents, Platform sessions, secret sets, phone numbers, campaigns, and the low-level client.v3 namespace.
The vendor classes, such as OpenAI and DeepgramSTT, and the builder methods, such as withLlm(), are shared with the Voice Agent API. For those, see the TypeScript SDK reference for Voice Agents.
Install
Platform support is in the SDK preview, version 3.0.0-alpha.3. You need Node.js 18 or later. Install the SDK in your project, and specify the version, because the default agora-agents release doesn't support the Platform API:
npm install agora-agents@3.0.0-alpha.3Import the classes you use, for example:
import { Agent, AgoraClient, Area, SavedAgent, secretRef } from 'agora-agents';AgoraClient
Create a client with one of the following authentication methods. To choose one, see Choose an authentication method.
-
Token authentication: Pass your App ID and App Certificate. The SDK generates a ConvoAI token for each Platform request.
const client = new AgoraClient({ area: Area.US, appId: process.env.AGORA_APP_ID!, appCertificate: process.env.AGORA_APP_CERTIFICATE!, }); -
Basic HTTP authentication: Pass your App ID, customer ID, and customer secret. The SDK sends
Authorization: Basic <base64_credentials>with each request.const client = new AgoraClient({ area: Area.US, appId: process.env.AGORA_APP_ID!, customerId: process.env.AGORA_CUSTOMER_ID!, customerSecret: process.env.AGORA_CUSTOMER_SECRET!, });
| Option | Type | Description |
|---|---|---|
area | Area | Required. The region for Voice Agent API routing. Platform requests use the Platform origin. |
appId | string | Required. Your Agora App ID. |
appCertificate | string | Your App Certificate. With token authentication, the SDK uses it to generate a token for each request. With Basic authentication, it's optional, and the SDK uses it only to generate the agent's RTC token. |
authToken | string | A token you generated yourself. The SDK sends it as Authorization: agora token=<authToken> instead of generating one. The token must include the ConvoAI service. |
customerId | string | Your customer ID, for Basic authentication. Set it with customerSecret. Don't combine it with authToken. |
customerSecret | string | Your customer secret, for Basic authentication. |
v3 | { baseUrl?: string; headers?: Record<string, string> } | Platform request settings. baseUrl overrides the Platform origin, which defaults to https://preview.ai.agora.io. You can also set the AGORA_AGENTS_V3_BASE_URL environment variable. The option takes precedence. |
Without an App Certificate, the SDK can't generate the agent's RTC token. To start an RTC session with a Basic client and no App Certificate, pass the RTC token when you create the session.
The client exposes the following Platform resources:
| Property | Description |
|---|---|
client.v3 | The low-level Platform namespace: agents, secrets, numbers, sessions, and campaigns. See Low-level API. |
client.secrets | The same object as client.v3.secrets. |
client.numbers | The same object as client.v3.numbers. |
client.campaigns | The same object as client.v3.campaigns. |
Agent
Agent is an immutable builder. Each builder method returns a new Agent. To save a configuration on the Platform, build it with the vendor classes and call save().
const agent = new Agent({ client })
.withStt(new DeepgramSTT({ model: 'nova-3', language: 'en-US' }))
.withLlm(new OpenAI({ model: 'gpt-4.1-mini' }))
.withTts(new OpenAITTS({ model: 'tts-1', voice: 'alloy' }))
.withVariable('customer_name', { type: 'str', required: true });
const savedAgent = await agent.save({ name: 'Support agent' });Variables
withVariable(name: string, definition: VariableDefinition): AgentDeclares a variable and returns a new Agent. The definition is validated locally.
| Field | Type | Description |
|---|---|---|
type | 'str' | 'int' | 'float' | 'bool' | 'date' | 'datetime' | Required. The data type. |
required | boolean | Whether every session must pass a value. |
options | Array<string | number | boolean> | The allowed values, 1 to 100 unique items. |
extract | boolean | Whether to extract the value after the session ends. Requires description. |
description | string | Up to 2,000 characters. Required when extract is true. |
A variable name starts with a lowercase letter and contains up to 64 lowercase letters, digits, and underscores.
Save an agent
save(options?: SaveOptions): Promise<SavedAgent>Saves the configuration and returns a SavedAgent. Without agentId, it creates a new agent. Names aren't unique, so saving twice creates two agents.
| Option | Type | Description |
|---|---|---|
name | string | The agent name. Defaults to agent-<timestamp>. |
agentId | string | Update this saved agent instead of creating one. Prefer savedAgent.update(). |
Start a session without saving
createSession(options: SessionOptions): AgentSessionCreates a session from the builder without saving it. The SDK starts an ephemeral session on the Platform when the configuration has a secret reference or a variable, or when you set a Platform session option such as maxDuration, values, labels, or dataPolicy. Otherwise, it uses the Voice Agent API. For the options, see Session options.
How the builder maps to the Platform
- Credentials: A model without an API key uses managed mode. A model with an API key uses BYOK. A saved agent must use a
secretRef()as the key. An ephemeral session also accepts a key value. - Instructions and messages: The LLM's system messages become the agent's
instructions. Its other messages becomemessages.greetingMessageandgreetingConfigsbecome the agent'sgreeting. - Pipeline: Only cascaded ASR, LLM, and TTS pipelines are supported. An MLLM configuration can't be saved or used in a Platform session.
- Unsupported fields: Builder settings without a Platform equivalent, such as SAL, advanced features, labels, RTC settings, and pipeline IDs, make
save()throw anUnsupportedFieldErrorthat lists them.
Secret references
secretRef(set: string, key: string): SecretRefReturns the reference $secrets.<set>.<key> for a key in a secret set. It validates both names locally and makes no request. Each name contains 1 to 64 letters, digits, and underscores.
SavedAgent
A handle to an agent saved on the Platform.
| Member | Description |
|---|---|
id | The agent ID. |
name | The agent name. |
etag | The agent's ETag when the handle was loaded or saved. |
raw | The client.v3.agents resource. |
SavedAgent.get(client, agentId) | Static. Loads a saved agent. Returns Promise<SavedAgent>. |
createSession(options) | Creates a session that runs this agent. Returns an AgentSession. See Session options. |
update(config, options?) | Saves a revised Agent to this agent ID, and keeps its name unless you pass { name }. The Agent must use the same client. Returns Promise<SavedAgent>. |
delete() | Deletes the agent. |
assignNumber(number, options?) | Routes inbound calls on a phone number to this agent. number is an E.164 string, a number ID, or a number object. Options: maxCallDurationSeconds, maxSilenceDurationMs. Returns the updated number. |
unassignNumber(number) | Removes this agent from a number's inbound routing. |
listNumbers() | Returns the numbers assigned to this agent. Scans all project numbers. |
A handle is a snapshot. If another process changes the agent, load it again with SavedAgent.get().
Session options
savedAgent.createSession() and agent.createSession() accept the following options for Platform sessions:
| Option | Type | Description |
|---|---|---|
channel | string | Required. The RTC channel. |
token | string | The RTC token for the agent's UID. The SDK doesn't generate it for Platform sessions. |
agentUid | string | The agent's UID in the channel. Omit it, or pass '0', to have the Platform assign one. |
remoteUids | string[] | Required. The UID of the user the agent talks to. Pass exactly one. |
values | Record<string, string | number | boolean> | Values for the agent's variables. |
labels | Record<string, string> | Labels returned in notification events. |
idleTimeout | number | Seconds without a user before the session ends, 0 to 3600. |
maxDuration | number | The maximum session length in seconds, 1 to 3600. |
gracefulStop | { enabled: boolean; timeout_ms?: number } | Lets the agent finish speaking before it stops. timeout_ms is 0 to 120000. |
dataPolicy | { retention: '30_days' | 'none' } | Whether Agora retains the session's conversation data. |
encryption | object | RTC media encryption settings. |
audioScenario | string | The RTC audio scenario, such as 'aiserver'. |
geofence | { area: string; exclude_area?: string } | Restricts the regions the session connects through. |
idempotencyKey | string | An Idempotency-Key for the start request. Retry an uncertain start with the same key: if the first attempt started the session, the retry fails with 409 IdempotencyKeyConflict instead of starting another. Use a new key for a new session. |
AgentSession
A session handle. On the Platform, the following methods are available:
| Method | Description |
|---|---|
start() | Starts the session. Returns Promise<string>, the session ID. |
getInfo() | Retrieves the session. The result includes status. |
update(config) | Updates a running session. Accepts only the RTC token, the conversation messages, and the LLM params. A params object replaces the current one. |
stop() | Stops the session. |
say(), interrupt(), think(), and the history and turns methods throw on Platform sessions.
To read or stop a session by ID without a handle, use client.v3.sessions.get({ agentSessionId }) and client.v3.sessions.stop({ agentSessionId }).
Low-level API
client.v3 has one resource for each part of the Platform REST API. Each method takes a request object and returns a promise of the parsed response. Request body fields use the REST API names, such as agent_name. Path and header fields use camelCase, such as agentSessionId and ifMatch.
To read response headers, such as ETag, call .withRawResponse() on the returned promise. It resolves to { data, rawResponse }.
const { data, rawResponse } = await client.v3.agents.get({ id: agentId }).withRawResponse();
const etag = rawResponse.headers.get('etag');Agents
| Method | REST API |
|---|---|
agents.create(request) | Create an agent |
agents.list(request?) | List agents |
agents.get({ id }) | Retrieve an agent |
agents.update({ id, ifMatch, ...changes }) | Update an agent |
agents.delete({ id }) | Delete an agent |
Sessions
| Method | REST API |
|---|---|
sessions.start(request) | Start a session |
sessions.startEphemeral(request) | Start an ephemeral session |
sessions.list(request?) | List sessions |
sessions.get({ agentSessionId }) | Retrieve a session |
sessions.update({ agentSessionId, ...changes }) | Update a session |
sessions.stop({ agentSessionId }) | Stop a session |
Secrets
| Method | REST API |
|---|---|
secrets.create({ name, secrets }) | Create a secret set |
secrets.list(request?) | List secret sets |
secrets.get({ name }) | Retrieve a secret set |
secrets.update({ name, secrets, ifMatch? }) | Update a secret set |
secrets.replace({ name, secrets, ifMatch }) | Replace a secret set |
secrets.delete({ name, ifMatch }) | Delete a secret set |
secrets.setKey({ name, key, value, ifMatch?, ifNoneMatch? }) | Set a secret key |
secrets.deleteKey({ name, key, ifMatch? }) | Delete a secret key |
Phone numbers
| Method | REST API |
|---|---|
numbers.create(request) | Create a phone number |
numbers.list(request?) | List phone numbers |
numbers.get({ id }) | Retrieve a phone number |
numbers.update({ id, ifMatch, ...changes }) | Update a phone number |
numbers.delete({ id }) | Delete a phone number |
Campaigns
| Method | REST API |
|---|---|
campaigns.create(request) | Create a campaign |
campaigns.list(request?) | List campaigns |
campaigns.get({ id }) | Retrieve a campaign |
campaigns.update({ id, ifMatch, ...changes }) | Update a campaign |
campaigns.delete({ id }) | Delete a campaign |
campaigns.pause({ id, idempotencyKey? }) | Pause a campaign |
campaigns.resume({ id, idempotencyKey? }) | Resume a campaign |
campaigns.cancel({ id, idempotencyKey? }) | Cancel a campaign |
Pagination
Each list() method returns one page: { data: { count, list }, has_more, next_cursor }. To continue, pass next_cursor as cursor. Each resource also has listAll(request?), an async generator that follows the cursors for you.
for await (const session of client.v3.sessions.listAll({ status: 'STOPPED', limit: 100 })) {
console.log(session.agent_session_id);
}sessions.list() returns running sessions by default. To list others, pass status, for example 'STOPPED,FAILED'.
Conditional writes and retries
Updates to agents, numbers, and campaigns, and deletes and replacements of secret sets, require the resource's current ETag in ifMatch. Get it from a raw response. If the resource changed since you read it, the request throws a PreconditionFailedError. Call await error.latest() to reload the resource. It doesn't retry the write.
The SDK retries GET requests up to maxRetries times. It never retries writes. To retry a session start safely, pass the same idempotencyKey. Other operations don't support idempotency keys.
Errors
| Error | Thrown when |
|---|---|
V3Error | The Platform returns an error. It has statusCode, body (usually with reason and detail), rawResponse, and requestId. For the reasons, see Status codes. |
PreconditionFailedError | A conditional write fails with 412. Extends V3Error. |
UnsupportedFieldError | The builder has settings with no Platform equivalent. fields lists them. Thrown before any request. |
SecretRefNotSupportedError | A secret reference is used on the Voice Agent API. |
NumberNotFoundError | assignNumber() or unassignNumber() can't find the number in the project. |
