# RESTful authentication (/en/api-reference/api-ref/conversational-ai/platform/authentication)

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


Conversational AI Platform REST API requests require authentication. Use one of the following methods:

- **[Token authentication](#token-authentication)**: Generate a token with your App ID and App Certificate, and set `Authorization: agora token="<your_token>"`.
- **[Basic HTTP authentication](#basic-http-authentication)**: Generate a Base64-encoded credential from your customer ID and customer secret, and set `Authorization: Basic <base64_credentials>`.

> **Info**
>
> Implement authentication on the server to mitigate the risk of data leakage.

## Choose an authentication method

You can use either method for any Platform API request. Choose the one recommended for your use case:

| Use case                                                                              | Recommended method                                      | Why                                                                                                                       |
| ------------------------------------------------------------------------------------- | ------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
| **Telephony only**: inbound calls, outbound calls, and campaigns, with no RTC channel | [Basic HTTP authentication](#basic-http-authentication) | You authenticate with your customer ID and customer secret. You don't need to generate tokens.                            |
| **RTC**, or **RTC and telephony**                                                     | [Token authentication](#token-authentication)           | An RTC session needs a token for the agent to join the channel. You can use the same token to authenticate your requests. |

## Token authentication

Token authentication uses a token generated on your server with your App ID and App Certificate. To authenticate with a token, include the `Authorization` header in each request:

```text
Authorization: agora token="<your_token>"
```

### Prerequisites

Before you begin, get the following values from [Agora Console](https://console.agora.io):

- **App ID**: A unique string that identifies your project.
- **App Certificate**: A string used to generate tokens.

> **Warning**
>
> Never expose your App Certificate in client-side code or public repositories. Generate tokens on your server only, and don't write tokens to public logs.

Tokens expire after a maximum of 86400 seconds.

### Choose the token services

The services a token needs depend on the request:

- **Requests that start an RTC session**: Use a token with the ConvoAI, RTC, and RTM services, such as one from [`ConvoAITokenBuilder.buildToken`](#build-a-convoai-token). Put the same token in the `Authorization` header and in `transport.token`, which lets the agent join the channel. This applies when you [start a session](start-session) or [start an ephemeral session](start-ephemeral-session) with an RTC transport, and when you renew the token with [Update a session](update-session).
- **All other requests**: A token with only the ConvoAI service is enough. These include managing agents, secrets, phone numbers, and campaigns; listing, retrieving, and stopping sessions; and starting telephony sessions. See [Build a token with specific services](#build-a-token-with-specific-services).

To start an RTC session, you can also generate a separate token for each place. Put the REST authentication token in the `Authorization` header and a token with the RTC service in `transport.token`.

When the token includes the RTC service, the token parameters must match the session request:

- `channelName` must match `transport.channel`.
- The account or UID must match `transport.uid`.

### Use a temporary token for testing

For testing, you can generate a temporary token in Agora Console. A temporary token is valid for 24 hours. For details, see [Credentials](/en/introduction/console-setup#credentials). When you start an RTC session, use the channel name you entered when you generated the token as `transport.channel` in your request.

In production, generate tokens on your server using the token builder library.

### Using the token builder library

The [AgoraDynamicKey repository](https://github.com/AgoraIO/Tools/tree/master/DynamicKey/AgoraDynamicKey) provides open-source token generation libraries for multiple languages, including `ConvoAITokenBuilder` and the ConvoAI service.

Install the token builder library for your language:

**Node.js**

```bash
npm install agora-token
```

**Golang**

```bash
# Pins the latest commit on the feature/access-token2-convoai-stt-services branch
go get github.com/AgoraIO/Tools/DynamicKey/AgoraDynamicKey/go/src@v0.0.0-20261010073935-b75635c32d30
```

**Python**

```bash
git clone --branch feature/access-token2-convoai-stt-services https://github.com/AgoraIO/Tools.git
cd Tools/DynamicKey/AgoraDynamicKey/python3
```

#### Build a ConvoAI token

`ConvoAITokenBuilder.buildToken` generates a token with the ConvoAI, RTC, and RTM services. Use it to start an RTC session, with the same token in the `Authorization` header and in `transport.token`:

**Node.js**

```js
const { ConvoAITokenBuilder } = require('agora-token');

const appId = '<your_app_id>';
const appCertificate = '<your_app_certificate>';
const channelName = '<your_channel_name>';
const agentUid = '<your_agent_uid>';
const tokenExpire = 86400; // Token lifetime, 24 hours, in seconds
const privilegeExpire = 3600; // RTC and RTM privilege lifetime, 1 hour, in seconds

const token = ConvoAITokenBuilder.buildToken(
  appId,
  appCertificate,
  channelName,
  agentUid,
  tokenExpire,
  privilegeExpire,
);
```

**Golang**

```go
package main

import (
	"fmt"
	"log"

	"github.com/AgoraIO/Tools/DynamicKey/AgoraDynamicKey/go/src/convoaitokenbuilder"
)

func main() {
	appID := "<your_app_id>"
	appCertificate := "<your_app_certificate>"
	channelName := "<your_channel_name>"
	agentUID := "<your_agent_uid>"

	tokenExpire := uint32(24 * 60 * 60) // Token lifetime, 24 hours, in seconds
	privilegeExpire := uint32(60 * 60)  // RTC and RTM privilege lifetime, 1 hour, in seconds

	token, err := convoaitokenbuilder.BuildToken(
		appID,
		appCertificate,
		channelName,
		agentUID,
		tokenExpire,
		privilegeExpire,
	)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println(token)
}
```

To run the example, save it as `main.go` in an empty folder, and run the following commands:

```bash
go mod init example.com/convoai-token-generator
go get github.com/AgoraIO/Tools/DynamicKey/AgoraDynamicKey/go/src@v0.0.0-20261010073935-b75635c32d30
go run main.go
```

The program prints a token that starts with `007`.

**Python**

```python
from src.convoai_token_builder import ConvoAITokenBuilder

token_expire = 86400     # Token lifetime, 24 hours, in seconds
privilege_expire = 3600  # RTC and RTM privilege lifetime, 1 hour, in seconds

token = ConvoAITokenBuilder.build_token(
    app_id, app_certificate, channel_name, agent_uid, token_expire, privilege_expire
)
```

The privilege lifetime must not exceed the token lifetime. To set the RTC role or each RTC and RTM privilege separately, use `buildTokenWithPrivilege` (`BuildTokenWithPrivilege` in Go, `build_token_with_privilege` in Python). It also adds the ConvoAI service automatically.

#### Build a token with specific services

To control exactly which services a token includes, build it with the `AccessToken2` API. The following examples build a token with the ConvoAI service only. Use this token in the `Authorization` header for requests that don't join an RTC channel:

**Node.js**

```js
const { AccessToken2, ServiceConvoAI } = require('agora-token/src/AccessToken2');

const tokenExpire = 86400; // Token lifetime, 24 hours, in seconds

const accessToken = new AccessToken2(appId, appCertificate, null, tokenExpire);
accessToken.add_service(new ServiceConvoAI());
const token = accessToken.build();
```

**Golang**

```go
import accesstoken "github.com/AgoraIO/Tools/DynamicKey/AgoraDynamicKey/go/src/accesstoken2"

const tokenExpire = 24 * 60 * 60 // Token lifetime, 24 hours, in seconds

accessToken := accesstoken.NewAccessToken(appID, appCertificate, tokenExpire)
accessToken.AddService(accesstoken.NewServiceConvoAI())
token, err := accessToken.Build()
```

**Python**

```python
from src.AccessToken2 import AccessToken, ServiceConvoAI

token_expire = 86400  # Token lifetime, 24 hours, in seconds

access_token = AccessToken(app_id, app_certificate, expire=token_expire)
access_token.add_service(ServiceConvoAI())
token = access_token.build()
```

To set the RTC privileges yourself, add the RTC service. The following examples build a token with the ConvoAI and RTC services, which works in the `Authorization` header and in `transport.token`. Each RTC privilege lifetime must not exceed the token lifetime:

**Node.js**

```js
const { AccessToken2, ServiceConvoAI, ServiceRtc } = require('agora-token/src/AccessToken2');

const tokenExpire = 86400; // Token lifetime, 24 hours, in seconds
const privilegeExpire = 3600; // RTC privilege lifetime, 1 hour, in seconds

const accessToken = new AccessToken2(appId, appCertificate, null, tokenExpire);

const rtc = new ServiceRtc(channelName, agentUid);
rtc.add_privilege(ServiceRtc.kPrivilegeJoinChannel, privilegeExpire);
rtc.add_privilege(ServiceRtc.kPrivilegePublishAudioStream, privilegeExpire);
rtc.add_privilege(ServiceRtc.kPrivilegePublishVideoStream, privilegeExpire);
rtc.add_privilege(ServiceRtc.kPrivilegePublishDataStream, privilegeExpire);

accessToken.add_service(rtc);
accessToken.add_service(new ServiceConvoAI());
const token = accessToken.build();
```

**Golang**

```go
import accesstoken "github.com/AgoraIO/Tools/DynamicKey/AgoraDynamicKey/go/src/accesstoken2"

const tokenExpire = 24 * 60 * 60 // Token lifetime, 24 hours, in seconds
const privilegeExpire = 60 * 60 // RTC privilege lifetime, 1 hour, in seconds

accessToken := accesstoken.NewAccessToken(appID, appCertificate, tokenExpire)

rtc := accesstoken.NewServiceRtc(channelName, agentUID)
rtc.AddPrivilege(accesstoken.PrivilegeJoinChannel, privilegeExpire)
rtc.AddPrivilege(accesstoken.PrivilegePublishAudioStream, privilegeExpire)
rtc.AddPrivilege(accesstoken.PrivilegePublishVideoStream, privilegeExpire)
rtc.AddPrivilege(accesstoken.PrivilegePublishDataStream, privilegeExpire)

accessToken.AddService(rtc)
accessToken.AddService(accesstoken.NewServiceConvoAI())
token, err := accessToken.Build()
```

**Python**

```python
from src.AccessToken2 import AccessToken, ServiceConvoAI, ServiceRtc

token_expire = 86400     # Token lifetime, 24 hours, in seconds
privilege_expire = 3600  # RTC privilege lifetime, 1 hour, in seconds

access_token = AccessToken(app_id, app_certificate, expire=token_expire)

rtc = ServiceRtc(channel_name, agent_uid)
rtc.add_privilege(ServiceRtc.kPrivilegeJoinChannel, privilege_expire)
rtc.add_privilege(ServiceRtc.kPrivilegePublishAudioStream, privilege_expire)
rtc.add_privilege(ServiceRtc.kPrivilegePublishVideoStream, privilege_expire)
rtc.add_privilege(ServiceRtc.kPrivilegePublishDataStream, privilege_expire)

access_token.add_service(rtc)
access_token.add_service(ServiceConvoAI())
token = access_token.build()
```

### Send a request with a token

The following example lists the agents in your project. It works with a token that has only the ConvoAI service, because it doesn't join an RTC channel:

```bash
curl --request GET \
  --url 'https://preview.ai.agora.io/conversational-ai/v1/projects/<your_app_id>/agents?limit=20' \
  --header 'Authorization: agora token="<your_token>"'
```

The following example starts an RTC session with a saved agent, using a token with the ConvoAI, RTC, and RTM services, such as one from [`ConvoAITokenBuilder.buildToken`](#build-a-convoai-token). It uses the same token in the `Authorization` header and in `transport.token`:

```bash
curl --request POST \
  --url https://preview.ai.agora.io/conversational-ai/v1/projects/<your_app_id>/sessions \
  --header 'Authorization: agora token="<your_token>"' \
  --header 'Content-Type: application/json' \
  --data '{
    "agent_id": "<your_agent_id>",
    "transport": {
      "type": "rtc",
      "channel": "<your_channel_name>",
      "token": "<your_token>",
      "uid": "1001",
      "subscribe_uids": ["1002"]
    },
    "lifecycle": {
      "idle_timeout_ms": 120000
    }
  }'
```

The token must be generated for `<your_channel_name>` and UID `1001`. To create an agent first, see [Create an agent](create-agent).

## Basic HTTP authentication

Basic HTTP authentication uses your Agora customer ID and customer secret. Generate a Base64-encoded credential from the `customer_id:customer_secret` string, then include it in the `Authorization` header:

```text
Authorization: Basic <base64_credentials>
```

### Generate Customer ID and Customer Secret

To generate a Customer ID and Customer Secret, do the following:

1. In [Agora Console](https://console.agora.io), click the username at the bottom of the navigation sidebar to open the account menu, then select **RESTful API Keys**.

   ![RESTful API keys](https://assets-docs.agora.io/images/console/restful-api-keys.png)

2. Select **Create API Key**. A Customer ID and Customer Secret are generated.

3. Select **Download** and save the file somewhere secure — you can download it only once. In the file, **Key** is your Customer ID and **Secret** is your Customer Secret.

4. Use the Customer ID (**Key**) and Customer Secret (**Secret**) to generate a Base64-encoded credential, and pass it to the `Authorization` parameter in the HTTP request header.

### Generate an authorization header using a third-party tool

For testing and debugging, you can use a [third-party online tool](https://www.debugbear.com/basic-auth-header-generator) to quickly generate your Authorization header. Enter your Customer ID as the Username and your Customer Secret as the Password. Your generated header should look like this:

```text
Authorization: Basic NDI1OTQ3N2I4MzYy...YwZjA=
```

### Generate an authorization header using code

The following examples read your customer ID and customer secret from the `AGORA_CUSTOMER_KEY` and `AGORA_CUSTOMER_SECRET` environment variables, and print the value to use in the `Authorization` header:

**Java**

```java
import java.nio.charset.StandardCharsets;
import java.util.Base64;

public class BasicAuthHeader {

    public static void main(String[] args) {
        // Read your customer ID and customer secret from environment variables
        String customerKey = System.getenv("AGORA_CUSTOMER_KEY");
        String customerSecret = System.getenv("AGORA_CUSTOMER_SECRET");

        // Join the customer ID and customer secret, then encode them with Base64
        String plainCredentials = customerKey + ":" + customerSecret;
        String base64Credentials = Base64.getEncoder()
                .encodeToString(plainCredentials.getBytes(StandardCharsets.UTF_8));

        // Create the Authorization header value
        String authorizationHeader = "Basic " + base64Credentials;
        System.out.println(authorizationHeader);
    }
}
```

**Golang**

```go
package main

import (
	"encoding/base64"
	"fmt"
	"os"
)

func main() {
	// Read your customer ID and customer secret from environment variables
	customerKey := os.Getenv("AGORA_CUSTOMER_KEY")
	customerSecret := os.Getenv("AGORA_CUSTOMER_SECRET")

	// Join the customer ID and customer secret, then encode them with Base64
	plainCredentials := customerKey + ":" + customerSecret
	base64Credentials := base64.StdEncoding.EncodeToString([]byte(plainCredentials))

	// Create the Authorization header value
	authorizationHeader := "Basic " + base64Credentials
	fmt.Println(authorizationHeader)
}
```

**PHP**

```php
<?php
// Read your customer ID and customer secret from environment variables
$customerKey = getenv("AGORA_CUSTOMER_KEY");
$customerSecret = getenv("AGORA_CUSTOMER_SECRET");

// Join the customer ID and customer secret, then encode them with Base64
$plainCredentials = $customerKey . ":" . $customerSecret;
$base64Credentials = base64_encode($plainCredentials);

// Create the Authorization header value
$authorizationHeader = "Basic " . $base64Credentials;
echo $authorizationHeader . PHP_EOL;
```

**C#**

```csharp
using System;
using System.Text;

public class BasicAuthHeader
{
    public static void Main()
    {
        // Read your customer ID and customer secret from environment variables
        string customerKey = Environment.GetEnvironmentVariable("AGORA_CUSTOMER_KEY");
        string customerSecret = Environment.GetEnvironmentVariable("AGORA_CUSTOMER_SECRET");

        // Join the customer ID and customer secret, then encode them with Base64
        string plainCredentials = customerKey + ":" + customerSecret;
        string base64Credentials = Convert.ToBase64String(Encoding.UTF8.GetBytes(plainCredentials));

        // Create the Authorization header value
        string authorizationHeader = "Basic " + base64Credentials;
        Console.WriteLine(authorizationHeader);
    }
}
```

**Node.js**

```js
'use strict';

// Read your customer ID and customer secret from environment variables
const customerKey = process.env.AGORA_CUSTOMER_KEY;
const customerSecret = process.env.AGORA_CUSTOMER_SECRET;

// Join the customer ID and customer secret, then encode them with Base64
const plainCredentials = customerKey + ':' + customerSecret;
const base64Credentials = Buffer.from(plainCredentials).toString('base64');

// Create the Authorization header value
const authorizationHeader = 'Basic ' + base64Credentials;
console.log(authorizationHeader);
```

**Python**

```python
import base64
import os

# Read your customer ID and customer secret from environment variables
customer_key = os.environ["AGORA_CUSTOMER_KEY"]
customer_secret = os.environ["AGORA_CUSTOMER_SECRET"]

# Join the customer ID and customer secret, then encode them with Base64
plain_credentials = customer_key + ":" + customer_secret
base64_credentials = base64.b64encode(plain_credentials.encode("utf-8")).decode("utf-8")

# Create the Authorization header value
authorization_header = "Basic " + base64_credentials
print(authorization_header)
```

## Related pages

- [Conversational AI Platform REST API overview](index)
- [Create an agent](create-agent)
- [Start a session](start-session)
