# Channels
## Channels
The `Channels` object, accessed from the [realtime library client constructor](https://ably.com/docs/api/realtime-sdk.md#channels), is used to create and destroy `Channel` objects. It exposes the following public methods:
### Channels Methods
#### getGet
`Channel get(String name, ChannelOptions channelOptions?)`
`ARTRealtimeChannel get(String channelName, ARTChannelOptions channelOptions);`
`Channel get(String channelName, ChannelOptions channelOptions)`
Creates a new [Channel](#properties) object if none for the channel exists, or returns the existing channel object.
#### releaseRelease
`release(String channelName)`
`void release(String channelName)`
`bool Release(string channelName)`
Releases all SDK-held references to a [Channel](#properties) object, enabling it to be garbage collected. It can be useful for applications that work with a continually changing set of channels on a single client and need to avoid unbounded memory growth; if this does not describe your application, don't call it.
This method only affects the local client-side representation of the channel. The channel itself on the Ably platform is not deleted or changed, and other client instances (in the same or different processes) are unaffected.
Channels not already in the `initialized`, `detached`, or `failed` [state](https://ably.com/docs/channels/states.md) are detached before release. After release, calling `channels.get(channelName)` returns a fresh channel object in the `initialized` state.
## Channel
The Channel object, created via the [Channels](#channels-object) object, is used to interact with a specific channel.
### Channel PropertiesARTRealtimeChannel PropertiesAbly::Realtime::Channel Attributesio.ably.lib.realtime.Channel MembersIO.Ably.Realtime.RealtimeChannel Properties
The `Channel` object exposes the following public propertiesattributesmembers:
#### stateState
The current `io.ably.lib.realtime.ChannelState state`[`IO.Ably.Realtime.ChannelState`](https://ably.com/docs/api/realtime-sdk/channels.md#channel-state) `state``Ably::Realtime::Channel::STATE state``ARTRealtimeChannelState``ChannelState` of this `Channel`. See the supported [channel states](https://ably.com/docs/channels/states.md) for more information.
#### errorReasonreasonerror_reasonErrorReason
When a channel failure occurs this attributememberproperty is populated.
The type is [`ErrorInfo`](https://ably.com/docs/api/realtime-sdk/types.md#error-info)[`AblyException`](https://ably.com/docs/api/realtime-sdk/types.md#ably-exception).
#### nameName
The name `String` unique to this channel.
#### presencePresence
Provides access to the [Presence](https://ably.com/docs/presence-occupancy/presence.md) object for this channel which can be used to access members present on the channel, or participate in presence.
#### push
Provides access to the [PushChannel](https://ably.com/docs/api/realtime-sdk/push.md#push-channel) object for this channel which can be used to access members present on the channel, or participate in presence.
#### annotations
Provides access to the [`RealtimeAnnotations`](#realtime-annotations) object for this channel, which can be used to publish, delete, retrieve and subscribe to [annotations](https://ably.com/docs/messages/annotations.md) on messages.
#### object
A public field providing access to the [RealtimeObject](https://ably.com/docs/liveobjects.md) for this channel, which can be used to read, modify and subscribe to LiveObjects on a channel.
An extension property provided by the AblyLiveObjects plugin, giving access to the [RealtimeObject](https://ably.com/docs/liveobjects.md) for this channel, which can be used to read, modify and subscribe to LiveObjects on a channel.
### Channel Methods
#### publishPublish
There are two overloaded versions of this method:
`Deferrable publish(String name, Object data) -> yields`
`void publish(String name, Object data, CompletionListener listener)`
`void Publish(string name, object data, Action callback = null, string clientId = null)`
`publish(name: String?, data: AnyObject?, callback: ((ARTErrorInfo?) -> Void)?)`
`Future publish(name: String name, data: Object data, message: Message message)`
Publish a single message on this channel based on a given event name and payload. A callbacklistener may optionally be passed in to this call to be notified of success or failure of the operation. When publish is called with this client library, it [won't attempt to implicitly attach to the channel](https://ably.com/docs/channels/states.md#attach), so long as [transient publishing](https://ably.com/docs/pub-sub/advanced.md#transient-publish) is available in the library. Otherwise, the client will implicitly attach.
`Deferrable publish(Message[] messages) -> yields`
`void publish(Message[] messages, CompletionListener listener)`
`void Publish(IEnumerable messages, Action callback = null)`
`publish(messages: [ ARTMessage ], callback: ((ARTErrorInfo?) -> Void)?)`
`Future publish(messages: List messages)`
Publish several messages on this channel. A callbacklistenerblock may optionally be passed in to this call to be notified of success or failure of the operation. When publish is called with this client library, it [won't attempt to implicitly attach to the channel](https://ably.com/docs/pub-sub/advanced.md#transient-publish). If the channel is `initialized` (i.e. no attempt to attach has yet been made for this channel), then calling `publish` will implicitly attach the channel.
The entire `messages` array is published atomically. This means that:
* Either they will all be successfully published or none of them will
* The [max message size](https://ably.com/docs/platform/pricing/limits.md#message) limit applies to the total size of all messages in the array
* The publish will only count as a single message for the purpose of [per-channel rate limit](https://ably.com/docs/platform/pricing/limits.md#message)
* If you are using client-specified message IDs, [they must conform to certain restrictions](https://faqs.ably.com/client-specified-message-id-restrictions-for-multiple-messages-published-atomically)
##### Parameters
| Parameter | Description | Type |
|-----------|-------------|------|
| data | data payload for the message. The supported payload types are String, Map, List, and null. | `Object` |
| message | A message object to publish | [`Message`](https://ably.com/docs/api/realtime-sdk/channels.md#message) |
| messages | An array of message objects to publish | [`Message []`](/docs/api/realtime-sdk/channels#message) |
| Parameter | Description | Type |
|-----------|-------------|------|
| data | data payload for the message. The supported payload types are Strings, JsonObject, binary data as byte arrays, and null. | `Object` |
| message | A message object to publish | [`Message`](https://ably.com/docs/api/realtime-sdk/channels.md#message) |
| messages | An array of message objects to publish | [`Message []`](/docs/api/realtime-sdk/channels#message) |
| listener | Listener to be notified on completion | [`CompletionListener`](https://ably.com/docs/api/realtime-sdk/channels.md#completion-listener) |
| Parameter | Description | Type |
|-----------|-------------|------|
| data | data payload for the message. The supported payload types are Strings, binary data as byte arrays, any plain c# class that can be serialized to Json, and null. | `Object` |
| message | A message object to publish | [`Message`](https://ably.com/docs/api/realtime-sdk/channels.md#message) |
| messages | An array of message objects to publish | [`Message []`](/docs/api/realtime-sdk/channels#message) |
| callback | is an action of the form `Action` which is called upon completion | - |
| Parameter | Description | Type |
|-----------|-------------|------|
| data | data payload for the message. The supported payload types are Strings, Hash or Array objects that can be serialized to JSON using `to_json`, binary data as `ASCII-8BIT` byte arrays, and null. (Note that if sending a byte array, it should be the entire payload; a hash or array with a bytearray field within it may not be correctly encoded) | `Object` |
| message | A message object to publish | [`Message`](https://ably.com/docs/api/realtime-sdk/channels.md#message) |
| messages | An array of message objects to publish | [`Message []`](/docs/api/realtime-sdk/channels#message) |
| &block | yields upon successfully publishing the message | - |
| Parameter | Description | Type |
|-----------|-------------|------|
| data | data payload for the message. The supported payload types are NS`String`, NS`Dictionary` or NS`Array` objects that can be serialized to JSON, binary data as `NSData`, and `nil`. | `Object` |
| message | A message object to publish | [`Message`](https://ably.com/docs/api/realtime-sdk/channels.md#message) |
| messages | An array of message objects to publish | [`Message []`](/docs/api/realtime-sdk/channels#message) |
| callback | called upon publishing the message, or with an error | - |
##### Callback result
On successful publish of the message, `err` is null. On failure to publish the message, `err` contains an [`ErrorInfo`](https://ably.com/docs/api/realtime-sdk/types.md#error-info) object describing the failure reason.
##### Callback result
On successful publish of the message, `error` is null. On failure to publish the message, `error` contains an [`ErrorInfo`](https://ably.com/docs/api/realtime-sdk/types.md#error-info) object describing the failure reason.
##### Listener result
On successful publish of the message, the `onSuccess` method of the [`CompletionListener`](#completion-listener) is called. On failure to publish the message, the `onError` method is called with an [`ErrorInfo`](https://ably.com/docs/api/realtime-sdk/types.md#error-info) argument describing the failure reason.
##### Returns
A [`Deferrable`](https://ably.com/docs/api/realtime-sdk/types.md#deferrable) object is returned from the method.
On successful publish of the message, the registered success blocks for the [`Deferrable`](https://ably.com/docs/api/realtime-sdk/types.md#deferrable) and any block provided to the method are executed. On failure to publish the message, the `errback` callbacks of the [`Deferrable`](https://ably.com/docs/api/realtime-sdk/types.md#deferrable) are called with an [`ErrorInfo`](https://ably.com/docs/api/realtime-sdk/types.md#error-info) argument describing the failure reason.
##### Returns
`Future`
On successful publish of the message, no exception will be thrown. On failure to publish the message, an `AblyException` will be thrown with an [`errorInfo`](https://ably.com/docs/api/realtime-sdk/types.md#error-info) property describing the failure reason.
#### subscribeSubscribe
There are overloaded versions of this method:
`void subscribe(MessageListener listener)`
`void Subscribe(Action handler)`
`subscribe → yields Message`
`subscribe(callback: (ARTMessage) -> Void) -> ARTEventListener?`
`StreamSubscription subscribe().listen((ably.Message) -> void)`
Subscribe to messages on this channel. The caller supplies a listener functiona lambda expressionan implementation of the [MessageListener](#message-listener) interfacea block, which is called each time one or more messages arrives on the channel.
`void subscribe(String name, MessageListener listener)`
`void Subscribe(string name, Action handler)`
`subscribe(String name) → yields Message`
`subscribe(name: String, callback: (ARTMessage) -> Void) -> ARTEventListener?`
`StreamSubscription subscribe(name: String).listen((ably.Message) -> void)`
Subscribe to messages with a given event name on this channel. The caller supplies a listener functiona lambda expressionan implementation of the [MessageListener](#message-listener) interfacea block, which is called each time one or more matching messages arrives on the channel.
`void subscribe(String[] names, MessageListener listener)`
`subscribe(String *names) → yields Message`
`StreamSubscription subscribe(names: List).listen((ably.Message) -> void)`
Subscribe a single listener to messages on this channel for multiple event `name` values.
##### Parameters
| Parameter | Description | Type |
|-----------|-------------|------|
| name | The event name to subscribe to | `String` |
| names | An array of event names to subscribe to | `String[]` |
| [`MessageListener`](#message-listener) listener | Message listener to be notified for matching messages | - |
| Parameter | Description | Type |
|-----------|-------------|------|
| name | The event name to subscribe to | `String` |
| handler | called with each matching [`message`](#message) when received on the channel | - |
| Parameter | Description | Type |
|-----------|-------------|------|
| name | The event name to subscribe to | `String` |
| names | An argument array of event names to subscribe to | `*argument` |
| &block | yields each matching message when received on the channel | - |
| Parameter | Description | Type |
|-----------|-------------|------|
| name | The event name to subscribe to | `String` |
| callback | called with each matching [`message`](#message) when received on the channel | - |
| Parameter | Description | Type |
|-----------|-------------|------|
| name | The event name to subscribe to | `String` |
| names | An array of event names to subscribe to | `String[]` |
##### Considerations
* If the channel is `initialized` (i.e. no attempt to attach has yet been made for this channel), then calling `subscribe` will implicitly attach the channel. However, regardless of the implicit attach outcome, the listenerblockhandler will still be registered
* Calling subscribe with an event name is a convenient way to subscribe only to messages matching that event name. But this is purely a client-side filter, for convenience. It has no effect on what messages are actually sent by the server to the client. All clients attached to a given channel receive every message sent on that channel (that their capabilities allow them to receive); the channel is the unit of distribution. To filter messages server-side, you need to use [filtered subscriptions](https://ably.com/docs/pub-sub/advanced.md#subscription-filters) and provide a `filter` when calling `subscribe()`.
* If `subscribe` is called more than once with the same listenerblockhandler, then duplicates will be registered. For example, if you `subscribe` twice with the same listenerblockhandler and a message is later received, the same listenerblockhandler will be invoked twice
* The registered listenerblockhandler remains active on the channel regardless of the current channel state. For example, if you call `subscribe` when a channel is `attached` and it later becomes `detached` or even `failed`, when the channel is reattached and a message is received, the listenersblockshandlers originally registered will still be invoked. Listeners are only removed when calling [`unsubscribe`](#unsubscribe)`streamSubscription.close` or when a channel is `released` using the `Realtime.channels.release(name)``Realtime.Channels.Release(name)` method
* If an exception is thrown in the subscribe listener and bubbles up to the event emitter, it will be caught and logged at `error` level, so as not to affect other listeners for the same event
#### unsubscribeUnsubscribe
There are three overloaded versions of this method:
`void unsubscribe(String name, MessageListener listener)`
`bool Unsubscribe(string eventName, Action handler)`
`unsubscribe(String name, &listener_proc)`
`unsubscribe(name: String, listener: ARTEventListener)`
Unsubscribe the given listener for the specified event name. This removes an earlier event-specific subscription.
`void unsubscribe(MessageListener listener)`
`bool Unsubscribe(Action handler)`
`unsubscribe(&listener_proc)`
`unsubscribe(listener: ARTEventListener)`
Unsubscribe the given listener (for any/all event names). This removes an earlier subscription.
`streamSubscription` obtained from a subscription can be used to cancel a listener by calling `streamSubscription.cancel`.
`unsubscribe()`
`void unsubscribe()`
`void Unsubscribe()`
`unsubscribe()`
Unsubscribes all listeners to messages on this channel. This removes all earlier subscriptions.
##### Parameters
| Parameter | Description | Type |
|-----------|-------------|------|
| name | The event name to unsubscribe from | `String` |
| listener | previously registered listener | [`MessageListener`](#message-listener) |
| Parameter | Description | Type |
|-----------|-------------|------|
| name | The event name to unsubscribe from | `String` |
| handler | is the lambda expression that was previously subscribed | - |
| Parameter | Description | Type |
|-----------|-------------|------|
| name | The event name to unsubscribe from | `String` |
| &listener_block | previously registered listener block | - |
| Parameter | Description | Type |
|-----------|-------------|------|
| name | The event name to unsubscribe from | `String` |
| listener | previous return value from a `subscribe` call | - |
| Parameter | Description | Type |
|-----------|-------------|------|
| name | The event name to unsubscribe from | `String` |
#### historyHistory
`PaginatedResult history(Param []` options)`
`Task> HistoryAsync(PaginatedRequestParams dataQuery, bool untilAttach = false)`
`Deferrable history(Hash options) -> yields PaginatedResult`
`history(query: ARTRealtimeHistoryQuery?, callback: (ARTPaginatedResult?, ARTErrorInfo?) -> Void) throws`
`Future> history(Hash options)`
Gets a [paginated](#paginated-result) set of historical messages for this channel. If the [channel is configured to persist messages to disk](https://faqs.ably.com/how-long-are-messages-stored-for), then message history will [typically be available for 24 - 72 hours](https://faqs.ably.com/how-long-are-messages-stored-for). If not, messages are only retained in memory by the Ably service for two minutes.
##### Parameters
| Parameter | Description | Type |
|-----------|-------------|------|
| options | an optional object containing the query parameters, as specified in the [message history API documentation](https://ably.com/docs/api/realtime-sdk/history.md#channel-history) | [`Param []`](#param) |
| Parameter | Description | Type |
|-----------|-------------|------|
| dataQuery | an optional object containing the query parameters, as specified in the [message history API documentation](https://ably.com/docs/api/realtime-sdk/history.md#channel-history) | `PaginatedRequestParams` |
| Parameter | Description | Type |
|-----------|-------------|------|
| options | an optional set of key value pairs containing the query parameters, as specified in the [message history API documentation](https://ably.com/docs/api/realtime-sdk/history.md#channel-history) | `Hash` |
| &block | yields a `PaginatedResult` object | - |
| Parameter | Description | Type |
|-----------|-------------|------|
| query | an optional object containing the query parameters, as specified in the [message history API documentation](https://ably.com/docs/api/realtime-sdk/history.md#channel-history) | `ARTRealtimeHistoryQuery` |
| callback | called with a [`ARTPaginatedResult`](#paginated-result)`<`[`ARTMessage`](#message)`>` object or an error | - |
| Parameter | Description | Type |
|-----------|-------------|------|
| options | an optional object containing the query parameters, as specified in the [message history API documentation](https://ably.com/docs/api/realtime-sdk/history.md#channel-history) | `Object` |
Further details of the supported `options` params, see [message history API documentation](https://ably.com/docs/api/realtime-sdk/history.md#channel-history).
##### Callback result
On success, `resultPage` contains a [`PaginatedResult`](#paginated-result) encapsulating an array of [`Message`](#message) objects corresponding to the current page of results. [`PaginatedResult`](#paginated-result) supports pagination using [`next()`](#paginated-result) and [`first()`](#paginated-result) methods.
On failure to retrieve message history, `err` contains an [`ErrorInfo`](https://ably.com/docs/api/realtime-sdk/types.md#error-info) object with the failure reason.
##### Returns
On success, the returned [`PaginatedResult`](#paginated-result) encapsulates an array of [`Message`](#message) objects corresponding to the current page of results. [`PaginatedResult`](#paginated-result) supports pagination using [`next`](#paginated-result) and [`first`](#paginated-result) methods.
Failure to retrieve the message history will raise an [`AblyException`](https://ably.com/docs/api/realtime-sdk/types.md#ably-exception)
##### Returns
The return value is `Task>` which needs to be awaited.
On success, the returned [`PaginatedResult`](#paginated-result) encapsulates an array of [`Message`](#message) objects corresponding to the current page of results. [`PaginatedResult`](#paginated-result) supports pagination using [`NextAsync`](#paginated-result) and [`FirstAsync`](#paginated-result) methods.
Failure to retrieve the message history will raise an [`AblyException`](https://ably.com/docs/api/realtime-sdk/types.md#ably-exception)
##### Returns
A [`Deferrable`](https://ably.com/docs/api/realtime-sdk/types.md#deferrable) object is returned from the method.
On success, the registered success blocks for the [`Deferrable`](https://ably.com/docs/api/realtime-sdk/types.md#deferrable) and any block provided to the method yield a [`PaginatedResult`](#paginated-result) that encapsulates an array of [`Message`](#message) objects corresponding to the current page of results. [`PaginatedResult`](#paginated-result) supports pagination using [`next()`](#paginated-result) and [`first()`](#paginated-result) methods.
Failure to retrieve the message history will trigger the `errback` callbacks of the [`Deferrable`](https://ably.com/docs/api/realtime-sdk/types.md#deferrable) with an [`ErrorInfo`](https://ably.com/docs/api/realtime-sdk/types.md#error-info) object with the failure reason.
#### getMessage
`Message getMessage(String serial)`
`Message get_message(serial_or_message)`
`getMessageWithSerial(_ serial: String, callback: (ARTMessage?, ARTErrorInfo?) -> Void)`
Retrieves the latest version of a specific message by its serial identifier. Requires the **history** [capability](https://ably.com/docs/auth/capabilities.md).
See [updating and deleting messages: retrieving the latest version](https://ably.com/docs/messages/updates-deletes.md#get) for more information.
##### Parameters
| Parameter | Description | Type |
|-----------|-------------|------|
| serial | Serial identifier string of the message to retrieve | `String` |
##### Returns
Returns a [`Message`](https://ably.com/docs/api/realtime-sdk/messages.md) object representing the latest version of the message.
| Parameter | Description | Type |
|-----------|-------------|------|
| serial_or_message | Either the serial identifier string of the message to retrieve, or a `Message` object containing a populated `serial` field | `str` or `Message` |
##### Returns
Returns a [`Message`](https://ably.com/docs/api/realtime-sdk/messages.md) object representing the latest version of the message.
On failure, raises an [`AblyException`](https://ably.com/docs/api/realtime-sdk/types.md#ably-exception).
| Parameter | Description | Type |
|-----------|-------------|------|
| serial | A serial identifier string of the message to retrieve | `String` |
| callback | A success or failure callback function. On success, it receives an [`ARTMessage`](https://ably.com/docs/api/realtime-sdk/messages.md) object representing the latest version of the message | - |
##### Callback result
On success, the callback receives a [`ARTMessage`](https://ably.com/docs/api/realtime-sdk/messages.md) object representing the latest version of the message.
On failure, the callback receives an [`ARTErrorInfo`](https://ably.com/docs/api/realtime-sdk/types.md#error-info) object which explains the error.
#### updateMessage
`void updateMessage(Message message, MessageOperation operation, Callback callback)`
`UpdateDeleteResult update_message(message, operation=None, params=dict())`
`update(_ message: ARTMessage, operation: ARTMessageOperation?, params: [String: ARTStringifiable]?, callback: ((ARTUpdateDeleteResult?, ARTErrorInfo?) -> Void)?)`
Publishes an update to an existing message with shallow mixin semantics. Non-null `name`, `data`, and `extras` fields in the provided message will replace the corresponding fields in the existing message, while null fields will be left unchanged. Requires the **message-update-own** or **message-update-any** [capability](https://ably.com/docs/auth/capabilities.md).
Note: Note that this publishes an update, it does not mutate the original message if passed in.
See [updating and deleting messages: updates](https://ably.com/docs/messages/updates-deletes.md#update) for more information.
##### Parameters
| Parameter | Description | Type |
|-----------|-------------|------|
| message | A [`Message`](https://ably.com/docs/api/realtime-sdk/messages.md) object containing a populated `serial` field and the fields to update | [`Message`](https://ably.com/docs/api/realtime-sdk/messages.md) |
| operation | An optional `MessageOperation` object containing metadata about the update operation. Can include `clientId`, `description`, and `metadata` fields | `MessageOperation` (optional) |
| Parameter | Description | Type |
|-----------|-------------|------|
| message | A [`ARTMessage`](https://ably.com/docs/api/realtime-sdk/messages.md) object containing a populated `serial` field and the fields to update | [`ARTMessage`](https://ably.com/docs/api/realtime-sdk/messages.md) |
| operation | An optional `ARTMessageOperation` object containing metadata about the update operation. Can include `clientId`, `description`, and `metadata` fields | `ARTMessageOperation` (optional) |
| params | Optional parameters sent as part of the request. As Ably adds supported parameters, they will be documented on the [docs pages](https://ably.com/docs) | `[String: ARTStringifiable]` (optional) |
| callback | A success or failure callback function. On success, it receives an `ARTUpdateDeleteResult` object containing the new version of the message | (optional) |
##### Returns
Invokes the provided `Callback` with an [`UpdateDeleteResult`](https://ably.com/docs/api/realtime-sdk/types.md#update-delete-result) object containing the new version of the message on success, or with an [`ErrorInfo`](https://ably.com/docs/api/realtime-sdk/types.md#error-info) object describing the error on failure.
##### Returns
Returns an [`UpdateDeleteResult`](https://ably.com/docs/api/realtime-sdk/types.md#update-delete-result) object containing the new version of the message.
On failure, raises an [`AblyException`](https://ably.com/docs/api/realtime-sdk/types.md#ably-exception).
##### Callback result
On success, the callback receives an [`ARTUpdateDeleteResult`](https://ably.com/docs/api/realtime-sdk/types.md#update-delete-result) object containing the new version of the message.
On failure, the callback receives an [`ARTErrorInfo`](https://ably.com/docs/api/realtime-sdk/types.md#error-info) object which explains the error.
#### deleteMessage
`void deleteMessage(Message message, MessageOperation operation, Callback callback)`
`UpdateDeleteResult delete_message(message, operation=None, params=dict())`
`delete(_ message: ARTMessage, operation: ARTMessageOperation?, params: [String: ARTStringifiable]?, callback: ((ARTUpdateDeleteResult?, ARTErrorInfo?) -> Void)?)`
Marks a message as deleted by publishing an update with an action of `MESSAGE_DELETE`. This does not remove the message from the server, and the full message history remains accessible. Uses shallow mixin semantics: non-null `name`, `data`, and `extras` fields in the provided message will replace the corresponding fields in the existing message, while null fields will be left unchanged. Requires the **message-delete-own** or **message-delete-any** [capability](https://ably.com/docs/auth/capabilities.md).
See [updating and deleting messages: deletes](https://ably.com/docs/messages/updates-deletes.md#delete) for more information.
##### Parameters
| Parameter | Description | Type |
|-----------|-------------|------|
| message | A [`Message`](https://ably.com/docs/api/realtime-sdk/messages.md) object containing a populated `serial` field | [`Message`](https://ably.com/docs/api/realtime-sdk/messages.md) |
| operation | An optional `MessageOperation` object containing metadata about the delete operation. Can include `clientId`, `description`, and `metadata` fields | `MessageOperation` (optional) |
| Parameter | Description | Type |
|-----------|-------------|------|
| message | A [`ARTMessage`](https://ably.com/docs/api/realtime-sdk/messages.md) object containing a populated `serial` field | [`ARTMessage`](https://ably.com/docs/api/realtime-sdk/messages.md) |
| operation | An optional `ARTMessageOperation` object containing metadata about the delete operation. Can include `clientId`, `description`, and `metadata` fields | `ARTMessageOperation` (optional) |
| params | Optional parameters sent as part of the request. As Ably adds supported parameters, they will be documented on the [docs pages](https://ably.com/docs) | `[String: ARTStringifiable]` (optional) |
| callback | A success or failure callback function. On success, it receives an `ARTUpdateDeleteResult` object containing the new version of the message | (optional) |
##### Returns
Invokes the provided `Callback` with an [`UpdateDeleteResult`](https://ably.com/docs/api/realtime-sdk/types.md#update-delete-result) object containing the new version of the message on success, or with an [`ErrorInfo`](https://ably.com/docs/api/realtime-sdk/types.md#error-info) object describing the error on failure.
##### Returns
Returns an [`UpdateDeleteResult`](https://ably.com/docs/api/realtime-sdk/types.md#update-delete-result) object containing the new version of the message.
On failure, raises an [`AblyException`](https://ably.com/docs/api/realtime-sdk/types.md#ably-exception).
##### Callback result
On success, the callback receives an [`ARTUpdateDeleteResult`](https://ably.com/docs/api/realtime-sdk/types.md#update-delete-result) object containing the new version of the message.
On failure, the callback receives an [`ARTErrorInfo`](https://ably.com/docs/api/realtime-sdk/types.md#error-info) object which explains the error.
#### appendMessage
`void appendMessage(Message message, MessageOperation operation, Callback callback)`
`UpdateDeleteResult append_message(message, operation=None, params=dict())`
`append(_ message: ARTMessage, operation: ARTMessageOperation?, params: [String: ARTStringifiable]?, callback: ((ARTUpdateDeleteResult?, ARTErrorInfo?) -> Void)?)`
Appends data to an existing message. The supplied `data` field is appended to the previous message's data, while all other fields (`name`, `extras`) replace the previous values if provided. Requires the **message-update-own** or **message-update-any** [capability](https://ably.com/docs/auth/capabilities.md).
See [updating and deleting messages: appends](https://ably.com/docs/messages/updates-deletes.md#append) for more information.
##### Parameters
| Parameter | Description | Type |
|-----------|-------------|------|
| message | A [`Message`](https://ably.com/docs/api/realtime-sdk/messages.md) object containing a populated `serial` field and the data to append | [`Message`](https://ably.com/docs/api/realtime-sdk/messages.md) |
| operation | An optional `MessageOperation` object containing metadata about the append operation. Can include `clientId`, `description`, and `metadata` fields | `MessageOperation` (optional) |
| Parameter | Description | Type |
|-----------|-------------|------|
| message | A [`ARTMessage`](https://ably.com/docs/api/realtime-sdk/messages.md) object containing a populated `serial` field and the data to append | [`ARTMessage`](https://ably.com/docs/api/realtime-sdk/messages.md) |
| operation | An optional `ARTMessageOperation` object containing metadata about the append operation. Can include `clientId`, `description`, and `metadata` fields | `ARTMessageOperation` (optional) |
| params | Optional parameters sent as part of the request. As Ably adds supported parameters, they will be documented on the [docs pages](https://ably.com/docs) | `[String: ARTStringifiable]` (optional) |
| callback | A success or failure callback function. On success, it receives an `ARTUpdateDeleteResult` object containing the new version of the message | - |
##### Returns
Invokes the provided `Callback` with an [`UpdateDeleteResult`](https://ably.com/docs/api/realtime-sdk/types.md#update-delete-result) object containing the new version of the message on success, or with an [`ErrorInfo`](https://ably.com/docs/api/realtime-sdk/types.md#error-info) object describing the error on failure.
##### Returns
Returns an [`UpdateDeleteResult`](https://ably.com/docs/api/realtime-sdk/types.md#update-delete-result) object containing the new version of the message.
On failure, raises an [`AblyException`](https://ably.com/docs/api/realtime-sdk/types.md#ably-exception).
##### Callback result
On success, the callback receives an [`ARTUpdateDeleteResult`](https://ably.com/docs/api/realtime-sdk/types.md#update-delete-result) object containing the new version of the message.
On failure, the callback receives an [`ARTErrorInfo`](https://ably.com/docs/api/realtime-sdk/types.md#error-info) object which explains the error.
#### getMessageVersions
`PaginatedResult getMessageVersions(String serial, Param[] params)`
`PaginatedResult get_message_versions(serial_or_message, params = dict())`
`getMessageVersions(withSerial serial: String, callback: @escaping (ARTPaginatedResult?, ARTErrorInfo?) -> Void)`
Retrieves all historical versions of a specific message, ordered by version. This includes the original message and all subsequent updates or delete operations. Requires the **history** [capability](https://ably.com/docs/auth/capabilities.md).
See [updating and deleting messages: message versions](https://ably.com/docs/messages/updates-deletes.md#versions) for more information.
##### Parameters
| Parameter | Description | Type |
|-----------|-------------|------|
| serialOrMessage | Either the serial identifier string of the message whose versions are to be retrieved, or a [`Message`](https://ably.com/docs/api/realtime-sdk/messages.md) object containing a populated `serial` field | `string` or [`Message`](https://ably.com/docs/api/realtime-sdk/messages.md) |
| params | Optional parameters sent as part of the query string | `Param[]` (optional) |
| Parameter | Description | Type |
|-----------|-------------|------|
| serial | A serial identifier string of the message whose versions are to be retrieved | `String` |
| callback | A success or failure callback function. On success, it receives an [`ARTPaginatedResult`](#paginated-result) object containing an array of [`ARTMessage`](#message) objects representing all versions of the message. | - |
##### Returns
On success, the returned [`PaginatedResult`](#paginated-result) encapsulates an array of [`Message`](#message) objects corresponding to the current page of results. [`PaginatedResult`](#paginated-result) supports pagination using [`next`](#paginated-result) and [`first`](#paginated-result) methods.
Failure to retrieve the message versions will raise an [`AblyException`](https://ably.com/docs/api/realtime-sdk/types.md#ably-exception)
##### Callback result
On success, the callback receives a [`ARTPaginatedResult`](#paginated-result) encapsulating an array of [`ARTMessage`](#message) version objects corresponding to the current page of results. [`ARTPaginatedResult`](#paginated-result) supports pagination using [`next()`](#paginated-result) and [`first()`](#paginated-result) methods.
On failure to retrieve message versions, the callback receives an [`ARTErrorInfo`](https://ably.com/docs/api/realtime-sdk/types.md#error-info) object with the failure reason.
#### attachAttach
`void attach()`
`void Attach(Action callback = null)`
`Deferrable attach -> yields`
`attach(callback: ((ARTErrorInfo?) -> Void)?)`
`Future attach()`
Attach to this channel ensuring the channel is created in the Ably system and all messages published on the channel will be received by any channel listeners registered using `subscribe()``Subscribe()``subscribe`. Any resulting channel state change will be emitted to any listeners registered using the [`on``On`](#on) or [`once``Once`](#once) methods.
As a convenience, `attach()``Attach()``attach` will be called implicitly if [`subscribe()``Subscribe()``subscribe`](#subscribe) for the `Channel` is called, or [`enter()``Enter()``enter`](https://ably.com/docs/api/realtime-sdk/presence.md#enter) or [`subscribe()``Subscribe()``subscribe`](https://ably.com/docs/api/realtime-sdk/presence.md#subscribe) is called on the [`Presence`](https://ably.com/docs/presence-occupancy/presence.md) for this `Channel`.
##### Parameters
| Parameter | Description | Type |
|-----------|-------------|------|
| &block | yields once the channel becomes attached | - |
| Parameter | Description | Type |
|-----------|-------------|------|
| callback | is a lambda expression of the form `Action` and is called once the channel attach succeeds or fails | - |
| Parameter | Description | Type |
|-----------|-------------|------|
| callback | called once the channel becomes attached or if an error occurs | - |
##### Returns
A [`Deferrable`](https://ably.com/docs/api/realtime-sdk/types.md#deferrable) object is returned from the attach method.
On successful attachment, the success callbacks for the [`Deferrable`](https://ably.com/docs/api/realtime-sdk/types.md#deferrable) are called and any block provided to the method is yielded. Failure to attach will trigger the `errback` callbacks of the [`Deferrable`](https://ably.com/docs/api/realtime-sdk/types.md#deferrable) with an [`ErrorInfo`](https://ably.com/docs/api/realtime-sdk/types.md#error-info) object with the failure reason.
##### Returns
`Future`
Failure to attach will throw an `AblyException` with an [errorInfo](https://ably.com/docs/api/realtime-sdk/types.md#error-info) property with the failure reason.
#### detachDetach
`void detach()`
`void Detach(Action callback = null)`
[`Deferrable`](https://ably.com/docs/api/realtime-sdk/types.md#deferrable) `detach -> yields`
`detach(callback: ((`[`ARTErrorInfo`](https://ably.com/docs/api/realtime-sdk/types.md#error-info)`?) -> Void)?)`
`Future detach()`
Detach from this channel. Any resulting channel state change will be emitted to any listeners registered using the [`on``On`](#on) or [`once``Once`](#once) methods.
Please note: Once all clients globally have detached from the channel, the channel will be released in the Ably service within two minutes.
##### Parameters
| Parameter | Description | Type |
|-----------|-------------|------|
| callback | is a lambda expression in the form `Action` and is called once the channel detach succeeds or fails | - |
| Parameter | Description | Type |
|-----------|-------------|------|
| &block | yields once the channel becomes detached | - |
| Parameter | Description | Type |
|-----------|-------------|------|
| callback | called once the channel becomes detached or if an error occurs | - |
##### Returns
A [`Deferrable`](https://ably.com/docs/api/realtime-sdk/types.md#deferrable) object is returned from the detach method.
On successful detachment, the registered success blocks for the [`Deferrable`](https://ably.com/docs/api/realtime-sdk/types.md#deferrable) and any block provided to the method are executed. Failure to detach will trigger the `errback` callbacks of the [`Deferrable`](https://ably.com/docs/api/realtime-sdk/types.md#deferrable) with an [`ErrorInfo`](https://ably.com/docs/api/realtime-sdk/types.md#error-info) object with the failure reason.
##### Returns
`Future`
Failure to detach will throw an `AblyException` with an [errorInfo](https://ably.com/docs/api/realtime-sdk/types.md#error-info) property with the failure reason.
#### onOn
There are two overloaded versions of this method:
`on(`[`ChannelEvent`](#channel-event)` *event) -> yields` [`ChannelStateChange`](#channel-state-change)
`void on(`[`ChannelEvent`](#channel-event)` event,` [`ChannelStateListener`](#channel-state-listener)` listener)`
`void On(`[`ChannelEvent`](#channel-event)` event, Action<`[`ChannelStateChange`](#channel-state-change)`> action)`
`on(event:` [`ARTChannelEvent`](#channel-event)`, call: (`[`ARTChannelStateChange?`](#channel-state-change)`) -> Void) -> ARTEventListener`
`Stream<`[`ChannelEvent`](#channel-event)`> on(`[`ChannelEvent`](#channel-event)` channelEvent)`
The Stream returned can be subscribed for with a listener.
`final streamSubscription = stream.listen(listener)`
Register the given listener blockfunctionlistener for the specified [`ChannelEvent`](#channel-event) on the `Channel`.
The listener is passed a [`ChannelStateChange``ARTChannelStateChange`](#channel-state-change) object that contains the current state, previous state, a boolean indicating whether the channel was resumed, and an optional reason for the state change.
`on -> yields ChannelStateChange`
`void On(Action listener)`
`void on(ChannelStateListener listener)`
`on(call: (ARTChannelStateChange?) -> Void) -> ARTEventListener`
`Stream on()`
The Stream returned can be subscribed for with a listener.
`final streamSubscription = stream.listen(listener)`
Register the given listener blockfunctionlambda expressionlistener for all [`ChannelEvents`](#channel-event) on the `Channel`.
The listener is passed a [`ChannelStateChange``ARTChannelStateChange`](#channel-state-change) object that contains the current state, previous state, the event, a boolean indicating whether the channel was resumed, and an optional reason for the state change.
If an exception is thrown in the listener and bubbles up to the event emitter, it will be caught and logged at `error` level, so as not to affect other listeners for the same event
##### Parameters
| Parameter | Description | Type |
|-----------|-------------|------|
| event | the channel event to subscribe to | [`ChannelEvent`](#channel-event) |
| listener | listener to be notified for matching event changes | [`ChannelStateListener`](#channel-state-listener) |
| Parameter | Description | Type |
|-----------|-------------|------|
| event | the channel event to subscribe to | [`ChannelEvent`](#channel-event) |
| action | lambda expression to be notified for matching event changes | [`ChannelStateChange`](#channel-state-listener) |
| Parameter | Description | Type |
|-----------|-------------|------|
| event | the channel event as a Symbol such as `:attached` or a `ChannelEvent` object to subscribe to | [`ChannelEvent`](#channel-event) |
| &block | listener block that is yielded to for matching event changes | - |
| Parameter | Description | Type |
|-----------|-------------|------|
| event | the `ARTChannelEvent` to subscribe to | [`ARTChannelEvent`](#channel-event) |
| call | called possibly with an [`ErrorInfo`](https://ably.com/docs/api/realtime-sdk/types.md#error-info) | - |
| Parameter | Description | Type |
|-----------|-------------|------|
| event | the channel event to subscribe to | [`ChannelEvent`](#channel-event) |
#### onceOnce
There are two overloaded versions of this method:
`once(ChannelEvent *event) -> yields ChannelStateChange`
`void once(ChannelEvent event, ChannelStateListener listener)`
`void Once(ChannelEvent event, Action action)`
`once(event: ARTChannelEvent, call: (ARTChannelStateChange?) -> Void) -> ARTEventListener`
`once(ChannelEvent event)`
Register the given listener blockfunctionlambda expressionlistener for a single occurrence of the specified [`ChannelEvent`](#channel-event) on the `Channel`. Once the listener has been called, it is removed as a registered listener and will not be called again.
The listener is passed a [`ChannelStateChange``ARTChannelStateChange`](#channel-state-change) object that contains the current state, previous state, the event, a boolean indicating whether the channel was resumed, and an optional reason for the event change.
`once -> yields ChannelStateChange`
`void once(ChannelStateListener listener)`
`void Once(Action listener)`
`once(call: (ARTChannelStateChange?) -> Void) -> ARTEventListener`
`once()`
Register the given listener blockfunctionlambda expressionlistener for a single occurrence of any [`ChannelEvent`](#channel-event) on the `Channel`. Once the listener has been called, it is removed as a registered listener and will not be called again.
The listener is passed a [`ChannelStateChange``ARTChannelStateChange`](#channel-state-change) object that contains the current state, previous state, the event, a boolean indicating whether the channel was resumed, and an optional reason for the event change.
If an exception is thrown in the listener and bubbles up to the event emitter, it will be caught and logged at `error` level, so as not to affect other listeners for the same event
##### Parameters
| Parameter | Description | Type |
|-----------|-------------|------|
| event | the channel event to subscribe to | [`ChannelEvent`](#channel-event) |
| listener | listener to be notified for a single occurrence of a matching event change | [`ChannelStateListener`](#channel-state-listener) |
| Parameter | Description | Type |
|-----------|-------------|------|
| event | the channel event to subscribe to | [`ChannelEvent`](#channel-event) |
| listener | listener lambda expression that is notified only once for a matching event change | - |
| Parameter | Description | Type |
|-----------|-------------|------|
| event | the channel event as a Symbol such as `:attached` or a `ChannelEvent` object to subscribe to | [`ChannelEvent`](#channel-event) |
| &block | listener block that is yielded to for a single occurrence of a matching event change | - |
| Parameter | Description | Type |
|-----------|-------------|------|
| event | the `ARTChannelEvent` to subscribe to | [`ARTChannelEvent`](#channel-event) |
| call | called possibly with an [`ErrorInfo`](https://ably.com/docs/api/realtime-sdk/types.md#error-info) | - |
| Parameter | Description | Type |
|-----------|-------------|------|
| event | the channel event to subscribe to | [`ChannelEvent`](#channel-event) |
#### offOff
There are two overloaded versions of this method:
`off(ChannelEvent *event, &block)`
`void off(ChannelEvent event, ChannelStateListener listener)`
`void Off(ChannelEvent event, Action listener)`
`off(event: ARTChannelEvent, listener: ARTEventListener)`
`off(ChannelEvent event)`
Remove the given listener blocklistener for the [`ChannelEvent`](#channel-event).
`off(&block)`
`void off(ChannelStateListener listener)`
`void Off(Action listener)`
`off(listener: ARTEventListener)`
`off()`
Remove the given listener block for all [`ChannelEvents`](#channel-event).
##### Parameters
| Parameter | Description | Type |
|-----------|-------------|------|
| event | the channel event to unsubscribe from | [`ChannelEvent`](#channel-event) |
| listener | is the listener to be removed | [`ChannelStateListener`](#channel-state-listener) |
| Parameter | Description | Type |
|-----------|-------------|------|
| event | the channel event to unsubscribe from | [`ChannelEvent`](#channel-event) |
| listener | is the listener function to be removed | - |
| Parameter | Description | Type |
|-----------|-------------|------|
| event | the channel event as a Symbol such as `:detached` or a `ChannelEvent` object to unsubscribe from | [`ChannelEvent`](#channel-event) |
| &block | is the listener block to be removed | - |
| Parameter | Description | Type |
|-----------|-------------|------|
| event | the `ARTChannelEvent` to unsubscribe from | [`ARTChannelEvent`](#channel-event) |
| listener | previous return value from a `on` or `once` call | - |
| Parameter | Description | Type |
|-----------|-------------|------|
| streamSubscription | obtained from calling `on` can be used to cancel a listener by calling `streamSubscription.cancel` | - |
## ARTRealtimeAnnotationsio.ably.lib.realtime.RealtimeAnnotationsRealtimeAnnotations
The `RealtimeAnnotations` object, accessed from the [annotations](#channel-annotations) property of a `Channel`, is used to publish, delete, retrieve, and subscribe to [annotations](https://ably.com/docs/messages/annotations.md) on messages. See the [annotations documentation](https://ably.com/docs/messages/annotations.md) for an overview of annotation concepts and types.
### RealtimeAnnotations Methods
#### publish
`void publish(Message message, Annotation annotation)`
`void publish(String messageSerial, Annotation annotation)`
`void publish(Message message, Annotation annotation, CompletionListener listener)`
`void publish(String messageSerial, Annotation annotation, CompletionListener listener)`
`publishForMessage(message: ARTMessage, annotation: ARTAnnotation, callback: ARTCallback?)`
`publishForMessageSerial(messageSerial: String, annotation: ARTAnnotation, callback: ARTCallback?)`
`async publish(msg_or_serial, annotation: Annotation)`
Publishes an [`Annotation`](https://ably.com/docs/api/realtime-sdk/types.md#annotation) for a message, identified either by a [`Message`](#message) instance or by its [`serial`](#serial). The annotation must include at least a `type`; other required fields depend on the annotation type. The `action` is set automatically to `annotation.create`.
If a [`clientId`](https://ably.com/docs/api/realtime-sdk/types.md#client-options) is set on the client, it will be associated with the published annotation. Some annotation [summarization methods](https://ably.com/docs/messages/annotations.md#annotation-types) require an [identified](https://ably.com/docs/auth/identified-clients.md) client.
##### Parameters
| Parameter | Description | Type |
|-----------|-------------|------|
| msg_or_serialmessage or messageSerial | The message to annotate, identified either by a [`Message`](#message) instance or by its `serial` | [`ARTMessage`](#message) or `String`[`Message`](#message) or `String` |
| annotation | The annotation to publish. Must include at least the `type` | [`ARTAnnotation`](https://ably.com/docs/api/realtime-sdk/types.md#annotation)[`Annotation`](https://ably.com/docs/api/realtime-sdk/types.md#annotation) |
#### delete
`void delete(Message message, Annotation annotation)`
`void delete(String messageSerial, Annotation annotation)`
`void delete(Message message, Annotation annotation, CompletionListener listener)`
`void delete(String messageSerial, Annotation annotation, CompletionListener listener)`
`deleteForMessage(message: ARTMessage, annotation: ARTAnnotation, callback: ARTCallback?)`
`deleteForMessageSerial(messageSerial: String, annotation: ARTAnnotation, callback: ARTCallback?)`
`async delete(msg_or_serial, annotation: Annotation)`
Publishes an annotation removal request for a message, removing the contribution that this `clientId` previously made to the [annotation summary](https://ably.com/docs/messages/annotations.md#annotation-summaries). The exact behaviour depends on the [annotation type](https://ably.com/docs/messages/annotations.md#annotation-types). The `action` is set automatically to `annotation.delete`.
The annotation must include at least a `type`, and may include a `name` for those annotation types where the name is needed to identify which contribution to remove.
##### Parameters
The parameters are the same as for [`publish`](#annotations-publish).
#### get
`PaginatedResult get(Message message, Param[] params)`
`PaginatedResult get(String messageSerial, Param[] params)`
`PaginatedResult get(Message message)`
`PaginatedResult get(String messageSerial)`
`void getAsync(Message message, Param[] params, Callback> callback)`
`void getAsync(String messageSerial, Param[] params, Callback> callback)`
`getForMessage(message: ARTMessage, query: ARTAnnotationsQuery, callback: ARTPaginatedAnnotationsCallback)`
`getForMessageSerial(messageSerial: String, query: ARTAnnotationsQuery, callback: ARTPaginatedAnnotationsCallback)`
`async get(msg_or_serial, params: dict | None = None) -> PaginatedResult`
Retrieves a [paginated result](#paginated-result) containing all individual [`Annotation`](https://ably.com/docs/api/realtime-sdk/types.md#annotation) events that have been published for a message, ordered from earliest to most recent.
If you only need the latest [annotation summary](https://ably.com/docs/messages/annotations.md#annotation-summaries) for a message, prefer [`channel.getMessage()`](https://ably.com/docs/messages/updates-deletes.md#get): the returned message contains the up-to-date `annotations.summary`. Use `annotations.get()` only when you need the full list of raw annotations.
##### Parameters
| Parameter | Description | Type |
|-----------|-------------|------|
| msg_or_serialmessage or messageSerial | The message to retrieve annotations for, identified either by a [`Message`](#message) instance or by its `serial` | [`ARTMessage`](#message) or `String`[`Message`](#message) or `String` |
| queryparams | An optional set of restrictions on which annotations to retrieve, in particular a `limit` | [`Param[]`](#param)[`ARTAnnotationsQuery`](https://ably.com/docs/api/realtime-sdk/types.md#annotations-query)`dict` |
##### Returns
A [`PaginatedResult`](#paginated-result) containing an array of [`Annotation`](https://ably.com/docs/api/realtime-sdk/types.md#annotation) objects.
#### subscribe
`void subscribe(AnnotationListener listener)`
`void subscribe(String type, AnnotationListener listener)`
`subscribe(callback: (ARTAnnotation) -> Void) -> ARTEventListener?`
`subscribe(type: String, callback: (ARTAnnotation) -> Void) -> ARTEventListener?`
`async subscribe(listener)`
`async subscribe(type_or_types, listener)`
Registers a listener that is called each time an individual [`Annotation`](https://ably.com/docs/api/realtime-sdk/types.md#annotation) is received on the channel.
To receive individual realtime annotations (instead of just the rolled-up [summaries](https://ably.com/docs/messages/annotations.md#annotation-summaries)), the channel must have requested the `ANNOTATION_SUBSCRIBE` [channel mode](https://ably.com/docs/channels/options.md#modes). Most clients will not need this and can rely on the summary updates instead.
##### Parameters
| Parameter | Description | Type |
|-----------|-------------|------|
| type | An optional annotation `type` (or array of types) to filter the listener on. If omitted, the listener is called for all annotations on the channel | `String` or `String[]` |
| listener | A function called with each received annotation | `AnnotationListener``(ARTAnnotation) -> Void``callable` |
#### unsubscribe
`void unsubscribe(AnnotationListener listener)`
`void unsubscribe(String type, AnnotationListener listener)`
`unsubscribe()`
`unsubscribe(listener: ARTEventListener)`
`unsubscribe(type: String, listener: ARTEventListener)`
`unsubscribe()`
`unsubscribe(listener)`
`unsubscribe(type_or_types, listener)`
Deregisters annotation listeners. When called with no arguments, removes all listeners. When called with a `listener`, removes that listener from all types it was registered for. When called with a `type` and a `listener`, removes the listener from that type only.
## Related types
### ARTRealtimeChannelStateChannel::STATE Enumio.ably.lib.realtime.ChannelState EnumIO.Ably.Realtime.ChannelState Enumably.ChannelState Enum
`io.ably.lib.realtime.ChannelState` is an enum representing all the [Realtime Channel states](https://ably.com/docs/channels/states.md).
#### Java
```
public enum ChannelState {
initialized, // 0
attaching, // 1
attached, // 2
detaching, // 3
detached, // 4
failed // 5
}
```
`IO.Ably.Realtime.ChannelState` is an enum representing all the [Realtime Channel states](https://ably.com/docs/channels/states.md).
#### Csharp
```
public enum ChannelState
{
Initialized = 0,
Attaching = 1,
Attached = 2,
Detaching= 3,
Detached = 4,
Failed = 5
};
```
`Ably::Realtime::Channel::STATE` is an enum-like value representing all the [Realtime Channel states](https://ably.com/docs/channels/states.md). `STATE` can be represented interchangeably as either symbols or constants.
#### Symbol states
##### Ruby
```
:initialized # => 0
:attaching # => 1
:attached # => 2
:detaching # => 3
:detached # => 4
:failed # => 5
```
#### Constant states
##### Ruby
```
Channel::STATE.Initialized # => 0
Channel::STATE.Attaching # => 1
Channel::STATE.Attached # => 2
Channel::STATE.Detaching # => 3
Channel::STATE.Detached # => 4
Channel::STATE.Failed # => 5
```
#### Example usage
##### Ruby
```
# Example with symbols
channel.on(:attached) { ... }
# Example with constants
channel.on(Ably::Realtime::Channel::STATE.Attached) { ... }
# Interchangeable
Ably::Realtime::Channel::STATE.Attached == :attached # => true
```
`ARTRealtimeChannelState` is an enum representing all the [Realtime Channel states](https://ably.com/docs/channels/states.md).
##### Objc
```
typedef NS_ENUM(NSUInteger, ARTRealtimeChannelState) {
ARTRealtimeChannelInitialized,
ARTRealtimeChannelAttaching,
ARTRealtimeChannelAttached,
ARTRealtimeChannelDetaching,
ARTRealtimeChannelDetached,
ARTRealtimeChannelFailed
};
```
##### Swift
```
public enum ARTRealtimeChannelState : UInt {
case Initialized
case Attaching
case Attached
case Detaching
case Detached
case Failed
}
```
`ably.ChannelState` is an enum representing all the [Realtime Channel states](https://ably.com/docs/channels/states.md).
##### Flutter
```
enum ChannelState {
initialized,
attaching,
attached,
detaching,
detached,
suspended,
failed
}
```
### ARTChannelEventChannel::EVENT Enumio.ably.lib.realtime.ChannelEvent EnumIO.Ably.Realtime.ChannelEvent Enumably.ChannelEvent Enum
`io.ably.lib.realtime.ChannelEvent` is an enum representing all the events that can be emitted be the `Channel`; either a [ChannelState](https://ably.com/docs/channels/states.md) or an `update` event.
#### Java
```
public enum ChannelEvent {
initialized, // 0
attaching, // 1
attached, // 2
detaching, // 3
detached, // 4
failed // 5
update // 6
}
```
`IO.Ably.Realtime.ChannelEvent` is an enum representing all the events that can be emitted be the `Channel`; either a [ChannelState](https://ably.com/docs/channels/states.md) or an `Update` event.
#### Csharp
```
public enum ChannelEvent
{
Initialized = 0,
Attaching = 1,
Attached = 2,
Detaching= 3,
Detached = 4,
Failed = 5,
Update = 6
};
```
`Ably::Realtime::Channel::EVENT` is an enum-like value representing all the events that can be emitted be the `Channel`; either a [ChannelState](https://ably.com/docs/channels/states.md) or an `:update` event. `EVENT` can be represented interchangeably as either symbols or constants.
#### Symbol states
##### Ruby
```
:initialized # => 0
:attaching # => 1
:attached # => 2
:detaching # => 3
:detached # => 4
:failed # => 5
:update # => 6
```
#### Constant states
##### Ruby
```
Channel::EVENT.Initialized # => 0
Channel::EVENT.Attaching # => 1
Channel::EVENT.Attached # => 2
Channel::EVENT.Detaching # => 3
Channel::EVENT.Detached # => 4
Channel::EVENT.Failed # => 5
Channel::EVENT.Update # => 6
```
`ARTChannelEvent` is the enum emitted as the event in `ARTRealtimeChannel.on`; either a [ChannelState](https://ably.com/docs/api/realtime-sdk/channels.md#channel-state) or an `Update` event.
##### Objc
```
typedef NS_ENUM(NSUInteger, ARTChannelEvent) {
ARTChannelEventInitialized,
ARTChannelEventAttaching,
ARTChannelEventAttached,
ARTChannelEventDetaching,
ARTChannelEventDetached,
ARTChannelEventFailed,
ARTChannelEventUpdate
};
```
##### Swift
```
enum ARTChannelEvent : UInt {
case Initialized
case Attaching
case Attached
case Detaching
case Detached
case Failed
case Update
}
```
`ably.ChannelEvent` is an enum representing all the events that can be emitted be the `Channel`; either a [ChannelState](https://ably.com/docs/channels/states.md) or an `update` event.
##### Flutter
```
enum ChannelEvent {
initialized,
attaching,
attached,
detaching,
detached,
suspended,
failed,
update
}
```
### ChannelStateChangeARTRealtimeChannelStateChangeio.ably.lib.realtime.ChannelStateListener.ChannelStateChangeIO.Ably.Realtime.ChannelStateChangedably.ChannelStateChange
A `Ably::Models::ChannelStateChange``ChannelStateChange``ARTRealtimeChannelStateChange``ChannelStateChanged` is a type encapsulating state change information emitted by the [`Channel`](https://ably.com/docs/channels.md) object. See [`Channel#on`](https://ably.com/docs/api/realtime-sdk/channels.md#on) to register a listener for one or more events.
#### Attributes
| Attribute | Description | Type |
|-----------|-------------|------|
| current | the new current state | [`ChannelState``Channel::STATE``ARTRealtimeChannelState`](https://ably.com/docs/api/realtime-sdk/types.md#channel-state) |
| previous | the previous state. (for the `update` event, this will be equal to the `current` state) | [`ChannelState``Channel::STATE``ARTRealtimeChannelState`](https://ably.com/docs/api/realtime-sdk/types.md#channel-state) |
| event | the event that triggered this state change | [`ChannelEvent``Channel::EVENT``ARTChannelEvent`](https://ably.com/docs/api/realtime-sdk/types.md#channel-event) |
| reason | an [`ErrorInfo`](https://ably.com/docs/api/realtime-sdk/types.md#error-info) containing any information relating to the transition | [`ErrorInfo`](https://ably.com/docs/api/realtime-sdk/types.md#error-info) |
| resumed | a boolean indicated whether message continuity on this channel is preserved, see [Nonfatal channel errors](https://ably.com/docs/channels/states.md#non-fatal-errors) for more info. | Boolean |
| Attribute | Description | Type |
|-----------|-------------|------|
| Current | the new current state | [`ChannelState`](https://ably.com/docs/api/realtime-sdk/types.md#channel-state) |
| Previous | the previous state. (for the `update` event, this will be equal to the `current` state) | [`ChannelState`](https://ably.com/docs/api/realtime-sdk/types.md#channel-state) |
| Event | the event that triggered this state change | [`ChannelEvent`](https://ably.com/docs/api/realtime-sdk/types.md#channel-event) |
| Reason | an [`ErrorInfo`](https://ably.com/docs/api/realtime-sdk/types.md#error-info) containing any information relating to the transition | [`ErrorInfo`](https://ably.com/docs/api/realtime-sdk/types.md#error-info) |
| Resumed | a boolean indicated whether message continuity on this channel is preserved, see [Nonfatal channel errors](https://ably.com/docs/channels/states.md#non-fatal-errors) for more info. | Boolean |
### ARTMessageAbly::Models::Messageio.ably.lib.types.MessageIO.Ably.Messageably.Message
A `Message` represents an individual message that is sent to or received from Ably.
#### nameName
The event name, if provided.
**Type: `String`**
#### dataData
The message payload, if provided.
**Type:** `String`, `ByteArray`, `JSONObject`, `JSONArray``String`, `byte[]`, _plain C# object that can be serialized to JSON_`String`, `Binary` (ASCII-8BIT String), `Hash`, `Array``NSString *`, `NSData *`, `NSDictionary *`, `NSArray *``String`, `NSData`, `Dictionary`, `Array``String`, `Map`, `List`
#### extrasExtras
Metadata and/or ancillary payloads, if provided. Valid payloads include [`push`](https://ably.com/docs/push/publish.md#payload), `headers` (a map of strings to strings for arbitrary customer-supplied metadata), [`ephemeral`](https://ably.com/docs/pub-sub/advanced.md#ephemeral), and [`privileged`](https://ably.com/docs/platform/integrations/skip-integrations.md) objects.
**Type:** `JSONObject`, `JSONArray`_plain C# object that can be converted to JSON_`Hash`, `Array``Dictionary`, `Array``NSDictionary *`, `NSArray *``Map`, `List`
#### idId
A Unique ID assigned by Ably to this message.
**Type: `String`**
#### clientIdclient_id
The client ID of the publisher of this message.
**Type: `String`**
#### connectionIdconnection_id
The connection ID of the publisher of this message.
**Type: `String`**
#### connectionKeyconnection_key
A connection key, which can optionally be included for a REST publish as part of the [publishing on behalf of a realtime client functionality](https://ably.com/docs/pub-sub/advanced.md#publish-on-behalf).
**Type: `String`**
#### timestampTimestamp
Timestamp of when the message was assigned a serial by the channel in the region in which it was published, as milliseconds since the epocha `Time` object.
**Type: `Integer``Long Integer``DateTimeOffset``Time``NSDate`**
#### encodingEncoding
This will typically be empty as all messages received from Ably are automatically decoded client-side using this value. However, if the message encoding cannot be processed, this attribute will contain the remaining transformations not applied to the `data` payload.
**Type: `String`**
### action
The action type of the message, one of the [`MessageAction`](https://ably.com/docs/api/realtime-sdk/types.md#message-action) enum values. _Type: `enum { MESSAGE_CREATE, MESSAGE_UPDATE, MESSAGE_DELETE, META, MESSAGE_SUMMARY }`_
### serial
A server-assigned identifier that will be the same in all future updates of this message. It can be used to add [annotations](https://ably.com/docs/messages/annotations.md) to a message or to [update or delete](https://ably.com/docs/messages/updates-deletes.md) it. Serial will only be set if you enable annotations, updates, deletes, and appends in [rules](https://ably.com/docs/channels.md#rules). _Type: `String`_
### annotations
An object containing information about annotations that have been made to the object. _Type: [`MessageAnnotations`](https://ably.com/docs/api/realtime-sdk/types.md#message-annotations)_
### version
An object containing version metadata for messages that have been updated or deleted. See [updating and deleting messages](https://ably.com/docs/messages/updates-deletes.md) for more information. _Type: [`MessageVersion`](#message-version)_
### Message constructors
#### Message.fromEncoded
`Message.fromEncoded(Object encodedMsg, ChannelOptions channelOptions?) -> Message`
A static factory method to create a [`Message`](https://ably.com/docs/api/realtime-sdk/types.md#message) from a deserialized `Message`-like object encoded using Ably's wire protocol.
##### Parameters
| Parameter | Description | Type |
|-----------|-------------|------|
| encodedMsg | a `Message`-like deserialized object | `Object` |
| channelOptions | an optional [`ChannelOptions`](https://ably.com/docs/api/realtime-sdk/types.md#channel-options). If you have an encrypted channel, use this to allow the library to decrypt the data | `Object` |
##### Returns
A [`Message`](https://ably.com/docs/api/realtime-sdk/types.md#message) object
#### Message.fromEncodedArray
`Message.fromEncodedArray(Object[] encodedMsgs, ChannelOptions channelOptions?) -> Message[]`
A static factory method to create an array of [`Messages`](https://ably.com/docs/api/realtime-sdk/types.md#message) from an array of deserialized `Message`-like object encoded using Ably's wire protocol.
##### Parameters
| Parameter | Description | Type |
|-----------|-------------|------|
| encodedMsgs | an array of `Message`-like deserialized objects | `Array` |
| channelOptions | an optional [`ChannelOptions`](https://ably.com/docs/api/realtime-sdk/types.md#channel-options). If you have an encrypted channel, use this to allow the library to decrypt the data | `Object` |
##### Returns
An `Array` of [`Message`](https://ably.com/docs/api/realtime-sdk/types.md#message) objects
### ARTChannelOptionsChannelOptions Hashio.ably.lib.types.ChannelOptionsIO.Ably.Rest.ChannelOptionsably.ChannelOptions
Channel options are used for setting [channel parameters](https://ably.com/docs/channels/options.md) and [configuring encryption](https://ably.com/docs/channels/options/encryption.md).
`ChannelOptions`, a Hash object, may optionally be specified when instancing a [`Channel`](https://ably.com/docs/channels.md), and this may be used to specify channel-specific options. The following key symbol values can be added to the Hash:
`io.ably.lib.types.ChannelOptions` may optionally be specified when instancing a [`Channel`](https://ably.com/docs/channels.md), and this may be used to specify channel-specific options.
`ART``ChannelOptions` may optionally be specified when instancing a [`Channel`](https://ably.com/docs/channels.md), and this may be used to specify channel-specific options.
`IO.Ably.ChannelOptions` may optionally be specified when instancing a [`Channel`](https://ably.com/docs/channels.md), and this may be used to specify channel-specific options.
`ably.ChannelOptions` may optionally be specified when instancing a [`Channel`](https://ably.com/docs/channels.md), and this may be used to specify channel-specific options.
#### PropertiesMembersAttributes
| Property | Description | Type |
|----------|-------------|------|
| paramsParams | Optional [parameters](https://ably.com/docs/channels/options.md) which specify behaviour of the channel | `Map``JSON Object` |
| cipherCipherParams | Requests encryption for this channel when not null, and specifies encryption-related parameters (such as algorithm, chaining mode, key length and key). See [an example](https://ably.com/docs/api/realtime-sdk/encryption.md#getting-started) | [`CipherParams`](https://ably.com/docs/api/realtime-sdk/encryption.md#cipher-params) or a `Param[]` list containing at a minimum a `key` |
| Property | Description | Type |
|----------|-------------|------|
| :cipher | Requests encryption for this channel when not null, and specifies encryption-related parameters (such as algorithm, chaining mode, key length and key). See [an example](https://ably.com/docs/channels/options/encryption.md) | [`CipherParams`](https://ably.com/docs/api/realtime-sdk/encryption.md#cipher-params) or an options hash containing at a minimum a `key` |
| Property | Description | Type |
|----------|-------------|------|
| cipher | Requests encryption for this channel when not null, and specifies encryption-related parameters (such as algorithm, chaining mode, key length and key). See [an example](https://ably.com/docs/channels/options/encryption.md) | [`CipherParams`](https://ably.com/docs/api/realtime-sdk/encryption.md#cipher-params) |
#### Static methods
##### withCipherKey
`static ChannelOptions.withCipherKey(Byte[] or String key)`
A helper method to generate a `ChannelOptions` for the simple case where you only specify a key.
###### Parameters
| Parameter | Description | Type |
|-----------|-------------|------|
| key | A binary `Byte[]` array or a base64-encoded `String` | `Byte[]` or `String` |
###### Returns
On success, the method returns a complete `ChannelOptions` object. Failure will raise an [`AblyException`](https://ably.com/docs/api/realtime-sdk/types.md#ably-exception).
#### io.ably.lib.realtime.ChannelStateListener
A `io.ably.lib.realtime.ChannelStateListener` is an interface allowing a client to be notified of [channel state changes](https://ably.com/docs/api/realtime-sdk/types.md#channel-state-change) for a [`Channel`](https://ably.com/docs/channels.md).
##### Java
```
public interface ChannelStateListener {
// Called when the channel state changes
public void onChannelStateChanged(ChannelStateChange stateChange, ErrorInfo reason);
}
```
#### io.ably.lib.realtime.CompletionListener
A `io.ably.lib.realtime.CompletionListener` is an interface allowing a client to be notified of the outcome of an asynchronous operation.
##### Java
```
public interface CompletionListener {
// Called when the associated operation completes successfully,
public void onSuccess();
// Called when the associated operation completes with an error.
public void onError(ErrorInfo reason);
}
```
### PaginatedRequestParams
`HistoryRequestParams` is a type that encapsulates the parameters for a history queries. For example usage see [`Channel#History`](https://ably.com/docs/api/realtime-sdk/history.md#channel-history).
#### Members
| Member | Description | Type |
|--------|-------------|------|
| Start | The start of the queried interval. default: _null_ | `DateTimeOffset` |
| End | The end of the queried interval. default: _null_ | `DateTimeOffset` |
| Limit | Limits the number of items returned by history or stats. default: _null_ | `Integer` |
| Direction | Enum which is either `Forwards` or `Backwards`. default: _Backwards_ | `Direction` enum |
| ExtraParameters | Optionally any extra query parameters that may be passed to the query. This is mainly used internally by the library to manage paging | `Dictionary` |
#### io.ably.lib.realtime.Channel.MessageListener
A `io.ably.lib.realtime.Channel.MessageListener` is an interface allowing a client to be notified when messages are received on a channel using a [channel subscription](https://ably.com/docs/pub-sub.md#subscribe).
##### Java
```
public interface MessageListener {
// Called when one or more messages are received
public void onMessage(Message message);
}
```
### PaginatedResultARTPaginatedResultAbly::Models::PaginatedResultio.ably.lib.types.PaginatedResultIO.Ably.PaginatedResult
A `PaginatedResult` is a type that represents a page of results for all message and presence history, stats and REST presence requests. The response from a [Ably REST API paginated query](https://ably.com/docs/api/rest-api.md#pagination) is accompanied by metadata that indicates the relative queries available to the `PaginatedResult` object.
#### PropertiesMembersAttributes
| Property | Description | Type |
|----------|-------------|------|
| itemsItems | contains the current page of results (for example an Array of [`Message`](#message) or `PresenceMessage` objects for a channel history request) | `Array ` |
#### Methods
##### firstFirst
`PaginatedResult first`
Returns a new [`PaginatedResult`](https://ably.com/docs/api/realtime-sdk/channels.md#paginated-result) for the first page of results. When using the Realtime library, the `first` method returns a [`Deferrable`](https://ably.com/docs/api/realtime-sdk/types.md#deferrable) and yields a `PaginatedResult`.
`PaginatedResult first()`
Returns a new `PaginatedResult` for the first page of results.
`Task> FirstAsync()`
Returns a new `PaginatedResult` for the first page of results. The method is asynchronous and returns a Task which needs to be awaited to get the `PaginatedResult`.
`first(callback: (ARTPaginatedResult?, ARTErrorInfo?) -> Void)`
Returns a new `PaginatedResult` for the first page of results.
`Future first()`
Returns a new `PaginatedResult` for the first page of results.
##### hasNextHasNexthas_next?
`Boolean hasNext()`
`Boolean has_next?`
Returns `true` if there are more pages available by calling `next``Next` and returns `false` if this page is the last page available.
##### isLastIsLastlast?
`Boolean isLast()`
`Boolean last?`
Returns `true` if this page is the last page and returns `false` if there are more pages available by calling `next``Next` available.
##### nextNext
`PaginatedResult next`
Returns a new [`PaginatedResult`](https://ably.com/docs/api/realtime-sdk/channels.md#paginated-result) loaded with the next page of results. If there are no further pages, then `null` is returned. When using the Realtime library, the `first` method returns a [`Deferrable`](https://ably.com/docs/api/realtime-sdk/types.md#deferrable) and yields a `PaginatedResult`.
`PaginatedResult next()`
Returns a new `PaginatedResult` loaded with the next page of results. If there are no further pages, then `Null` is returned.
`Task> NextAsync()`
Returns a new `PaginatedResult` loaded with the next page of results. If there are no further pages, then a blank PaginatedResult will be returned. The method is asynchronous and return a Task which needs to be awaited to get the `PaginatedResult`.
`next(callback: (ARTPaginatedResult?, ARTErrorInfo?) -> Void)`
Returns a new `PaginatedResult` loaded with the next page of results. If there are no further pages, then `nil` is returned.
`Future next()`
Returns a new `PaginatedResult` loaded with the next page of results. If there are no further pages, then `null` is returned.
#### Example
##### Java
```
PaginatedResult firstPage = channel.history();
System.out.println("Page 0 item 0:" + firstPage.items[0].data);
if (firstPage.hasNext) {
PaginatedResult nextPage = firstPage.next();
System.out.println("Page 1 item 1:" + nextPage.items[1].data);
System.out.println("More pages?:" + Strong.valueOf(nextPage.hasNext()));
};
```
##### Csharp
```
PaginatedResult firstPage = await channel.HistoryAsync(null);
Message firstMessage = firstPage.Items[0];
Console.WriteLine("Page 0 item 0: " + firstMessage.data);
if (firstPage.HasNext)
{
var nextPage = await firstPage.NextAsync();
Console.WriteLine("Page 1 item 1:" + nextPage.Items[1].data);
Console.WriteLine("More pages?: " + nextPage.HasNext());
}
```
##### Ruby
```
# When using the REST sync library
first_page = channel.history
puts "Page 0 item 0: #{first_page.items[0].data}"
if first_page.has_next?
next_page = first_page.next
puts "Page 1 item 1: #{next_page.items[1].data}"
puts "Last page?: #{next_page.is_last?}"
end
# When using the Realtime EventMachine library
channel.history do |first_page|
puts "Page 0 item 0: #{first_page.items[0].data}"
if first_page.has_next?
first_page.next do |next_page|
puts "Page 1 item 1: #{next_page.items[1].data}"
puts "Last page?: #{next_page.is_last?}"
end
end
end
```
##### Objc
```
[channel history:^(ARTPaginatedResult *paginatedResult, ARTErrorInfo *error) {
NSLog(@"Page 0 item 0: %@", paginatedResult.items[0].data);
[paginatedResult next:^(ARTPaginatedResult *nextPage, ARTErrorInfo *error) {
NSLog(@"Page 1 item 1: %@", nextPage.items[1].data);
NSLog(@"Last page?: %d", nextPage.isLast());
}];
}];
```
##### Swift
```
channel.history { paginatedResult, error in
guard let paginatedResult = paginatedResult else {
print("No results available")
return
}
print("Page 0 item 0: \((paginatedResult.items[0] as! ARTMessage).data)")
paginatedResult.next { nextPage, error in
guard let nextPage = nextPage else {
print("No next page available")
return
}
print("Page 1 item 1: \((nextPage.items[1] as! ARTMessage).data)")
print("Last page? \(nextPage.isLast())")
}
}
```
### io.ably.lib.types.Param
`Param` is a type encapsulating a key/value pair. This type is used frequently in method parameters allowing key/value pairs to be used more flexible, see [`Channel#history`](https://ably.com/docs/api/realtime-sdk/history.md#channel-history) for an example.
Please note that `key` and `value` attributes are always strings. If an `Integer` or other value type is expected, then you must coerce that type into a `String`.
#### Members
| Parameter | Description | Type |
|-----------|-------------|------|
| key | The key value | `String` |
| value | The value associated with the `key` | `String` |
## Related Topics
- [Constructor](https://ably.com/docs/api/realtime-sdk.md): Realtime Client Library SDK API reference section for the constructor object.
- [Connection](https://ably.com/docs/api/realtime-sdk/connection.md): Realtime Client Library SDK API reference section for the connection object.
- [Channel Metadata](https://ably.com/docs/api/realtime-sdk/channel-metadata.md): Realtime Client Library SDK API reference section for channel metadata.
- [Messages](https://ably.com/docs/api/realtime-sdk/messages.md): Realtime Client Library SDK API reference section for the message object.
- [Presence](https://ably.com/docs/api/realtime-sdk/presence.md): Realtime Client Library SDK API reference section for the presence object.
- [Authentication](https://ably.com/docs/api/realtime-sdk/authentication.md): Realtime Client Library SDK API reference section for authentication.
- [History](https://ably.com/docs/api/realtime-sdk/history.md): Realtime Client Library SDK API reference section for the history methods.
- [Push Notifications - Admin](https://ably.com/docs/api/realtime-sdk/push-admin.md): Realtime Client Library SDK API reference section for push notifications admin.
- [Push Notifications - Devices](https://ably.com/docs/api/realtime-sdk/push.md): Realtime Client Library SDK API reference section for push notification device subscription.
- [Encryption](https://ably.com/docs/api/realtime-sdk/encryption.md): Realtime Client Library SDK API reference section for the crypto object.
- [Statistics](https://ably.com/docs/api/realtime-sdk/statistics.md): Realtime Client Library SDK API reference section for the stats object.
- [Types](https://ably.com/docs/api/realtime-sdk/types.md): Realtime Client Library SDK API reference section for types.
## Documentation Index
To discover additional Ably documentation:
1. Fetch [llms.txt](https://ably.com/llms.txt) for the canonical list of available pages.
2. Identify relevant URLs from that index.
3. Fetch target pages as needed.
Avoid using assumed or outdated documentation paths.