# Web (/en/api-reference/api-ref/signaling/web)

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

The Signaling SDK API reference is divided into the following sections:

* [Setup](#setup)
* [User authentication](#user-authentication)
* [Channels](#channels)
* [Topics](#topics)
* [Messages](#messages)
* [Presence](#presence)
* [Storage](#storage)
* [Lock](#lock)
* [Enumerated types](#enumerated-types)
* [Troubleshooting](#troubleshooting)

## Setup [#setup]

The API reference for the Signaling SDK documents interface descriptions, methods, basic usage, and return values of the Signaling APIs.

Before you initialize a Signaling client instance, import the Signaling JavaScript SDK into your project:

* Using CDN:

```html
    <script src="your_path_to_signaling_sdk/agora-rtm.x.y.z.min.js"></script>
```

* Using a package manager:

```bash
    npm install agora-rtm-sdk
```

### Initialization [#initialization]

#### Description [#description]

Initialization in Signaling refers to creating and initializing a Signaling client instance. When initializing the instance, you need to pass in parameters including `appId` and `userId`. You can create a project and get the App ID on the Agora console.

<CalloutContainer type="info">
  <CalloutTitle>
    Information
  </CalloutTitle>

  <CalloutDescription>
    <br />- The initialization step needs to be completed before calling the other Signaling APIs. <br />- In order to identifying users and devices, you need to ensure that `userId` is globally unique and remains constant throughout the lifecycle of the user or device.
  </CalloutDescription>
</CalloutContainer>

#### Method [#method]

You can create and initialize an instance as follows:

```javascript
class RTM(
    constructor(
        appId: string,
        userId: string,
        rtmConfig?: {
             encryptionMode: string,
             cipherKey: string,
             salt: Uint8Array,
             useStringUserId: boolean,
             presenceTimeout: number,
             logUpload: boolean,
             logLevel: string,
             cloudProxy: boolean
         }
    );
)
```

|  Parameter  |     Type    | Required | Default | Description                                                       |
| :---------: | :---------: | :------: | :-----: | ----------------------------------------------------------------- |
|   `appId`   |    string   | Required |    -    | The App ID of your Agora project on the Agora console.            |
|   `userId`  |    string   | Required |    -    | The unique ID to identify a user or device.                       |
| `rtmConfig` | `RTMConfig` | Optional |    -    | The configuration parameters for initialization, see `RTMConfig`. |

#### Basic Usage [#basic-usage]

```javascript
const { RTM } = AgoraRTM;
const rtm = new RTM("yourAppId", "Tony");
```

#### Return Value [#return-value]

A Signaling client instance. Now you can call other Signaling APIs.

### RTMConfig [#rtmconfig]

#### Description [#description-1]

`RTMConfig` is used to configure additional properties when you initializing a Signaling client instance. These configuration properties take effect throughout the lifecycle of the Signaling client and affect the behaviors of the Signaling client.

#### Method [#method-1]

You can create a `RTMConfig` instance as follows:

```javascript
const { RTMConfig } = AgoraRTM;
```

|       Property      |    Type    | Required | Default | 描述                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| :-----------------: | :--------: | :------: | :-----: | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|   `encryptionMode`  |   string   | Optional |    -    | Encryption mode for end-to-end messages. If you do not set this property or set it as `NONE`, end-to-end encryption is disabled. For details, see [Encryption Mode](#enumvencryptionmod-e).                                                                                                                                                                                                                                                                                                   |
|        `salt`       | Uint8Array | Optional |    -    | The salt required for encryption. The value must be a 32-byte binary array.                                                                                                                                                                                                                                                                                                                                                                                                                   |
|     `cipherKey`     |   string   | Optional |    -    | The key used for encryption and decryption. You must set this property if you want to enable message encryption.                                                                                                                                                                                                                                                                                                                                                                              |
|  `presenceTimeout`  |   number   | Optional |  `300`  | Presence timeout in seconds, and the value range is \[5,300]. This parameter refers the delay imposed by the Signaling server before sending a `REMOTE_TIMEOUT` event notification to other users once it determines that a client has timed out. If the client reconnects and returns to the channel within the specified time, the Signaling server does not send the `REMOTE_TIMEOUT` event notification to other participants or delete the temporary user data associated with the user. |
|     `logUpload`     |   boolean  | Optional | `false` | Whether to upload logs to the server: <br />- `true`: Enable log upload <br />- `false`: Disable log upload.                                                                                                                                                                                                                                                                                                                                                                                  |
|     `cloudProxy`    |   boolean  | Optional | `false` | Whether to enable the cloud proxy: <br />- `true`: Enable. <br />- `false`: Disable. Note: This feature applies to the Message channels and User channels only.                                                                                                                                                                                                                                                                                                                               |
|  `useStringUserId`  |   boolean  | Optional |  `true` | Whether to use string-type user IDs: <br />- `true`: Use string-type user IDs. <br />- `false`: Use number-type user IDs. If you set the property as `false`, SDK automatically converts string-type user IDs to number-type ones. In this case, the `userId` parameter must be a numeric string (for example, "123456"), otherwise initialization fails.                                                                                                                                     |
|      `logLevel`     |   string   | Optional |    -    | Set the output level of SDK log. For details, see [log output level](#enumvlogleve-l).                                                                                                                                                                                                                                                                                                                                                                                                        |
| `heartbeatInterval` |   number   | Optional |   `5`   | Heartbeat interval in seconds, and the value range is \[5,1800]. This parameter refers to the time interval at which the client sends heartbeat packets to the Signaling server. If the client fails to send heartbeat packets to the Signaling server within the specified time, the Signaling server determines that the client has timed out. Please note that this parameter affects the PCU count, which in turn affects billing.                                                        |
|   `privateConfig`   |   object   | Optional |    -    | When using the private deployment feature of Signaling, you need to configure this parameter.                                                                                                                                                                                                                                                                                                                                                                                                 |

`privateConfig` contains the following properties:

|      Property      |    Type   | Required | Default | Description                                                                                                                                                                                                                                                  |
| :----------------: | :-------: | :------: | :-----: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|    `serviceType`   | string\[] | Optional |    -    | Service type. See [Service Types](#enumvrtmservicetyp-e).                                                                                                                                                                                                    |
| `accessPointHosts` | string\[] | Optional |    -    | An addresses list of servers to access the Signaling service. Only supports domain name.                                                                                                                                                                     |
| `eventUploadHosts` | string\[] | Optional |    -    | An addresses list of servers for event uploading. Only supports domain name.                                                                                                                                                                                 |
|  `logUploadHosts`  | string\[] | Optional |    -    | An addresses list of servers for log uploading. Only supports domain name.                                                                                                                                                                                   |
|   `originDomains`  | string\[] | Optional |    -    | A list of domain suffixes used when connecting to the Signaling service. Only supports domain name.                                                                                                                                                          |
|    `domainMode`    |   number  | Optional |   `1`   | Domain name format of the SDK edge node server in private deployments of Signaling. The following values are supported:<br />- `1` (default): Custom format. For example, `ip.**`. <br />- `2`: legacy private deployment format. For example, `ip.edge.**`. |

<CalloutContainer type="warning">
  <CalloutTitle>
    Note
  </CalloutTitle>

  <CalloutDescription>
    To upgrade the privately deployed Signaling Web SDK to v2.2.4 or later, set `domainMode` to `2` for compatibility. If you omit this parameter or use the default value `1`, the SDK may fail to connect to the Signaling server.
  </CalloutDescription>
</CalloutContainer>

#### Basic Usage [#basic-usage-1]

```javascript
const { RTM, EncryptionMode } = AgoraRTM;
const rtmConfig = {
    encryptionMode : EncryptionMode.AES_256_GCM,
    salt : yourSalt,
    cipherKey : "yourCipherKey",
    presenceTimeout : 300,
    logUpload : true,
    logLevel : "debug",
    cloudProxy : false,
    useStringUserId : false,
    privateConfig: {
        serviceType: ["MESSAGE", "STREAM"],
        domainMode: 2
    },
    heartbeatInterval: 5
};
const rtm = new RTM("yourAppId", "Tony", rtmConfig);
```

### Event Listeners [#event-listeners]

#### Description [#description-2]

Signaling has a total of 8 types of event notifications, as shown in the following table:

|         Event Type         | Description                                                                                                                                                                                                        |
| :------------------------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|          `message`         | Receive message event notifications in subscribed message channels and subscribed topics.                                                                                                                          |
|         `presence`         | Receive presence event notifications in subscribed message channels and joined stream channels.                                                                                                                    |
|           `topic`          | Receive all topic event notifications in joined stream channels.                                                                                                                                                   |
|          `storage`         | Receive channel metadata event notifications in subscribed message channels and joined stream channels, and the user metadata event notification of the subscribed users.                                          |
|           `lock`           | Receive lock event notifications in subscribed message channels and joined stream channels.                                                                                                                        |
|          `status`          | (Deprecated) Receive event notifications when client connection status changes. For details, see [SDK connection state](#enumvconnectionstat-e) and [SDK connection state change reason](#enumvconnectionreaso-n). |
|         `linkState`        | Receive event notifications when client connection status changes. For details, see [SDK Link State Types](#enumvlinkstat-e).                                                                                      |
| `tokenPrivilegeWillExpire` | Receive event notifications when the client tokens are about to expire.                                                                                                                                            |

#### Add event listeners [#add-event-listeners]

You can add event listeners as follows:

```javascript
 // Add message event listeners
 // Message
rtm.addEventListener("message", event => {
    const channelType = event.channelType; // Which channel type it is, Should be "STREAM", "MESSAGE" or "USER".
    const channelName = event.channelName; // Which channel does this message come from
    const topic = event.topicName; // Which Topic does this message come from, it is valid when the channelType is "STREAM".
    const messageType = event.messageType; // Which message type it is, Should be "STRING" or "BINARY" .
    const customType = event.customType; // User defined type
    const publisher = event.publisher; // Message publisher
    const message = event.message; // Message payload
    const timestamp = event.timestamp; // Event timestamp
});
 // Presence
rtm.addEventListener("presence", event => {
    const action = event.eventType; // Which action it is ,should be one of 'SNAPSHOT'、'INTERVAL'、'JOIN'、'LEAVE'、'TIMEOUT、'STATE_CHANGED'、'OUT_OF_SERVICE'.
    const channelType = event.channelType; // Which channel type it is, Should be "STREAM", "MESSAGE" or "USER".
    const channelName = event.channelName; // Which channel does this event come from
    const publisher = event.publisher; // Who trigger this event
    const states = event.stateChanged; // User state payload, only for stateChanged event
    const interval = event.interval; // Interval payload, only for interval event
    const snapshot = event.snapshot; // Snapshot payload, only for snapshot event
    const timestamp = event.timestamp; // Event timestamp
});
 // Topic
rtm.addEventListener("topic", event => {
    const action = event.evenType; // Which action it is ,should be one of 'SNAPSHOT'、'JOIN'、'LEAVE'.
    const channelName = event.channelName; // Which channel does this event come from
    const publisher = event.userId; // Who trigger this event
    const topicInfos = event.topicInfos; // Topic information payload
    const totalTopics = event.totalTopics; // How many topics
    const timestamp = event.timestamp; // Event timestamp
});
 // Storage
rtm.addEventListener("storage", event => {
    const channelType = event.channelType; // Which channel type it is, Should be "STREAM", "MESSAGE" or "USER".
    const channelName = event.channelName; // Which channel does this event come from
    const publisher = event.publisher; // Who trigger this event
    const storageType = event.storageType; // Which category the event is, should be 'USER'、'CHANNEL'
    const action = event.eventType; // Which action it is ,should be one of "SNAPSHOT"、"SET"、"REMOVE"、"UPDATE" or "NONE"
    const data = event.data; // 'USER_METADATA' or 'CHANNEL_METADATA' payload
    const timestamp = event.timestamp; // Event timestamp
});
 // Lock
rtm.addEventListener("lock", event => {
    const channelType = event.channelType; // Which channel type it is, Should be "STREAM", "MESSAGE" or "USER".
    const channelName = event.channelName; // Which channel does this event come from
    const publisher = event.publisher; // Who trigger this event
    const action = event.evenType; // Which action it is ,should be one of 'SET'、'REMOVED'、'ACQUIRED'、'RELEASED'、'EXPIRED'、'SNAPSHOT'
    const lockName = event.lockName; // Which lock it effect
    const ttl = event.ttl; // The ttl of this lock
    const snapshot = event.snapshot; // Snapshot payload
    const owner = event.owner; // The owner of this lock
    const timestamp = event.timestamp; // Event timestamp
});
 // Connection State Change
rtm.addEventListener("status", event => {
    const currentState = event.state; // Which connection state right now
    const changeReason = event.reason; // Why trigger this event
    const timestamp = event.timestamp; // Event timestamp
});
 // Link State Change
rtm.addEventListener('linkState', event => {
    const currentState = event.currentState;
    const previousState = event.previousState;
    const serviceType = event.serviceType;
    const operation = event.operation;
    const reason = event.reason;
    const affectedChannels = event.affectedChannels;
    const unrestoredChannels = event.unrestoredChannels;
    const timestamp = event.timestamp;
    const isResumed = event.isResumed;
 // Token Privilege Will Expire
rtm.addEventListener("tokenPrivilegeWillExpire", (channelName) => {
    const channelName = channelName; // Which Channel Token Will Expire
});
```

#### Remove event listeners [#remove-event-listeners]

You can call the `config. removedelegate[javascript]` method to remove a specified event listener.

```javascript
rtm.removeEventListener("status", statusHandler);
```

### login [#login]

#### Description [#description-3]

After creating and initializing a Signaling client instance, you need to perform the `login` operation to log in to the Signaling service. With successful login, the client establishes a long link to the Signaling server and allow the client to access Signaling resources.

#### Method [#method-2]

You can call the `login` method as follows:

```javascript
rtm.login(options?: object): Promise<LoginResponse>;
```

| Parameter |  Type  | Required | Default | Description                         |
| :-------: | :----: | :------: | :-----: | :---------------------------------- |
| `options` | object | Optional |    -    | Options for logging into a channel. |

The `options` object includes the following properties:

| Property |  Type  | Required | Default | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| :------: | :----: | :------: | :-----: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|  `token` | string | Optional |    -    | The token used for logging to the Signaling system.<br />- If your project enables token authentication, you can provide either the [Signaling temporary token](https://agora-token-generator-demo.vercel.app/) or the Signaling token generated by your token server. See [User authentication](/en/realtime-media/rtm/build/connect-and-authenticate/authentication-workflow) and [Deploy Signaling token generator](https://github.com/AgoraIO/Tools/tree/master/DynamicKey/AgoraDynamicKey).<br />- If your project does not enable token authentication, you can enter an empty string or the App ID of a project that enables Signaling services. |

#### Basic Usage [#basic-usage-2]

```javascript
try{
    const result = await rtm.login({ token: "your_token" });
    console.log(result);
} catch (status){
    console.log(status);
}
```

#### Return Value [#return-value-1]

If the method call succeeds, the `LoginResponse` response as follows is returned:

```javascript
type LoginResponse = {
    timestamp: number // Reserved property, indicating the timestamp of the successful operation
}
```

If the method call fails, the `ErrorInfo` response as follows is returned:

```javascript
type ErrorInfo = {
    error: boolean; // Whether there is an error in this operation
    operation: string; // The API name of this operation
    errorCode: number; // Error code.
    reason: string; // Error reason.
}
```

To find out the cause of the error and get the corresponding solution, use the `errorCode` field with the [error codes table](#error-codes-table).

### logout [#logout]

#### Description [#description-4]

You can log out of the Signaling system if you don't need to perform any operation.

#### Method [#method-3]

You can call the `logout` method as follows:

```javascript
rtm.logout(): Promise<LogoutResponse>;
```

#### Basic Usage [#basic-usage-3]

```javascript
try{
    const result = await rtm.logout();
    console.log(result);
} catch (status){
    console.log(status);
}
```

#### Return Value [#return-value-2]

If the method call succeeds, the `LogoutResponse` response as follows is returned:

```javascript
type LoginResponse = {
    timestamp: number // Reserved property, indicating the timestamp of the successful operation
}
```

If the method call fails, the `ErrorInfo` response as follows is returned:

```javascript
type ErrorInfo = {
    error: boolean; // Whether there is an error in this operation
    operation: string; // The API name of this operation
    errorCode: number; // Error code.
    reason: string; // Error reason.
}
```

To find out the cause of the error and get the corresponding solution, use the `errorCode` field with the [error codes table](#error-codes-table).

## User authentication [#user-authentication]

Authentication is the process of validating the identity of each user before they access a system. Agora uses digital tokens to authenticate users and their privileges.

Signaling provides 3 types of channels: message channels, user channels and stream channels. Different types of channels require different types of tokens:

* For message channels and user channels: When logging in to the Signaling system using the `login` method, you only need to pass the token that enables Signaling service.
* For stream channels: In addition to the Signaling token, when joining a stream channel using the `joinTopic` method, you also need to pass the token that enables RTC service.

The token is valid for up to 24 hours. Agora recommends that you update the token before it expires. This article describes how to update the token.

For more information on generating and using tokens, see the following guide:

### renewToken [#renewtoken]

#### Description [#description-5]

Call the `renewToken` method to renew the RTC token.

Different parameter settings applies to different token types:

* RTM Token: Only need to fill in the `token` parameter.
* RTC Token: Need to fill in both the `token` and `channelName` parameters.

To ensure timely token updates, Agora recommends listening for the `tokenPrivilegeWillExpire` callback. See [Event listeners](#event-listeners) for details. Once you successfully add the event listener, when the RTC token is about to expire within 30 seconds, the SDK triggers the `tokenPrivilegeWillExpire` callback to notify the user about the impending token expiration.

Upon receiving this callback, you can generate a new token on the server-side and call the `renewToken` method to provide the SDK with the newly generated token.

#### Method [#method-4]

You can call the `renewToken` method as follows:

```javascript
rtm.renewToken(token: string, options?: object): Promise<RenewTokenResponse>
```

| Parameters |  Type  | Required | Default | Description                          |
| :--------: | :----: | :------: | :-----: | ------------------------------------ |
|   `token`  | string | Required |    -    | The newly generated Signaling token. |
|  `options` | object | Optional |    -    | Token options.                       |

`options` contains the following properties:

|    Property   |  Type  | Required | Default | Description                                             |
| :-----------: | :----: | :------: | :-----: | ------------------------------------------------------- |
| `channelName` | string | Optional |    -    | Channel name. For RTC token, this property is required. |

#### Basic usage [#basic-usage-4]

Example 1: Renew the Signaling token

```javascript
rtmClient.addEventListener('tokenPrivilegeWillExpire', async (channelName) => {
    if(!channelName){
        // The RTM Token is about to expire
        const newToken = "<Your new token>";
        await rtmClient.renewToken(newToken);
    }
});

```

Example 2: Renew the RTC token

```javascript
rtmClient.addEventListener('tokenPrivilegeWillExpire', async (streamChannelName) => {
    if(streamChannelName){
        // The RTC Token is about to expire
        const newToken = "<Your new token>";
        await rtmClient.renewToken(newToken, {
            channelName: streamChannelName
        });
    }
});
```

#### Return value [#return-value-3]

If the method call succeeds, the `RenewTokenResponse` response as follows is returned:

```javascript
type RenewTokenResponse = {
    timestamp: number , // Timestamp of the successful operation.
}
```

If the method call fails, the `ErrorInfo` response as follows is returned:

```javascript
type ErrorInfo = {
    error: boolean; // Whether there is an error in this operation
    operation: string; // The API name of this operation
    errorCode: number; // Error code.
    reason: string; // Error reason.
}
```

To find out the cause of the error and get the corresponding solution, use the `errorCode` field with the [error codes table](#error-codes-table).

## Channels [#channels]

Signaling provides a highly efficient channel management mechanism for data transmission. Any user who subscribes or joins a channel can receive messages and events transmitted within 100 milliseconds. Signaling allows clients to subscribe to hundreds or even thousands of channels. Most Signaling APIs perform actions such as sending, receiving, and encrypting based on channels.

Based on capabilities of Agora, Signaling channels are divided into two types to match different application use-cases:

* Message Channel: Follows the industry-standard Pub/Sub (publish/subscribe) mode. You can send and receive messages within the channel by subscribing to a channel, and do not need to create the channel in advance. There is no limit to the number of publishers and subscribers in a channel.

* Stream Channel: Follows a concept similar to the observer pattern in the industry, where users need to create and join a channel before sending and receiving messages. You can create different topics in the channel, and messages are organized and managed through topics.

### subscribeTopic [#subscribetopic]

#### Description [#description-6]

Signaling provides event notification capabilities for messages and states. By listening for callbacks, you can receive messages and events within subscribed channels. For information on how to add and set up event listeners, see [Event Listener](#event-listeners).

By calling the `subscribeTopic` method, the client can subscribe to a message channel and start receiving messages and event notifications within the channel. After successfully calling this method, users who subscribe to the channel and enable the presence event listener can receive a `presence` event with the `REMOTE_JOIN` type.

<CalloutContainer type="info">
  <CalloutTitle>
    Information
  </CalloutTitle>

  <CalloutDescription>
    This method only applies to the message channel.
  </CalloutDescription>
</CalloutContainer>

#### Method [#method-5]

You can call the `subscribeTopic` method as follows:

```javascript
rtm.subscribe(
    channelName: string,
    options?: object
): Promise<SubscribeResponse>;
```

|   Parameter   |  Type  | Required | Default | Description                        |
| :-----------: | :----: | :------: | :-----: | :--------------------------------- |
| `channelName` | string |    Yes   |    -    | The channel name.                  |
|   `options`   | object | Optional |    -    | Options for subscribing a channel. |

The `options` object includes the following properties:

|    Property    |   Type  | Required | Default | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
| :------------: | :-----: | :------: | :-----: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|  `withMessage` | boolean | Optional |  `true` | Whether to subscribe to message event notifications in the channel.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| `withPresence` | boolean | Optional |  `true` | Whether to subscribe to presence event notifications in the channel.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
|    `beQuiet`   | boolean | Optional | `false` | Whether to set the silent mode. If you set this parameter as `true`, the SDK has the following behaviors:<br />- You can still receive other users' event notifications.<br />- Event notifications related to your channel activity such as subscribing or unsubscribing the channel, and actions related to setting, getting, or deleting temporary user states, can not be broadcasted to other users.<br />- When calling the `getOnlineUsers` method, your information can not be found.<br />- When calling the `getUserChannels` method, channels that you subscribe in silent mode can not be detected. |
| `withMetadata` | boolean | Optional | `false` | Whether to subscribe to storage event notifications in the channel.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
|   `withLock`   | boolean | Optional | `false` | Whether to subscribe to lock event notifications in the channel.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |

#### Basic usage [#basic-usage-5]

```javascript
const options ={
    withMessage : true,
    withPresence : true,
    beQuiet : false,
    withMetadata : false,
    withLock : false
};
try {
    const result = await rtm.subscribe("chat_room", options);
    console.log(result);
} catch (status) {
    console.log(status);
}
```

#### Return value [#return-value-4]

If the method call succeeds, the `SubscribeTopicResponse` response as follows is returned:

```javascript
type SubscribeResponse = {
    timestamp : number // Timestamp of the successful operation.
    channelName : string // Channel name.
}
```

If the method call fails, the `ErrorInfo` response as follows is returned:

```javascript
type ErrorInfo = {
    error: boolean; // Whether there is an error in this operation
    operation: string; // The API name of this operation
    errorCode: number; // Error code.
    reason: string; // Error reason.
}
```

To find out the cause of the error and get the corresponding solution, use the `errorCode` field with the [error codes table](#error-codes-table).

### unsubscribeTopic [#unsubscribetopic]

#### Description [#description-7]

If you no longer need to subscribe to a channel, you can call the `unsubscribeTopic` method to cancel your subscription. After successfully unsubscribing from the channel, other users who subscribe to the channel and enable event listeners can receive a `presence` event notification with the `REMOTE_LEAVE` type. For details, see [Event Listener](#event-listeners).

<CalloutContainer type="info">
  <CalloutTitle>
    Information
  </CalloutTitle>

  <CalloutDescription>
    This method only applies to the message channel.
  </CalloutDescription>
</CalloutContainer>

#### Method [#method-6]

You can call the `unsubscribeTopic` method as follows:

```javascript
rtm.unsubscribe(
    channelName: string
): Promise<UnsubscribeResponse>;
```

|   Parameter   |  Type  | Required | Default | Description       |
| :-----------: | :----: | :------: | :-----: | :---------------- |
| `channelName` | string |    Yes   |    -    | The channel name. |

#### Basic usage [#basic-usage-6]

```javascript
try {
    const result = await rtm.unsubscribe("chat_room");
    console.log(result);
} catch (status) {
    console.log(status);
}
```

#### Return value [#return-value-5]

If the method call succeeds, the `UnsubscribeTopicResponse` response as follows is returned:

```javascript
type UnsubscribeResponse = {
    timestamp : number // Timestamp of the successful operation.
    channelName : string // Channel name.
}
```

If the method call fails, the `ErrorInfo` response as follows is returned:

```javascript
type ErrorInfo = {
    error: boolean; // Whether there is an error in this operation
    operation: string; // The API name of this operation
    errorCode: number; // Error code.
    reason: string; // Error reason.
}
```

To find out the cause of the error and get the corresponding solution, use the `errorCode` field with the [error codes table](#error-codes-table).

### createAgoraRtmClient [#createagorartmclient]

#### Description [#description-8]

Before using a stream channel, you need to call the `createAgoraRtmClient` method to create an `RTMStreamChannel` instance. After successfully creating the instance, you can call its relevant methods to implement functions, such as joining the channel, leaving the channel, sending messages in a topic, and subscribing to messages in a topic.

<CalloutContainer type="info">
  <CalloutTitle>
    Information
  </CalloutTitle>

  <CalloutDescription>
    This method only applies to the stream channel.
  </CalloutDescription>
</CalloutContainer>

#### Method [#method-7]

You can call the `createAgoraRtmClient` method as follows:

```javascript
rtm.createStreamChannel(chanelName: string): RTMStreamChannel;
```

|   Parameter   |  Type  | Required | Default | Description       |
| :-----------: | :----: | :------: | :-----: | :---------------- |
| `channelName` | string |    Yes   |    -    | The channel name. |

#### Basic usage [#basic-usage-7]

```javascript
try{
    const Loc_stChannel = await rtm.createStreamChannel( "Location");
    console.log("Create Stream Channel success!: ");
} catch (status){
    console.log(status);
}
```

#### Return value [#return-value-6]

An `RTMStreamChannel` instance.

### joinTopic [#jointopic]

#### Description [#description-9]

After successfully creating a stream channel, you can call the `joinTopic` method to join the stream channel. Once you join the channel, you can implement channel-related functions. At this point, users who subscribe to the channel and add event listeners can receive the following event notifications:

* Local users:
  * `presence` event notification with the `SNAPSHOT` type.
  * `topic`event notification with the `SNAPSHOT` type.
* Remote users: `presence` event notification with the `REMOTE_JOIN` type.

<CalloutContainer type="info">
  <CalloutTitle>
    Information
  </CalloutTitle>

  <CalloutDescription>
    This method only applies to the stream channel.
  </CalloutDescription>
</CalloutContainer>

#### Method [#method-8]

You can call the `joinTopic` method as follows:

```javascript
join(options?: object): Promise<JoinChannelResponse>;
```

| Parameter |  Type  | Required | Default | Description                    |
| :-------: | :----: | :------: | :-----: | :----------------------------- |
| `options` | object | Optional |    -    | Options for joining a channel. |

The `options` object includes the following properties:

|    Property    |   Type  | Required | Default | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
| :------------: | :-----: | :------: | :-----: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|     `token`    |  string | Optional |    -    | The token used for joining a stream channel, which is currently the same as the RTC token.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| `withPresence` | boolean | Optional |  `true` | Whether to subscribe to presence event notifications in the channel.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
|    `beQuiet`   | boolean | Optional | `false` | Whether to set the silent mode. If you set this parameter as `true`, the SDK has the following behaviors:<br />- You can still receive other users' event notifications.<br />- Event notifications related to your channel activity such as joining or leaving the channel, and actions related to setting, getting, or deleting temporary user states, can not be broadcasted to other users.<br />- When calling the `getOnlineUsers` method, your information can not be found.<br />- When calling the `getUserChannels` method, channels that you subscribe in silent mode can not be detected. |
| `withMetadata` | boolean | Optional | `false` | Whether to subscribe to storage event notifications in the channel.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
|   `withLock`   | boolean | Optional | `false` | Whether to subscribe to lock event notifications in the channel.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |

#### Basic usage [#basic-usage-8]

```javascript
const options ={
    token : "yourToken",
    withPresence : true,
    beQuiet : false,
    withMetadata : false,
    withLock : false
};
try {
    const result = await stChannel.join(options);
    console.log(result);
} catch (status) {
    console.log(status);
}
```

#### Return value [#return-value-7]

If the method call succeeds, the `JoinTopicResponse` response as follows is returned:

```javascript
type JoinChannelResponse = {
    timestamp : number , // Timestamp of the successful operation.
    channelName : string // Channel name.
}
```

If the method call fails, the `ErrorInfo` response as follows is returned:

```javascript
type ErrorInfo = {
    error: boolean; // Whether there is an error in this operation
    operation: string; // The API name of this operation
    errorCode: number; // Error code.
    reason: string; // Error reason.
}
```

To find out the cause of the error and get the corresponding solution, use the `errorCode` field with the [error codes table](#error-codes-table).

### leaveTopic [#leavetopic]

#### Description [#description-10]

If you no longer need to stay in a channel, you can call the `leaveTopic` method to leave the channel. After leaving the channel, you can no longer receive any messages, states, or event notifications from this channel. At the same time, you can no loger be the topic publisher or subscriber of all topics. If you want to restore your previous publisher role and subscribing relationship, you need to call `joinTopic`, `joinTopic` and `subscribeTopic` methods in order.

After successfully leaving the channel, remote users in the channel can receive a `presence` event notification with the `REMOTE_LEAVE` type. For details, see [Event Listener](#event-listeners).

<CalloutContainer type="info">
  <CalloutTitle>
    Information
  </CalloutTitle>

  <CalloutDescription>
    This method only applies to the stream channel.
  </CalloutDescription>
</CalloutContainer>

#### Method [#method-9]

You can call the `leaveTopic` method as follows:

```javascript
leave(): Promise<LeaveChannelResponse>;
```

#### Basic usage [#basic-usage-9]

```javascript
try{
    const result = await streamChannel.leave();
    console.log(result);
} catch (status){
    console.log(status);
}
```

#### Return value [#return-value-8]

If the method call succeeds, the `LeaveTopicResponse` response as follows is returned:

```javascript
type LeaveChannelResponse = {
    timestamp : number // Timestamp of the successful operation.
    channelName : string // Channel name.
}
```

If the method call fails, the `ErrorInfo` response as follows is returned:

```javascript
type ErrorInfo = {
    error: boolean; // Whether there is an error in this operation
    operation: string; // The API name of this operation
    errorCode: number; // Error code.
    reason: string; // Error reason.
}
```

To find out the cause of the error and get the corresponding solution, use the `errorCode` field with the [error codes table](#error-codes-table).

## Topics [#topics]

Topic is a data stream management mechanism in stream channels. Users can use topics to subscribe to and distribute data streams, as well as notify events in data streams in stream channels.

<CalloutContainer type="info">
  <CalloutTitle>
    Information
  </CalloutTitle>

  <CalloutDescription>
    Topics only exist in stream channels. Therefore, before using relevant features, users need to create an `RTMStreamChannel` instance.
  </CalloutDescription>
</CalloutContainer>

For more information on the features of topic, click the following card:

### joinTopic [#jointopic-1]

#### Description [#description-11]

The purpose of joining a topic is to register as one of the message publishers for the topic, so that the user can send messages in the topic. This operation does not affect whether or not the user becomes a subscriber to the topic.

<CalloutContainer type="info">
  <CalloutTitle>
    Information
  </CalloutTitle>

  <CalloutDescription>
    * Currently, Signaling supports a single client joining up to 8 topics in the same stream channel at a time.
    * Before joining a topic, a user need to create an `RTMStreamChannel` instance and call the `joinTopic` method to join the stream channel.
  </CalloutDescription>
</CalloutContainer>

After successfully joining a topic, users who subscribe to that topic and add event listeners can receive the `topic` event notification with the `REMOTE_JOIN` type. For details, see [Event Listener](#event-listeners).

#### Method [#method-10]

You can call the `joinTopic` method as follows:

```javascript
joinTopic(
    topicName: string,
    options?: object
): Promise<JoinTopicResponse>;
```

|  Parameter  |  Type  | Required | Default |       Description      |
| :---------: | :----: | :------: | :-----: | :--------------------: |
| `topicName` | string |    Yes   |    -    |     The topic name.    |
|  `options`  | object | Optional |    -    | The reserved property. |

#### Basic usage [#basic-usage-10]

```javascript
try {
    const result = await stChannel.joinTopic( "gesture", options);
    console.log( result);
} catch (status) {
     console.log(status);
}
```

#### Return value [#return-value-9]

If the method call succeeds, the `JoinTopicResponse` response as follows is returned:

```javascript
type JoinTopicResponse = {
    timestamp: number , // Timestamp of the successful operation.
    topicName: string // Topic name.
}
```

If the method call fails, the `ErrorInfo` response as follows is returned:

```javascript
type ErrorInfo = {
    error: boolean; // Whether there is an error in this operation
    operation: string; // The API name of this operation
    errorCode: number; // Error code.
    reason: string; // Error reason.
}
```

To find out the cause of the error and get the corresponding solution, use the `errorCode` field with the [error codes table](#error-codes-table).

### publishTopicMessage [#publishtopicmessage]

#### Description [#description-12]

Call the `publishTopicMessage` method to send messages to a topic. Users who subscribe to this topic and the message publisher in the channel can receive the message within 100 ms. Before calling the `publishTopicMessage` method, users need to join the stream channel, and then register as a message publisher for that topic by calling the `joinTopic` method.

The messages sent by users are encrypted with TLS during transmission, and data link encryption is enabled by default and cannot be disabled. To achieve a higher level of data security, users can also enable client encryption during initialization. For details, see [Setup](#setup).

#### Method [#method-11]

You can call the `publishTopicMessage` method as follows:

```javascript
publishTopicMessage(
    topicName: string,
    message: string | Uint8Array,
    options?: object
): Promise<PublishTopicMessageResponse>;
```

|  Parameter  |         Type         | Required | Default | Description                                              |
| :---------: | :------------------: | :------: | :-----: | :------------------------------------------------------- |
| `topicName` |        string        | Required |    -    | The topic name.                                          |
|  `message`  | string \| Uint8Array | Required |    -    | The message payload. Supports string or Uint8Array type. |
|  `options`  |        object        | Optional |    -    | The message options.                                     |

The `options` object includes the following property:

|   Property   |  Type  | Required | Default | Description                                      |
| :----------: | :----: | :------: | :-----: | :----------------------------------------------- |
| `customType` | string | Optional |    -    | A user-defined field. Only supports string type. |

#### Basic usage [#basic-usage-11]

Example 1: Send string messages to a specified channel.

```javascript
try {
    const result = await stChannel.publishTopicMessage( "Gesture", JSON.stringify({such: "object"}) );
    console.log(result);
} catch (status) {
    console.log(status);
}
```

Example 2: Send Uint8Array messages to a specified channel.

```javascript
const str2ab = function(str) {
    var buf = new ArrayBuffer(str.length * 2); // Each character occupies 2 bytes.
    var bufView = new Uint16Array(buf);
    for (var i = 0, strLen = str.length; i < strLen; i++) {
        bufView[i] = str.charCodeAt(i);
    }
    return buf;
}
var Message=str2ab("hello world")
try {
    const result = await stChannel.publishTopicMessage( "Gesture",Message);
    console.log(result);
} catch (status) {
    console.log(status);
}

```

#### Return value [#return-value-10]

If the method call succeeds, the `PublishTopicMessageResponse` response as follows is returned:

```javascript
type PublishTopicMessageResponse = {
    timestamp: number , // Timestamp of the successful operation.
    topicName: string // Topic name.
}
```

If the method call fails, the `ErrorInfo` response as follows is returned:

```javascript
type ErrorInfo = {
    error: boolean; // Whether there is an error in this operation
    operation: string; // The API name of this operation
    errorCode: number; // Error code.
    reason: string; // Error reason.
}
```

To find out the cause of the error and get the corresponding solution, use the `errorCode` field with the [error codes table](#error-codes-table).

### leaveTopic [#leavetopic-1]

#### Description [#description-13]

To release resources when you no longer need to publish messages to a topic, you can call the `leaveTopic` method to unregister as a message publisher for that topic. This method does not affect whether or not you subscribe to that topic or any other operations performed by other users on that topic.

After successfully calling this method, users who subscribe to the channel and enable event listeners can receive the `topic` event notification with the `REMOTE_LEAVE` type. For details, see [Event Listener](#event-listeners).

#### Method [#method-12]

You can call the `leaveTopic` method as follows:

```javascript
leaveTopic(topicName: string): Promise<LeaveTopicResponse>;
```

|  Parameter  |  Type  | Required | Default | Description     |
| :---------: | :----: | :------: | :-----: | :-------------- |
| `topicName` | string | Required |    -    | The topic name. |

#### Basic usage [#basic-usage-12]

```javascript
try {
    const result = await stChannel.leaveTopic("gesture");
    console.log(result);
} catch (status) {
     console.log(status);
}
```

#### Return value [#return-value-11]

If the method call succeeds, the `LeaveTopicResponse` response as follows is returned:

```javascript
type LeaveTopicResponse = {
    timestamp: number , // Timestamp of the successful operation.
    topicName: string // Topic name.
}
```

If the method call fails, the `ErrorInfo` response as follows is returned:

```javascript
type ErrorInfo = {
    error: boolean; // Whether there is an error in this operation
    operation: string; // The API name of this operation
    errorCode: number; // Error code.
    reason: string; // Error reason.
}
```

To find out the cause of the error and get the corresponding solution, use the `errorCode` field with the [error codes table](#error-codes-table).

### subscribeTopic [#subscribetopic-1]

#### Description [#description-14]

After joining a channel, you can call the `subscribeTopic` method to subscribe to message publishers of topics in the channel.

`subscribeTopic` is an incremental method. For example, if you call this method for the first time with a subscribing list of \[UserA, UserB], and then call it again with a subscribing list of \[UserB, UserC], the final successful subscribing result is \[UserA, UserB, UserC].

There is no limit to the number of message publishers that can be registered for a single topic in a channel, but a user can only subscribe to a maximum of 50 topics at the same time in the same channel, and a maximum of 64 message publishers in each topic.

#### Method [#method-13]

You can call the `subscribeTopic` method as follows:

```javascript
subscribeTopic(
    topicName: string,
    options?: object
): Promise<SubscribeTopicResponse>;
```

|  Parameter  |  Type  | Required | Default | Description              |
| :---------: | :----: | :------: | :-----: | :----------------------- |
| `topicName` | string | Required |    -    | The topic name.          |
|  `options`  | object | Optional |    -    | The subscribing options. |

The `options` object includes the following property:

| Property |    Type   | Required | Default | Description                                                                                                                                                       |
| :------: | :-------: | :------: | :-----: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|  `users` | string\[] | Optional |    -    | A list of user IDs of message publishers that you want to subscribe to. If you do not set this property, you can randomly subscribe to up to 64 users by default. |

#### Basic usage [#basic-usage-13]

Example 1: Subscribe to a specified message publisher in a topic.

```javascript
var UIDs = ["zhangsan","lisi","wangwu"]
try {
    const result = await rtm.subscribeTopic( "Gesture", { users:UIDs } );
    console.log(result);
} catch (status) {
    console.log( status);
}
```

Example 2: Randomly subscribe to 64 message publisher in a topic.

```javascript
try {
    const result = await stChannel.subscribeTopic("Gesture");
    console.log(result);
}catch(status) {
    console.log(status);
}
```

#### Return value [#return-value-12]

If the method call succeeds, the `SubscribeTopicResponse` response as follows is returned:

```javascript
type SubscribeTopicResponse = {
    succeedUsers : string[] , // A list of users who successfully subscribe to the topic.
    failedUsers : string[], // A list of users who fail to subscribe to the topic.
    failedDetails : [ // A list of reasons for subscription failure.
        {
            user : string , // User ID.
            errorCode : number , // Error code.
            reason : string // Reason for the error.
        },
    ],
    timestamp : number, // Timestamp of the successful operation.
    topiclName : string // Topic name.
}
```

If the method call fails, the `ErrorInfo` response as follows is returned:

```javascript
type ErrorInfo = {
    error: boolean; // Whether there is an error in this operation
    operation: string; // The API name of this operation
    errorCode: number; // Error code.
    reason: string; // Error reason.
}
```

To find out the cause of the error and get the corresponding solution, use the `errorCode` field with the [error codes table](#error-codes-table).

### unsubscribeTopic [#unsubscribetopic-1]

#### Description [#description-15]

If you are no longer interested in a topic or no longer need to subscribe to one or more message publishers in the topic, you can call the `unsubscribeTopic` method to unsubscribe from the topic or unsubscribe from specific message publishers in the topic.

#### Method [#method-14]

You can call the `unsubscribeTopic` method as follows:

```javascript
unsubscribeTopic(
    topicName: string,
    options?: object
): Promise<UnsubscribeTopicResponse>;
```

|  Parameter  |  Type  | Required | Default | Description                |
| :---------: | :----: | :------: | :-----: | :------------------------- |
| `topicName` | string | Required |    -    | The topic name.            |
|  `options`  | object | Optional |    -    | The unsubscribing options. |

The `options` object includes the following property:

| Property |    Type   | Required | Default | Description                                                                                                                                             |
| :------: | :-------: | :------: | :-----: | :------------------------------------------------------------------------------------------------------------------------------------------------------ |
|  `users` | string\[] | Optional |    -    | A list of user IDs of message publishers that you want to unsubscribe from. If you do not set this property, you can unsubscribe from the entire topic. |

#### Basic usage [#basic-usage-14]

Example 1: Unsubscribe from a specified message publisher in a topic.

```javascript
try {
    const result = await rtm.unsubscribeTopic( "Gesture", { users:["Tony","Bo"] });
    console.log("unsubscribe Topic success: ", result);
} catch (status) {
    console.log("unsubscribe Topic failed: ", result);
}
```

Example 2: Randomly unsubscribe from 64 message publisher in a topic.

```javascript
try {
    const result = await rtm.unsubscribeTopic("Gesture");
    console.log("unsubscribe topic success: ", result);
} catch (status) {
    console.log("unsubscribe topic failed: ", result);
}
```

#### Return value [#return-value-13]

If the method call succeeds, the `UnsubscribeTopicResponse` response as follows is returned:

```javascript
type UnsubscribeTopicResponse = {
    timestamp: number , // Timestamp of the successful operation.
}
```

If the method call fails, the `ErrorInfo` response as follows is returned:

```javascript
type ErrorInfo = {
    error: boolean; // Whether there is an error in this operation
    operation: string; // The API name of this operation
    errorCode: number; // Error code.
    reason: string; // Error reason.
}
```

To find out the cause of the error and get the corresponding solution, use the `errorCode` field with the [error codes table](#error-codes-table).

## Messages [#messages]

Sending and receiving messages is the most basic function of the Signaling service. Any message sent by the Signaling server can be delivered to any online subscribing user within 100 ms. Depending on your business requirements, you can send messages to one user only or broadcast messages to multiple users.

Signaling offers 3 types of channels: message channels, user channels, and stream channels. These channel types have the following differences in how messages are transmitted and methods are called:

* Message Channel: The real-time channel. Messages are transmitted through the channel, and the channel is highly scalable. Local users can call the `publishTopicMessage` method, set the `channelType` parameter to `MESSAGE`, and set the `channelName` parameter to the channel name to send messages in the channel. The remote users can call the `subscribeTopic` method to subscribe to the channel and receive messages.
* User Channel: The real-time channel. Messages are transmitted to the specified user. Local users can call the `publishTopicMessage` method, set the `channelType` parameter to `USER`, and set the `channelName` parameter to the user ID to send messages to the specified user. The specified remote users receive messages through the `message` event notifications.
* Stream Channel: The streaming transmission channel. Messages are transmitted through the topic. Users need to join a channel first, and then join a topic. Local users can call the `publishTopicMessage` method to send messages in the topic, and remote users can call the `subscribeTopic` method to subscribe to the topic and receive messages.

This page introduces how to send and receive messages in a message channel or a user channel.

### publishTopicMessage [#publishtopicmessage-1]

#### Description [#description-16]

You can directly call the `publishTopicMessage` method to send messages to all online users who subscribe to the channel. Even if you do not subscribe to the channel, you can still send messages in the channel.

<CalloutContainer type="info">
  <CalloutTitle>
    Information
  </CalloutTitle>

  <CalloutDescription>
    The following practices can effectively improve the reliability of message transmission:<br />- The message payload should be within 32 KB; otherwise, the sending will fail. <br />- The upper limit of the rate at which messages are sent to a single channel is 60 QPS. If the sending rate exceeds the limit, some messages will be discarded. A lower rate is better, as long as the requirements are met.
  </CalloutDescription>
</CalloutContainer>

After successfully calling this method, the SDK triggers a `message` event notification. Users who subscribe to the channel and enabled the event listener can receive this event notification. For details, see [Event Listener](#event-listeners).

#### Method [#method-15]

You can call the `publishTopicMessage` method as follows:

```javascript
rtm.publish(
    channelName: string,
    message: string | Uint8Array,
    options?: object
): Promise<PublishResponse>;
```

|   Parameter   |         Type         | Required | Default | Description                                                                                                                |
| :-----------: | :------------------: | :------: | :-----: | :------------------------------------------------------------------------------------------------------------------------- |
|   `message`   | string \| Uint8Array | Required |    -    | The message payload. Supports string or Uint8Array type.                                                                   |
| `channelName` |        string        | Required |    -    | Fill in a channel name to send messages in a specified channel, or fill in a user ID to send messages to a specified user. |
|   `options`   |        object        | Optional |    -    | The message options.                                                                                                       |

The `options` object includes the following property:

|    Property   |  Type  | Required | Default | Description                                                     |
| :-----------: | :----: | :------: | :-----: | :-------------------------------------------------------------- |
|  `customType` | string | Optional |    -    | A user-defined field. Only supports string type.                |
| `channelType` | string | Optional |    -    | Channel type. For details, see [Channel Types](#channel-types). |

#### Basic usage [#basic-usage-15]

Example 1: Send string messages to a specified channel.

```javascript
try {
    const result = await rtm.publish( "my_channel", "Hello world" );
    console.log(result);
} catch (status) {
    console.log(status);
}
```

Example 2: Send Uint8Array messages to a specified channel.

```javascript
const str2ab = function(str) {
    var buf = new ArrayBuffer(str.length * 2); // Each character occupies 2 bytes.
    var bufView = new Uint16Array(buf);
    for (var i = 0, strLen = str.length; i < strLen; i++) {
        bufView[i] = str.charCodeAt(i);
    }
    return buf;
};
var Message=str2ab("hello world");
try {
    const result = await rtm.publish("my_channel", Message );
    console.log(result);
} catch (status) {
    console.log(status);
}
```

Example 3: Send string messages to a specified user.

```javascript
try {
    const result = await rtm.publish("user_b", "Hello world", { channelType: "USER"} );
    console.log(result);
} catch (status) {
    console.log(status);
}
```

Example 4: Send Uint8Array messages to a specified user.

```javascript
const str2ab = function(str) {
    var buf = new ArrayBuffer(str.length * 2); // 每个字符占用 2 个字节
    var bufView = new Uint16Array(buf);
    for (var i = 0, strLen = str.length; i < strLen; i++) {
        bufView[i] = str.charCodeAt(i);
    }
    return buf;
};
var Message=str2ab("hello world");
try {
    const result = await rtm.publish("user_b", Message, { channelType: "USER"} );
    console.log(result);
} catch (status) {
    console.log(status);
}
```

<CalloutContainer type="info">
  <CalloutTitle>
    Information
  </CalloutTitle>

  <CalloutDescription>
    After successfully calling this method, the SDK triggers a `message` event notification. Users who subscribe to the channel and enable event listener can receive this event notification. For details, see [Event Listener](#event-listeners).
  </CalloutDescription>
</CalloutContainer>

#### Return value [#return-value-14]

If the method call succeeds, the `PublishTopicMessageResponse` response as follows is returned:

```javascript
type PublishResponse = {
    timestamp: number , // Timestamp of the successful operation.
    chanelName : string // Channel name.
}
```

If the method call fails, the `ErrorInfo` response as follows is returned:

```javascript
type ErrorInfo = {
    error: boolean; // Whether there is an error in this operation
    operation: string; // The API name of this operation
    errorCode: number; // Error code.
    reason: string; // Error reason.
}
```

To find out the cause of the error and get the corresponding solution, use the `errorCode` field with the [error codes table](#error-codes-table).

### Receive [#receive]

Signaling provides event notifications for messages, states, and event changes. By listening for callbacks, you can receive messages and events within subscribed channels. As an example, the code snippet below shows how to receive messages from the user channel.

```javascript
rtm.addEventListener("message", event => {
    const channelType = event.channelType; // Which channel type it is, Should be "STREAM", "MESSAGE" or "USER" .
    const channelName = event.channelName; // Which channel does this message come from
    const topic = event.topicName; // Which Topic does this message come from, it is valid when the channelType is "STREAM".
    const messageType = event.messageType; // Which message type it is, Should be "STRING" or "BINARY" .
    const customType = event.customType; // User defined type
    const publisher = event.publisher; // Message publisher
    const message = event.message; // Message payload
    const timestamp = event.timestamp; // Message timestamp
});
```

For information on how to add and set event listeners, see [Event Listener](#event-listeners).

## Presence [#presence]

The presence feature provides the ability to monitor user online, offline, and user historical state change. With the Presence feature, you can get real-time access to the following information:

* Real-time event notification when a user joins or leaves a specified channel.
* Real-time event notification when the custom temporary user state changes.
* Query which channels a specified user has joined or subscribed to.
* Query which users have joined a specified channel and their temporary user state data.

<CalloutContainer type="info">
  <CalloutTitle>
    Information
  </CalloutTitle>

  <CalloutDescription>
    **Presence** applies to both message channels and stream channels.
  </CalloutDescription>
</CalloutContainer>

### getOnlineUsers [#getonlineusers]

#### Description [#description-17]

Call the `getOnlineUsers` method to query user information in real time such as the number of online users, the list of online users and their temporary user status in the specified channel.

#### Method [#method-16]

You can call the `getOnlineUsers` method as follows:

```javascript
rtm.presence.getOnlineUsers(
    channelName: string,
    channelType: string,
    options?: object
): Promise<getOnlineUsersResponse>;
```

|   Parameter   |  Type  | Required | Default | Description                                                     |
| :-----------: | :----: | :------: | :-----: | :-------------------------------------------------------------- |
| `channelName` | string | Required |    -    | Channel name.                                                   |
| `channelType` | string | Required |    -    | Channel type. For details, see [Channel Types](#channel-types). |
|   `options`   | object | Optional |    -    | Query options.                                                  |

`options` contains the following properties:

|     Property     |   Type  | Required | Default | Description                                                                                                                                                                                                     |
| :--------------: | :-----: | :------: | :-----: | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `includedUserId` | boolean | Optional |  `true` | Whether the returned result contains the user ID of online users.                                                                                                                                               |
|  `includedState` | boolean | Optional | `false` | Whether the returned result contains the temporary user state of online users.                                                                                                                                  |
|      `page`      |  string | Optional |    -    | Page number of the returned result. If you do not provide this property, the SDK returns the first page by default. You can check whether there is next page in the `nextPage` property of the returned result. |

#### Basic Usage [#basic-usage-16]

```javascript
const options = {
    includedUserId : true ,
    includedState : true,
    page : "yourBookMark"
}
try{
    const result = await rtm.presence.getOnlineUsers( "chat_room", "MESSAGE", options );
    console.log(result);
} catch(status){
    console.log(status);
}
```

#### Return Value [#return-value-15]

If the method call succeeds, the `WhoNowResponse` response as follows is returned:

```javascript
type getOnlineUsersResponse = {
    timestamp: number , // Timestamp of the successful operation.
    totalOccupancy : number , // Number of the online users in the channel.
    occupants : Array<object> , // List of the online users in the channel and their temporary user state.
    nextPage : string // Page number of the next page.
}
```

If the method call fails, the `ErrorInfo` response as follows is returned:

```javascript
type ErrorInfo = {
    error: boolean; // Whether there is an error in this operation
    operation: string; // The API name of this operation
    errorCode: number; // Error code.
    reason: string; // Error reason.
}
```

To find out the cause of the error and get the corresponding solution, use the `errorCode` field with the [error codes table](#error-codes-table).

### getUserChannels [#getuserchannels]

#### Description [#description-18]

In use-cases such as statistic analytics and debugging, you may need to know all the channels that a specified user has subscribed to or joined. Call the `getUserChannels` method to get the list of channels where the specified user is in real time.

#### Method [#method-17]

You can call the `getUserChannels` method as follows:

```javascript
rtm.presence.getUserChannels(userId: string): Promise<GetUserChannelsResponse>;
```

| Parameter |  Type  | Required | Default | Description                                                                                     |
| :-------: | :----: | :------: | :-----: | :---------------------------------------------------------------------------------------------- |
|  `userId` | string | Required |    -    | If you set this parameter to an empty string `""`, the SDK uses the `userId` of the local user. |

#### Basic Usage [#basic-usage-17]

```javascript
try{
    const result = await rtm.presence.whereNow( "Tony" );
    console.log(result);
} catch(status){
    console.log(status);
}
```

#### Return Value [#return-value-16]

If the method call succeeds, the `WhereNowResponse` response as follows is returned:

```javascript
type GetUserChannelsResponse = {
    timestamp: number , // Timestamp of the successful operation.
    totalChannel : number , // Number of the channels that the user has joined or subscribed to.
    channels : Array<object> // List of the channels including channel name and channel type.
}
```

If the method call fails, the `ErrorInfo` response as follows is returned:

```javascript
type ErrorInfo = {
    error: boolean; // Whether there is an error in this operation
    operation: string; // The API name of this operation
    errorCode: number; // Error code.
    reason: string; // Error reason.
}
```

To find out the cause of the error and get the corresponding solution, use the `errorCode` field with the [error codes table](#error-codes-table).

### setState [#setstate]

#### Description [#description-19]

To meet different requirements in different business use-cases for setting user states, Signaling provides the `setState` method to customize the temporary user state. Users can add custom statuses such as scores, game status, location, mood, and hosting status for themselves.

The `setState` method sets temporary user state. It means these user states remains in the channel as long as the user stays subscribed to the channel and stays online, and they disappear when the user leaves the channel or disconnects from Signaling. If you need to restore user states when rejoining a channel or reconnecting, you need to cache the data locally in real time. If you want to permanently save user states, Agora recommends you use the `setUserMetadata` method of the storage function instead.

If a user modifies the temporary user status, Signaling triggers the `presence` event notification of the `REMOTE_STATE_CHANGED` type in real time . You can receive the event by subscribing to the channel and configuring the corresponding property.

#### Method [#method-18]

Set the temporary user state as follows:

```javascript
rtm.presence.setState(
    channelName: string,
    channelType: string,
    state: object
): Promise<SetStateResponse>;
```

|   Parameter   |  Type  | Required | Default | Description                                                                  |
| :-----------: | :----: | :------: | :-----: | :--------------------------------------------------------------------------- |
| `channelName` | string | Required |    -    | Channel name.                                                                |
| `channelType` | string | Required |    -    | Channel type. For details, see [Channel Types](#channel-types).              |
|    `state`    | object | Required |    -    | A JSON object that consists of key-value pairs. The key must be string type. |

<CalloutContainer type="info">
  <CalloutTitle>
    Information
  </CalloutTitle>

  <CalloutDescription>
    The keys in the `state` property do not support containing `[`, `]`, and `.` characters.
  </CalloutDescription>
</CalloutContainer>

#### Basic Usage [#basic-usage-18]

```javascript
var newState = { "mood":"pumped", "isTyping":false};

try{
    const result = await rtm.Presence.setState("chat_room", "MESSAGE", newState);
    console.log(result);
} catch(status){
    console.log(status);
}
```

#### Return Value [#return-value-17]

If the method call succeeds, the `SetStateResponse` response as follows is returned:

```javascript
type SetStateResponse = {
    timestamp: number , // Timestamp of the successful operation.
}
```

If the method call fails, the `ErrorInfo` response as follows is returned:

```javascript
type ErrorInfo = {
    error: boolean; // Whether there is an error in this operation
    operation: string; // The API name of this operation
    errorCode: number; // Error code.
    reason: string; // Error reason.
}
```

To find out the cause of the error and get the corresponding solution, use the `errorCode` field with the [error codes table](#error-codes-table).

### getState [#getstate]

#### Description [#description-20]

To get the temporary user state of a specified user in the channel, you can use the `getState` method.

#### Method [#method-19]

Get the temporary user state as follows:

```javascript
rtm.presence.getState(
    userId: string,
    channelName: string,
    channelType: string,
): Promise<GetStateResponse>;
```

|   Parameter   |  Type  | Required | Default | Description                                                     |
| :-----------: | :----: | :------: | :-----: | :-------------------------------------------------------------- |
|    `userId`   | string | Required |    -    | User ID.                                                        |
| `channelName` | string | Required |    -    | Channel name.                                                   |
| `channelType` | string | Required |    -    | Channel type. For details, see [Channel Types](#channel-types). |

#### Basic Usage [#basic-usage-19]

```javascript
try{
    const result = await rtm.presence.getState("Tony", "chat_room", "MESSAGE" );
    const.log(result);
} catch (status) {
    console.log(status);
}
```

#### Return Value [#return-value-18]

If the method call succeeds, the `GetStateResponse` response as follows is returned:

```javascript
type GetStateResponse = {
    timestamp: number , // Timestamp of the successful operation.
    userId : string , // User ID.
    states : object , // Key-value pairs of the user states.
    statesCount : number // Numbers of the user states.
}
```

If the method call fails, the `ErrorInfo` response as follows is returned:

```javascript
type ErrorInfo = {
    error: boolean; // Whether there is an error in this operation
    operation: string; // The API name of this operation
    errorCode: number; // Error code.
    reason: string; // Error reason.
}
```

To find out the cause of the error and get the corresponding solution, use the `errorCode` field with the [error codes table](#error-codes-table).

### removeState [#removestate]

#### Description [#description-21]

When a temporary user state is no longer needed, you can call the `removeState` method to remove it. When the user state is removed, the user who has subscribed to the channel and enabled the presence event monitoring receives the `presence` notification in the `REMOTE_STATE_CHANGED` type. For details, see [Event Listener](#event-listeners).

#### Method [#method-20]

You can call the `removeState` method as follows:

```javascript
rtm.presence.removeState(
    channelName: string,
    channelType: string,
    options?: object
): Promise<RemoveStateResponse>;
```

|   Parameter   |  Type  | Required | Default | Description                                                     |
| :-----------: | :----: | :------: | :-----: | :-------------------------------------------------------------- |
| `channelName` | string | Required |    -    | Channel name.                                                   |
| `channelType` | string | Required |    -    | Channel type. For details, see [Channel Types](#channel-types). |
|   `options`   | object | Optional |    -    | Options for removing the state.                                 |

The `options` object includes the following property:

| Property |    Type   | Required | Default | Description                                                                                                                         |
| :------: | :-------: | :------: | :-----: | :---------------------------------------------------------------------------------------------------------------------------------- |
| `states` | string\[] | Optional |    -    | The list of keys of the user states that you want to remove. If you do not provide this parameter, all the user states are removed. |

<CalloutContainer type="info">
  <CalloutTitle>
    Information
  </CalloutTitle>

  <CalloutDescription>
    The keys in the `states` property do not support containing `[`, `]`, and `.` characters.
  </CalloutDescription>
</CalloutContainer>

#### Basic Usage [#basic-usage-20]

```javascript
const options = {
    states:["mode","Typing"]
}
try{
    const result = await rtm.Presence.removeState("chat_room", "MESSAGE" , options);
    console.log(result);
} catch (status) {
    console.log(status);
}
```

#### Return Value [#return-value-19]

If the method call succeeds, the `RemoveStateResponse` response as follows is returned:

```javascript
type RemoveStateResponse = {
    timestamp: number , // Timestamp of the successful operation.
}
```

If the method call fails, the `ErrorInfo` response as follows is returned:

```javascript
type ErrorInfo = {
    error: boolean; // Whether there is an error in this operation
    operation: string; // The API name of this operation
    errorCode: number; // Error code.
    reason: string; // Error reason.
}
```

To find out the cause of the error and get the corresponding solution, use the `errorCode` field with the [error codes table](#error-codes-table).

## Storage [#storage]

The storage feature provides a dynamic database mechanism that allows developers to dynamically set, store, update, and delete data such as channel metadata and user metadata.

### setChannelMetadata [#setchannelmetadata]

#### Description [#description-22]

The `setChannelMetadata` method sets metadata for a message channel or stream channel. A channel can only have one set of metadata, but each set of metadata can have one or more metadata items. If you call this method multiple times, the SDK retrieves the `key` of the metadata items in turn and apply settings according to the following rules:

* If you set metadata with different `key`, the SDK adds each set of metadata in sequence according to the order of the method calls.
* If you set metadata with the same `key`, the `value` of the last setting overwrites the previous one.

After successfully setting channel metadata, users who subscribe to the channel and enable event listeners can receive the `storage` event notification with the `CHANNEL` type. For details, see [Event Listener](#event-listeners).

Channel metadata also introduces the version control logic CAS (Compare And Set). This method provides two independent version control fields, and you can set one or more of them according to your actual business use-case:

* Enable version number verification for the entire set of channel metadata by setting the `majorRevision` property in the `options` parameter.
* Enable version number verification for a single metadata item by setting the `revision` property in the `data` parameter.

When setting channel metadata or metadata items, you can control whether to enable version number verification by specifying the revision property:

* The default value of the revision property is `-1`, indicating that no CAS verification is performed for this method call. If the channel metadata or metadata item already exists, the latest value overwrites the previous one. If the channel metadata or metadata item does not exist, the SDK creates it.
* If the revision property is a positive integer, CAS verification is performed for this method call. If the channel metadata or metadata item already exists, the SDK updates the corresponding value after the version number verification succeeds. If the channel metadata or metadata item does not exist, the SDK returns the error code.

#### Method [#method-21]

You can call the `setChannelMetadata` method as follows:

```javascript
rtm.storage.setChannelMetadata(
    channelName: string,
    channelType: string,
    data: Array<object>,
    options?: object
): Promise<SetChannelMetadataResponse>;
```

|   Parameter   |          Type         | Required | Default | Description                                                                                                                                                            |
| :-----------: | :-------------------: | :------: | :-----: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `channelName` |         string        | Required |    -    | Channel name.                                                                                                                                                          |
| `channelType` |         string        | Required |    -    | Channel type. For details, see [Channel Types](#channel-types).                                                                                                        |
|     `data`    | Array\&lt;object\&gt; | Required |    -    | An array of metadata items. A metadata item is a JSON object that includes predefined properties. You cannot set properties other than predefined ones in this object. |
|   `options`   |         object        | Optional |    -    | Options for setting metadata.                                                                                                                                          |

`data` contains the following properties:

|  Property  |  Type  | Required |      Default      | Description                                                                                                                                                                                                                                                                                      |
| :--------: | :----: | :------: | :---------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|    `key`   | string | Required |         -         | The `key` of the metadata item.                                                                                                                                                                                                                                                                  |
|   `value`  | string | Optional | Empty string `''` | The `value` of the metadata item.                                                                                                                                                                                                                                                                |
| `revision` | number | Optional |        `-1`       | <br />- Returns the real version number in read operations.<br />- Serves as a version control switch in write operations:<br />- `-1`: Disable the version verification. <br />- > `0`: Enable the version verification. Only operations that match the target version number can be performed. |

`options` contains the following properties:

|     Property    |   Type  | Required |      Default      | Description                                                                                                                                                                                    |
| :-------------: | :-----: | :------: | :---------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `majorRevision` |  number | Optional |        `-1`       | A version control switch:<br />- `-1`: Disable the version verification.<br />- > `0`: Enable the version verification. Only operations that match the target version number can be performed. |
|    `lockName`   |  string | Optional | Empty string `''` | The name of the lock. If set, only users who call the `acquireLock` method to acquire the lock can perform operations.                                                                         |
|  `addTimeStamp` | boolean | Optional |      `false`      | Whether to record the timestamp of the edit.                                                                                                                                                   |
|   `addUserId`   | boolean | Optional |      `false`      | Whether to record the ID of the editor.                                                                                                                                                        |

#### Basic usage [#basic-usage-21]

```javascript
const data = [
    {
        key : "Apple",
        value : "100"
        revision : 174298200
    },
    {
        key : "Banana",
        value : "200",
        revision : 174298100
    }
];
const options = {
    majorRevision : 174298270,
    lockName: "lockName",
    addTimeStamp : true,
    addUserId : true
};
try {
    const result = await rtm.storage.setChannelMetadata( "channel_name", "MESSAGE", data, options );
    console.log(result);
} catch (status) {
    console.log(status);
}
```

#### Return value [#return-value-20]

If the method call succeeds, the `SetChannelMetadataResponse` response as follows is returned:

```javascript
type SetChannelMetadataResponse = {
    timestamp: number , // Timestamp of the successful operation.
    channelName : string , // Channel name.
    channelType : string , // Channel type.
    totalCount : number // Number of metadata items.
}
```

If the method call fails, the `ErrorInfo` response as follows is returned:

```javascript
type ErrorInfo = {
    error: boolean; // Whether there is an error in this operation
    operation: string; // The API name of this operation
    errorCode: number; // Error code.
    reason: string; // Error reason.
}
```

To find out the cause of the error and get the corresponding solution, use the `errorCode` field with the [error codes table](#error-codes-table).

### getChannelMetadata [#getchannelmetadata]

#### Description [#description-23]

`getChannelMetadata` 方法可以获取指定频道的 Metadata。

#### Method [#method-22]

You can call the `getChannelMetadata` method as follows:

```javascript
rtm.storage.getChannelMetadata(
    channelName: string,
    channelType: string
): Promise<GetChannelMetadataResponse>;
```

|   Parameter   |  Type  | Required | Default | Description                                                     |
| :-----------: | :----: | :------: | :-----: | :-------------------------------------------------------------- |
| `channelName` | string | Required |    -    | Channel name.                                                   |
| `channelType` | string | Required |    -    | Channel type. For details, see [Channel Types](#channel-types). |

#### Basic usage [#basic-usage-22]

```javascript
try {
    const result = await rtm.storage.getChannelMetadata("channel_name", "MESSAGE");
    console.log(result);
} catch (status) {
    console.log(status);
}
```

#### Return value [#return-value-21]

If the method call succeeds, the `GetChannelMetadataResponse` response as follows is returned:

```javascript
type GetChannelMetadataResponse = {
    timestamp: number , // Timestamp of the successful operation.
    channelName : string , // Channel name.
    channelType : string , // Channel type.
    totalCount : number , // Number of metadata items.
    majorRevision : number , // Version of metadata.
    metadata : Record<string, MetaDataDetail> // JSON object containing metadata item.
}
```

`MetaDataDetail` contains the following properties:

```javascript
type MetaDataDetail = {
    value: string , // Value of a metadata item.
    revision : number , // Version of a metadata item.
    updated : string , // Timestamp of the last update.
    authorUid : string , // User ID of the last editor.
}
```

If the method call fails, the `ErrorInfo` response as follows is returned:

```javascript
type ErrorInfo = {
    error: boolean; // Whether there is an error in this operation
    operation: string; // The API name of this operation
    errorCode: number; // Error code.
    reason: string; // Error reason.
}
```

To find out the cause of the error and get the corresponding solution, use the `errorCode` field with the [error codes table](#error-codes-table).

### removeChannelMetadata [#removechannelmetadata]

#### Description [#description-24]

Call the `removeChannelMetadata` method to remove channel metadata or metadata items.

When removing channel metadata or metadata items, you can control whether to enable version number verification by specifying the revision property:

* The default value of the revision property is `-1`, indicating that no CAS verification is performed for this method call. If the channel metadata or metadata item already exists, the SDK removes it. If the channel metadata or metadata item does not exist, the SDK returns the error code.
* If the revision property is a positive integer, CAS verification is performed for this method call. If the channel metadata or metadata item already exists, the SDK removes the corresponding value after the version number verification succeeds. If the channel metadata or metadata item does not exist, the SDK returns the error code.

After successfully removing channel metadata or metadata items, users who subscribe to the channel and enable event listeners can receive the `storage` event notification with the `CHANNEL` type. For details, see [Event Listener](#event-listeners).

#### Method [#method-23]

You can call the `removeChannelMetadata` method as follows:

```javascript
rtm.storage.removeChannelMetadata(
    channelName: string,
    channelType: string,
    options?: object
): Promise<RemoveChannelMetadataResponse>;
```

|   Parameter   |  Type  | Required | Default | Description                                                     |
| :-----------: | :----: | :------: | :-----: | :-------------------------------------------------------------- |
| `channelName` | string | Required |    -    | Channel name.                                                   |
| `channelType` | string | Required |    -    | Channel type. For details, see [Channel Types](#channel-types). |
|   `options`   | object | Optional |    -    | Options for setting metadata.                                   |

`options` contains the following properties:

|     Property    |          Type         | Required |      Default      | Description                                                                                                                                                                                    |
| :-------------: | :-------------------: | :------: | :---------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|      `data`     | Array\&lt;object\&gt; | Required |         -         | An array of metadata items. A metadata item is a JSON object that includes predefined properties. You cannot set properties other than predefined ones in this object.                         |
| `majorRevision` |         number        | Optional |        `-1`       | A version control switch:<br />- `-1`: Disable the version verification.<br />- > `0`: Enable the version verification. Only operations that match the target version number can be performed. |
|    `lockName`   |         string        | Optional | Empty string `''` | The name of the lock. If set, only users who call the `acquireLock` method to acquire the lock can perform operations.                                                                         |
|  `addTimeStamp` |        boolean        | Optional |      `false`      | Whether to record the timestamp of the edit.                                                                                                                                                   |
|   `addUserId`   |        boolean        | Optional |      `false`      | Whether to record the ID of the editor.                                                                                                                                                        |

`data` contains the following properties:

|  Property  |  Type  | Required |      Default      | Description                                                                                                                                                                                                                                                                                      |
| :--------: | :----: | :------: | :---------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|    `key`   | string | Required |         -         | The `key` of the metadata item.                                                                                                                                                                                                                                                                  |
|   `value`  | string | Optional | Empty string `''` | The `value` of the metadata item.                                                                                                                                                                                                                                                                |
| `revision` | number | Optional |        `-1`       | <br />- Returns the real version number in read operations.<br />- Serves as a version control switch in write operations:<br />- `-1`: Disable the version verification. <br />- > `0`: Enable the version verification. Only operations that match the target version number can be performed. |

#### Basic usage [#basic-usage-23]

```javascript
const data = [
    {
        key : "Apple",
        revision : 174298200
    }
];
const options = {
    data : data,
    majorRevision : 174298270,
};
try {
    const result = await rtm.storage.removeChannelMetadata("channel_name", "MESSAGE", options);
    console.log(result);
} catch (status) {
    console.log(status);
}
```

#### Return value [#return-value-22]

If the method call succeeds, the `RemoveChannelMetadataResponse` response as follows is returned:

```javascript
type RemoveChannelMetadataResponse = {
    timestamp: number , // Timestamp of the successful operation.
    channelName : string , // Channel name.
    channelType : string , // Channel type.
    totalCount : number // Number of metadata items.
}
```

If the method call fails, the `ErrorInfo` response as follows is returned:

```javascript
type ErrorInfo = {
    error: boolean; // Whether there is an error in this operation
    operation: string; // The API name of this operation
    errorCode: number; // Error code.
    reason: string; // Error reason.
}
```

To find out the cause of the error and get the corresponding solution, use the `errorCode` field with the [error codes table](#error-codes-table).

### updateChannelMetadata [#updatechannelmetadata]

#### Description [#description-25]

The `updateChannelMetadata` method can update existing channel metadata. Each time you call this method, you can update one channel metadata or an array of channel metadata items.

After successfully updating, users who subscribe to the channel and enable event listeners can receive the `storage` event notification with the `CHANNEL` type. For details, see [Event Listener](#event-listeners).

<CalloutContainer type="info">
  <CalloutTitle>
    Information
  </CalloutTitle>

  <CalloutDescription>
    You cannot use this method to update metadata items which do not exist.
  </CalloutDescription>
</CalloutContainer>

#### Method [#method-24]

You can call the `updateChannelMetadata` method as follows:

```javascript
rtm.storage.updateChannelMetadata(
    channelName: string,
    channelType: string,
    data: Array<object>,
    options?: object
): Promise<UpdateChannelMetadataResponse>;
```

|   Parameter   |          Type         | Required | Default | Description                                                                                                                                                            |
| :-----------: | :-------------------: | :------: | :-----: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `channelName` |         string        | Required |    -    | Channel name.                                                                                                                                                          |
| `channelType` |         string        | Required |    -    | Channel type. For details, see [Channel Types](#channel-types).                                                                                                        |
|     `data`    | Array\&lt;object\&gt; | Required |    -    | An array of metadata items. A metadata item is a JSON object that includes predefined properties. You cannot set properties other than predefined ones in this object. |
|   `options`   |         object        | Optional |    -    | Options for setting metadata.                                                                                                                                          |

`data` contains the following properties:

|  Property  |  Type  | Required |      Default      | Description                                                                                                                                                                                                                                                                                      |
| :--------: | :----: | :------: | :---------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|    `key`   | string | Required |         -         | The `key` of the metadata item.                                                                                                                                                                                                                                                                  |
|   `value`  | string | Optional | Empty string `''` | The `value` of the metadata item.                                                                                                                                                                                                                                                                |
| `revision` | number | Optional |        `-1`       | <br />- Returns the real version number in read operations.<br />- Serves as a version control switch in write operations:<br />- `-1`: Disable the version verification. <br />- > `0`: Enable the version verification. Only operations that match the target version number can be performed. |

`options` contains the following properties:

|     Property    |   Type  | Required |      Default      | Description                                                                                                                                                                                    |
| :-------------: | :-----: | :------: | :---------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `majorRevision` |  number | Optional |        `-1`       | A version control switch:<br />- `-1`: Disable the version verification.<br />- > `0`: Enable the version verification. Only operations that match the target version number can be performed. |
|    `lockName`   |  string | Optional | Empty string `''` | The name of the lock. If set, only users who call the `acquireLock` method to acquire the lock can perform operations.                                                                         |
|  `addTimeStamp` | boolean | Optional |      `false`      | Whether to record the timestamp of the edit.                                                                                                                                                   |
|   `addUserId`   | boolean | Optional |      `false`      | Whether to record the ID of the editor.                                                                                                                                                        |

#### Basic usage [#basic-usage-24]

```javascript
const data = [
    {
        key : "Apple",
        value : "120",
        revision : 174298200
    },
    {
        key : "Banana",
        value : "220",
        revision : 174298100
    }
];
const options = {
    majorRevision : 174298270,
    addTimeStamp : true,
    addUserId : true
};
try {
    const result = await rtm.storage.updateChannelMetadata("channel_name", "MESSAGE", data, options);
    console.log(result);
} catch (status) {
    console.log(status);
}
```

#### Return value [#return-value-23]

If the method call succeeds, the `UpdateChannelMetadataResponse` response as follows is returned:

```javascript
type UpdateChannelMetadataResponse = {
    timestamp: number , // Timestamp of the successful operation.
    channelName : string , // Channel name.
    channelType : string , // Channel type.
    totalCount : number // Number of metadata items.
}
```

If the method call fails, the `ErrorInfo` response as follows is returned:

```javascript
type ErrorInfo = {
    error: boolean; // Whether there is an error in this operation
    operation: string; // The API name of this operation
    errorCode: number; // Error code.
    reason: string; // Error reason.
}
```

To find out the cause of the error and get the corresponding solution, use the `errorCode` field with the [error codes table](#error-codes-table).

### setUserMetadata [#setusermetadata]

#### Description [#description-26]

The `setUserMetadata` method sets metadata for a user. A user can only have one set of metadata, but each set of metadata can have one or more metadata items. If you call this method multiple times, the SDK retrieves the `key` of the metadata items in turn and apply settings according to the following rules:

* If you set metadata with different `key`, the SDK adds each set of metadata in sequence according to the order of the method calls.
* If you set metadata with the same `key`, the `value` of the last setting overwrites the previous one.

After successfully setting user metadata, users who subscribe to the user metadata and enable event listeners can receive the `storage` event notification with the `USER` type. For details, see [Event Listener](#event-listeners).

User metadata also introduces the version control logic CAS (Compare And Set). This method provides two independent version control fields, and you can set one or more of them according to your actual business use-case:

* Enable version number verification for the entire set of user metadata by setting the `majorRevision` property in the `options` parameter.
* Enable version number verification for a single metadata item by setting the `revision` property in the `data` parameter.

When setting user metadata or metadata items, you can control whether to enable version number verification by specifying the revision property:

* The default value of the revision property is `-1`, indicating that no CAS verification is performed for this method call. If the user metadata or metadata item already exists, the latest value overwrites the previous one. If the user metadata or metadata item does not exist, the SDK creates it.
* If the revision property is a positive integer, CAS verification is performed for this method call. If the user metadata or metadata item already exists, the SDK updates the corresponding value after the version number verification succeeds. If the user metadata or metadata item does not exist, the SDK returns the error code.

#### Method [#method-25]

You can call the `setUserMetadata` method as follows:

```javascript
rtm.storage.setUserMetadata(
    data: Array<object>,
    options?: object
): Promise<SetUserMetadataResponse>;
```

| Parameter |          Type         | Required | Default | Description                                                                                                                                                            |
| :-------: | :-------------------: | :------: | :-----: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|   `data`  | Array\&lt;object\&gt; | Required |    -    | An array of metadata items. A metadata item is a JSON object that includes predefined properties. You cannot set properties other than predefined ones in this object. |
| `options` |         object        | Optional |    -    | Options for setting metadata.                                                                                                                                          |

`data` contains the following properties:

|  Property  |  Type  | Required |      Default      | Description                                                                                                                                                                                                                                                                                      |
| :--------: | :----: | :------: | :---------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|    `key`   | string | Required |         -         | The `key` of the metadata item.                                                                                                                                                                                                                                                                  |
|   `value`  | string | Optional | Empty string `''` | The `value` of the metadata item.                                                                                                                                                                                                                                                                |
| `revision` | number | Optional |        `-1`       | <br />- Returns the real version number in read operations.<br />- Serves as a version control switch in write operations:<br />- `-1`: Disable the version verification. <br />- > `0`: Enable the version verification. Only operations that match the target version number can be performed. |

`options` contains the following properties:

|     Property    |   Type  | Required |              Default              | Description                                                                                                                                                                                    |
| :-------------: | :-----: | :------: | :-------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|     `userId`    |  string | Optional | The `userId` of the current user. | The user ID.                                                                                                                                                                                   |
| `majorRevision` |  number | Optional |                `-1`               | A version control switch:<br />- `-1`: Disable the version verification.<br />- > `0`: Enable the version verification. Only operations that match the target version number can be performed. |
|    `lockName`   |  string | Optional |         Empty string `''`         | The name of the lock. If set, only users who call the `acquireLock` method to acquire the lock can perform operations.                                                                         |
|  `addTimeStamp` | boolean | Optional |              `false`              | Whether to record the timestamp of the edit.                                                                                                                                                   |
|   `addUserId`   | boolean | Optional |              `false`              | Whether to record the ID of the editor.                                                                                                                                                        |

#### Basic usage [#basic-usage-25]

```javascript
const data = [
    {
        key : "Name",
        value : "Tony"
        revision : 174298200
    },
    {
        key : "Mute",
        value : "true",
        revision : 174298100
    }
];
const options = {
    userId : "Tony",
    majorRevision : 174298270,
    addTimeStamp : ture，
    addUserId : true
};
try {
    const result = await rtm.storage.setUserMetadata(data, options);
    console.log(result);
} catch (status) {
    console.log(status);
}
```

#### Return value [#return-value-24]

If the method call succeeds, the `SetUserMetadataResponse` response as follows is returned:

```javascript
type SetUserMetadataResponse = {
    timestamp: number , // Timestamp of the successful operation.
    userId : string , // User ID.
    totalCount : number // Number of metadata items.
}
```

If the method call fails, the `ErrorInfo` response as follows is returned:

```javascript
type ErrorInfo = {
    error: boolean; // Whether there is an error in this operation
    operation: string; // The API name of this operation
    errorCode: number; // Error code.
    reason: string; // Error reason.
}
```

To find out the cause of the error and get the corresponding solution, use the `errorCode` field with the [error codes table](#error-codes-table).

### getUserMetadata [#getusermetadata]

#### Description [#description-27]

`getUserMetadata` 方法可以获取指定用户的 Metadata 和 User Metadata Item。

#### Method [#method-26]

You can call the `getUserMetadata` method as follows:

```javascript
rtm.storage.getUserMetadata(options?: object): Promise<GetUserMetadataResponse>;
```

| Parameter |  Type  | Required |              Default              | Description  |
| :-------: | :----: | :------: | :-------------------------------: | :----------- |
|  `userId` | string | Optional | The `userId` of the current user. | The user ID. |

#### Basic usage [#basic-usage-26]

```javascript
try {
    const result = await rtm.storage.getUserMetadata({ userId: "Tony" });
    console.log(result);
} catch (status) {
    console.log(status);
}
```

#### Return value [#return-value-25]

If the method call succeeds, the `GetChannelMetadataResponse` response as follows is returned:

```javascript
type GetChannelMetadataResponse = {
    timestamp: number , // Timestamp of the successful operation.
    userId : string , // User ID.
    totalCount : number , // Number of metadata items.
    majorRevision : number , // Version of metadata.
    metadata : Record<string, MetaDataDetail> // JSON object containing metadata item.
}
```

`MetaDataDetail` contains the following properties:

```javascript
type MetaDataDetail = {
    value: string , // Value of a metadata item.
    revision : number , // Version of a metadata item.
    updated : string , // Timestamp of the last update.
    authorUid : string , // User ID of the last editor.
}
```

If the method call fails, the `ErrorInfo` response as follows is returned:

```javascript
type ErrorInfo = {
    error: boolean; // Whether there is an error in this operation
    operation: string; // The API name of this operation
    errorCode: number; // Error code.
    reason: string; // Error reason.
}
```

To find out the cause of the error and get the corresponding solution, use the `errorCode` field with the [error codes table](#error-codes-table).

### removeUserMetadata [#removeusermetadata]

#### Description [#description-28]

Call the `removeUserMetadata` method to remove user metadata or metadata items.

After successfully removing user metadata or metadata items, users who subscribe to the user metadata and enable event listeners can receive the `storage` event notification with the `USER` type. For details, see [Event Listener](#event-listeners).

#### Method [#method-27]

You can call the `removeUserMetadata` method as follows:

```javascript
rtm.storage.removeUserMetadata(
    options?: object
): Promise<RemoveUserMetadataResponse>;
```

| Parameter |  Type  | Required | Default | Description                   |
| :-------: | :----: | :------: | :-----: | :---------------------------- |
| `options` | object | Optional |    -    | Options for setting metadata. |

`options` contains the following properties:

|     Property    |          Type         | Required |              Default              | Description                                                                                                                                                                                    |
| :-------------: | :-------------------: | :------: | :-------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|     `userId`    |         string        | Optional | The `userId` of the current user. | The user ID.                                                                                                                                                                                   |
|      `data`     | Array\&lt;object\&gt; | Required |                 -                 | An array of metadata items. A metadata item is a JSON object that includes predefined properties. You cannot set properties other than predefined ones in this object.                         |
| `majorRevision` |         number        | Optional |                `-1`               | A version control switch:<br />- `-1`: Disable the version verification.<br />- > `0`: Enable the version verification. Only operations that match the target version number can be performed. |
|    `lockName`   |         string        | Optional |         Empty string `''`         | The name of the lock. If set, only users who call the `acquireLock` method to acquire the lock can perform operations.                                                                         |
|  `addTimeStamp` |        boolean        | Optional |              `false`              | Whether to record the timestamp of the edit.                                                                                                                                                   |
|   `addUserId`   |        boolean        | Optional |              `false`              | Whether to record the ID of the editor.                                                                                                                                                        |

`data` contains the following properties:

|  Property  |  Type  | Required |      Default      | Description                                                                                                                                                                                                                                                                                      |
| :--------: | :----: | :------: | :---------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|    `key`   | string | Required |         -         | The `key` of the metadata item.                                                                                                                                                                                                                                                                  |
|   `value`  | string | Optional | Empty string `''` | The `value` of the metadata item.                                                                                                                                                                                                                                                                |
| `revision` | number | Optional |        `-1`       | <br />- Returns the real version number in read operations.<br />- Serves as a version control switch in write operations:<br />- `-1`: Disable the version verification. <br />- > `0`: Enable the version verification. Only operations that match the target version number can be performed. |

#### Basic usage [#basic-usage-27]

```javascript
const data = [
    {
        key : "Mute",
        revision : 174298100
    }
];
const options = {
    userId: "Tony",
    data : data,
    majorRevision : 174298270
};
try {
    const result = await rtm.storage.removeUserMetadata(options);
    console.log(result);
} catch (status) {
    console.log(status);
}
```

#### Return value [#return-value-26]

If the method call succeeds, the `RemoveUserMetadataResponse` response as follows is returned:

```javascript
type RemoveUserMetadataResponse = {
    timestamp: number , // Timestamp of the successful operation.
    userId : string , // User ID.
    totalCount : number // Number of metadata items.
}
```

If the method call fails, the `ErrorInfo` response as follows is returned:

```javascript
type ErrorInfo = {
    error: boolean; // Whether there is an error in this operation
    operation: string; // The API name of this operation
    errorCode: number; // Error code.
    reason: string; // Error reason.
}
```

To find out the cause of the error and get the corresponding solution, use the `errorCode` field with the [error codes table](#error-codes-table).

### updateUserMetadata [#updateusermetadata]

#### Description [#description-29]

The `updateUserMetadata` method can update existing user metadata. Each time you call this method, you can update one user metadata or an array of user metadata items.

After successfully updating, users who subscribe to the user metadata and enable event listeners can receive the `storage` event notification with the `USER` type. For details, see [Event Listener](#event-listeners).

<CalloutContainer type="info">
  <CalloutTitle>
    Information
  </CalloutTitle>

  <CalloutDescription>
    You cannot use this method to update metadata items which do not exist.
  </CalloutDescription>
</CalloutContainer>

#### Method [#method-28]

You can call the `updateUserMetadata` method as follows:

```javascript
rtm.storage.updateUserMetadata(
    data: Array<object>,
    options?: object
): Promise<UpdateUserMetadataResponse>;
```

| Parameter |          Type         | Required | Default | Description                                                                                                                                                            |
| :-------: | :-------------------: | :------: | :-----: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|   `data`  | Array\&lt;object\&gt; | Required |    -    | An array of metadata items. A metadata item is a JSON object that includes predefined properties. You cannot set properties other than predefined ones in this object. |
| `options` |         object        | Optional |    -    | Options for setting metadata.                                                                                                                                          |

`data` contains the following properties:

|  Property  |  Type  | Required |      Default      | Description                                                                                                                                                                                                                                                                                      |
| :--------: | :----: | :------: | :---------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|    `key`   | string | Required |         -         | The `key` of the metadata item.                                                                                                                                                                                                                                                                  |
|   `value`  | string | Optional | Empty string `''` | The `value` of the metadata item.                                                                                                                                                                                                                                                                |
| `revision` | number | Optional |        `-1`       | <br />- Returns the real version number in read operations.<br />- Serves as a version control switch in write operations:<br />- `-1`: Disable the version verification. <br />- > `0`: Enable the version verification. Only operations that match the target version number can be performed. |

`options` contains the following properties:

|     Property    |   Type  | Required |              Default              | Description                                                                                                                                                                                    |
| :-------------: | :-----: | :------: | :-------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|     `userId`    |  string | Optional | The `userId` of the current user. | The user ID.                                                                                                                                                                                   |
| `majorRevision` |  number | Optional |                `-1`               | A version control switch:<br />- `-1`: Disable the version verification.<br />- > `0`: Enable the version verification. Only operations that match the target version number can be performed. |
|    `lockName`   |  string | Optional |         Empty string `''`         | The name of the lock. If set, only users who call the `acquireLock` method to acquire the lock can perform operations.                                                                         |
|  `addTimeStamp` | boolean | Optional |              `false`              | Whether to record the timestamp of the edit.                                                                                                                                                   |
|   `addUserId`   | boolean | Optional |              `false`              | Whether to record the ID of the editor.                                                                                                                                                        |

#### Basic usage [#basic-usage-28]

```javascript
const data = [
    {
        key : "Mute",
        value : "false",
        revision : 174298100
    }
];
const options = {
    userId : "Tony",
    majorRevision : 174298270,
    addTimeStamp : true,
    addUserId : true
};
try {
    const result = await rtm.storage.updateUserMetadata(data, options);
    console.log(result);
} catch (status) {
    console.log(status);
}
```

#### Return value [#return-value-27]

If the method call succeeds, the `UpdateUserMetadataResponse` response as follows is returned:

```javascript
type UpdateUserMetadataResponse = {
    timestamp: number , // Timestamp of the successful operation.
    userId : string , // User ID.
    totalCount : number // Number of metadata items.
}
```

If the method call fails, the `ErrorInfo` response as follows is returned:

```javascript
type ErrorInfo = {
    error: boolean; // Whether there is an error in this operation
    operation: string; // The API name of this operation
    errorCode: number; // Error code.
    reason: string; // Error reason.
}
```

To find out the cause of the error and get the corresponding solution, use the `errorCode` field with the [error codes table](#error-codes-table).

### subscribeUserMetadata [#subscribeusermetadata]

#### Description [#description-30]

The `subscribeUserMetadata` method can subscribe to metadata for a specified user. After successfully subscribing and enabling event listeners, you can receive the `storage` event notification with the `USER` type when the metadata for that user changes. For details, see [Event Listener](#event-listeners).

#### Method [#method-29]

You can call the `subscribeUserMetadata` method as follows:

```javascript
rtm.storage.subscribeUserMetadata(userId: string): Promise<SubscribeUserMetaResponse>;
```

| Parameter |  Type  | Required |              Default              | Description  |
| :-------: | :----: | :------: | :-------------------------------: | :----------- |
|  `userId` | string | Optional | The `userId` of the current user. | The user ID. |

#### Basic usage [#basic-usage-29]

```javascript
try {
    const result = await rtm.storage.subscribeUserMetadata("Tony");
    console.log(result);
} catch (status) {
    console.log(status);
}
```

#### Return value [#return-value-28]

If the method call succeeds, the `SubscribeUserMetaResponse` response as follows is returned:

```javascript
type SubscribeUserMetaResponse = {
    timestamp: number , // Timestamp of the successful operation.
    userId : string , // User ID.
}
```

### unsubscribeUserMetadata [#unsubscribeusermetadata]

#### Description [#description-31]

If you do not need to receive notifications of changes to a user metadata, call the `unsubscribeUserMetadata` method to unsubscribe.

#### Method [#method-30]

You can call the `unsubscribeUserMetadata` method as follows:

```javascript
rtm.storage.unsubscribeUserMetadata(userId: string): Promise<UnsubscribeUserMetaResponse>;
```

| Parameter |  Type  | Required |              Default              | Description  |
| :-------: | :----: | :------: | :-------------------------------: | :----------- |
|  `userId` | string | Optional | The `userId` of the current user. | The user ID. |

#### Basic usage [#basic-usage-30]

```javascript
try {
    const result = await rtm.storage.unsubscribeUserMetadata("Tony");
    console.log("result");
} catch (status) {
    console.log(status);
}
```

#### Return value [#return-value-29]

If the method call succeeds, the `UnsubscribeUserMetaResponse` response as follows is returned:

```javascript
type UnsubscribeUserMetaResponse = {
    timestamp: number , // Timestamp of the successful operation.
    userId : string , // User ID.
}
```

## Lock [#lock]

A critical resource can only be used by one process at a time. If a critical resource is shared between different processes, each process needs to adopt a mutually exclusive method to prevent mutual interference. Signaling provides a full set of lock solutions. By controlling different processes in a distributed system, you can solve the competition problem when users access shared resources.

<CalloutContainer type="success">
  <CalloutTitle>
    Prompt
  </CalloutTitle>

  <CalloutDescription>
    The client is able to set, remove, and revoke locks. We recommend that you control the permissions of the these operations on the client side based on your business needs.
  </CalloutDescription>
</CalloutContainer>

### setLock [#setlock]

#### Description [#description-32]

You need to configure the lock name, time to live (TTL) and other parameters by calling the `setLock` method. If the configuration succeeds, all users in the channel receives the `lock` event notifications of the `SET` type. For details, see [Event Listeners](#event-listeners).

#### Method [#method-31]

You can call the `setLock` method as follows:

```javascript
rtm.lock.setLock(
    channelName: string,
    channelType: string,
    lockName: string,
    options?: object
): Promise<SetLockResponse>;
```

|   Parameter   |  Type  | Required | Default | Description                                                     |
| :-----------: | :----: | :------: | :-----: | :-------------------------------------------------------------- |
| `channelName` | string | Required |    -    | Channel name.                                                   |
| `channelType` | string | Required |    -    | Channel type. For details, see [Channel Types](#channel-types). |
|   `lockName`  | string | Required |    -    | Lock name.                                                      |
|   `options`   | object | Optional |    -    | Options for setting locks.                                      |

`options` contains the following properties:

| Property |  Type  | Required | Default | Description                                                                                                                                                                                                                                                                                                       |
| :------: | :----: | :------: | :-----: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|   `ttl`  | number | Optional |   `10`  | Time to live in seconds of the lock, and the value range is \[10,300]. When the user who owns the lock goes offline, if the user returns to the channel within the time they can still use the lock; otherwise, the lock is released and the users who listen for the `lock` event receives the `RELEASED` event. |

#### Basic Usage [#basic-usage-31]

```javascript
try{
    const result = await rtm.Lock.setLock(
        channel:"my_channel",
        channelType:"STREAM",
        lockName: "my_lock",
        { ttl: 30 }
    );
    console.log(result);
} catch (status) {
    console.log(status);
}
```

#### Return Value [#return-value-30]

If the method call succeeds, the `SetLockResponse` response as follows is returned:

```javascript
type SetLockResponse = {
    timestamp: number , // Timestamp of the successful operation.
    channelName : string , // Channel name.
    channelType : string , // Channel type.
    lockName : string // Lock name.
}
```

If the method call fails, the `ErrorInfo` response as follows is returned:

```javascript
type ErrorInfo = {
    error: boolean; // Whether there is an error in this operation
    operation: string; // The API name of this operation
    errorCode: number; // Error code.
    reason: string; // Error reason.
}
```

To find out the cause of the error and get the corresponding solution, use the `errorCode` field with the [error codes table](#error-codes-table).

### acquireLock [#acquirelock]

#### Description [#description-33]

After setting a lock, you can call the `acquireLock` method on the client to acquire the right to own the lock. When you acquire the lock, other users in the channel receives the `lock` event of the `ACQUIRED` type. For details, see [Event Listener](#event-listeners).

#### Method [#method-32]

You can call the `acquireLock` method as follows:

```javascript
rtm.lock.acquireLock(
    channelName: string,
    channelType: string,
    lockName: string,
    options?: object
): Promise<AcquireLockResponse>;
```

|   Parameter   |  Type  | Required | Default | Description                                                     |
| :-----------: | :----: | :------: | :-----: | :-------------------------------------------------------------- |
| `channelName` | string | Required |    -    | Channel name.                                                   |
| `channelType` | string | Required |    -    | Channel type. For details, see [Channel Types](#channel-types). |
|   `lockName`  | string | Required |    -    | Lock name.                                                      |
|   `options`   | object | Optional |    -    | Options for setting locks.                                      |

`options` contains the following properties:

| Property |   Type  | Required | Default | Description                                                                                                    |
| :------: | :-----: | :------: | :-----: | :------------------------------------------------------------------------------------------------------------- |
|  `retry` | boolean | Optional | `false` | If the lock acquisition fails, whether to retry until the acquisition succeeds or the user leaves the channel. |

#### Basic Usage [#basic-usage-32]

```javascript
try{
    const result = await rtm.Lock.acquireLock(
        "chat_room",
        "STREAM",
        "my_lock",
        {retry:false}
    );
    console.log(result);
} catch (status) {
    console.log(status);
}
```

#### Return Value [#return-value-31]

If the method call succeeds, the `AcquireLockResponse` response as follows is returned:

```javascript
type AcquireLockResponse = {
    timestamp: number , // Timestamp of the successful operation.
    channelName : string , // Channel name.
    channelType : string , // Channel type.
    lockName : string // Lock name.
}
```

If the method call fails, the `ErrorInfo` response as follows is returned:

```javascript
type ErrorInfo = {
    error: boolean; // Whether there is an error in this operation
    operation: string; // The API name of this operation
    errorCode: number; // Error code.
    reason: string; // Error reason.
}
```

To find out the cause of the error and get the corresponding solution, use the `errorCode` field with the [error codes table](#error-codes-table).

### releaseLock [#releaselock]

#### Description [#description-34]

When a user no longer needs to own a lock, the user can call the `releaseLock` method on the client side to release the lock. When the lock is released, other users in the channel receives the `lock` event of `RELEASED` type. For details, see [Event Listeners](#event-listeners).

At this time, if other users want to acquire the lock, they can call the `acquireLock` method on the client side to compete. New users acquiring locks have the same contention priority as the users who set the `retry` property to automatically retry to acquire locks.

#### Method [#method-33]

You can call the `acquireLock` method as follows:

```javascript
rtm.lock.releaseLock(
    channelName: string,
    channelType: string,
    lockName: string
): Promise<ReleaseLockResponse>;
```

|    Property   |  Type  | Required | Default | Description                                                     |
| :-----------: | :----: | :------: | :-----: | :-------------------------------------------------------------- |
| `channelName` | string | Required |    -    | Channel name.                                                   |
| `channelType` | string | Required |    -    | Channel type. For details, see [Channel Types](#channel-types). |
|   `lockName`  | string | Required |    -    | Lock name.                                                      |

#### Basic Usage [#basic-usage-33]

```javascript
try{
    const result = await rtm.lock.releaseLock(
        "chat_room",
        "STREAM",
        "my_lock"
    );
    console.log(result);
} catch (status) {
    console.log(status);
}
```

#### Return Value [#return-value-32]

If the method call succeeds, the `ReleaseLockResponse` response as follows is returned:

```javascript
type ReleaseLockResponse = {
    timestamp: number , // Timestamp of the successful operation.
    channelName : string , // Channel name.
    channelType : string , // Channel type.
    lockName : string // Lock name.
}
```

If the method call fails, the `ErrorInfo` response as follows is returned:

```javascript
type ErrorInfo = {
    error: boolean; // Whether there is an error in this operation
    operation: string; // The API name of this operation
    errorCode: number; // Error code.
    reason: string; // Error reason.
}
```

To find out the cause of the error and get the corresponding solution, use the `errorCode` field with the [error codes table](#error-codes-table).

### revokeLock [#revokelock]

#### Description [#description-35]

You may need to take back a lock owned by another user and allow the other users to acquire the lock. You can call the `revokeLock` method to revoke the lock. When the lock is revoked, all users in the channel receives the `lock` event of the `RELEASED` type. For details, see [Event Listeners](#event-listeners).

At this time, if other users want to acquire the lock, they can call the `acquireLock` method on the client side to compete. New users acquiring locks have the same contention priority as the users who set the `retry` property to automatically retry to acquire locks.

#### Method [#method-34]

You can call the `revokeLock` method as follows:

```javascript
rtm.lock.revokeLock(
    channelName: string,
    channelType: string,
    lockName: string,
    owner: string
): Promise<RevokeLockResponse>;
```

|    Property   |  Type  | Required | Default | Description                                                     |
| :-----------: | :----: | :------: | :-----: | :-------------------------------------------------------------- |
| `channelName` | string | Required |    -    | Channel name.                                                   |
| `channelType` | string | Required |    -    | Channel type. For details, see [Channel Types](#channel-types). |
|   `lockName`  | string | Required |    -    | Lock name.                                                      |
|    `owner`    | string | Required |    -    | User ID of the lock owner.                                      |

#### Basic Usage [#basic-usage-34]

```javascript
try{
    const result = await rtm.lock.revokeLockLock(
        "chat_room",
        "STREAM",
        "my_lock",
        "Tony"
    );
    console.log(result);
} catch (status) {
    console.log(status);
}
```

#### Return Value [#return-value-33]

If the method call succeeds, the `RevokeLockResponse` response as follows is returned:

```javascript
type RevokeLockResponse = {
    timestamp: number , // Timestamp of the successful operation.
    channelName : string , // Channel name.
    channelType : string , // Channel type.
    lockName : string // Lock name.
}
```

If the method call fails, the `ErrorInfo` response as follows is returned:

```javascript
type ErrorInfo = {
    error: boolean; // Whether there is an error in this operation
    operation: string; // The API name of this operation
    errorCode: number; // Error code.
    reason: string; // Error reason.
}
```

To find out the cause of the error and get the corresponding solution, use the `errorCode` field with the [error codes table](#error-codes-table).

### getMessages [#getmessages]

#### Description [#description-36]

If you want to query the lock information such as lock total number, lock name, and lock user, time to live, you can call the `getMessages` method on the client.

#### Method [#method-35]

You can call the `getMessages` method as follows:

```javascript
rtm.lock.getLock(
    channelName: string,
    channelType: string
): Promise<GetLockResponse>;
```

|    Property   |  Type  | Required | Default | Description                                                     |
| :-----------: | :----: | :------: | :-----: | :-------------------------------------------------------------- |
| `channelName` | string | Required |    -    | Channel name.                                                   |
| `channelType` | string | Required |    -    | Channel type. For details, see [Channel Types](#channel-types). |

#### Basic Usage [#basic-usage-35]

```javascript
try{
    const result = await rtm.lock.getLock("chat_room","STREAM");
    console.log(result);
} catch (status) {
    console.log(status);
}
```

#### Return Value [#return-value-34]

If the method call succeeds, the `GetLockResponse` response as follows is returned:

```javascript
type GetLockResponse = {
    timestamp: number , // Timestamp of the successful operation.
    channelName : string , // Channel name.
    channelType : string , // Channel type.
    totalLocks : string, // Total lock number.
    lockDetails : [{
         lockName: string, // Lock name.
         owner: string, // Lock owner.
         ttl: number // Time to live in seconds of the lock.
     }]
}
```

If the method call fails, the `ErrorInfo` response as follows is returned:

```javascript
type ErrorInfo = {
    error: boolean; // Whether there is an error in this operation
    operation: string; // The API name of this operation
    errorCode: number; // Error code.
    reason: string; // Error reason.
}
```

To find out the cause of the error and get the corresponding solution, use the `errorCode` field with the [error codes table](#error-codes-table).

### removeLock [#removelock]

#### Description [#description-37]

If you no longer need a lock, you can remove the lock by calling the `removeLock` method. When the lock is successfully removed, all the users in the channel receives the `lock` event notification in the `REMOVED` type. For details, see [Event Handlers](#setup#eventhandlers).

#### Method [#method-36]

You can call the `removeLock` method as follows:

```javascript
rtm.lock.removeLock(
    channelName: string,
    channelType: string,
    lockName: string
): Promise<RemoveLockResponse>;
```

|    Property   |  Type  | Required | Default | Description                                                     |
| :-----------: | :----: | :------: | :-----: | :-------------------------------------------------------------- |
| `channelName` | string | Required |    -    | Channel name.                                                   |
| `channelType` | string | Required |    -    | Channel type. For details, see [Channel Types](#channel-types). |
|   `lockName`  | string | Required |    -    | Lock name.                                                      |

#### Basic Usage [#basic-usage-36]

```javascript
try{
    const result = await rtm.Lock.removeLockLock(
        "chat_room",
        "STREAM",
        "my_lock"
    );
    console.log(result);
} catch (status) {
    console.log(status);
}
```

#### Return Value [#return-value-35]

If the method call succeeds, the `RemoveLockResponse` response as follows is returned:

```javascript
type RemoveLockResponse = {
    timestamp: number , // Timestamp of the successful operation.
    channelName : string , // Channel name.
    channelType : string , // Channel type.
    lockName : string, // Lock name.
}
```

If the method call fails, the `ErrorInfo` response as follows is returned:

```javascript
type ErrorInfo = {
    error: boolean; // Whether there is an error in this operation
    operation: string; // The API name of this operation
    errorCode: number; // Error code.
    reason: string; // Error reason.
}
```

To find out the cause of the error and get the corresponding solution, use the `errorCode` field with the [error codes table](#error-codes-table).

## Enumerated types [#enumerated-types]

### Channel Types [#channel-types]

| Value     | Description      |
| :-------- | :--------------- |
| `MESSAGE` | Message channel. |
| `STREAM`  | Stream channel.  |
| `USER`    | User channel.    |

### SDK Link State Types [#sdk-link-state-types]

| Value          | Description                                             |
| :------------- | :------------------------------------------------------ |
| `IDLE`         | The initial state.                                      |
| `CONNECTING`   | The SDK is trying to connect with the Signaling system. |
| `CONNECTED`    | The SDK connects with the Signaling system.             |
| `DISCONNECTED` | The SDK disconnects with the Signaling system.          |
| `SUSPENDED`    | The SDK suspends the connecting task.                   |
| `FAILED`       | The SDK fails to connect with the Signaling system.     |

### SDK Link State Change Reasons [#sdk-link-state-change-reasons]

| Value                                | Description                          |
| :----------------------------------- | :----------------------------------- |
| `UNKNOWN`                            | Unknown reason.                      |
| `LOGIN`                              | Logging in.                          |
| `LOGIN_SUCCESS`                      | Login successful.                    |
| `LOGIN_TIMEOUT`                      | Login timeout.                       |
| `LOGIN_NOT_AUTHORIZED`               | Login not authorized.                |
| `LOGIN_REJECTED`                     | Login rejected.                      |
| `RELOGIN`                            | Re-login.                            |
| `LOGOUT`                             | Logout.                              |
| `AUTO_RECONNECT`                     | Auto-reconnect.                      |
| `RECONNECT_TIMEOUT`                  | Reconnect timeout.                   |
| `RECONNECT_SUCCESS`                  | Reconnect successful.                |
| `JOIN`                               | Joining a channel.                   |
| `JOIN_SUCCESS`                       | Join channel successful.             |
| `JOIN_FAILED`                        | Join channel failed.                 |
| `REJOIN`                             | Re-join a channel.                   |
| `LEAVE`                              | Leave a channel.                     |
| `INVALID_TOKEN`                      | Invalid token.                       |
| `TOKEN_EXPIRED`                      | Token expired.                       |
| `INCONSISTENT_APP_ID`                | Inconsistent App ID.                 |
| `INVALID_CHANNEL_NAME`               | Invalid channel name.                |
| `INVALID_USER_ID`                    | Invalid user ID.                     |
| `NOT_INITIALIZED`                    | SDK not initialized.                 |
| `RTM_SERVICE_NOT_CONNECTED`          | RTM service not connected.           |
| `CHANNEL_INSTANCE_EXCEED_LIMITATION` | Channel instance exceeds the limit.  |
| `OPERATION_RATE_EXCEED_LIMITATION`   | Operation rate exceeds the limit.    |
| `CHANNEL_IN_ERROR_STATE`             | Channel in error state.              |
| `PRESENCE_NOT_CONNECTED`             | Presence service not connected.      |
| `SAME_UID_LOGIN`                     | Same user ID login.                  |
| `KICKED_OUT_BY_SERVER`               | Kicked out by server.                |
| `KEEP_ALIVE_TIMEOUT`                 | Keepalive timeout.                   |
| `CONNECTION_ERROR`                   | Connection error.                    |
| `PRESENCE_NOT_READY`                 | Presence service not ready.          |
| `NETWORK_CHANGE`                     | Network changed.                     |
| `SERVICE_NOT_SUPPORTED`              | Service not supported.               |
| `STREAM_CHANNEL_NOT_AVAILABLE`       | Stream Channel not available.        |
| `STORAGE_NOT_AVAILABLE`              | Storage not available.               |
| `LOCK_NOT_AVAILABLE`                 | Lock not available.                  |
| `LOGIN_TOO_FREQUENT`                 | The login operation is too frequent. |

### (Deprecated) Reasons for the SDK Connection State Change [#deprecated-reasons-for-the-sdk-connection-state-change]

| Value                | Description                                                               |
| :------------------- | :------------------------------------------------------------------------ |
| `CONNECTING`         | The SDK is connecting with the Signaling system.                          |
| `LOGIN_SUCCESS`      | The SDK logged in the Signaling system successfully.                      |
| `REJECTED_BY_SERVER` | The SDK is rejected by the server.                                        |
| `LOST`               | The SDK lost the connection with the Signaling system.                    |
| `INTERRUPTED`        | The connection was interrupted.                                           |
| `LOGOUT`             | The SDK logged out of the Signaling system.                               |
| `/`                  | The SDK is banned by the server.                                          |
| `SAME_UID_LOGIN`     | The same user ID was used to join the same channel on different devices.  |
| `TOKEN_EXPIRED`      | The used token expired. You need to request a new token from your server. |

### (Deprecated) SDK Connection States [#deprecated-sdk-connection-states]

| Value          | Description                                                      |
| :------------- | :--------------------------------------------------------------- |
| `DISCONNECTED` | The SDK has disconnected with the server.                        |
| `CONNECTING`   | The SDK is connecting with the server.                           |
| `CONNECTED`    | The SDK has connected with the server.                           |
| `RECONNECTING` | The connection is lost. The SDK is reconnecting with the server. |
| `FAILED`       | The SDK failed to connect with the server.                       |

### End-to-End Encryption Modes [#end-to-end-encryption-modes]

| Value         | Description       |
| :------------ | :---------------- |
| `NONE`        | No encryption.    |
| `AES_128_GCM` | AES-128-GCM mode. |
| `AES_256_GCM` | AES-256-GCM mode. |

### Lock Event Types [#lock-event-types]

| Value      | Description                                                |
| :--------- | :--------------------------------------------------------- |
| `SNAPSHOT` | The snapshot of the lock when the user joined the channel. |
| `SET`      | The lock is set.                                           |
| `REMOVED`  | he lock is removed.                                        |
| `ACQUIRED` | The lock is acquired.                                      |
| `RELEASED` | The lock is released.                                      |
| `EXPIRED`  | The lock expired.                                          |

### Log Output Levels [#log-output-levels]

| Value   | Description                                                                                     |
| :------ | :---------------------------------------------------------------------------------------------- |
| `none`  | No log.                                                                                         |
| `info`  | Output the log at the `error`, `warn`, or `info` level. Agora recommends you set to this value. |
| `warn`  | Output the log at the `error` or `warn` level.                                                  |
| `error` | Output the log at the `error` level.                                                            |
| `debug` | Output the log at all levels.                                                                   |

### Message Types [#message-types]

| Value    | Description  |
| :------- | :----------- |
| `BINARY` | Binary type. |
| `STRING` | String type. |

### Presence Event Types [#presence-event-types]

| Value                  | Description                                                                                                        |
| :--------------------- | :----------------------------------------------------------------------------------------------------------------- |
| `SNAPSHOT`             | When users joined a channel for the first time, they received a snapshot of the channel pushed by the server.      |
| `INTERVAL`             | When users in the channel reach the limit, the event notifications are sent at intervals rather than in real time. |
| `REMOTE_JOIN`          | A remote user joined the channel.                                                                                  |
| `REMOTE_LEAVE`         | A remote user left the channel.                                                                                    |
| `REMOTE_TIMEOUT`       | A remote user's connection timed out.                                                                              |
| `REMOTE_STATE_CHANGED` | A remote user's temporary state changed.                                                                           |
| `ERROR_OUT_OF_SERVICE` | The user did not enable presence when joining the channel.                                                         |

### Service Types [#service-types]

| Value     | Description                                                                                                 |
| :-------- | :---------------------------------------------------------------------------------------------------------- |
| `MESSAGE` | The foundational services comprise the message channel, user channel, presence, storage, and lock services. |
| `STREAM`  | The stream channel service.                                                                                 |

<CalloutContainer type="info">
  <CalloutTitle>
    Information
  </CalloutTitle>

  <CalloutDescription>
    To fully utilize all services offered by Signaling, you can employ bitwise operations to simultaneously configure two service types.
  </CalloutDescription>
</CalloutContainer>

### Storage Event Types [#storage-event-types]

| Value      | Description                                                                                                                                                     |
| :--------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `SNAPSHOT` | When a user subscribes to channel metadata or user etadata for the first time, or joins a channel, the local user receives notifications of this type of event. |
| `SET`      | Occurs when calling `setChannelMetadata` or `setUserMetadata`. This event only occurs in incremental data update mode.                                          |
| `UPDATE`   | Occurs when calling methods to set, update, or delete the channel metadata or user metadata.                                                                    |
| `REMOVE`   | Occurs when calling `removeChannelMetadata` or `removeUserMetadata`. This event only occurs in incremental data update mode.                                    |

### Storage Types [#storage-types]

| Value     | Description             |
| :-------- | :---------------------- |
| `USER`    | User metadata event.    |
| `CHANNEL` | Channel metadata event. |

### Topic Event Types [#topic-event-types]

| Value          | Description                                                 |
| :------------- | :---------------------------------------------------------- |
| `SNAPSHOT`     | The snapshot of the topic when the user joined the channel. |
| `REMOTE_JOIN`  | A remote user joined the channel.                           |
| `REMOTE_LEAVE` | A remote user left the channel.                             |

## Troubleshooting [#troubleshooting]

Refer to the following information for troubleshooting API calls.

### ErrorInfo [#errorinfo]

```javascript
type ErrorInfo = {
    error: boolean; // Whether there is an error in this operation
    operation: string; // The API name of this operation
    errorCode: number; // Error code.
    reason: string; // Error reason.
}
```

To find out the cause of the error and get the corresponding solution, use the `errorCode` field with the [error codes table](#error-codes-table).

### Error codes table [#error-codes-table]

Refer to the following error codes table to identify and troubleshoot the problem:

| Error code | Error description                                    | Cause and solution                                                                                                                                                                                                                                                                                                                                   |
| :--------- | :--------------------------------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `0`        | `RTM_ERROR_OK`                                       | Correct call                                                                                                                                                                                                                                                                                                                                         |
| `-10002`   | `RTM_ERROR_NOT_LOGIN`                                | The user called the API without logging in to Signaling, disconnected due to timeout, or actively logged out. Please log in to Signaling first.                                                                                                                                                                                                      |
| `-10003`   | `RTM_ERROR_INVALID_APP_ID`                           | Invalid App ID: <br /> - Check that the App ID is correct. <br /> - Ensure that Signaling has been activated for the App ID.                                                                                                                                                                                                                         |
| `-10005`   | `RTM_ERROR_INVALID_TOKEN`                            | Invalid Token: <br /> - The token is invalid, check whether the Token Provider generates a valid Signaling Token.                                                                                                                                                                                                                                    |
| `-10006`   | `RTM_ERROR_INVALID_USER_ID`                          | Invalid User ID: <br /> - Check if user ID is empty. <br /> - Check if the user ID contains illegal characters.                                                                                                                                                                                                                                      |
| `-10008`   | `RTM_ERROR_INVALID_CHANNEL_NAME`                     | Invalid channel name: <br /> - Check if the channel name is empty. <br /> - Check if the channel name contains illegal characters.                                                                                                                                                                                                                   |
| `-10009`   | `RTM_ERROR_TOKEN_EXPIRED`                            | Token expired. Call `renewToken` to reacquire the Token.                                                                                                                                                                                                                                                                                             |
| `-10010`   | `RTM_ERROR_LOGIN_NO_SERVER_RESOURCES`                | Server resources are limited. It is recommended to log in again.                                                                                                                                                                                                                                                                                     |
| `-10011`   | `RTM_ERROR_LOGIN_TIMEOUT`                            | Login timeout. Check whether the current network is stable and switch to a stable network environment.                                                                                                                                                                                                                                               |
| `-10012`   | `RTM_ERROR_LOGIN_REJECTED`                           | SDK login rejected by the server: <br /> - Check tha Signaling is activated on your App ID. <br /> - Check if the token or `userId` is banned.                                                                                                                                                                                                       |
| `-10013`   | `RTM_ERROR_LOGIN_ABORTED`                            | SDK login interrupted due to unknown problem: <br /> - Check that the current network is stable and switch to a stable network environment. <br /> - The current `userId` is logged in.                                                                                                                                                              |
| `-10015`   | `RTM_ERROR_LOGIN_NOT_AUTHORIZED`                     | No Signaling service permissions. Possible reasons include:<br />- Signaling is not enabled in Console. <br />- Service payment overdue. <br />- Account suspension.                                                                                                                                                                                 |
| `-10017`   | `RTM_ERROR_DUPLICATE_OPERATION`                      | Repeat the operation.                                                                                                                                                                                                                                                                                                                                |
| `-10018`   | `RTM_ERROR_INSTANCE_ALREADY_RELEASED`                | Repeat `rtm` instantiation or `RTMStreamChannel` instantiation.                                                                                                                                                                                                                                                                                      |
| `-10019`   | `RTM_ERROR_INVALID_CHANNEL_TYPE`                     | Invalid channel type. The SDK only supports the following channel types. Please use the correct value: <br /> - `MESSAGE`: Message Channel <br /> - `STREAM`: Stream Channel <br /> - `USER`: User Channel                                                                                                                                           |
| `-10020`   | `RTM_ERROR_INVALID_ENCRYPTION_PARAMETER`             | Message encryption parameters are invalid. <br />- Check that the encryption key generated is a String. <br />- Check that the generated encryption salt is `Uint8Array` type and that the length is 32 bytes. <br />- Check that the encryption method matches the encryption key and the encryption salt.                                          |
| `-10021`   | `RTM_ERROR_OPERATION_RATE_EXCEED_LIMITATION`         | Channel metadata or User Metadata -related API call frequency is exceeding the limit. Please control the call frequency within 10/second.                                                                                                                                                                                                            |
| `-10022`   | `RTM_ERROR_SERVICE_NOT_SUPPORTED`                    | The service type is not supported. Check whether the service type you set in `ServiceType` is correct. This error code is only applicable to the private deployment function.                                                                                                                                                                        |
| `-10023`   | `RTM_ERROR_LOGIN_CANCELED`                           | The login operation has been canceled. Possible reasons are as follows: <br />- After calling the `login` method, if you call the method again before receiving the call result, the previous call operation will be canceled and the SDK will execute the next call. <br />- Calling the `logout` method to log out before successfully logging in. |
| `-10025`   | `RTM_ERROR_NOT_CONNECTED`                            | Not connected to the Signaling server. When you call APIs related to message subscription, metadata, or the Lock module, this error is reported if the Signaling service is not connected.                                                                                                                                                           |
| `-10026`   | `RTM_ERROR_RENEW_TOKEN_TIMEOUT`                      | Token renewal timed out.                                                                                                                                                                                                                                                                                                                             |
| `-11001`   | `RTM_ERROR_CHANNEL_NOT_JOINED`                       | The user has not joined the channel: <br /> - The user is not online, offline or has not joined the channel<br /> - Check for typos in `userId`.                                                                                                                                                                                                     |
| `-11002`   | `RTM_ERROR_CHANNEL_NOT_SUBSCRIBED`                   | The user has not subscribed to the channel: <br /> - The user is not online, offline or has not joined the channel<br /> - Check for typos in `userId`.                                                                                                                                                                                              |
| `-11003`   | `RTM_ERROR_CHANNEL_EXCEED_TOPIC_USER_LIMITATION`     | The number of subscribers to this topic exceeds the limit.                                                                                                                                                                                                                                                                                           |
| `-11005`   | `RTM_ERROR_CHANNEL_INSTANCE_EXCEED_LIMITATION`       | The number of created or subscribed channels exceeds the limit. See [API usage limits](/en/realtime-media/rtm/reference/limitations) for details.                                                                                                                                                                                                    |
| `-11006`   | `RTM_ERROR_CHANNEL_IN_ERROR_STATE`                   | Channel is not available. Please recreate the Stream Channel or resubscribe to the Message Channel.                                                                                                                                                                                                                                                  |
| `-11007`   | `RTM_ERROR_CHANNEL_JOIN_FAILED`                      | Failed to join this channel: <br /> - Check if the number of joined channels exceeds the limit. <br /> - Check if the channel name is illegal. <br /> - Check if the network is disconnected.                                                                                                                                                        |
| `-11008`   | `RTM_ERROR_CHANNEL_INVALID_TOPIC_NAME`               | Invalid topic name: <br /> - Check whether the topic name contains illegal characters. <br /> - Check if the topic name is empty.                                                                                                                                                                                                                    |
| `-11009`   | `RTM_ERROR_CHANNEL_INVALID_MESSAGE`                  | Invalid message. Check whether the message type is legal, Signaling only supports `string`, `Uint8Array` type messages.                                                                                                                                                                                                                              |
| `-11010`   | `RTM_ERROR_CHANNEL_MESSAGE_LENGTH_EXCEED_LIMITATION` | Message length exceeded limit. Check if the message payload size exceeds the limit: <br /> - Message Channel single message package limit is 32 KB. <br /> - Stream Channel single message package limit is 1 KB.                                                                                                                                    |
| `-11012`   | `RTM_ERROR_CHANNEL_NOT_AVAILABLE`                    | Invalid user list: <br /> - Check if the user list is empty<br /> - Check if the user list contains illegal items.                                                                                                                                                                                                                                   |
| `-11013`   | `RTM_ERROR_CHANNEL_TOPIC_NOT_SUBSCRIBED`             | The topic is not subscribed.                                                                                                                                                                                                                                                                                                                         |
| `-11014`   | `RTM_ERROR_CHANNEL_EXCEED_TOPIC_LIMITATION`          | The number of topics exceeds the limit.                                                                                                                                                                                                                                                                                                              |
| `-11015`   | `RTM_ERROR_CHANNEL_JOIN_TOPIC_FAILED`                | Failed to join this topic. Check whether the number of added topics exceeds the limit.                                                                                                                                                                                                                                                               |
| `-11016`   | `RTM_ERROR_CHANNEL_TOPIC_NOT_JOINED`                 | The topic has not been joined. To send a message, you need to join the Topic first.                                                                                                                                                                                                                                                                  |
| `-11017`   | `RTM_ERROR_CHANNEL_TOPIC_NOT_EXIST`                  | The topic does not exist. Check that the topic name is correct.                                                                                                                                                                                                                                                                                      |
| `-11018`   | `RTM_ERROR_CHANNEL_INVALID_TOPIC_META`               | The `meta` parameters in the topic are invalid. Check if the `meta` parameter exceeds 256 bytes.                                                                                                                                                                                                                                                     |
| `-11019`   | `RTM_ERROR_CHANNEL_SUBSCRIBE_TIMEOUT`                | Channel subscription timed out. Check for broken connections.                                                                                                                                                                                                                                                                                        |
| `-11020`   | `RTM_ERROR_CHANNEL_SUBSCRIBE_TOO_FREQUENT`           | The channel subscription operation is too frequent. Make sure that the subscription operation of the same channel within a 5 seconds interval does not exceed 2 attempts.                                                                                                                                                                            |
| `-11021`   | `RTM_ERROR_CHANNEL_SUBSCRIBE_FAILED`                 | Channel subscription failed. Check if the number of subscribed channels exceeds the limit.                                                                                                                                                                                                                                                           |
| `-11023`   | `RTM_ERROR_CHANNEL_ENCRYPT_MESSAGE_FAILED`           | Message encryption failed: <br /> - Check that the `cipherKey` is valid. <br /> - Check that the `salt` is valid. <br /> - Check if `encryptionMode` mode matches the `cipherKey` and `salt`.                                                                                                                                                        |
| `-11024`   | `RTM_ERROR_CHANNEL_PUBLISH_MESSAGE_FAILED`           | Message publishing failed. Check for broken connections.                                                                                                                                                                                                                                                                                             |
| `-11026`   | `RTM_ERROR_CHANNEL_PUBLISH_MESSAGE_TIMEOUT`          | Message publishing timed out. Check for broken connections.                                                                                                                                                                                                                                                                                          |
| `-11028`   | `RTM_ERROR_CHANNEL_LEAVE_FAILED`                     | Failed to leave the channel. Check for broken connections.                                                                                                                                                                                                                                                                                           |
| `-11029`   | `RTM_ERROR_CHANNEL_CUSTOM_TYPE_LENGTH_OVERFLOW`      | Custom type length overflow. The length of the `customType` field must to be within 32 characters.                                                                                                                                                                                                                                                   |
| `-11030`   | `RTM_ERROR_CHANNEL_INVALID_CUSTOM_TYPE`              | `customType` field is invalid. Check the `customType` field for illegal characters.                                                                                                                                                                                                                                                                  |
| `-11033`   | `RTM_ERROR_CHANNEL_RECEIVER_OFFLINE`                 | When sending a user message, the remote user is offline: <br /> - Check if the user ID set when calling the method is correct.<br /> - Check if the remote user is logged in and online.                                                                                                                                                             |
| `-12001`   | `RTM_ERROR_STORAGE_OPERATION_FAILED`                 | Storage operation failed.                                                                                                                                                                                                                                                                                                                            |
| `-12002`   | `RTM_ERROR_STORAGE_METADATA_ITEM_EXCEED_LIMITATION`  | The number of Storage Metadata Items exceeds the limit.                                                                                                                                                                                                                                                                                              |
| `-12003`   | `RTM_ERROR_STORAGE_INVALID_METADATA_ITEM`            | Invalid Metadata Item.                                                                                                                                                                                                                                                                                                                               |
| `-12004`   | `RTM_ERROR_STORAGE_INVALID_ARGUMENT`                 | Invalid argument.                                                                                                                                                                                                                                                                                                                                    |
| `-12005`   | `RTM_ERROR_STORAGE_INVALID_REVISION`                 | Invalid Revision parameter.                                                                                                                                                                                                                                                                                                                          |
| `-12006`   | `RTM_ERROR_STORAGE_METADATA_LENGTH_OVERFLOW`         | Metadata overflows.                                                                                                                                                                                                                                                                                                                                  |
| `-12007`   | `RTM_ERROR_STORAGE_INVALID_LOCK_NAME`                | Invalid Lock name.                                                                                                                                                                                                                                                                                                                                   |
| `-12008`   | `RTM_ERROR_STORAGE_LOCK_NOT_ACQUIRED`                | The Lock was not acquired.                                                                                                                                                                                                                                                                                                                           |
| `-12009`   | `RTM_ERROR_STORAGE_INVALID_KEY`                      | Invalid Metadata key.                                                                                                                                                                                                                                                                                                                                |
| `-12010`   | `RTM_ERROR_STORAGE_INVALID_VALUE`                    | Invalid metadata value.                                                                                                                                                                                                                                                                                                                              |
| `-12011`   | `RTM_ERROR_STORAGE_KEY_LENGTH_OVERFLOW`              | Metadata key length overflow.                                                                                                                                                                                                                                                                                                                        |
| `-12012`   | `RTM_ERROR_STORAGE_VALUE_LENGTH_OVERFLOW`            | Metadata value length overflow.                                                                                                                                                                                                                                                                                                                      |
| `-12014`   | `RTM_ERROR_STORAGE_OUTDATED_REVISION`                | Outdated Revision parameter.                                                                                                                                                                                                                                                                                                                         |
| `-12015`   | `RTM_ERROR_STORAGE_NOT_SUBSCRIBE`                    | This channel is not subscribed.                                                                                                                                                                                                                                                                                                                      |
| `-12017`   | `RTM_ERROR_STORAGE_SUBSCRIBE_USER_EXCEED_LIMITATION` | The number of subscribers exceeds the limit.                                                                                                                                                                                                                                                                                                         |
| `-12018`   | `RTM_ERROR_STORAGE_OPERATION_TIMEOUT`                | Storage operation timed out.                                                                                                                                                                                                                                                                                                                         |
| `-12019`   | `RTM_ERROR_STORAGE_NOT_AVAILABLE`                    | The Storage service is not available.                                                                                                                                                                                                                                                                                                                |
| `-13001`   | `RTM_ERROR_PRESENCE_NOT_CONNECTED`                   | The user is not connected to the system.                                                                                                                                                                                                                                                                                                             |
| `-13003`   | `RTM_ERROR_PRESENCE_INVALID_ARGUMENT`                | Invalid argument.                                                                                                                                                                                                                                                                                                                                    |
| `-13004`   | `RTM_ERROR_PRESENCE_CACHED_TOO_MANY_STATES`          | The temporary user state cached before joining the channel exceeds the limit. See [API usage limits](/en/realtime-media/rtm/reference/limitations) for details.                                                                                                                                                                                      |
| `-13005`   | `RTM_ERROR_PRESENCE_STATE_COUNT_OVERFLOW`            | The number of temporary user state key/value pairs exceeds the limit. See [API usage limits](/en/realtime-media/rtm/reference/limitations) for details.                                                                                                                                                                                              |
| `-13006`   | `RTM_ERROR_PRESENCE_INVALID_STATE_KEY`               | Invalid state key.                                                                                                                                                                                                                                                                                                                                   |
| `-13008`   | `RTM_ERROR_PRESENCE_STATE_KEY_SIZE_OVERFLOW`         | Presence key length overflow.                                                                                                                                                                                                                                                                                                                        |
| `-13009`   | `RTM_ERROR_PRESENCE_STATE_VALUE_SIZE_OVERFLOW`       | Presence value overflow                                                                                                                                                                                                                                                                                                                              |
| `-13011`   | `RTM_ERROR_PRESENCE_USER_NOT_EXIST`                  | The user does not exist.                                                                                                                                                                                                                                                                                                                             |
| `-13012`   | `RTM_ERROR_PRESENCE_OPERATION_TIMEOUT`               | Presence operation timed out.                                                                                                                                                                                                                                                                                                                        |
| `-13013`   | `RTM_ERROR_PRESENCE_OPERATION_FAILED`                | Presence operation failed.                                                                                                                                                                                                                                                                                                                           |
| `-14001`   | `RTM_ERROR_LOCK_OPERATION_FAILED`                    | Lock operation failed.                                                                                                                                                                                                                                                                                                                               |
| `-14002`   | `RTM_ERROR_LOCK_OPERATION_TIMEOUT`                   | Lock operation timed out.                                                                                                                                                                                                                                                                                                                            |
| `-14003`   | `RTM_ERROR_LOCK_OPERATION_PERFORMING`                | Lock operation in progress.                                                                                                                                                                                                                                                                                                                          |
| `-14004`   | `RTM_ERROR_LOCK_ALREADY_EXIST`                       | Lock already exists.                                                                                                                                                                                                                                                                                                                                 |
| `-14005`   | `RTM_ERROR_LOCK_INVALID_NAME`                        | Invalid Lock name.                                                                                                                                                                                                                                                                                                                                   |
| `-14006`   | `RTM_ERROR_LOCK_NOT_ACQUIRED`                        | The Lock was not acquired.                                                                                                                                                                                                                                                                                                                           |
| `-14007`   | `RTM_ERROR_LOCK_ACQUIRE_FAILED`                      | Failed to acquire the Lock.                                                                                                                                                                                                                                                                                                                          |
| `-14008`   | `RTM_ERROR_LOCK_NOT_EXIST`                           | The Lock does not exist.                                                                                                                                                                                                                                                                                                                             |
| `-14009`   | `RTM_ERROR_LOCK_NOT_AVAILABLE`                       | Lock service is not available.                                                                                                                                                                                                                                                                                                                       |
