diff --git a/gatsby-config.ts b/gatsby-config.ts
index 8a401ef7d0..3812a0491a 100644
--- a/gatsby-config.ts
+++ b/gatsby-config.ts
@@ -83,7 +83,7 @@ export const plugins = [
className: `gatsby-copyable-header`,
removeAccents: true,
isIconAfterHeader: true,
- elements: [`h2`, `h3`],
+ elements: [`h2`, `h3`, `h4`],
},
},
{
diff --git a/src/data/nav/chat.ts b/src/data/nav/chat.ts
index 9a2e2d828f..bf7db4a56f 100644
--- a/src/data/nav/chat.ts
+++ b/src/data/nav/chat.ts
@@ -168,6 +168,67 @@ export default {
link: '/docs/api/chat-rest',
name: 'REST API',
},
+ {
+ name: 'JavaScript SDK',
+ pages: [
+ {
+ name: 'ChatClient',
+ link: '/docs/chat/api/javascript/chat-client',
+ },
+ {
+ name: 'Authentication',
+ link: '/docs/chat/api/javascript/auth',
+ },
+ {
+ name: 'Connection',
+ link: '/docs/chat/api/javascript/connection',
+ },
+ {
+ name: 'Rooms',
+ link: '/docs/chat/api/javascript/rooms',
+ },
+ {
+ name: 'Room',
+ link: '/docs/chat/api/javascript/room',
+ },
+ {
+ name: 'Room reactions',
+ link: '/docs/chat/api/javascript/room-reactions',
+ },
+ {
+ name: 'Message',
+ link: '/docs/chat/api/javascript/message',
+ },
+ {
+ name: 'Messages',
+ link: '/docs/chat/api/javascript/messages',
+ },
+ {
+ name: 'Message reactions',
+ link: '/docs/chat/api/javascript/messages-reactions',
+ },
+ {
+ name: 'Presence',
+ link: '/docs/chat/api/javascript/presence',
+ },
+ {
+ name: 'Occupancy',
+ link: '/docs/chat/api/javascript/occupancy',
+ },
+ {
+ name: 'Typing',
+ link: '/docs/chat/api/javascript/typing',
+ },
+ {
+ name: 'Subscriptions',
+ link: '/docs/chat/api/javascript/subscriptions',
+ },
+ {
+ name: 'ErrorInfo',
+ link: '/docs/chat/api/javascript/error-info',
+ },
+ ],
+ },
],
},
],
diff --git a/src/pages/docs/chat/api/javascript/auth.mdx b/src/pages/docs/chat/api/javascript/auth.mdx
new file mode 100644
index 0000000000..6f525b6287
--- /dev/null
+++ b/src/pages/docs/chat/api/javascript/auth.mdx
@@ -0,0 +1,193 @@
+---
+title: Authentication
+meta_description: "Ably Chat JavaScript API references for authentication."
+---
+
+The [ChatClient](/docs/chat/api/javascript/chat-client) requires a realtime client generated by the core [Pub/Sub SDK](/docs/basics) to establish a connection with Ably. This realtime client is used to handle authentication with Ably.
+
+There are broadly three mechanisms of authentication with Ably:
+
+* JSON Web Tokens (JWT): a standard JWT constructed to be compatible with Ably.
+* Ably Tokens: a token generated by the Ably service for authentication. Your server can create a tokenRequest for clients to authenticate with Ably, or it can request an Ably Token directly from Ably and pass that to clients.
+* Basic authentication: a method of authenticating using only your API key. This should only be used during development or server-side where it cannot be exposed.
+
+JWTs are recommended for authenticating in a production environment. Use Ably Tokens if your JWT is too large, such as when you are requesting a large set of capabilities, or have very long clientIds. This is because there is a limit on URL length in browsers when using JWTs as an accessToken query param. The other use-case for Ably Tokens is because claims are publicly visible in JWTs. Ably Tokens are encrypted so clientIds and capabilities cannot be inspected.
+
+---
+
+## Pub/Sub constructor
+
+The Pub/Sub constructor instantiates a realtime client that can be passed to the [`ChatClient`](/docs/chat/api/javascript/chat-client).
+
+`new Ably.Realtime(ClientOptions clientOptions)`
+
+### Parameters
+
+Use the following parameters:
+
+| Parameter | Description | Type |
+| --------- | ----------- | ---- |
+| `clientOptions` | The options to pass to customize the client connection. | [`ClientOptions`](#clientoptions) |
+
+### ClientOptions
+
+The following `ClientOptions` can be set:
+
+| Property | Description | Type |
+| -------- | ----------- | ---- |
+| `clientId` | *Optional* The identity of the client. It may also be implicit within an Ably Token or JWT. This is required to use the Chat SDK. | String |
+| `authUrl` | *Optional* A URL that the SDK uses to obtain a fresh Ably Token or JWT. | String |
+| `authCallback` | *Optional* A function in the form `function(tokenParams, callback(err, tokenOrTokenRequest))` which is called when a fresh Ably Token or JWT is required. | Callable |
+| `key` | *Optional* A full API key obtained from your Ably dashboard. This should only used with basic authentication for your authentication server or for clients in development environments. | String |
+
+---
+
+## Auth
+
+The `Auth` interface creates TokenRequest objects and obtains Ably Tokens from Ably to issue to less-trusted clients.
+
+Access it via `RealtimeClient.Auth`.
+
+### Properties
+
+It has the following properties:
+
+| Property | Description | Type |
+| -------- | ----------- | ---- |
+| `clientId` | The identity of the client. It may also be implicit within an Ably Token or JWT. This is required to use the Chat SDK. | String |
+
+---
+
+## Fetch a new token
+
+`auth.authorize()`
+
+Instructs the SDK to fetch a new Ably Token or JWT.
+
+It upgrades the current realtime connection to use the new token if the client is already connected. If they haven't yet connected then it initiates a connection to Ably.
+
+Any [`TokenParams`](#tokenparams) and [`AuthOptions`](#authoptions) will be used as the new defaults for subsequent implicit and explicit token requests. They also entirely replace, as opposed to merging with, the current stored values.
+
+`authorize(TokenParams tokenParams?, AuthOptions authOptions?): Promise`
+
+### Parameters
+
+Use the following parameters:
+
+| Parameter | Description | Type |
+| --------- | ----------- | ---- |
+| `tokenParams` | *Optional* The parameters of the token for the request. | [`TokenParams`](#tokenparams) |
+| `authOptions` | *Optional* The authentication options for the request. | [`AuthOptions`](#authoptions) |
+
+#### TokenParams
+
+An object used in the parameters of token authentication requests for defining the required attributes of a token.
+
+It has the following properties:
+
+| Property | Description | Type |
+| -------- | ----------- | ---- |
+| `capability` | *Optional* The JSON stringified [capabilities](/docs/auth/capabilities) for the token. If the request is successful, this will be an intersection of these capabilities and the issuing API key. | String |
+| `clientId` | *Optional* The identity of the client. This is required to use the Chat SDK. | String |
+| `nonce` | *Optional* An opaque string of at least 16 characters to ensure uniqueness of the request. | String |
+| `timestamp` | *Optional* The timestamp of the request in milliseconds since the Unix epoch. Used with the `nonce` to ensure uniqueness of the request. | Integer |
+| `ttl` | *Optional* The time to live for the token in milliseconds. The default is 60 minutes. | Integer |
+
+#### AuthOptions
+
+An object used when making authentication requests. If supplied it will replace the default values provided when the connection was established rather than merging with them.
+
+It has the following properties:
+
+| Property | Description | Type |
+| -------- | ----------- | ---- |
+| `authCallback` | *Optional* A function in the form `function(tokenParams, callback(err, tokenOrTokenRequest))` which is called when a fresh Ably Token or JWT is required. | Callable |
+| `authUrl` | *Optional* A URL that the SDK uses to obtain a fresh Ably Token or JWT. | String |
+| `authMethod` | *Optional* The HTTP method to use for `authUrl` requests. Either `GET` or `POST`. The default is `GET`. | String |
+| `authHeaders` | *Optional* A set of key-value pair headers to add to `authUrl` requests. | Object |
+| `authParams` | *Optional* A set of key-value pairs to add to `authUrl` requests. When the `authMethod` is `GET` params are added to the URL. When the `authMethod` is `POST` they are sent as URL-encoded form data. | Object |
+| `tokenDetails` | *Optional* An authenticated `TokenDetails` object. This is commonly used in testing. In production it is preferable to use a method that renews the token automatically since they are short-lived. | [`TokenDetails`](#tokendetails) |
+| `key` | *Optional* A full API key string. Used for basic authentication requests. | String |
+| `token` | *Optional* An authenticated token. Either a `TokenDetails` object, a token string from the `token` property of a `TokenDetails` component of a `TokenRequest` response, or a JWT. This is commonly used in testing. In production it is preferable to use a method that renews the token automatically since they are short-lived. | String \| Object |
+| `queryTime` | *Optional* If `true`, queries Ably for the current time when issuing `TokenRequests`. The default is `false`. | Boolean |
+| `useTokenAuth` | *Optional* If `true`, forces the SDK to use token authentication. | Boolean |
+
+#### TokenDetails
+
+Contains an Ably Token and its associated metadata.
+
+It has the following properties:
+
+| Property | Description | Type |
+| -------- | ----------- | ---- |
+| `token` | The Ably Token itself. | String |
+| `expires` | The timestamp of when the token expires in milliseconds since the Unix epoch. | Integer |
+| `issued` | The timestamp of when the token was issued in milliseconds since the Unix epoch. | Integer |
+| `capability` | *Optional* The [capabilities](/docs/auth/capabilities) associated with the token. | String |
+| `clientId` | *Optional* The identity of the client. This is required to use the Chat SDK. | String |
+
+#### TokenRequest
+
+Contains the properties of a request for a token to Ably. Tokens are generated using [`requestToken()`](#requesttoken).
+
+It has the following properties:
+
+| Property | Description | Type |
+| -------- | ----------- | ---- |
+| `keyName` | The name of the API key against which the request was is made. Note that the name is public, whereas the secret is private. | String |
+| `timestamp` | The timestamp of when the request was made in milliseconds since the Unix epoch. | Integer |
+| `capability` | The [capabilities](/docs/auth/capabilities) for the token. If the request is successful, this will be an intersection of these capabilities and the issuing API key. | String |
+| `nonce` | An opaque string of at least 16 characters to ensure uniqueness of the request. | String |
+| `mac` | The Message Authentication Code (MAC) for the request. | String |
+| `ttl` | *Optional* The time to live for the token in milliseconds. | Integer |
+| `clientId` | *Optional* The identity of the client. This is required to use the Chat SDK. | String |
+
+### Returns
+
+Returns a promise. On success, the promise is fulfilled with the new [`TokenDetails`](#tokendetails) once the connection has been upgraded or initiated. On failure, the connection will move to the `SUSPENDED` or `FAILED` state, and the promise will be rejected with an [`ErrorInfo`](/docs/chat/api/javascript/error-info) object which explains the error.
+
+---
+
+## Create a tokenRequest
+
+`auth.createTokenRequest()`
+
+Creates and signs an Ably [`TokenRequest`](#tokenrequest) based on the specified [`TokenParams`](#tokenparams) and [`AuthOptions`](#authoptions). If no `TokenParams` or `AuthOptions` are specified it will use those already stored by the SDK, set in the [`ClientOptions`](#clientoptions) when the SDK was instantiated or updated via an [`authorize()`](#authorize) request. New values replace the existing ones rather than merging with them.
+
+`createTokenRequest(TokenParams tokenParams?, AuthOptions authOptions?): Promise`
+
+### Parameters
+
+Use the following parameters:
+
+| Parameter | Description | Type |
+| --------- | ----------- | ---- |
+| `tokenParams` | *Optional* The parameters of the token for the request. | [`TokenParams`](#tokenparams) |
+| `authOptions` | *Optional* The authentication options for the request. | [`AuthOptions`](#authoptions) |
+
+### Returns
+
+Returns a promise. On success it will be fulfilled with a [`TokenRequest`](#tokenrequest) object. Upon failure, the promise will be rejected with an [`ErrorInfo`](/docs/chat/api/javascript/error-info) object which explains the error.
+
+---
+
+## Request a token
+
+`auth.requestToken()`
+
+Calls the `requestToken` endpoint to obtain an Ably Token according to the specified [`TokenParams`](#tokenparams) and [`AuthOptions`](#authoptions). If no `TokenParams` or `AuthOptions` are specified it will use those already stored by the SDK, set in the [`ClientOptions`](#clientoptions) when the SDK was instantiated or updated via an [`authorize()`](#authorize) request. New values replace the existing ones rather than merging with them.
+
+`requestToken(TokenParams tokenParams?, AuthOptions authOptions?): Promise`
+
+### Parameters
+
+Use the following parameters:
+
+| Parameter | Description | Type |
+| --------- | ----------- | ---- |
+| `tokenParams` | *Optional* The parameters of the token for the request. | [`TokenParams`](#tokenparams) |
+| `authOptions` | *Optional* The authentication options for the request. | [`AuthOptions`](#authoptions) |
+
+### Returns
+
+Returns a promise. On success it will be fulfilled with a [`TokenDetails`](#tokendetails) object. Upon failure, the promise will be rejected with an [`ErrorInfo`](/docs/chat/api/javascript/error-info) object which explains the error.
diff --git a/src/pages/docs/chat/api/javascript/chat-client.mdx b/src/pages/docs/chat/api/javascript/chat-client.mdx
new file mode 100644
index 0000000000..2032288b4d
--- /dev/null
+++ b/src/pages/docs/chat/api/javascript/chat-client.mdx
@@ -0,0 +1,126 @@
+---
+title: ChatClient
+meta_description: "Ably Chat JavaScript API references for the ChatClient constructor."
+---
+
+The `ChatClient` class is the core client for Ably Chat.
+
+---
+
+## Accessors
+
+| Property | Description | Type |
+| -------- | ----------- | ---- |
+| `clientId` | The clientId of the current client. | String |
+| `clientOptions` | The resolved client options for the client, including any defaults that have been set. | [`ChatClientOptions`](#chatclientoptions) |
+| `connection` | The underlying connection to Ably, which can be used to monitor the client's connection to Ably servers. | [`Connection`](/docs/chat/api/javascript/connection) |
+| `realtime` | The underlying Ably Realtime client. | [`Realtime`](#realtime) |
+| `rooms` | The rooms object, which provides access to chat rooms. | [`Rooms`](/docs/chat/api/javascript/rooms) |
+
+---
+
+## Constructor
+
+`new ChatClient()`
+
+Creates a new ChatClient instance.
+
+`new ChatClient(realtime: Realtime, clientOptions?: ChatClientOptions): ChatClient`
+
+### Parameters
+
+Use the following parameters:
+
+| Parameter | Description | Type |
+| --------- | ----------- | ---- |
+| `realtime` | The Ably Realtime client. | [`Realtime`](#realtime) |
+| `clientOptions` | *Optional* The client options. | [`ChatClientOptions`](#chatclientoptions) |
+
+#### ChatClientOptions
+
+The following `ChatClientOptions` can be set:
+
+| Properties | Description | Type |
+| ---------- | ----------- | ---- |
+| `logLevel` | *Optional* The logging level to use. The default is `LogLevel.Error`. | [`LogLevel`](#loglevel) |
+| `logHandler` | *Optional* A custom log handler. The default behavior will log messages to the console. | [`LogHandler`](#loghandler) |
+
+#### LogLevel
+
+An enum representing the different log levels.
+
+Logs of higher severity than the specified `LogLevel` are automatically logged.
+
+It has the following members:
+
+| Member | Description |
+| ------ | ----------- |
+| `Silent` | No logging will be performed. |
+| `Trace` | Something routine and expected has occurred. This level will provide logs for the vast majority of operations and function calls. |
+| `Debug` | Development information, messages that are useful when trying to debug library behavior, but superfluous to normal operation. |
+| `Info` | Informational messages. Operationally significant to the library but not out of the ordinary. |
+| `Warn` | Anything that is not immediately an error, but could cause unexpected behavior in the future. For example, passing an invalid value to an option. Indicates that some action should be taken to prevent future errors. |
+| `Error` | A given operation has failed and cannot be automatically recovered. The error may threaten the continuity of operation. |
+
+#### LogHandler
+
+A function that handles log messages.
+
+`LogHandler: (message: string, level: LogLevel, context?: LogContext) => void`
+
+Use the following parameters:
+
+| Parameter | Description | Type |
+| --------- | ----------- | ---- |
+| `message` | The message being logged. | String |
+| `logLevel` | The log level of the message. | [`LogLevel`](#loglevel) |
+| `context` | *Optional* The context of the log message as key-value pairs. | [`LogContext`](#logcontext) |
+
+#### LogContext
+
+Represents the context of a log message. It is an object of key-value pairs that can be used to provide additional context to a log message.
+
+`LogContext: Record`
+
+### Returns
+
+Returns a new `ChatClient` instance.
+
+
+```javascript
+import * as Ably from 'ably';
+import { ChatClient, LogLevel } from '@ably/chat';
+
+const realtimeClient = new Ably.Realtime({ key: 'your-api-key' });
+const chatClient = new ChatClient(realtimeClient, {
+ logLevel: 'LogLevel.Debug'
+});
+```
+
+
+---
+
+## Realtime
+
+The Chat constructor requires a realtime client generated using the core [Pub/Sub SDK](/docs/basics) to establish a connection with Ably. The realtime client handles [authentication](/docs/chat/api/javascript/auth) with Ably.
+
+`new Ably.Realtime(ClientOptions clientOptions)`
+
+### Parameters
+
+Use the following parameters:
+
+| Parameter | Description | Type |
+| --------- | ----------- | ---- |
+| `clientOptions` | The options to pass to customize the client connection. | [`ClientOptions`](#clientoptions) |
+
+### ClientOptions
+
+The following `ClientOptions` can be set:
+
+| Property | Description | Type |
+| -------- | ----------- | ---- |
+| `clientId` | *Optional* The identity of the client. It may also be implicit within an Ably Token or JWT. This is required to use the Chat SDK. | String |
+| `authUrl` | *Optional* A URL that the SDK uses to obtain a fresh Ably Token or JWT. | String |
+| `authCallback` | *Optional* A function in the form `function(tokenParams, callback(err, tokenOrTokenRequest))` which is called when a fresh Ably Token or JWT is required. | Callable |
+| `key` | *Optional* A full API key obtained from your Ably dashboard. This should only used with basic authentication for your authentication server or for clients in development environments. | String |
diff --git a/src/pages/docs/chat/api/javascript/connection.mdx b/src/pages/docs/chat/api/javascript/connection.mdx
new file mode 100644
index 0000000000..44ffd01ca3
--- /dev/null
+++ b/src/pages/docs/chat/api/javascript/connection.mdx
@@ -0,0 +1,93 @@
+---
+title: Connection
+meta_description: "Ably Chat JavaScript API references for the Connection interface."
+---
+
+The `Connection` interface represents a connection to Ably.
+
+Access it via `chatClient.connection`.
+
+---
+
+## Accessors
+
+| Property | Description | Type |
+| -------- | ----------- | ---- |
+| `error` | The current error, if any, that caused the connection to enter the current status. | [`ErrorInfo`](/docs/chat/api/javascript/error-info) \| `undefined` |
+| `status` | The current status of the connection. | [`ConnectionStatus`](#connectionstatus) |
+
+---
+
+### ConnectionStatus
+
+A `Connection` is in one of the following states:
+
+| ConnectionStatus | Description |
+| ---------------- | ----------- |
+| `Initialized` | The connection has been initialized but has not yet been opened. |
+| `Connecting` | The connection is currently attempting to open. |
+| `Connected` | The connection is open and messages can be sent and received. |
+| `Disconnected` | The connection is temporarily disconnected and will attempt to reconnect automatically. |
+| `Suspended` | The connection is in an extended period of disconnection, but it will attempt to reconnect. Rooms will be reattached on a successful reconnection, however message history will not be automatically recovered. |
+| `Failed` | The connection has permanently failed and will not attempt to reconnect. |
+
+---
+
+## Listen for connection status changes
+
+`connection.onStatusChange()`
+
+Registers a listener that will be called whenever the connection status changes.
+
+`onStatusChange(listener: ConnectionStatusListener): StatusSubscription`
+
+### Parameters
+
+Use the following parameters:
+
+| Parameter | Description | Type |
+| --------- | ----------- | ---- |
+| `listener` | The function to call when the status changes. | [`ConnectionStatusListener`](#connectionstatuslistener) |
+
+#### ConnectionStatusListener
+
+A function that can be called when the connection status changes.
+
+`ConnectionStatusListener: (change: ConnectionStatusChange) => void`
+
+It uses the following parameters:
+
+| Parameter | Description | Type |
+| --------- | ----------- | ---- |
+| `change` | The change in connection status. | [`ConnectionStatusChange`](#connectionstatuschange) |
+
+#### ConnectionStatusChange
+
+An interface that represents a change in connection status.
+
+It has the following properties:
+
+| Property | Description | Type |
+| -------- | ----------- | ---- |
+| `previous` | The previous connection status. | [`ConnectionStatus`](#connectionstatus) |
+| `current` | The current connection status. | [`ConnectionStatus`](#connectionstatus) |
+| `reason` | *Optional* The error that caused the change, if any. | [`ErrorInfo`](/docs/chat/api/javascript/error-info) |
+| `timestamp` | The time at which the status change occurred. | Date |
+
+### Returns
+
+Returns a [`StatusSubscription`](/docs/chat/api/javascript/subscriptions#statussubscription) object that can be used to unregister the listener.
+
+
+```javascript
+const subscription = chatClient.connection.onStatusChange((change) => {
+ console.log(`Connection status changed from ${change.previous} to ${change.current}`);
+ if (change.reason) {
+ console.error('Error:', change.reason);
+ }
+});
+
+// Unsubscribe when done
+subscription.off();
+```
+
diff --git a/src/pages/docs/chat/api/javascript/error-info.mdx b/src/pages/docs/chat/api/javascript/error-info.mdx
new file mode 100644
index 0000000000..ef69ea524c
--- /dev/null
+++ b/src/pages/docs/chat/api/javascript/error-info.mdx
@@ -0,0 +1,17 @@
+---
+title: ErrorInfo
+meta_description: "Ably Chat JavaScript API references for the ErrorInfo class."
+---
+
+The `ErrorInfo` class is a generic Ably error object that contains an Ably-specific status code, and a generic status code. Errors returned from the Ably server are compatible with the `ErrorInfo` structure and should result in errors that inherit from `ErrorInfo`.
+
+---
+
+## Properties
+
+| Property | Description | Type |
+| -------- | ----------- | ---- |
+| `code` | The Ably [error code](https://github.com/ably/ably-common/blob/main/protocol/errors.json). | Number |
+| `statusCode` | The HTTP status code corresponding to this error, where applicable. | Number |
+| `message` | Additional message information, where available. | String |
+| `cause` | *Optional* The underlying cause of the error, where applicable. | String \| `ErrorInfo` \| `Error` |
diff --git a/src/pages/docs/chat/api/javascript/message.mdx b/src/pages/docs/chat/api/javascript/message.mdx
new file mode 100644
index 0000000000..71bce0a97c
--- /dev/null
+++ b/src/pages/docs/chat/api/javascript/message.mdx
@@ -0,0 +1,393 @@
+---
+title: Message
+meta_description: "Ably Chat JavaScript API references for the Message interface."
+---
+
+The `Message` interface represents a single message in a chat room.
+
+---
+
+## Accessors
+
+It has the following accessors:
+
+| Accessor | Description | Type |
+| -------- | ----------- | ---- |
+| `isDeleted` | Indicates if the message has been deleted. | Boolean |
+| `deletedAt` | The timestamp at which the message was deleted. | Date \| `undefined` |
+| `deletedBy` | The clientId of the user who deleted the message. | String \| `undefined` |
+| `isUpdated` | Indicates if the message has been updated. | Boolean |
+| `updatedAt` | The timestamp at which the message was updated. | Date \| `undefined` |
+| `updatedBy` | The clientId of the user who updated the message. | String \| `undefined` |
+
+---
+
+## Properties
+
+It has the following properties:
+
+| Property | Description | Type |
+| -------- | ----------- | ---- |
+| `action` | The action type of the message. This can be used to determine if the message was created, updated, or deleted. | [`ChatMessageAction`](#chatmessageaction) |
+| `clientId` | The clientId of the user who created the message. | String |
+| `createdAt` | The timestamp at which the message was created. | Date |
+| `headers` | The headers of a chat message. Headers enable attaching extra info to a message, which can be used for various features such as linking to a relative point in time of a livestream video or flagging this message as important or pinned. This value is always set. If there are no headers, this is an empty object. Do not use the headers for authoritative information. There is no server-side validation. When reading the headers, treat them like user input. | [`MessageHeaders`](#messageheaders) |
+| `metadata` | The metadata of a chat message. Allows for attaching extra info to a message, which can be used for various features such as animations, effects, or simply to link it to other resources such as images, relative points in time, etc. This value is always set. If there is no metadata, this is an empty object. Do not use metadata for authoritative information. There is no server-side validation. When reading the metadata treat it like user input. | [`MessageMetadata`](#messagemetadata) |
+| `operation` | *Optional* The details of the operation that modified the message. This is only set for update and delete actions. It contains information about the operation: the clientId of the user who performed the operation, a description, and metadata. | [`Operation`](#operation) |
+| `reactions` | The reactions summary for this message. | [`MessageReactions`](#messagereactions) |
+| `serial` | The unique identifier of the message. | String |
+| `text` | The text of the message. | String |
+| `timestamp` | The timestamp at which this version was updated, deleted, or created. | Date |
+| `version` | A unique identifier for the latest version of this message. | String |
+
+---
+
+### ChatMessageAction
+
+An enum that represents the types of action of a message.
+
+It has the following members:
+
+| Member | Description |
+| ------ | ----------- |
+| `Create` | The message was created. |
+| `Update` | The message was updated. |
+| `Delete` | The message was deleted. |
+
+### MessageHeaders
+
+MessageHeaders enable attaching extra info to a message. Uses include linking to a relative point in time of a livestream video or flagging this message as important or pinned.
+
+`MessageHeaders: Record`
+
+### MessageMetadata
+
+MessageMetadata enables attaching extra info to a message. Uses include animations, effects, or simply to link it to other resources such as images or relative points in time.
+
+`MessageMetadata: Record`
+
+### Operation
+
+The details of an operation that modified a message.
+
+It has the following properties:
+
+| Properties | Description | Type |
+| ---------- | ----------- | ---- |
+| `clientId` | The clientId of the user who performed the operation. | String |
+| `description` | A description of the operation. | String |
+| `metadata` | Metadata associated with the operation. | [`MessageOperationMetadata`](#messageoperationmetadata) |
+
+#### MessageOperationMetadata
+
+The metadata contained in the `operations` field of a message. It represents the metadata supplied to a message update or deletion request.
+
+Do not use metadata for authoritative information. There is no server-side validation. When reading the metadata, treat it like user input.
+
+`MessageOperationMetadata: Record`
+
+### MessageReactions
+
+Represents a summary of all [reactions on a message](/docs/chat/api/javascript/messages-reactions).
+
+It has the following properties:
+
+| Property | Description |
+| -------- | ----------- |
+| `distinct` | Map of reaction to the summary (total and clients) for reactions of type `MessageReactionType.Distinct`. |
+| `multiple` | Map of reaction to the summary (total and clients) for reactions of type `MessageReactionType.Multiple`. |
+| `unique` | Map of reaction to the summary (total and clients) for reactions of type `MessageReactionType.Unique`. |
+
+---
+
+## Was message created after a given message
+
+`message.after()`
+
+Determines if the message was created after a given message. This comparison is based on global order, so does not necessarily represent the order that messages are received in realtime from the backend.
+
+`after(message: Message): boolean`
+
+### Parameters
+
+Use the following parameters:
+
+| Parameter | Description | Type |
+| --------- | ----------- | ---- |
+| `message` | The message to compare against. | `Message` |
+
+### Returns
+
+Returns `true` if this message was created after the given message, in global order.
+
+Throws an [`ErrorInfo`](/docs/chat/api/javascript/error-info) if:
+
+* The `serial` of either message is invalid.
+
+
+```javascript
+const isAfter = message1.after(message2);
+```
+
+
+## Was message created before a given message
+
+`message.before()`
+
+Determines if the message was created before a given message. This comparison is based on global order, so does not necessarily represent the order that messages are received in realtime from the backend.
+
+`before(message: Message): boolean`
+
+### Parameters
+
+Use the following parameters:
+
+| Parameter | Description | Type |
+| --------- | ----------- | ---- |
+| `message` | The message to compare against. | `Message` |
+
+### Returns
+
+Returns `true` if this message was created before the given message, in global order.
+
+Throws an [`ErrorInfo`](/docs/chat/api/javascript/error-info) if:
+
+* The `serial` of either message is invalid.
+
+
+```javascript
+const isBefore = message1.before(message2);
+```
+
+
+## Is message equal to a given message
+
+`message.equal()`
+
+Determines if the message is equal to a given message.
+
+Note that this method compares messages based on `Message.serial` alone. It returns `true` if the two messages represent different versions of the same message.
+
+`equal(message: Message): boolean`
+
+### Parameters
+
+Use the following parameters:
+
+| Parameter | Description | Type |
+| --------- | ----------- | ---- |
+| `message` | The message to compare against. | `Message` |
+
+### Returns
+
+Returns `true` if the two messages are the same message.
+
+
+```javascript
+const isEqual = message1.equal(message2);
+```
+
+
+## Is message the same as a given message
+
+`message.isSameAs()`
+
+Alias for [`message.equal()`](#equal).
+
+`isSameAs(message: Message): boolean`
+
+## Is message a newer version of a given message
+
+`message.isNewerVersionOf()`
+
+Determines if a message is a newer version of a given message.
+
+Note that negating this function does not mean that the message is an older version of the same message, as the two may be different messages entirely.
+
+`isNewerVersionOf(message: Message): boolean`
+
+### Parameters
+
+Use the following parameters:
+
+| Parameter | Description | Type |
+| --------- | ----------- | ---- |
+| `message` | The message to compare against. | `Message` |
+
+### Returns
+
+Returns `true` if the two messages are the same message (`isSameAs` returns `true`) and this message is a newer version.
+
+
+```javascript
+const isNewer = message1.isNewerVersionOf(message2);
+```
+
+
+## Is message an older version of a given message
+
+`message.isOlderVersionOf()`
+
+Determines if the message is an older version of a given message.
+
+Note that negating this function does not mean that the message is a newer version of the same message, as the two may be different messages entirely.
+
+`isOlderVersionOf(message: Message): boolean`
+
+### Parameters
+
+Use the following parameters:
+
+| Parameter | Description | Type |
+| --------- | ----------- | ---- |
+| `message` | The message to compare against. | `Message` |
+
+### Returns
+
+Returns `true` if the two messages are the same message (`isSameAs` returns true) and this message is an older version.
+
+
+```javascript
+const isOlder = message1.isOlderVersionOf(message2);
+```
+
+
+## Is message the same version as a given message
+
+`message.isSameVersionAs()`
+
+Determines if the message is the same version as a given message.
+
+`isSameVersionAs(message: Message): boolean`
+
+### Parameters
+
+Use the following parameters:
+
+| Parameter | Description | Type |
+| --------- | ----------- | ---- |
+| `message` | The message to compare against. | `Message` |
+
+### Returns
+
+Returns `true` if the two messages are the same message and have the same version.
+
+
+```javascript
+const isSameVersion = message1.isSameVersionAs(message2);
+```
+
+
+## Create a copy of a message
+
+`message.copy()`
+
+Creates a copy of the message with fields replaced per the parameters. This is used with [`messages.update()`](/docs/chat/api/javascript/messages#update) to easily create a copy of an existing message in order to update it.
+
+`copy(params?: MessageCopyParams): Message`
+
+### Parameters
+
+Use the following parameters:
+
+| Parameter | Description | Type |
+| --------- | ----------- | ---- |
+| `params` | *Optional* The parameters to replace in the message. | [`MessageCopyParams`](#messagecopyparams) |
+
+#### MessageCopyParams
+
+The following `MessageCopyParams` can be set:
+
+| Parameters | Description | Type |
+| ---------- | ----------- | ---- |
+| `text` | *Optional* The new text for the message. | String |
+| `metadata` | *Optional* The new metadata for the message. | [`MessageMetadata`](#messagemetadata) |
+| `headers` | *Optional* The new headers for the message. | [`MessageHeaders`](#messageheaders) |
+
+### Returns
+
+Returns the message copy.
+
+
+```javascript
+const copiedMessage = message.copy({text: 'Updated text'});
+```
+
+
+## Create a new message with an event applied
+
+`message.with()`
+
+Creates a new message instance with the event applied.
+
+Note: This method will not replace the message reactions if the event is of type `Message`.
+
+`with(event: Message | ChatMessageEvent | MessageReactionSummaryEvent): Message`
+
+### Parameters
+
+Use the following parameters:
+
+| Parameter | Description | Type |
+| --------- | ----------- | ---- |
+| `event` | The event to be applied to the returned message. | `Message` \| [`ChatMessageEvent`](#chatmessageevent) \| [`MessageReactionSummaryEvent`](#messagereactionsummaryevent) |
+
+#### ChatMessageEvent
+
+The payload of a message event.
+
+It has the following properties:
+
+| Properties | Description | Type |
+| ---------- | ----------- | ---- |
+| `type` | The type of the message event. | [`ChatMessageEventType`](#chatmessageeventtype) |
+| `data` | The message data. | `Message` |
+
+#### ChatMessageEventType
+
+An enum that represents the types of message events.
+
+It has the following members:
+
+| Member | Description |
+| ------ | ----------- |
+| `Created` | Fires when a new message is created. |
+| `Updated` | Fires when a message is updated. |
+| `Deleted` | Fires when a message is deleted. |
+
+#### MessageReactionSummaryEvent
+
+An interface that represents a summary of message reactions. This event aggregates different types of reactions for a specific message.
+
+It has the following properties:
+
+| Properties | Description | Type |
+| ---------- | ----------- | ---- |
+| `type` | The type of the reaction event. | [`MessageReactionEventType`](#messagereactioneventtype) |
+| `data` | The reaction summary data. | [`MessageReactions`](#messagereactions) |
+
+#### MessageReactionEventType
+
+An enum representing the different message reaction events.
+
+It has the following members:
+
+| Member | Description |
+| ------ | ----------- |
+| `Added` | A reaction was added. |
+| `Removed` | A reaction was removed. |
+
+### Returns
+
+Returns a new message instance with the event applied. If the event is a no-op, such as an event for an old version, the same message is returned (not a copy).
+
+Throws an [`ErrorInfo`](/docs/chat/api/javascript/error-info) if:
+
+* The event is for a different message.
+* The event if of the type `ChatMessageEventType.Created`.
+
+
+```javascript
+const updatedMessage = message.with(messageEvent);
+```
+
diff --git a/src/pages/docs/chat/api/javascript/messages-reactions.mdx b/src/pages/docs/chat/api/javascript/messages-reactions.mdx
new file mode 100644
index 0000000000..3ca88fc7aa
--- /dev/null
+++ b/src/pages/docs/chat/api/javascript/messages-reactions.mdx
@@ -0,0 +1,255 @@
+---
+title: MessagesReactions
+meta_description: "Ably Chat JavaScript API references for the MessageReactions interface."
+---
+
+The `MessagesReactions` interface is used to add, delete, and subscribe to reactions on individual messages.
+
+Access it via `room.messages.reactions`.
+
+---
+
+## Send a message reaction
+
+`room.messages.reactions.send()`
+
+React to an existing message.
+
+`send(messageSerial: Serial, params: AddMessageReactionParams): Promise`
+
+### Parameters
+
+Use the following parameters:
+
+| Parameter | Description | Type |
+| --------- | ----------- | ---- |
+| `messageSerial` | The serial of the message to react to. | [`Serial`](#serial) |
+| `params` | Describe the reaction to add. | [`AddMessageReactionParams`](#addmessagereactionparams) |
+
+#### Serial
+
+A serial is used to identify a particular message, reaction or other chat event. It is the identifier for that event in the chat history.
+
+Serials can be conveyed either as a string, or an object that contains serial as a property. Message is included for type hinting and LLM purposes.
+
+The string-form of the serial should not be parsed or interpreted in any way, as it is subject to change without warning.
+
+`Serial: Message | string | { serial: string }`
+
+#### AddMessageReactionParams
+
+The parameters that can be added to a message reaction.
+
+It has the following properties:
+
+| Property | Description | Type |
+| -------- | ----------- | ---- |
+| `count` | The count of the reaction for type `MessageReactionType.Multiple`. Defaults to 1 if not set. | Number |
+| `name` | The reaction name to add, i.e. the emoji to use. | String |
+| `type` | The type of reaction. Uses the default type configured in the [`MessageOptions`](/docs/chat/api/javascript/rooms#messageoptions) of the room if not set. | [`MessageReactionType`](#messagereactiontype) |
+
+#### MessageReactionType
+
+An enum that represents the types of reactions for a message.
+
+It has the following members:
+
+| Member | Description |
+| ------ | ----------- |
+| `Distinct` | Allows for at most one reaction of each type per client per message. It is possible for a client to add multiple reactions to the same message as long as they are different (e.g. different emojis). Duplicates are not counted in the summary. This is similar to reactions on Slack. |
+| `Multiple` | Allows any number of reactions, including repeats, and they are counted in the summary. The reaction payload also includes a count of how many times each reaction should be counted (defaults to 1 if not set). This is similar to the clap feature on Medium. |
+| `Unique` | Allows for at most one reaction per client per message. If a client reacts to a message a second time, only the second reaction is counted in the summary. This is similar to reactions on iMessage, Facebook Messenger or WhatsApp. |
+
+### Returns
+
+Returns a promise. On success, the promise is fulfilled when the reaction is added. On failure, the promise is rejected with an [`ErrorInfo`](/docs/chat/api/javascript/error-info).
+
+
+```javascript
+await room.messages.reactions.send(message, {
+ name: '❤️',
+ type: MessageReactionType.Multiple,
+ count: 100,
+});
+```
+
+
+---
+
+## Delete a reaction from a message
+
+`room.messages.reactions.delete()`
+
+Delete a message reaction.
+
+`delete(messageSerial: Serial, params?: DeleteMessageReactionParams): Promise`
+
+### Parameters
+
+Use the following parameters:
+
+| Parameter | Description | Type |
+| --------- | ----------- | ---- |
+| `messageSerial` | The serial of the message to remove the reaction from. | [`Serial`](#serial) |
+| `params` | *Optional* The type of reaction annotation and the specific reaction to remove. The reaction to remove is required for all types except [`MessageReactionType.Unique`](#messagereactiontype). | [`DeleteMessageReactionParams`](#deletemessagereactionparams) |
+
+#### DeleteMessageReactionParams
+
+The following `DeleteMessageReactionParams` can be set:
+
+| Parameters | Description | Type |
+| ---------- | ----------- | ---- |
+| `name` | *Optional* The reaction to remove. Required for all reaction types except `Unique`. | String |
+| `type` | *Optional* The type of reaction annotation. Defaults to the room's default reaction type if not specified. | [`MessageReactionType`](#messagereactiontype) |
+
+### Returns
+
+Returns a promise. On success, the promise is fulfilled when the reaction is deleted. On failure, the promise is rejected with an [`ErrorInfo`](/docs/chat/api/javascript/error-info).
+
+
+```javascript
+await room.messages.reactions.delete(message.serial, {
+ type: '👍',
+ reactionType: 'reaction:unique.v1'
+});
+```
+
+
+---
+
+## Subscribe to message reaction summaries
+
+`room.messages.reactions.subscribe()`
+
+Subscribe to message reaction summaries. Use this to keep message reaction counts up to date efficiently in the UI.
+
+`subscribe(listener: MessageReactionListener): Subscription`
+
+### Parameters
+
+Use the following parameters:
+
+| Parameter | Description | Type |
+| --------- | ----------- | ---- |
+| `listener` | The listener to call when a message reaction summary is received. | [`MessageReactionListener`](#messagereactionlistener) |
+
+#### MessageReactionListener
+
+A listener that listens for message reaction summary events.
+
+`MessageReactionListener: (event: MessageReactionSummaryEvent) => void`
+
+It uses the following parameters:
+
+| Parameter | Description | Type |
+| --------- | ----------- | ---- |
+| `event` | A message reaction summary event. Use with [`message.with()`](/docs/chat/api/javascript/message#with) to keep an up-to-date reaction count. | [`MessageReactionSummaryEvent`](#messagereactionsummaryevent) |
+
+#### MessageReactionSummaryEvent
+
+An interface that represents a summary of message reactions. It aggregates different reaction types such as distinct, multiple, and unique for a specific message.
+
+It has the following properties:
+
+| Property | Description | Type |
+| -------- | ----------- | ---- |
+| `type` | The type of reaction event. | [`MessageReactionEventType.Summary`](#messagereactioneventtype) |
+| `summary` | The message reactions summary. | `{summary: { distinct: SummaryDistinct Values, messageSerial: string, multiple: SummaryMultipleValues, unique: SummaryUniqueValues, }` |
+
+The properties of a `summary` are:
+
+| Property | Description | Type |
+| -------- | ----------- | ---- |
+| `distinct` | Map of distinct reactions. | `SummaryDistinctValues` |
+| `multiple` | Map of multiple reactions. | `SummaryMultipleValues` |
+| `distinct` | Map of unique reactions. | `SummaryUniqueValues` |
+| `messageSerial` | The message serial. | String |
+
+#### MessageReactionEventType
+
+An enum representing the different message reaction events.
+
+It has the following members:
+
+| Member | Description |
+| ------ | ----------- |
+| `Create` | A reaction was added. |
+| `Delete` | A reaction was removed. |
+| `Summary` | The reaction summary was updated for the message. |
+
+### Returns
+
+Returns a [`Subscription`](/docs/chat/api/javascript/subscriptions#subscription) object that can be used to unsubscribe from message reactions.
+
+---
+
+## Subscribe to individual reaction events
+
+`room.messages.reactions.subscribeRaw()`
+
+Subscribe to individual reaction events.
+
+Note that [reaction summaries](#subscribe) are recommended for the majority of use cases, especially if you only need to keep track of reaction counts and clients.
+
+`subscribeRaw(listener: MessageRawReactionListener): Subscription`
+
+### Parameters
+
+Use the following parameters:
+
+| Parameter | Description | Type |
+| --------- | ----------- | ---- |
+| `listener` | The listener to call when a message reaction event is received. | [`MessageRawReactionListener`](#messagerawreactionlistener) |
+
+#### MessageRawReactionListener
+
+A listener that listens for individual message reaction events.
+
+`MessageRawReactionListener: (event: MessageRawReactionEvent) => void`
+
+It uses the following parameters:
+
+| Parameter | Description | Type |
+| --------- | ----------- | ---- |
+| `event` | An individual message reaction event. | [`MessageRawReactionEvent`](#messagerawreactionevent) |
+
+#### MessageRawReactionEvent
+
+An interface that represents an individual message reaction event.
+
+It has the following properties:
+
+| Property | Description | Type |
+| -------- | ----------- | ---- |
+| `timestamp` | The timestamp when the reaction event occurred. | Date |
+| `type` | The type of reaction event. | [`MessageReactionEventType.Create`](#messagereactioneventtype) \| [`MessageReactionEventType.Delete`](#messagereactioneventtype) |
+| `reaction` | The message reaction that was received. | `reaction: { clientId: string; count?: number; messageSerial: string; name: string; type: MessageReactionType;}` |
+
+The properties of a `reaction` are:
+
+| Property | Description | Type |
+| -------- | ----------- | ---- |
+| `clientId` | The client ID of the user who added or removed the reaction. | String |
+| `count` | The count of the reaction for type `MessageReactionType.Multiple`. | Number |
+| `messageSerial` | The serial of the message that was reacted to. | String |
+| `name` | The reaction name, i.e. the emoji that was used. | String |
+| `type` | The reaction that was added or removed. | [`MessageReactionType`](#messagereactiontype) |
+
+### Returns
+
+Returns a [`Subscription`](/docs/chat/api/javascript/subscriptions#subscription) object that can be used to unsubscribe from message reactions.
+
+
+```javascript
+const subscription = room.messages.reactions.subscribeRaw((event) => {
+ if (event.type === 'MessageReactionEventType.Create') {
+ console.log(`${event.clientId} reacted to message ${event.messageSerial} with ${event.reaction}`);
+ } else {
+ console.log(`${event.clientId} removed ${event.reaction} from message ${event.messageSerial}`);
+ }
+});
+
+// Unsubscribe when done
+await subscription.unsubscribe();
+```
+
diff --git a/src/pages/docs/chat/api/javascript/messages.mdx b/src/pages/docs/chat/api/javascript/messages.mdx
new file mode 100644
index 0000000000..939e4030b7
--- /dev/null
+++ b/src/pages/docs/chat/api/javascript/messages.mdx
@@ -0,0 +1,398 @@
+---
+title: Messages
+meta_description: "Ably Chat JavaScript API references for the Messages interface."
+---
+
+The `Messages` interface is used to send and subscribe to messages in a chat room.
+
+Access it via `room.messages`.
+
+---
+
+## Properties
+
+| Property | Description | Type |
+| -------- | ----------- | ---- |
+| reactions | Add, delete, and subscribe to message reactions. | [`MessageReactions`](/docs/chat/api/javascript/messages-reactions) |
+
+---
+
+## Send a message
+
+`room.messages.send()`
+
+Send a message in the chat room.
+
+This method uses the Ably Chat API endpoint for sending messages.
+
+Note that the Promise may resolve before OR after the message is received from the realtime channel. This means you may see the message that was just sent in a callback to `subscribe()` before the returned promise resolves.
+
+`send(params: SendMessageParams): Promise`
+
+### Parameters
+
+Use the following parameters:
+
+| Parameter | Description | Type |
+| --------- | ----------- | ---- |
+| `params` | An object containing the text, headers and metadata for the message. | [`SendMessageParams`](#sendmessageparams) |
+
+#### SendMessageParams
+
+The following `SendMessageParams` can be set:
+
+| Parameters | Description | Type |
+| ---------- | ----------- | ---- |
+| `text` | The text content of the message. | String |
+| `metadata` | *Optional* Metadata to attach to the message. Allows for attaching extra info to a message, which can be used for various features such as animations, effects, or simply to link it to other resources such as images, relative points in time, etc. This value is always set on received messages. If there is no metadata, this is an empty object. Do not use metadata for authoritative information. There is no server-side validation. When reading the metadata, treat it like user input. | [`MessageMetadata`](#messagemetadata) |
+| `headers` | *Optional* Headers to attach to the message. Headers enable attaching extra info to a message, which can be used for various features such as linking to a relative point in time of a livestream video or flagging this message as important or pinned. This value is always set on received messages. If there are no headers, this is an empty object. Do not use the headers for authoritative information. There is no server-side validation. When reading the headers, treat them like user input. | [`MessageHeaders`](#messageheaders) |
+
+#### MessageMetadata
+
+Metadata enables attaching extra info to a message. Uses include animations, effects, or simply to link it to other resources such as images or relative points in time.
+
+`MessageMetadata: Record`
+
+#### MessageHeaders
+
+Headers enable attaching extra info to a message. Uses include linking to a relative point in time of a livestream video or flagging this message as important or pinned.
+
+`MessageHeaders: Record`
+
+### Returns
+
+Returns a promise. On success, the promise is fulfilled with the [`Message`](/docs/chat/api/javascript/message) object that was sent. On failure, the promise is rejected with an [`ErrorInfo`](/docs/chat/api/javascript/error-info).
+
+
+```javascript
+const message = await room.messages.send({
+ text: 'Hello, world!',
+ metadata: { priority: 'high' },
+ headers: { timestamp: Date.now() }
+});
+```
+
+
+---
+
+## Update a message
+
+`room.messages.update()`
+
+Update a message in the chat room.
+
+Note that the promise may resolve before or after the updated message is received from the room. This means you may see the update that was just sent in a callback to `subscribe()` before the returned promise resolves.
+
+The [`Message`](/docs/chat/api/javascript/message) instance returned by this method is the state of the message as a result of the update operation. If you have a subscription to message events via `subscribe()`, you should discard the message instance returned by this method and use the event payloads from the subscription instead.
+
+This method uses PUT-like semantics: if headers and metadata are omitted from the [`updateParams`](#updateparams), then the existing headers and metadata are replaced with the empty objects.
+
+`update(serial: Serial, updateParams: UpdateMessageParams, details?: OperationDetails): Promise`
+
+### Parameters
+
+Use the following parameters:
+
+| Parameter | Description | Type |
+| --------- | ----------- | ---- |
+| `serial` | A string or object that conveys the serial of the message to update. | [`Serial`](#serial) |
+| `updateParams` | The parameters for updating the message. | [`UpdateMessageParams`](#updatemessageparams) |
+| `details` | *Optional* Optional details to record about the update action. | [`OperationDetails`](#operationdetails) |
+
+#### Serial
+
+A serial is used to identify a particular message, reaction or other chat event. It is the identifier for that event in the chat history.
+
+Serials can be conveyed either as a string, or an object that contains serial as a property. Message is included for type hinting and LLM purposes.
+
+The string-form of the serial should not be parsed or interpreted in any way, as it is subject to change without warning.
+
+`Serial: Message | string | { serial: string }`
+
+#### UpdateMessageParams
+
+The following `UpdateMessageParams` can be set:
+
+| Parameters | Description | Type |
+| ---------- | ----------- | ---- |
+| `text` | The new text content for the message. | String |
+| `metadata` | *Optional* Metadata to attach to the message. This will replace the existing metadata on the message. Do not use metadata for authoritative information. There is no server-side validation. When reading the metadata, treat it like user input. | [`MessageMetadata`](#messagemetadata) |
+| `headers` | *Optional* Headers to attach to the message. This will replace the existing headers on the message. Do not use the headers for authoritative information. There is no server-side validation. When reading the headers, treat them like user input. | [`MessageHeaders`](#messageheaders) |
+
+#### OperationDetails
+
+Details to record about an operation (update or delete).
+
+| Parameters | Description | Type |
+| ---------- | ----------- | ---- |
+| `description` | *Optional* A description of the operation. | String |
+| `metadata` | *Optional* Metadata associated with the operation. Do not use metadata for authoritative information. There is no server-side validation. When reading the metadata, treat it like user input. | [`OperationMetadata`](#operationmetadata) |
+
+#### MessageOperationMetadata
+
+The metadata contained in the `operations` field of a message. It represents the metadata supplied to a message update or deletion request.
+
+Do not use metadata for authoritative information. There is no server-side validation. When reading the metadata, treat it like user input.
+
+`OperationMetadata: Record`
+
+### Returns
+
+Returns a promise. On success, the promise is fulfilled with the updated [`Message`](/docs/chat/api/javascript/message) object. On failure, the promise is rejected with an [`ErrorInfo`](/docs/chat/api/javascript/error-info).
+
+
+```javascript
+const updatedMessage = await room.messages.update(
+ message.serial,
+ {
+ text: 'Updated message text',
+ metadata: { edited: true, editedAt: Date.now() }
+ },
+ {
+ description: 'Fixed typo'
+ }
+);
+```
+
+
+---
+
+## Delete a message
+
+`room.messages.delete()`
+
+Delete a message in the chat room.
+
+This method performs a 'soft' delete, meaning the message is marked as deleted.
+
+Note that the promise may resolve before or after the message is deleted from the realtime channel. This means you may see the message that was just deleted in a callback to `subscribe` before the returned promise resolves.
+
+The [`Message`](/docs/chat/api/javascript/message) instance returned by this method is the state of the message as a result of the delete operation. If you have a subscription to message events via `subscribe()`, you should discard the message instance returned by this method and use the event payloads from the subscription instead.
+
+Should you wish to restore a deleted message, and providing you have the appropriate permissions, you can simply send an update to the original message.
+
+`delete(serial: Serial, deleteMessageParams?: DeleteMessageParams): Promise`
+
+### Parameters
+
+Use the following parameters:
+
+| Parameter | Description | Type |
+| --------- | ----------- | ---- |
+| `serial` | A string or object that conveys the serial of the message to delete. | [`Serial`](#serial) |
+| `deleteMessageParams` | *Optional* Optional details to record about the delete action. | [`DeleteMessageParams`](#deletemessageparams) |
+
+#### DeleteMessageParams
+
+The following `DeleteMessageParams` can be set:
+
+| Parameters | Description | Type |
+| ---------- | ----------- | ---- |
+| `description` | *Optional* A description of why the message was deleted. | String |
+| `metadata` | *Optional* Metadata associated with the deletion. Do not use metadata for authoritative information. There is no server-side validation. When reading the metadata, treat it like user input. | [`OperationMetadata`](#operationmetadata) |
+
+### Returns
+
+Returns a promise. On success, the promise is fulfilled with the deleted [`Message`](/docs/chat/api/javascript/message) object. On failure, the promise is rejected with an [`ErrorInfo`](/docs/chat/api/javascript/error-info).
+
+
+```javascript
+const deletedMessage = await room.messages.delete(
+ message.serial,
+ {
+ description: 'Message violated community guidelines',
+ metadata: { reason: 'inappropriate content' }
+ }
+);
+```
+
+
+---
+
+## Get message history
+
+`room.messages.history()`
+
+Get messages that have been previously sent to the chat room, based on the provided options.
+
+Note that the [`historyBeforeSubscribe()`](#historyBeforeSubscribe) method enables clients to retrieve messages in a continuous manner when they first subscribe to a room, or rejoin after a period of disconnection.
+
+`history(options: QueryOptions): Promise>`
+
+### Parameters
+
+Use the following parameters:
+
+| Parameter | Description | Type |
+| --------- | ----------- | ---- |
+| `options` | Options for the query. | [`QueryOptions`](#queryoptions) |
+
+#### QueryOptions
+
+The following `QueryOptions` can be set:
+
+| Parameters | Description | Type |
+| ---------- | ----------- | ---- |
+| `start` | *Optional* The start of the time window to query from. Messages with `timestamps` equal to or greater than this value will be returned. The default is the beginning of time. | Number |
+| `end` | *Optional* The end of the time window to query to. Messages with `timestamps` less than this value will be returned. The default is now. | Number |
+| `orderBy` | *Optional* The direction to query messages in. The default is `NewestFirst`. | [`OrderBy`](#orderby) |
+| `limit` | *Optional* The maximum number of messages to return. The default is 100. | Number |
+
+#### OrderBy
+
+The order in which messages are returned in a history request.
+
+It has the following members:
+
+| Member | Description |
+| ------ | ----------- |
+| `NewestFirst` | Query messages in descending order (newest to oldest). |
+| `OldestFirst` | Query messages in ascending order (oldest to newest). |
+
+### Returns
+
+Returns a promise. On success, the promise is fulfilled with a [`PaginatedResult`](#paginatedresult) containing an array of [`Message`](/docs/chat/api/javascript/message) objects. This paginated result can be used to fetch more messages if available. On failure, the promise is rejected with an [`ErrorInfo`](/docs/chat/api/javascript/error-info).
+
+#### PaginatedResult
+
+A paginated result containing messages and methods to navigate through pages.
+
+It has the following properties:
+
+| Property | Description | Type |
+| -------- | ----------- | ---- |
+| `items` | The array of messages in the current page. | [`Message`](/docs/chat/api/javascript/message)[] |
+| `next` | A method to fetch the next page of results. Returns a promise with the next `PaginatedResult`. Throws if there are no more pages. | `() => Promise>` |
+| `hasNext` | Indicates whether there are more pages available. | Boolean |
+| `isLast` | Indicates whether this is the last page. | Boolean |
+
+
+```javascript
+const result = await room.messages.history({
+ limit: 50,
+ direction: 'backwards'
+});
+
+console.log(`Retrieved ${result.items.length} messages`);
+
+if (result.hasNext) {
+ const nextPage = await result.next();
+ console.log(`Retrieved ${nextPage.items.length} more messages`);
+}
+```
+
+
+---
+
+## Subscribe to message events
+
+`room.messages.subscribe()`
+
+Subscribe to new messages in this chat room.
+
+`subscribe(listener: MessageListener): MessageSubscriptionResponse`
+
+### Parameters
+
+Use the following parameters:
+
+| Parameter | Description | Type |
+| --------- | ----------- | ---- |
+| `listener` | Callback that will be called when a message event is received. | [`MessageListener`](#messagelistener) |
+
+#### MessageListener
+
+A listener that listens for message events.
+
+`MessageListener: (event: ChatMessageEvent) => void`
+
+It uses the following parameters:
+
+| Parameter | Description | Type |
+| --------- | ----------- | ---- |
+| `event` | A message event. | [`ChatMessageEvent`](#chatmessageevent) |
+
+#### ChatMessageEvent
+
+An interface that represents a message event.
+
+It has the following properties:
+
+| Property | Description | Type |
+| -------- | ----------- | ---- |
+| `type` | The type of message event. | [`ChatMessageEventType`](#chatmessageeventtype) |
+| `message` | The message associated with the event. | [`Message`](/docs/chat/api/javascript/message) |
+
+#### ChatMessageEventType
+
+An enum that represents the types of message events.
+
+It has the following members:
+
+| Member | Description |
+| ------ | ----------- |
+| `Created` | A new message was created. |
+| `Updated` | A message was updated. |
+| `Deleted` | A message was deleted. |
+
+### Returns
+
+Returns a [`MessageSubscriptionResponse`](/docs/chat/api/javascript/subscriptions#messagesubscriptionresponse) object that allows you to control the subscription.
+
+
+```javascript
+const subscription = room.messages.subscribe((event) => {
+ switch (event.type) {
+ case 'message.created':
+ console.log('New message:', event.message.text);
+ break;
+ case 'message.updated':
+ console.log('Updated message:', event.message.text);
+ break;
+ case 'message.deleted':
+ console.log('Deleted message:', event.message.serial);
+ break;
+ }
+});
+
+// Unsubscribe when done
+await subscription.unsubscribe();
+```
+
+
+---
+
+## Get message history from before a subscription
+
+`historyBeforeSubscribe()`
+
+Get the messages that were sent to the room before the [listener was subscribed](#subscribe). This method is useful for providing conversational context when a user first joins a room, or when they subsequently rejoin it later on. It also ensures that the message history they see is continuous, without any overlap of messages being returned between their subscription and their history call.
+
+`historyBeforeSubscribe()` is returned in the [`MessageSubscriptionResponse`](/docs/chat/api/javascript/subscriptions#messagesubscriptionresponse) object when you call [`subscribe()`](#subscribe).
+
+If the client experiences a discontinuity event, where the connection was lost and could not be resumed, the starting point of `historyBeforeSubscribe` is reset. Calls to `historyBeforeSubscribe` will wait for continuity to be restored before resolving.
+
+To ensure that no messages are missed, you should call `historyBeforeSubscribe` after any period of discontinuity to fill any gaps in the message history.
+
+`historyBeforeSubscribe( params: Omit,): Promise>`
+
+### Parameters
+
+Use the following parameters:
+
+| Parameter | Description | Type |
+| --------- | ----------- | ---- |
+| `params` | The options for the query, omitting `orderBy`. | [`QueryOptions`](#queryoptions) |
+
+
+### Returns
+
+Returns a promise. On success, the promise is fulfilled with a [`PaginatedResult`](#paginatedresult) containing an array of [`Message`](/docs/chat/api/javascript/message) objects from newest to oldest. This paginated result can be used to fetch more messages if available. On failure, the promise is rejected with an [`ErrorInfo`](/docs/chat/api/javascript/error-info).
+
+
+```javascript
+const { historyBeforeSubscribe } = room.messages.subscribe(listener);
+
+await historyBeforeSubscribe({ limit: 10 });
+```
+
diff --git a/src/pages/docs/chat/api/javascript/occupancy.mdx b/src/pages/docs/chat/api/javascript/occupancy.mdx
new file mode 100644
index 0000000000..8558cc0bb3
--- /dev/null
+++ b/src/pages/docs/chat/api/javascript/occupancy.mdx
@@ -0,0 +1,94 @@
+---
+title: Occupancy
+meta_description: "Ably Chat JavaScript API references for the Occupancy interface."
+---
+
+The `Occupancy` interface is used to subscribe to occupancy updates and fetch the occupancy metrics of a room.
+
+Occupancy is disabled in a room by default. Enable it using the `enableEvents` property in the [`OccupancyOptions`](/docs/chat/api/javascript/rooms#OccupancyOptions) of a room.
+
+Access it via `room.occupancy`.
+
+---
+
+## Get the room occupancy
+
+`room.occupancy.get()`
+
+Get the current occupancy of the room as an instantaneous value from the server.
+
+`get(): Promise`
+
+### Returns
+
+Returns a promise. On success, the promise is fulfilled with an `OccupancyData` object containing the current occupancy metrics. On failure, the promise is rejected with an [`ErrorInfo`](/docs/chat/api/javascript/error-info).
+
+#### OccupancyData
+
+An interface that represents an occupancy data of a chat room.
+
+It has the following properties:
+
+| Property | Description | Type |
+| -------- | ----------- | ---- |
+| `connections` | The number of connections attached to the channel. | `number` |
+| `presenceMembers` | The number of users entered into the [presence](/docs/chat/api/javascript/presence) set. | `number` |
+
+---
+
+## Get the current room occupancy
+
+`room.occupancy.current()`
+
+Get the latest occupancy data received from realtime events.
+
+`current(): undefined | OccupancyData`
+
+### Returns
+
+The latest occupancy data, or undefined if no realtime events have been received in the room yet.
+
+--
+
+## Subscribe to occupancy
+
+`room.occupancy.subscribe()`
+
+Subscribe the provided listener to occupancy occupancy events.
+
+`subscribe(listener: OccupancyListener): Subscription`
+
+### Parameters
+
+It uses the following parameters:
+
+| Parameter | Description | Type |
+| --------- | ----------- | ---- |
+| `listener` | Function called when an occupancy update is received | `OccupancyListener` |
+
+#### OccupancyListener
+
+A listener that listens for occupancy events.
+
+`OccupancyListener: (event: OccupancyEvent) => void`
+
+It uses the following parameters:
+
+| Parameter | Description | Type |
+| --------- | ----------- | ---- |
+| `event` | An occupancy event. | [`OccupancyEvent`](#occupancyevent) |
+
+#### OccupancyEvent
+
+An interface that represents an occupancy event.
+
+It has the following properties:
+
+| Property | Description | Type |
+| -------- | ----------- | ---- |
+| `occupancy` | The occupancy data associated with the event. Contains the number of `connections` and `presenceMembers`. | `occupancy: { connections: number; presenceMembers: number }` |
+| `type` | The type of the occupancy event. Will always be `Updated`. ||
+
+### Returns
+
+Returns a [`Subscription`](/docs/chat/api/javascript/subscriptions#subscription) object that can be used to unsubscribe the listener.
diff --git a/src/pages/docs/chat/api/javascript/presence.mdx b/src/pages/docs/chat/api/javascript/presence.mdx
new file mode 100644
index 0000000000..87e8cdf208
--- /dev/null
+++ b/src/pages/docs/chat/api/javascript/presence.mdx
@@ -0,0 +1,305 @@
+---
+title: Presence
+meta_description: "Ably Chat JavaScript API references for the Presence interface."
+---
+
+The `Presence` interface is used to enter and subscribe to the presence set of a chat room.
+
+Presence is enabled in a room by default. Disable it using the `enableEvents` property in the [`PresenceOptions`](/docs/chat/api/javascript/rooms#PresenceOptions) of a room.
+
+Access it via `room.presence`.
+
+---
+
+## Enter the presence set
+
+`room.presence.enter()`
+
+Enters the client into the presence set. Will emit an `enter` event to all subscribers. Repeat calls will trigger `update` events.
+
+`enter(data?: unknown): Promise`
+
+### Parameters
+
+Use the following parameters:
+
+| Parameter | Description | Type |
+| --------- | ----------- | ---- |
+| `data` | *Optional* The user's data, a JSON serializable object that will be sent to all subscribers. | Unknown |
+
+### Returns
+
+Returns a promise. On success, the promise is fulfilled. On failure, the promise is rejected with an [`ErrorInfo`](/docs/chat/api/javascript/error-info).
+
+Throws if:
+
+* The room is not in the `attached` or `attaching` state.
+
+
+```javascript
+await room.presence.enter({status: 'online', activity: 'viewing'});
+```
+
+
+---
+
+## Update presence data
+
+`room.presence.update()`
+
+Updates a client's presence `data`. Will emit an `update` event to all subscribers. If the client is not already in the presence set, it will be treated as an [`enter`](#enter) event.
+
+`update(data?: unknown): Promise`
+
+### Parameters
+
+Use the following parameters:
+
+| Parameter | Description | Type |
+| --------- | ----------- | ---- |
+| `data` | *Optional* The user's data, a JSON serializable object that will be sent to all subscribers. | Unknown |
+
+### Returns
+
+Returns a promise. On success, the promise is fulfilled. On failure, the promise is rejected with an [`ErrorInfo`](/docs/chat/api/javascript/error-info).
+
+Throws if:
+
+* The room is not in the `attached` or `attaching` state.
+
+
+```javascript
+await room.presence.update({status: 'away', lastSeen: new Date()});
+```
+
+
+---
+
+## Leave the presence set
+
+`room.presence.leave()`
+
+Removes the client from the presence set. Will emit a `leave` event to all subscribers. If the client is not already part of the presence set, it will be treated as a no-op.
+
+`leave(data?: unknown): Promise`
+
+### Parameters
+
+Use the following parameters:
+
+| Parameter | Description | Type |
+| --------- | ----------- | ---- |
+| `data` | *Optional* The user's data, a JSON serializable object that will be sent to all subscribers. | Unknown |
+
+### Returns
+
+Returns a promise. On success, the promise is fulfilled. On failure, the promise is rejected with an [`ErrorInfo`](/docs/chat/api/javascript/error-info).
+
+Throws if:
+
+* The room is not in the `attached` or `attaching` state.
+
+
+```javascript
+await room.presence.leave({reason: 'User logged out'});
+```
+
+
+---
+
+## Get current presence members
+
+`room.presence.get()`
+
+Get a list of the current users in the presence set by returning the latest presence message for each.
+
+`get(params?: RealtimePresenceParams): Promise`
+
+### Parameters
+
+Use the following parameters:
+
+| Parameter | Description | Type |
+| --------- | ----------- | ---- |
+| `params` | *Optional* Parameters that control how the presence set is retrieved. | [`RealtimePresenceParams`](#realtimepresenceparams) |
+
+#### RealtimePresenceParams
+
+Parameters for retrieving presence members.
+
+It has the following properties:
+
+| Properties | Description | Type |
+| ---------- | ----------- | ---- |
+| `waitForSync` | *Optional* Whether to wait for a full presence set synchronization between Ably and the clients on the channel before returning the results. Synchronization begins as soon as the channel is attached. When set to `true`, the results will be returned as soon as the sync is complete. When set to `false`, the current list of members will be returned without the sync completing. The default is `true`. | Boolean |
+| `clientId` | *Optional* Filters the array of returned presence members for a specific client using its ID. | String |
+| `connectionId` | *Optional* Filters the array of returned presence members for a specific connection. | String |
+
+### Returns
+
+Returns a promise. On success, the promise is fulfilled with an array of [`PresenceMember`](#presencemember). On failure, the promise is rejected with an [`ErrorInfo`](/docs/chat/api/javascript/error-info).
+
+#### PresenceMember
+
+Represents a member in the presence set.
+
+It has the following properties:
+
+| Properties | Description | Type |
+| ---------- | ----------- | ---- |
+| `clientId` | The client ID of the presence member. | String |
+| `data` | The data associated with the presence member. | Unknown |
+| `extras` | The extras associated with the presence member. | Unknown |
+| `updatedAt` | The timestamp when this presence member was last updated. | Number |
+
+
+```javascript
+const members = await room.presence.get();
+console.log(`${members.length} users present`);
+```
+
+
+---
+
+## Check if a user is present
+
+`room.presence.isUserPresent()`
+
+Check if a user is part of the presence set using their `clientId`.
+
+`isUserPresent(clientId: string): Promise`
+
+### Parameters
+
+Use the following parameters:
+
+| Parameter | Description | Type |
+| --------- | ----------- | ---- |
+| `clientId` | The client ID to check if it is present in the room. | String |
+
+### Returns
+
+Returns a promise. On success, the promise is fulfilled with a boolean indicating whether the user is present. On failure, the promise is rejected with an [`ErrorInfo`](/docs/chat/api/javascript/error-info).
+
+Throws if:
+
+* The room is not in the `attached` or `attaching` state.
+
+
+```javascript
+const isPresent = await room.presence.isUserPresent('user123');
+if (isPresent) {
+ console.log('User is currently in the room');
+}
+```
+
+
+---
+
+## Subscribe to specific presence events
+
+`room.presence.subscribe()`
+
+Subscribe the provided listener to a list of presence events.
+
+Note: This requires presence events to be enabled via the `enableEvents` option in the [`PresenceOptions`](/docs/chat/api/javascript/rooms#PresenceOptions) provided to the room. If this is not enabled, an error will be thrown.
+
+`subscribe(eventOrEvents: PresenceEventType | PresenceEventType[], listener?: PresenceListener): Subscription`
+
+### Parameters
+
+Use the following parameters:
+
+| Parameter | Description | Type |
+| --------- | ----------- | ---- |
+| `eventOrEvents` | Single event name or array of events to subscribe to. | [`PresenceEventType`](#presenceeventtype) \| `PresenceEventType`[] |
+| `listener` | *Optional* Listener to register. | [`PresenceListener`](#presencelistener) |
+
+#### PresenceEventType
+
+An enum that represents the types of presence events.
+
+It has the following members:
+
+| Member | Description |
+| ------ | ----------- |
+| `Enter` | A member has entered the presence set. |
+| `Leave` | A member has left the presence set. |
+| `Update` | A member has updated their presence data. |
+| `Present` | Get the current presence set when subscribing. |
+
+#### PresenceListener
+
+A listener that listens for presence events.
+
+`PresenceListener: (event: PresenceEvent) => void`
+
+It uses the following parameters:
+
+| Parameter | Description | Type |
+| --------- | ----------- | ---- |
+| `event` | A presence event. | [`PresenceEvent`](#presenceevent) |
+
+#### PresenceEvent
+
+Represents a presence event.
+
+It has the following properties:
+
+| Properties | Description | Type |
+| ---------- | ----------- | ---- |
+| `type` | The type of presence event. | [`PresenceEventType`](#presenceeventtype) |
+| `member` | The presence member associated with the event. | [`PresenceMember`](#presencemember) |
+
+### Returns
+
+Returns a [`Subscription`](/docs/chat/api/javascript/subscriptions#subscription) object.
+
+Throws an [`ErrorInfo`](/docs/chat/api/javascript/error-info) with `code` 40000 if:
+
+* Presence events are not enabled.
+
+
+```javascript
+const subscription = room.presence.subscribe(['enter', 'leave'], (presenceEvent) => {
+ console.log(`${presenceEvent.member.clientId} ${presenceEvent.type} the room`);
+});
+
+// Unsubscribe when done
+subscription.unsubscribe();
+```
+
+
+---
+
+## Subscribe to all presence events
+
+`room.presence.subscribeAll()`
+
+Subscribe the provided listener to all presence events.
+
+`subscribe(listener?: PresenceListener): Subscription`
+
+### Parameters
+
+Use the following parameters:
+
+| Parameter | Description | Type |
+| --------- | ----------- | ---- |
+| `listener` | *Optional* Listener to subscribe. | [`PresenceListener`](#presencelistener) |
+
+#### Returns
+
+Returns a [`Subscription`](/docs/chat/api/javascript/subscriptions#subscription) object.
+
+Throws an [`ErrorInfo`](/docs/chat/api/javascript/error-info) with code 40000 if:
+
+* Presence events are not enabled.
+
+
+```javascript
+const subscription = room.presence.subscribe((presenceEvent) => {
+ console.log('Presence event:', presenceEvent.type, presenceEvent.member);
+});
+```
+
diff --git a/src/pages/docs/chat/api/javascript/room-reactions.mdx b/src/pages/docs/chat/api/javascript/room-reactions.mdx
new file mode 100644
index 0000000000..e6b823a910
--- /dev/null
+++ b/src/pages/docs/chat/api/javascript/room-reactions.mdx
@@ -0,0 +1,137 @@
+---
+title: RoomReactions
+meta_description: "Ably Chat JavaScript API references for the RoomReactions interface."
+---
+
+The `RoomReactions` interface is used to send and subscribe to ephemeral, room-level reactions.
+
+Access it via `room.reactions`.
+
+---
+
+## Send a room reaction
+
+`room.reactions.send()`
+
+Send a reaction to the room including some metadata.
+
+`send(params: SendReactionParams): Promise`
+
+### Parameters
+
+Use the following parameters:
+
+| Parameter | Description | Type |
+| --------- | ----------- | ---- |
+| `params` | An object containing the type, headers and metadata of the room reaction. | [`SendReactionParams`](#sendreactionparams) |
+
+#### SendReactionParams
+
+The following `SendReactionParams` parameters can be set:
+
+| Parameters | Description | Type |
+| ---------- | ----------- | ---- |
+| `name` | The name of the reaction. | String |
+| `metadata` | *Optional* Metadata associated with the reaction. | [`Metadata`](#roomreactionmetadata) |
+| `headers` | *Optional* Headers associated with the reaction. | [`Headers`](#roomreactionheaders) |
+
+#### RoomReactionHeaders
+
+`RoomReactionHeaders` enable attaching extra info to a reaction. Do not use headers for authoritative information. There is no server-side validation. When reading the headers, treat them like user input.
+
+`RoomReactionHeaders: Record`
+
+#### RoomReactionMetadata
+
+`RoomReactionMetadata` enables attaching extra info to a reaction. Do not use metadata for authoritative information. There is no server-side validation. When reading the metadata, treat it like user input.
+
+`RoomReactionMetadata: Record`
+
+### Returns
+
+Returns a promise. On success, the promise is fulfilled when the reaction was sent. On failure, the promise is rejected with an [`ErrorInfo`](/docs/chat/api/javascript/error-info).
+
+Note that it is possible to receive your own reaction via the reactions listener before this promise resolves.
+
+Throws if:
+
+* The `Connection` is not in the `Connected` state.
+
+
+```javascript
+await room.reactions.send({
+ name: '👍',
+ metadata: { userId: 'user123' }
+});
+```
+
+
+---
+
+## Subscribe to room reactions
+
+`room.reactions.subscribe()`
+
+Subscribe to receive room-level reactions.
+
+`subscribe(listener: RoomReactionListener): Subscription`
+
+### Parameters
+
+Use the following parameters:
+
+| Parameter | Description | Type |
+| --------- | ----------- | ---- |
+| `listener` | The listener function to be called when a reaction is received. | [`RoomReactionListener`](#roomreactionlistener) |
+
+#### RoomReactionListener
+
+A listener that listens for room reaction events.
+
+`RoomReactionListener: (event: RoomReactionEvent) => void`
+
+It uses the following parameters:
+
+| Parameter | Description | Type |
+| --------- | ----------- | ---- |
+| `event` | A room reaction event. | [`RoomReaction`](#roomreactionevent) |
+
+#### RoomReactionEvent
+
+An interface that represents a room reaction event.
+
+It has the following properties:
+
+| Property | Description | Type |
+| -------- | ----------- | ---- |
+| `roomReaction` | The reaction that was received. | [`RoomReaction`](#roomreaction) |
+| `type` | The type of reaction. | Reaction |
+
+#### RoomReaction
+
+An interface that represents a room reaction event.
+
+It has the following properties:
+
+| Property | Description | Type |
+| -------- | ----------- | ---- |
+| `name` | The name of the reaction. | String |
+| `clientId` | The client ID of the user who sent the reaction. | String |
+| `timestamp` | The timestamp when the reaction was sent. | Date |
+| `metadata` | *Optional* Metadata associated with the reaction. | [`RoomReactionMetadata`](#roomreactionmetadata) |
+| `headers` | *Optional* Headers associated with the reaction. | [`RoomReactionHeaders`](#roomreactionheaders) |
+
+### Returns
+
+Returns a [`Subscription`](/docs/chat/api/javascript/subscriptions#subscription) object that allows you to control the subscription.
+
+
+```javascript
+const subscription = room.reactions.subscribe((reaction) => {
+ console.log(`${reaction.clientId} reacted with ${reaction.type}`);
+});
+
+// Unsubscribe when done
+await subscription.unsubscribe();
+```
+
diff --git a/src/pages/docs/chat/api/javascript/room.mdx b/src/pages/docs/chat/api/javascript/room.mdx
new file mode 100644
index 0000000000..1effec5268
--- /dev/null
+++ b/src/pages/docs/chat/api/javascript/room.mdx
@@ -0,0 +1,206 @@
+---
+title: Room
+meta_description: "Ably Chat JavaScript API references for the Room interface."
+---
+
+The `Room` interface represents a chat room.
+
+Access it via `ChatClient.rooms.get(name)`.
+
+---
+
+## Accessors
+
+It has the following accessors:
+
+| Property | Description | Type |
+| -------- | ----------- | ---- |
+| `name` | The unique name of the room. | String |
+| `status` | The current status of the room. | [`RoomStatus`](#roomstatus) |
+| `error` | The current error, if any, that caused the room to enter the current status. | [`ErrorInfo`](/docs/chat/api/javascript/error-info) \| `undefined` |
+| `channel` | The underlying Ably realtime channel used for the room. | [`RealtimeChannel`](/docs/channels) |
+| `messages` | Allows you to send, subscribe to, and query messages in the room. | [`Messages`](/docs/chat/api/javascript/messages) |
+| `presence` | Interact with presence events in the room. | [`Presence`](/docs/chat/api/javascript/presence) |
+| `occupancy` | Interact with occupancy metrics for the room. | [`Occupancy`](/docs/chat/api/javascript/occupancy) |
+| `reactions` | Interact with room-level reactions. | [`RoomReactions`](/docs/chat/api/javascript/room-reactions) |
+| `typing` | Interact with typing events in the room. | [`Typing`](/docs/chat/api/javascript/typing) |
+
+---
+
+## RoomStatus
+
+A `Room` is in one of the following states:
+
+| RoomStatus | Description |
+| ---------- | ----------- |
+| `Initializing` | The SDK is initializing the room. |
+| `Initialized` | A temporary state when a room is first initialized. |
+| `Attaching` | The room is attaching to Ably. |
+| `Attached` | The room is attached to Ably. |
+| `Detaching` | The room is detaching from Ably. |
+| `Detached` | The room is detached from Ably. |
+| `Failed` | The room failed to attach to Ably. |
+| `Suspended` | The room is suspended, and automatic reattachment has been temporarily disabled. |
+| `Releasing` | The room is in the process of releasing and is no long usable. |
+| `Released` | The room is released and no longer usable. |
+
+---
+
+## Attach to a room
+
+`room.attach()`
+
+Attaches to the room in order to receive events in realtime.
+
+If a room fails to attach, it will enter either the `Suspended` or `Failed` [state](#roomstatus).
+
+If the room enters the `Failed` state, then the SDK will not automatically retry attaching and intervention is required.
+
+If the room enters the `Suspended` state, then the call to attach will reject with an [`ErrorInfo`](/docs/chat/api/javascript/error-info) that caused the suspension. However, the SDK will retry attaching to the room automatically after a delay.
+
+`attach(): Promise`
+
+### Returns
+
+Returns a promise. On success, the promise is fulfilled and the room begins receiving real-time events. On failure, the promise is rejected with an [`ErrorInfo`](/docs/chat/api/javascript/error-info).
+
+
+```javascript
+const room = await client.rooms.get('room:general');
+await room.attach();
+```
+
+
+---
+
+## Detach from a room
+
+`room.detach()`
+
+Detaches from the room to stop receiving events.
+
+`detach(): Promise`
+
+### Returns
+
+Returns a promise. On success, the promise is fulfilled and the room stops receiving events. On failure, the promise is rejected with an [`ErrorInfo`](/docs/chat/api/javascript/error-info).
+
+
+```javascript
+await room.detach();
+```
+
+
+---
+
+## Listen for RoomStatus changes
+
+`room.onStatusChange()`
+
+Registers a listener that is called whenever the [`RoomStatus`](#roomstatus) changes.
+
+`onStatusChange(listener: RoomStatusListener): StatusSubscription`
+
+### Parameters
+
+Use the following parameters:
+
+| Parameter | Description | Type |
+| --------- | ----------- | ---- |
+| `listener` | Function called when the room status changes. | [`RoomStatusListener`](#roomstatuslistener) |
+
+#### RoomStatusListener
+
+A function that is called when the [`RoomStatus`](#roomstatus) of a room changes.
+
+`RoomStatusListener: (change: RoomStatusChange) => void`
+
+It uses the following parameters:
+
+| Parameter | Description | Type |
+| --------- | ----------- | ---- |
+| `change` | The change in `RoomStatus`. | [`RoomStatusChange`](#roomstatuschange) |
+
+#### RoomStatusChange
+
+An interface that represents a change in the [`RoomStatus`](#roomstatus) of a room.
+
+It has the following properties:
+
+| Property | Description | Type |
+| -------- | ----------- | ---- |
+| `previous` | The previous status of the room. | [`RoomStatus`](#roomstatus) |
+| `current` | The current status of the room. | [`RoomStatus`](#roomstatus) |
+| `error` | *Optional* The error that caused the change. | [`ErrorInfo`](/docs/chat/api/javascript/error-info) |
+
+### Returns
+
+Returns a [`StatusSubscription`](/docs/chat/api/javascript/subscriptions#statussubscription) object with an `off()` method to remove the listener.
+
+
+```javascript
+room.onStatusChange((status) => {
+ console.log(`Room status changed to: ${status}`);
+});
+```
+
+
+---
+
+## Register a discontinuity handler
+
+`room.onDiscontinuity()`
+
+Registers a handler that is called whenever a discontinuity is detected. Discontinuity occurs when a connection is interrupted and a `Room` cannot be resumed from its previous state.
+
+If the discontinuity lasts for less than 2 minutes, then the SDK will automatically reattach to any rooms and replay any missed messages once it reconnects.
+
+If the discontinuity last for longer than 2 minutes, then use [`historyBeforeSubscribe()`](/docs/chat/api/javascript/messages#historyBeforeSubscribe) to retrieve any missed messages.
+
+`onDiscontinuity(handler: DiscontinuityListener): StatusSubscription`
+
+### Parameters
+
+Use the following parameters:
+
+| Parameter | Description | Type |
+| --------- | ----------- | ---- |
+| `handler` | Function called when a discontinuity is detected. | `DiscontinuityListener` |
+
+#### DiscontinuityListener
+
+A handler for discontinuity events.
+
+`DiscontinuityListener: (error: ErrorInfo) => void`
+
+It uses the following parameters:
+
+| Parameter | Description | Type |
+| --------- | ----------- | ---- |
+| `error` | The error that occurred to cause the discontinuity. | [`ErrorInfo`](/docs/chat/api/javascript/error-info) |
+
+### Returns
+
+Returns a `StatusSubscription` object with an `off()` method to remove the handler.
+
+
+```javascript
+const { off } = room.onDiscontinuity((reason: ErrorInfo) => {
+ // Recover from the discontinuity
+});
+```
+
+
+---
+
+## Get RoomOptions
+
+`room.options()`
+
+Returns the [`RoomOptions`](/docs/chat/api/javascript/rooms#roomoptions) used to create the room.
+
+`options(): RoomOptions`
+
+### Returns
+
+Returns a copy of the [`RoomOptions`](/docs/chat/api/room#roomoptions) used to create the room.
diff --git a/src/pages/docs/chat/api/javascript/rooms.mdx b/src/pages/docs/chat/api/javascript/rooms.mdx
new file mode 100644
index 0000000000..f04b611ef7
--- /dev/null
+++ b/src/pages/docs/chat/api/javascript/rooms.mdx
@@ -0,0 +1,127 @@
+---
+title: Rooms
+meta_description: "Ably Chat JavaScript API references for the Rooms interface."
+---
+
+The `Rooms` interface manages the lifecycle of chat rooms.
+
+Access it via `ChatClient.rooms`.
+
+---
+
+## Create a room
+
+`ChatClient.rooms.get()`
+
+Create or retrieve `Room` object. Optionally provide custom configuration to the room.
+
+Call [`release()`](#release) when the `Room` object is no longer needed. If a call to `get()` is made for a room that is currently being released, then the promise will only resolve when the release operation is complete.
+
+If a call to `get()` is made, followed by a subsequent call to `release()` before the promise resolves, then the promise will reject with an error.
+
+`get(name: string, options?: RoomOptions): Promise`
+
+### Parameters
+
+Use the following parameters:
+
+| Parameter | Description | Type |
+| --------- | ----------- | ---- |
+| `name` | The name of the room to create or retrieve. | String |
+| `options` | *Optional* Custom configuration options for the room. | [`RoomOptions`](#roomoptions) |
+
+#### RoomOptions
+
+The following `RoomOptions` can be set:
+
+| Properties | Description | Type |
+| ---------- | ----------- | ---- |
+| `messages` | *Optional* The configuration for messages in the room. | [`MessageOptions`](#messageoptions) |
+| `occupancy` | *Optional* The configuration for occupancy in the room. | [`OccupancyOptions`](#occupancyoptions) |
+| `presence` | *Optional* The configuration for presence in the room. | [`PresenceOptions`](#presenceoptions) |
+| `typing` | *Optional* The configuration for typing indicators in the room. | [`TypingOptions`](#typingoptions) |
+
+#### MessageOptions
+
+The following `MessageOptions` can be set:
+
+| Properties | Description | Type |
+| ---------- | ----------- | ---- |
+| `defaultMessageReactionType` | *Optional* The default type of message reaction. Other types can still be sent by specifying the `type` parameter when reacting to a message. The default value is `distinct`. | [`MessageReactionType`](#messagereactiontype) |
+| `rawMessageReactions` | *Optional* Whether subscribers should receive individual message reactions, rather than just aggregates. The default value is `false`. | Boolean |
+
+#### MessageReactionType
+
+An enum that represents the types of reactions for a message.
+
+It has the following members:
+
+| Member | Description |
+| ------ | ----------- |
+| `Distinct` | Allows for at most one reaction of each type per client per message. It is possible for a client to add multiple reactions to the same message as long as they are different (e.g. different emojis). Duplicates are not counted in the summary. This is similar to reactions on Slack. |
+| `Multiple` | Allows any number of reactions, including repeats, and they are counted in the summary. The reaction payload also includes a count of how many times each reaction should be counted (defaults to 1 if not set). This is similar to the clap feature on Medium. |
+| `Unique` | Allows for at most one reaction per client per message. If a client reacts to a message a second time, only the second reaction is counted in the summary. This is similar to reactions on iMessage, Facebook Messenger or WhatsApp. |
+
+#### OccupancyOptions
+
+The following `OccupancyOptions` can be set:
+
+| Properties | Description | Type |
+| ---------- | ----------- | ---- |
+| `enableEvents` | *Optional* Sets whether the client should receive [occupancy](docs/chat/api/javascript/occupancy) events. If enabled, the client will receive messages detailing the changing room occupancy. The default value is `false`. | Boolean |
+
+#### PresenceOptions
+
+The following `PresenceOptions` can be set:
+
+| Properties | Description | Type |
+| ---------- | ----------- | ---- |
+| `enableEvents` | *Optional* Sets whether the client should receive [presence](docs/chat/api/javascript/presence) events. If enabled, the client will presence updates about other clients in the room. Note that even if the client hasn't subscribed to presence, they are still streamed presence events by the server. Clients can also still register their presence in the room without receiving presence events. The default value is `true`. | Boolean |
+
+#### TypingOptions
+
+The following `TypingOptions` can be set:
+
+| Properties | Description | Type |
+| ---------- | ----------- | ---- |
+| `heartbeatThrottleMs` | *Optional* Set the minimum time interval between consecutive `typing.started` events. The interval is reset after a `typing.stopped` event. The default value is `10000`. | Number |
+
+### Returns
+
+Returns a promise. On success, the promise is fulfilled with the new or existing room object. On failure, the promise is rejected with an [`ErrorInfo`](/docs/chat/api/javascript/error-info) if a room with the same name but different `options` already exists.
+
+
+```javascript
+const room = await chatClient.rooms.get('livestream-1', {occupancy: {enableEvents: true}});
+```
+
+
+---
+
+## Release a room
+
+`ChatClient.rooms.release()`
+
+Releases a `Room` object, allowing for it to be garbage collected.
+
+This will release the reference to the `Room` object from the `Rooms` collection and detach it from Ably. It does not unsubscribe the client from any events. Call [`Rooms.get()`](#get) if you want to get the `Room` object back.
+
+`release(name: string): Promise`
+
+### Parameters
+
+Use the following parameters:
+
+| Parameter | Description | Type |
+| --------- | ----------- | ---- |
+| `name` | The name of the room to release. | String |
+
+### Returns
+
+Returns a promise. On success, the promise is fulfilled. On failure, the promise is rejected with an [`ErrorInfo`](/docs/chat/api/javascript/error-info).
+
+
+```javascript
+await rooms.release('livestream-1');
+```
+
diff --git a/src/pages/docs/chat/api/javascript/subscriptions.mdx b/src/pages/docs/chat/api/javascript/subscriptions.mdx
new file mode 100644
index 0000000000..c39303898f
--- /dev/null
+++ b/src/pages/docs/chat/api/javascript/subscriptions.mdx
@@ -0,0 +1,81 @@
+---
+title: Subscriptions
+meta_description: "Ably Chat JavaScript API references for interfaces that manage the lifecycle of subscriptions."
+---
+
+The following interfaces are used to manage the lifecycle of subscriptions.
+
+## Subscription
+
+A response object that allows you to control the subscription.
+
+### Properties
+
+It has the following properties:
+
+| Property | Description | Type |
+| -------- | ----------- | ---- |
+| `unsubscribe` | A method to unsubscribe from events. | `() => Promise` |
+
+### Returned by
+
+It is returned by the following methods:
+
+* [`room.messages.reactions.subscribe()`](/docs/chat/api/javascript/messages-reactions#subscribe)
+* [`room.messages.reactions.subscribeRaw()`](/docs/chat/api/javascript/messages-reactions#subscribeRaw)
+* [`room.occupancy.subscribe()`](/docs/chat/api/javascript/occupancy#subscribe)
+* [`room.presence.subscribe()`](/docs/chat/api/javascript/presence#subscribe)
+* [`room.presence.subscribeAll()`](/docs/chat/api/javascript/presence#subscribeAll)
+* [`room.reactions.subscribe()`](/docs/chat/api/javascript/room-reactions#subscribe)
+* [`room.typing.subscribe()`](/docs/chat/api/javascript/typing#subscribe)
+
+---
+
+## MessageSubscriptionResponse
+
+A response object that allows you to control the subscription to message events.
+
+### Properties
+
+It has the following properties:
+
+| Property | Description | Type |
+| -------- | ----------- | ---- |
+| `unsubscribe` | A method to unsubscribe from message events. | `() => Promise` |
+
+There is a difference between unsubscribing from messages and detaching from a room. Messages are sent to users as soon as they attach to a room, irrespective of whether a listener has been registered by calling `subscribe()`. Unsubscribing only deregisters the listener. The [`detach()`](/docs/chat/api/javascript/room#detach) method detaches a user from the room. At that point a user will no longer receive any messages that are sent to the room.
+
+### Methods
+
+It has the following methods:
+
+| Method | Description |
+| ------ | ----------- |
+| [`historyBeforeSubscribe()`](/docs/chat/api/javascript/messages#historyBeforeSubscribe) | Get the messages sent before the listener was subscribed. |
+
+### Returned by
+
+It is returned by the following methods:
+
+* [`room.messages.subscribe()`]()/docs/chat/api/javascript/messages#subscribe)
+
+---
+
+## StatusSubscription
+
+An interface that represents a subscription to status change events. It also provides a method of cleaning up subscriptions that are no longer needed.
+
+### Properties
+
+It has the following properties:
+
+| Property | Description | Type |
+| -------- | ----------- | ---- |
+| `off` | Unsubscribes from the status change events. It will ensure that no further status change events will be sent to the subscriber and that references to the subscriber are cleaned up. | `() => void` |
+
+### Returned by
+
+It is returned by the following methods:
+
+* [`connection.onStatusChange()`](/docs/chat/api/javascript/connection#onStatusChange)
+* [`room.onStatusChange()`](/docs/chat/api/javascript/room#onStatusChange)
diff --git a/src/pages/docs/chat/api/javascript/typing.mdx b/src/pages/docs/chat/api/javascript/typing.mdx
new file mode 100644
index 0000000000..7075c269c1
--- /dev/null
+++ b/src/pages/docs/chat/api/javascript/typing.mdx
@@ -0,0 +1,183 @@
+---
+title: Typing
+meta_description: "Ably Chat JavaScript API references for the Typing interface."
+---
+
+The `Typing` interface is used to send typing events on keystrokes and subscribe to typing events emitted by other users.
+
+Access it via `room.typing`.
+
+---
+
+## Get the users currently typing
+
+`room.typing.current()`
+
+Get the set of users that are currently typing in the room by their `clientId`s.
+
+`current(): Set`
+
+### Returns
+
+Returns the set of `clientId`s of all users that are currently typing.
+
+
+```javascript
+const currentlyTypingClientIds = room.typing.current();
+```
+
+
+---
+
+## Start typing
+
+`room.typing.keystroke()`
+
+Send a `typing.started` event to the server. Events are throttled according to the [`heartbeatThrottleMs TypingOption`](/docs/chat/api/javascript/rooms#typingoptions). If an event has already been sent within the configured interval then the operation is a no-op.
+
+Calls to `keystroke()` and `stop()` are serialized and will always resolve in the correct order.
+
+* For example, if multiple `keystroke()` calls are made in quick succession before the first `keystroke()` call has sent a `typing.started` event to the server, followed by one `stop()` call, the `stop()` call will execute as soon as the first `keystroke()` call completes. All intermediate `keystroke()` calls will be treated as no-ops.
+* The most recent `keystroke()` or `stop()` will always determine the final state, ensuring operations resolve to a consistent and correct state.
+
+`keystroke(): Promise`
+
+#### Returns
+
+Returns a promise. On success, the promise is fulfilled. On failure, the promise is rejected with an [`ErrorInfo`](/docs/chat/api/javascript/error-info).
+
+Throws if:
+
+* The `Connection` is not in the `Connected` state.
+* The operation fails to send the event to the server.
+* There is a problem acquiring the mutex that controls serialization.
+
+
+```javascript
+await room.typing.keystroke();
+```
+
+
+---
+
+## Stop typing
+
+`room.typing.stop()`
+
+Send a `typing.stopped` event to the server. If an event has already been sent within the configured interval then the operation is a no-op.
+
+Calls to `keystroke()` and `stop()` are serialized and will always resolve in the correct order.
+
+* For example, if multiple `keystroke()` calls are made in quick succession before the first `keystroke()` call has sent a `typing.started` event to the server, followed by one `stop()` call, the `stop()` call will execute as soon as the first `keystroke()` call completes. All intermediate `keystroke()` calls will be treated as no-ops.
+* The most recent `keystroke()` or `stop()` will always determine the final state, ensuring operations resolve to a consistent and correct state.
+
+`stop(): Promise`
+
+### Returns
+
+Returns a promise. On success, the promise is fulfilled. On failure, the promise is rejected with an [`ErrorInfo`](/docs/chat/api/javascript/error-info).
+
+Throws if:
+
+* The `Connection` is not in the `Connected` state.
+* The operation fails to send the event to the server.
+* There is a problem acquiring the mutex that controls serialization.
+
+
+```javascript
+await room.typing.stop();
+```
+
+
+---
+
+## Subscribe to typing events
+
+`room.typing.subscribe()`
+
+Subscribe to all typing events by registering a listener.
+
+`subscribe(listener: TypingListener): Subscription`
+
+### Parameters
+
+Use the following parameters:
+
+| Parameter | Description | Type |
+| --------- | ----------- | ---- |
+| `listener` | Function called when a typing event is received. | `TypingListener` |
+
+#### TypingListener
+
+A listener that listens for typing events.
+
+`TypingListener: (event: TypingSetEvent) => void`
+
+It uses the following parameters:
+
+| Parameter | Description | Type |
+| --------- | ----------- | ---- |
+| `event` | A typing event. | [`TypingSetEvent`](#typingsetevent) |
+
+#### TypingSetEvent
+
+An interface that represents a change in the state of currently typing users.
+
+It has the following properties:
+
+| Property | Description | Type |
+| -------- | ----------- | ---- |
+| `change` | The change that resulted in the new set of users currently typing. Contains the `clientId` of the user and whether they started or stopped typing. | `change: { clientId: string; type: [TypingEventType](#typingeventtype) }` |
+| `currentlyTyping` | The set of `clientId`s that are currently typing. | `Set` |
+| `type` | The type of event. | [`TypingSetEventType`](#typingseteventtype) |
+
+The following is an example of a TypingSetEvent:
+
+
+```json
+{
+ "type": "typing.set.changed",
+ "currentlyTyping": {
+ "clemons",
+ "zoranges",
+ },
+ "change": {
+ "type": "typing.started",
+ "clientId": "clemons"
+ }
+}
+```
+
+
+#### TypingEventType
+
+An enum that represents the types of events emitted by users typing in a room.
+
+It has the following members:
+
+| Member | Description |
+| ------ | ----------- |
+| `typing.started` | Sent when a user starts typing. |
+| `typing.stopped` | Sent when a user stops typing. |
+
+#### TypingSetEventType
+
+An enum representing the typing set event types.
+
+It has the following members:
+
+| Member | Description |
+| ------ | ----------- |
+| `SetChanged` | Event triggered when a change occurs in the set of users currently typing. |
+
+### Returns
+
+Returns a [`Subscription`](/docs/chat/api/javascript/subscriptions#subscription) object with an `unsubscribe()` method to remove the listener.
+
+
+```javascript
+const {unsubscribe} = room.typing.subscribe((event) => {
+ console.log(event);
+});
+```
+