+```shell
curl -H 'Authorization: Bearer ' ...
```
+
-h3(#obtain-token). Obtain token details using the Control API
+### Obtain token details using the Control API
You can use the Control API to obtain information about your access token, such as its capabilities and the user and account it is assigned to. This is shown in the following request:
-```[sh]
+
+```shell
curl --location --request GET 'https://control.ably.net/v1/me' \
--header 'Authorization: Bearer '
```
+
Sample response:
-```[json]
+
+```json
{
"token": {
"id": "a975eecd-b189-4f5b-9f07-1197f3407193",
@@ -120,66 +118,65 @@ Sample response:
}
}
```
+
-h2(#ids). Account ID and app ID
+## Account ID and app ID
-Operations that affect your entire account, such as "listing the apps":/docs/api/control-api/#operation/listApps associated with that account, require an account ID. Those that affect individual apps, such as "creating an API key":/docs/api/control-api/#tag/keys/paths/~1apps~1{app_id}~1keys/post, require an app ID.
+Operations that affect your entire account, such as [listing the apps](/docs/api/control-api/#operation/listApps) associated with that account, require an account ID. Those that affect individual apps, such as [creating an API key](/docs/api/control-api/#tag/keys/paths/~1apps~1{app_id}~1keys/post), require an app ID.
-h3(#account-id). How to find your account ID
+### How to find your account ID
-In the "Ably dashboard":https://ably.com/accounts/any, on the top menu bar, select your account from the dropdown list and then select "Account settings":
+In the [Ably dashboard](https://ably.com/accounts/any), on the top menu bar, select your account from the dropdown list and then select **Account settings**:
-
-
+```shell
curl --request GET \
--url 'https://control.ably.net/v1/accounts/${ACCOUNT_ID}/stats?unit=minute&limit=2' \
--header 'Authorization: Bearer ${ACCESS_TOKEN}' \
--header 'Content-Type: application/json'
```
+
-See the "API reference":/docs/api/control-api#tag/accounts/paths/~1accounts~1{account_id}~1stats/get for information on the request body.
+See the [API reference](/docs/api/control-api#tag/accounts/paths/~1accounts~1{account_id}~1stats/get) for information on the request body.
-Sample response, with @entries@ trimmed for readability:
+Sample response, with `entries` trimmed for readability:
-```[json]
+
+```json
[
{
"intervalId": "2024-10-17:08:45",
@@ -207,8 +204,9 @@ Sample response, with @entries@ trimmed for readability:
}
]
```
+
-h3(#examples-apps). Apps
+### Apps
You can use the Control API to perform tasks such as listing and creating Ably apps. Operations available include:
@@ -216,14 +214,15 @@ You can use the Control API to perform tasks such as listing and creating Ably a
* Create an app
* Update an app
* Delete an app
-* Update an app's "APNs":https://developer.apple.com/library/archive/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/APNSOverview.html info
+* Update an app's [APNs](https://developer.apple.com/library/archive/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/APNSOverview.html) info
* Retrieve app statistics
-h4(#examples-create-app). Create an app
+#### Create an app
To create an app:
-```[sh]
+
+```shell
curl --location --request POST 'https://control.ably.net/v1/accounts/${ACCOUNT_ID}/apps' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer ${ACCESS_TOKEN}' \
@@ -239,12 +238,14 @@ curl --location --request POST 'https://control.ably.net/v1/accounts/${ACCOUNT_I
"apnsUseSandboxEndpoint": false
}'
```
+
-See the "API reference":/docs/api/control-api/#tag/apps/paths/~1accounts~1{account_id}~1apps/post for information on the request body.
+See the [API reference](/docs/api/control-api/#tag/apps/paths/~1accounts~1{account_id}~1apps/post) for information on the request body.
Sample response:
-```[json]
+
+```json
{
"accountId": "VgQpOZ",
"id": "bh4QSw",
@@ -256,20 +257,24 @@ Sample response:
"modified": 1625813276973
}
```
+
-h4(#examples-list-apps). List apps
+#### List apps
To list all the Ably apps associated with your account:
-```[sh]
+
+```shell
curl "https://control.ably.net/v1/accounts/${ACCOUNT_ID}/apps" \
--header "Authorization: Bearer ${ACCESS_TOKEN}" \
--header "Accept: application/json"
```
+
Sample response:
-```[json]
+
+```json
[
{
"accountId": "VgQpOZ",
@@ -284,12 +289,14 @@ Sample response:
...
]
```
+
-h4(#examples-app-stats). Retrieve app statistics
+#### Retrieve app statistics
To retrieve app-level statistics:
-```[sh]
+
+```shell
curl --location --request POST 'https://control.ably.net/v1/apps/${APP_ID}/stats' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer ${ACCESS_TOKEN}' \
@@ -298,12 +305,14 @@ curl --location --request POST 'https://control.ably.net/v1/apps/${APP_ID}/stats
"limit": 1
}'
```
+
-See the "API reference":/docs/api/control-api#tag/apps/paths/~1apps~1{app_id}~1stats/get for information on the request body.
+See the [API reference](/docs/api/control-api#tag/apps/paths/~1apps~1{app_id}~1stats/get) for information on the request body.
-Sample response, with @entries@ trimmed for readability:
+Sample response, with `entries` trimmed for readability:
-```[json]
+
+```json
[
{
"intervalId": "2024-10-17:15",
@@ -319,27 +328,31 @@ Sample response, with @entries@ trimmed for readability:
}
]
```
+
-h3(#examples-queues). Queues
+### Queues
-You can use the Control API to manage "Ably queues":/docs/integrations/queues. The main operations are:
+You can use the Control API to manage [Ably queues](/docs/integrations/queues). The main operations are:
* List all Ably queues
* Create a queue
* Delete a queue
-h4(#examples-queues-list). List queues
+#### List queues
To list all queues associated with an app ID:
-```[sh]
+
+```shell
curl --location --request GET 'https://control.ably.net/v1/apps/${APP_ID}/queues' \
--header 'Authorization: Bearer ${ACCESS_TOKEN}'
```
+
Sample response:
-```[json]
+
+```json
[
{
"id": "28GY6a:us-east-1-a:Test",
@@ -374,12 +387,14 @@ Sample response:
...
]
```
+
-h4(#examples-queues-create). Create a queue
+#### Create a queue
To create a queue for an app:
-```[sh]
+
+```shell
curl --location --request POST 'https://control.ably.net/v1/apps/${APP_ID}/queues' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer ${ACCESS_TOKEN}' \
@@ -390,12 +405,14 @@ curl --location --request POST 'https://control.ably.net/v1/apps/${APP_ID}/queue
"region": "eu-west-1-a"
}'
```
+
-See the "API reference":/docs/api/control-api/#tag/queues/paths/~1apps~1{app_id}~1queues/post for information on the request body.
+See the [API reference](/docs/api/control-api/#tag/queues/paths/~1apps~1{app_id}~1queues/post) for information on the request body.
Sample response:
-```[json]
+
+```json
{
"id": "28GY6a:eu-west-1-a:Queue 123",
"appId": "28GY6a",
@@ -427,8 +444,9 @@ Sample response:
"deadletterId": "28GY6a:eu-west-1-a:deadletter"
}
```
+
-h3(#examples-keys). Keys
+### Keys
You can use the Control API to manage Ably API keys. The main operations are:
@@ -437,20 +455,23 @@ You can use the Control API to manage Ably API keys. The main operations are:
* Update a key
* Revoke a key
-Control API enables you to create a key that has different "capabilities":/docs/auth/capabilities for different channels.
+Control API enables you to create a key that has different [capabilities](/docs/auth/capabilities) for different channels.
-h4(#examples-keys-list). List API keys
+#### List API keys
To list all keys associated with an app ID:
-```[sh]
+
+```shell
curl --location --request GET 'https://control.ably.net/v1/apps/${APP_ID}/keys' \
--header 'Authorization: Bearer ${ACCESS_TOKEN}'
```
+
Sample response:
-```[json]
+
+```json
[
{
"appId": "28GY6a",
@@ -468,12 +489,14 @@ Sample response:
...
]
```
+
-h4(#examples-keys-create). Create a key
+#### Create a key
The following example demonstrates how to create an Ably API key:
-```[sh]
+
+```shell
curl --location --request POST 'https://control.ably.net/v1/apps/${APP_ID}/keys' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer ${ACCESS_TOKEN}' \
@@ -490,12 +513,14 @@ curl --location --request POST 'https://control.ably.net/v1/apps/${APP_ID}/keys'
}
}'
```
+
-This request creates an API key with the key name @My key name@. Note that this key specifies different capabilities for each channel, for example, on @channel1@ this key has publish and subscribe capabilities. On @channel2@ the key only has the history capability.
+This request creates an API key with the key name `My key name`. Note that this key specifies different capabilities for each channel, for example, on `channel1` this key has publish and subscribe capabilities. On `channel2` the key only has the history capability.
Sample response:
-```[json]
+
+```json
{
"appId": "28GY6a",
"id": "Eg063g",
@@ -514,12 +539,14 @@ Sample response:
"modified": 1630506079278
}
```
+
-h4(#examples-keys-update). Update a key
+#### Update a key
-The following request updates the key name, and also adds the history capability to @channel1@:
+The following request updates the key name, and also adds the history capability to `channel1`:
-```[sh]
+
+```shell
curl --location --request PATCH 'https://control.ably.net/v1/apps/${APP_ID}/keys/${KEY_ID}' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer ${ACCESS_TOKEN}' \
@@ -537,10 +564,12 @@ curl --location --request PATCH 'https://control.ably.net/v1/apps/${APP_ID}/keys
}
}'
```
+
Sample response:
-```[json]
+
+```json
{
"appId": "28GY6a",
"id": "RCSMrg",
@@ -560,21 +589,23 @@ Sample response:
"modified": 1630507811349
}
```
-
-h4(#examples-keys-revoke). Revoke a key
+
+#### Revoke a key
To revoke a specific key for a specific app:
-```[sh]
+
+```shell
curl --location --request POST 'https://control.ably.net/v1/apps/${APP_ID/keys/${KEY_ID}/revoke' \
--header 'Authorization: Bearer ${ACCESS_TOKEN}'
```
+
In this case there is only a status code returned (200), or an error code.
-h3(#examples-rules). Rules
+### Rules
-You can use the Control API to manage Ably "integration rules":/docs/integrations. The main operations are:
+You can use the Control API to manage Ably [integration rules](/docs/integrations). The main operations are:
* List all rules for an app
* List details of a specific rule using rule ID
@@ -582,18 +613,21 @@ You can use the Control API to manage Ably "integration rules":/docs/integration
* Update a rule
* Delete a rule
-h4(#examples-rules-list). List rules
+#### List rules
To list the rules for an app:
-```[sh]
+
+```shell
curl --location --request GET 'https://control.ably.net/v1/apps/${APP_ID}/rules' \
--header 'Authorization: Bearer ${ACCESS_TOKEN}'
```
+
Sample response:
-```[json]
+
+```json
[
{
"id": "oO-Tug",
@@ -627,34 +661,38 @@ Sample response:
...
]
```
+
-h4(#examples-rules-list-id). List a rule by rule ID
+#### List a rule by rule ID
-```[sh]
+
+```shell
curl --location --request GET 'https://control.ably.net/v1/apps/${APP_ID}/rules/${RULE_ID}' \
--header 'Authorization: Bearer ${ACCESS_TOKEN}'
```
-
+
The rule details are returned for the specified rule.
-h4(#examples-rules-create). Create a rule
+#### Create a rule
The following example creates a rule with the following configuration:
-|_. Parameter |_. Value |_. Description |
-| @ruleType@ | http | The type of rule, in this case a webhook rule |
-| @requestMode@ | single | Request mode can be single or batched |
-| @channelFilter@ | ^my-channel.* | An optional regular expression that allows the rule to be applied to the specified channel set |
-| @type@ | channel.message | Source type. This means that the source event that will trigger this rule is any message on the channel |
-| @url@ | https://example.com/webhooks | The webhook endpoint. This is the URL triggered for the event |
-| @format@ | json | Format of encoding for the rule, in this case JSON |
-| @name@ | User-Agent | Optional header or headers, including custom headers that might be required. In this case a user agent header is specified (this needs to be set for some providers) |
-| @value@ | user-agent-name | The value of the header |
-| @enveloped@ | true | Wrap packet in "metadata":/docs/integrations/webhooks#envelope |
+| Parameter | Value | Description |
+| --------- | ----- | ----------- |
+| `ruleType` | http | The type of rule, in this case a webhook rule |
+| `requestMode` | single | Request mode can be single or batched |
+| `channelFilter` | `^my-channel.*` | An optional regular expression that allows the rule to be applied to the specified channel set |
+| `type` | channel.message | Source type. This means that the source event that will trigger this rule is any message on the channel |
+| `url` | `https://example.com/webhooks` | The webhook endpoint. This is the URL triggered for the event |
+| `format` | json | Format of encoding for the rule, in this case JSON |
+| `name` | User-Agent | Optional header or headers, including custom headers that might be required. In this case a user agent header is specified (this needs to be set for some providers) |
+| `value` | user-agent-name | The value of the header |
+| `enveloped` | true | Wrap packet in [metadata](/docs/integrations/webhooks#envelope) |
The corresponding request is:
-```[sh]
+
+```shell
curl --location --request POST 'https://control.ably.net/v1/apps/${APP_ID}/rules' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer ${ACCESS_TOKEN}' \
@@ -682,10 +720,12 @@ curl --location --request POST 'https://control.ably.net/v1/apps/${APP_ID}/rules
}
}'
```
+
Sample response:
-```[json]
+
+```json
{
"id": "3DySkw",
"appId": "28GY6a",
@@ -720,14 +760,16 @@ Sample response:
}
}
```
+
This shows the created webhook rule.
-h4(#examples-rules-update). Update a rule
+#### Update a rule
If you need to change a rule you can update it. For example, if you wanted to change the webhook endpoint URL you could carry out the following request:
-```[sh]
+
+```shell
curl --location --request PATCH 'https://control.ably.net/v1/apps/${APP_ID}/rules/${RULE_ID}' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer ${ACCESS_TOKEN}' \
@@ -738,90 +780,77 @@ curl --location --request PATCH 'https://control.ably.net/v1/apps/${APP_ID}/rule
}
}'
```
+
The response is the same as for rule creation, but reflects the updated information.
-h4(#examples-rules-delete). Delete a rule
+#### Delete a rule
If you need to delete a rule you can:
-```[sh]
+
+```shell
curl --location --request DELETE 'https://control.ably.net/v1/apps/${APP_ID}/rules/${RULE_ID}' \
--header 'Authorization: Bearer ${ACCESS_TOKEN}'
```
+
In this case there is only a status code returned (204), or an error code.
-h2(#postman). Testing with Postman
+## Testing with Postman
-The Control API is designed for programmatic access to your account. However, you can try out individual requests using either a command line tool such as "Curl":https://curl.se/ or "HTTPie":https://httpie.io/, or a graphical tool such as "Postman":https://www.postman.com/ or "Paw":https://paw.cloud/. The following section shows you how to make requests using Postman.
+The Control API is designed for programmatic access to your account. However, you can try out individual requests using either a command line tool such as [Curl](https://curl.se/) or [HTTPie](https://httpie.io/), or a graphical tool such as [Postman](https://www.postman.com/) or [Paw](https://paw.cloud/). The following section shows you how to make requests using Postman.
-h3(#importing). Importing the OpenAPI document into Postman
+### Importing the OpenAPI document into Postman
-A convenient way to try out the Control API is by importing the OpenAPI document into "Postman":https://www.postman.com/, and then sending requests and checking the responses. To do this, perform the following steps:
+A convenient way to try out the Control API is by importing the OpenAPI document into [Postman](https://www.postman.com/), and then sending requests and checking the responses. To do this, perform the following steps:
-1. Make sure you have "Postman":https://www.postman.com/downloads/ installed.
+1. Make sure you have [Postman](https://www.postman.com/downloads/) installed.
-2. Start Postman and select "File > Import" from the main menu. The import dialog is displayed:
+2. Start Postman and select **File > Import** from the main menu. The import dialog is displayed:
-
-
+```javascript
const ably = new Ably.Realtime({
authUrl: '/auth', // Your authentication URL
endpoint: 'example-eu', // Replace with your custom endpoint name
});
```
+
-The following example demonstrates how to set up the Ably Realtime client using "your own subdomain:":#option-2
+The following example demonstrates how to set up the Ably Realtime client using [your own subdomain:](#option-2)
-```[javascript]
+
+```javascript
const ably = new Ably.Realtime({
authUrl: '/auth', // Your authentication URL
endpoint: 'realtime.example.com', // Your custom WebSocket endpoint
@@ -143,15 +147,18 @@ const ably = new Ably.Realtime({
]
});
```
+
You should then test that all client SDKs can connect, publish, and receive messages (where applicable) before rolling out these changes to production code.
-Where possible, you should also inspect your network traffic to verify that the client SDKs are calling the endpoints for your custom endpoint. Instead of connections to @realtime.ably.net@ you should see connections to @[ENDPOINT].realtime.ably.net@, or your own custom CNAME domain.
+Where possible, you should also inspect your network traffic to verify that the client SDKs are calling the endpoints for your custom endpoint. Instead of connections to `realtime.ably.net` you should see connections to `[ENDPOINT].realtime.ably.net`, or your own custom CNAME domain.
-h3. Roll out your changes
+### Roll out your changes
Once all your client library SDKs are using the new endpoint and traffic is arriving at the correct endpoints, the team at Ably will be able to actively reroute your traffic based on your endpoint settings.
If you have regional constraints on your account, then please contact your customer success manager who will ensure that the regional constraints are applied and tested too.
-*Note*: Services are assigned to a custom endpoint on a per-account basis. This means that all apps within an account _must be migrated at the same time_.
+
+```json
+{
+ "error": "new ErrorInfo('Batched response includes errors', 40020, 400)",
+ "batchResponse": "results"
+}
+```
+
+
+## 40022: Invalid resource
+
+This error occurs when the requested resource is invalid or already exists. It is typically returned by requests to the [Control API](/docs/platform/account/control-api).
+
+Examples of this error include attempting to create a resource that already exists or providing an invalid resource name.
+
+**Resolution:** The following steps can help resolve this issue:
+* Ensure that an app with the requested name does not already exist in your account. If it does, use a different name.
+* Verify that the [capabilities](/docs/auth/capabilities#capability-operations) listed in the request are valid when creating an API key.
+
+## 40023: Action requires a newer protocol version
+
+This error occurs when the requested operation is only available in a newer version of the Ably protocol than the one specified in the request. This can happen if the client is using an older version of the Ably SDK that does not support the requested operation.
+
+Examples of this error include attempting to use [channel objects](/docs/liveobjects) or message annotations, updates and deletes from an Ably SDK that does not support protocol version 2.
+
+**Resolution:** The following steps can help resolve this issue:
+* Upgrade the Ably SDK to a version that supports the requested operation.
+
+## 40030: Invalid publish request (unspecified)
+
+This error occurs when a [publish request](/docs/pub-sub#publish) is malformed.
+
+## 40032: Invalid publish request (impermissible extras field)
+
+This error occurs when a published message contains arbitrary fields in the [`extras`](/docs/api/realtime-sdk/messages#extras) payload that are not allowed by the Ably service. The `extras` field is reserved for specific objects related to Ably.
+
+**Resolution:** Place any additional data inside the `headers` field within `extras`. The `headers` field must be a flat object (`map
+```javascript
+const extras = {
+ headers: {
+ header1: 'value1',
+ header2: 'value2'
+ }
+};
+```
+
+
+## 40100: Unauthorized
+
+This error occurs when an action cannot be performed due to a lack of [authentication](/docs/auth). There will be additional info in the `message` property about the reason the action could not be performed.
+
+## 40101: Invalid credentials
+
+This error occurs when [authentication](/docs/auth) credentials are invalid. The specific error message may provide further details about the cause.
+
+An example of this error is when a signed token request is invalid due to a mismatched cryptographic signature (MAC does not match) or when the `clientId` specified in the Ably SDK does not match the `clientId` in the access token.
+
+**Resolution:** Review your authentication setup and token request implementation. Ensure the following:
+
+* The cryptographic signature (MAC) is correct - If a signed token request is invalid, Ably will reject it.
+* The API key used to generate the token request is accurate - Double-check for missing or extra characters.
+* The token request JSON is correctly formatted and unaltered, including:
+** `keyName`: Must match the API key used in the request.
+** `clientId`: If provided, it must match the one in the client constructor.
+** `ttl`: Must be an integer in milliseconds.
+** `timestamp`: Must be an integer in milliseconds.
+** `capability`: Must be stringified JSON, not raw JSON.
+** `nonce`: Must be a randomly generated string value.
+** `mac`: Must be correctly generated using the secret key.
+* The `clientId` in the SDK matches the one in the token. If a `clientId` is provided in the token, it must align with the `clientId` set in the Ably client options.
+* A `clientId` cannot be changed on an existing connection. Ensure consistency in authentication.
+* For JWT authentication, confirm that `clientId` is correctly set in `x-ably-clientId`.
+
+## 40102: Incompatible credentials
+
+This error occurs when [authentication](/docs/auth) credentials do not match the existing connection, causing the connection to enter the [failed state](/docs/connect/states).
+
+Examples of this error include:
+
+* Attempting to authenticate with an API key from a different app than the one used for the original connection
+* Resuming a connection using credentials tied to a different app
+* Calling `auth.authorize` with an API key that differs from the one originally used to establish the connection
+
+## 40103: Invalid use of Basic auth over non-TLS transport
+
+This error occurs when an API key is used over a non-TLS (unencrypted) connection, which is not permitted due to security risks. API keys are long-lived credentials, making them more vulnerable if exposed. Unlike short-lived tokens, API keys remain valid indefinitely, meaning a compromised key presents a significant security risk.
+
+Non-TLS transports can be inspected by network devices routing traffic between the client and Ably. Ably does not allow API key authentication over non-TLS connections. However, Ably supports [basic authentication](/docs/auth/basic) over TLS and [token authentication](/docs/auth/token) over non-TLS connections.
+
+**Resolution:** Select the appropriate [authentication mechanism](/docs/auth#selecting-auth) for your use case.
+
+## 40104: Timestamp not current
+
+This error occurs when a signed token request sent to Ably is too old. Ably enforces timestamp validation to ensure [`TokenRequest`](/docs/auth/token#token-request) remain valid for a limited time, reducing the risk of interception and misuse.
+
+**Resolutions:** The following steps can help resolve this issue:
+* Ensure that the authentication servers clock is accurate when generating signed token requests.
+* If time synchronization is unreliable, set the `queryTime` [ClientOptions](/docs/api/rest-sdk/types#client-options) object to true when initializing the Ably client. This ensures Ably's server time is used.
+* Do not cache signed token requests on the authentication server or client. Each token request must be freshly generated and used immediately.
+* If using Next.js 13, prevent caching issues by setting revalidate to 0 or changing the request method from `GET` to `POST` using the `authMethod` [ClientOption](/docs/api/rest-sdk/types#client-options).
+
+## 40105: Nonce value replayed
+
+This error occurs when a signed [token request](/docs/api/realtime-sdk/types#token-request) has been used more than once. Ably enforces nonce (number used once) checks to ensure that each signed token request is unique, as a security measure.
+
+Examples of this error include:
+* A client sends a signed token request to Ably but does not receive the response due to network issues. If the client automatically retries the HTTP request in a fallback data center, Ably detects the duplicate nonce and rejects it.
+* An authentication server caches and reuses signed token requests instead of generating a unique one for each request.
+* A misconfigured [`authCallback`](/docs/auth/token#auth-callback) function reuses the same token request on every invocation instead of generating a fresh one.
+* The `tokenRequest` is not renewed. A new token request should be requested from your server at this point:
+
+
+```javascript
+var tokenRequest = "";
+var ably = new Ably.Realtime({
+ authCallback: function(tokenParams, callback) {
+ // This is a mistake. The tokenRequest is not renewed.
+ A new token request should be requested from your server at this point */
+ callback(null, tokenRequest);
+ }
+});
+```
+
+
+**Resolution:** The following steps can help resolve this issue:
+* Ensure that each token request is unique and never cached by the authentication server or client.
+* Always generate a new token request each time authCallback is invoked.
+* If retrieving a token request over HTTP, prevent caching by using the Cache-Control header (no-cache, no-store, must-revalidate) or by adding a cache-busting query string parameter, where the number is regenerated for every request, for example, `?rnd=73849275`.
+* If network issues are suspected, check logs and debug the token request process to confirm proper request handling.
+
+## 40106: Unable to obtain credentials from given parameters
+
+This error occurs when invalid [authentication](/docs/auth) options (key or token) are provided to the Ably SDK, preventing successful authentication.
+
+An example of this error is when no [API key](/docs/auth#api-keys) or [token](/docs/auth/token) is supplied, or when an authentication request is made using a token to request another token, instead of an API key.
+
+## 40111: Connection limits exceeded
+
+This error occurs when the peak [connection limit](/docs/platform/pricing/limits#connection) for your account has been exceeded, preventing new connections from being established until existing ones disconnect.
+
+## 40112: Account blocked (message limits exceeded)
+
+This error occurs when your account has exceeded the allocated [message limit](/docs/platform/pricing/limits#message) based on your [package](/docs/pricing#packages). Once this limit is reached, further message publishing is blocked.
+
+## 40114: Account-wide peak channel limit exceeded
+
+This error occurs when your account has exceeded the concurrent [channel limit](/docs/platform/pricing/limits#channel), preventing additional channels from being created.
+
+Examples of this error are when the application attempts to open more channels than the account allows, causing new channel creation to be blocked. Also, during development, an implementation error or bug causes unintended channel creation, leading to the limit being reached.
+
+**Resolution:** Detach unused channels to free up space for new ones.
+
+## 40115: Account restricted (request limit exceeded)
+
+This error occurs when your account has exceeded the allocated [limits](/docs/platform/pricing/limits) based on your [package](/docs/pricing#packages).
+
+## 40125: Maximum number of rules per application exceeded
+
+This error occurs when the application has reached the maximum number of [integration rules](/docs/integrations) set by the [limits](/docs/platform/pricing/limits#app-limits) for your current package.
+
+## 40127: Maximum number of keys per application exceeded
+
+This error occurs when the application has reached the maximum number of [API keys](/docs/platform/account/app/api) set by the [limits](/docs/platform/pricing/limits#app-limits) for your current package.
+
+## 40131: Key revoked
+
+This error occurs when the [Ably API key](/docs/auth#api-keys) used to initialize the SDK is no longer valid because it has been [revoked](/docs/auth/revocation) by an admin of the application.
+
+**Resolution:** The following steps can help resolve this issue:
+* If you are an admin, go to the [API keys tab](/docs/platform/account/app/api) in the Ably dashboard to check for valid keys. Use an existing valid key or create a new one with the necessary permissions.
+* If you are not an admin, request a new API key from an administrator or obtain a token request generated with a valid key.
+
+## 40133: Wrong key; cannot revoke tokens with a different key than the one that issued them
+
+This error occurs when the [Ably API key](/docs/auth#api-keys) used to authorize a token [revocation](/docs/auth/revocation) request does not match the key that originally issued the token.
+
+**Resolution:** The following steps can help resolve this issue:
+* Ensure that the public API key ID used in the request matches the key that originally issued the token.
+* Verify that the `keyname` in the request path corresponds with the API key used for authentication.
+
+## 40141: Token revoked
+
+This error occurs when attempting to authenticate with a [token](/docs/auth/token) that has been [revoked](/docs/auth/revocation) and is no longer valid.
+
+**Resolution:** Ensure that you are using a valid, [non-revoked](/docs/auth/revocation). token for authentication. If needed, generate a new token and use it for authorization.
+
+## 40142: Token expired
+
+This error occurs when the authentication [token](/docs/auth/token#refresh) has expired and is no longer valid for use.
+
+An example of this error is when a client attempts to authenticate with a token that has exceeded its time-to-live (TTL).
+
+**Resolution:** The following steps can help resolve this issue:
+* Use [`authUrl`](/docs/auth/token#auth-url) or [`authCallback`](/docs/auth/token#auth-callback) in your client configuration to enable automatic token renewal.
+* If `authUrl` or `authCallback` is correctly configured, the client SDK will automatically renew the token when needed, so you may see this error temporarily before renewal occurs.
+
+## 40143: Token unrecognized
+
+This error occurs when the provided token is not recognized as a valid Ably [token](/docs/auth/token), Ably [JWT](/docs/auth/token#jwt), or a JWT containing a valid Ably token.
+
+An example of this error is when a JWT is incorrectly formatted or when an Ably token does not follow the expected structure, for example: `
+```text
+Rate limit exceeded; request rejected (nonfatal);
+metric = channel.maxRate;
+interval = 2018-01-05:10:10:3;
+permitted rate = 5000;
+current rate = 5015;
+scope = channel:[YOUR APP ID]:[YOUR CHANNEL]
+(status: 429, code: 42910) (code: 42910, http status: 429)
+```
+
+
+**Resolution:** Wait for the rate limit period to reset before retrying. Optimize your message publishing to stay within allowed limits. Upgrade your package if higher throughput is required. Review your account limits to determine which restriction has been hit.
+
+## 42911: Maximum account-wide instantaneous messages rate exceeded
+
+This error occurs when the number of [messages](/docs/platform/pricing/limits#message) sent per second exceeds the limit imposed on an account. To maintain service reliability for all users, Ably enforces usage limits at different levels, including monthly, hourly, and per-second thresholds.
+
+## 42912: Channel iteration call already in progress
+
+This error occurs when multiple concurrent [metadata REST requests](/docs/metadata-stats/metadata#rest) are made to retrieve a list of active channels. The API is rate-limited, allowing only one in-flight call at a time. Additional concurrent requests will be rejected with this error.
+
+**Resolution:** The following steps can help resolve this issue:
+* Ensure that only one request is in progress at any given time.
+* Implement request queuing or backoff strategies to avoid sending concurrent calls.
+* If you require enhanced channel [enumeration capabilities](/docs/api/rest-api#enumeration-rest), visit this page to request access to the preview API.
+
+## 42922: Rate limit exceeded; too many requests
+
+This error occurs when a client has made too many requests within a 5-minute time window, causing the request to be rejected. The [limit](/docs/platform/pricing/limits#hitting) remains in effect for up to 30 seconds but may persist longer if request volume remains above the threshold from the same IP address.
+
+This rate limit is in place to protect the Ably platform and is not expected during normal use.
+
+## 50001: Internal channel error
+
+This error occurs when there is an internal issue on an Ably channel.
+
+## 50002: Internal connection error
+
+This error occurs when there is an internal connection issue.
+
+## 50003: Timeout error
+
+This error occurs when a [connection](/docs/connect) request to Ably times out.
+
+An example of this error is when a client attempts to publish a message to a channel, but the operation fails to complete within the allowed time.
+
+Examples of this error include:
+* Poor network conditions affecting connectivity.
+* Improper usage of the Ably SDKs leading to unexpected delays.
+* Temporary Ably server issues impacting response times.
+
+## 50305: Ably's routing layer was unable to service this request
+
+This error occurs as a result of a request not being handled due to an internal routing error within the Ably service.
+
+## 61002: Activation failed: Present clientId is not compatible with existing device registration
+
+This error occurs when you previously [activated](/docs/push/configure/device#activate-devices) a device for push notifications with a specific `clientId`, but then changed the `clientId` used for authentication. The mismatch causes the error because the push notification setup tracks the `clientId` and other details to prevent accidental changes between app launches. The `clientId` is linked to registrations, such as subscribing by `clientId`.
+
+**Resolution:** If you need to change your client's `clientId`, deactivate and reactivate the device. This process triggers an internal `device.reset()` call, which clears and resets the old device details.
+
+## 70001: Reactor operation failed (POST operation failed)
+
+This error occurs when a Reactor rule fails due to an issue with the configured endpoint. Ably attempts to send a POST request, but the response is unexpected or unsuccessful.
+
+## 70002: Reactor operation failed (POST operation returned unexpected code)
+
+This error occurs when Ably sends a webhook to your server, but the server refuses or returns an unexpected response code. While Ably will retry the request multiple times, repeated failures indicate an issue on the server side.
+
+## 72000: Ingress operation failed
+
+This error occurs due to an internal error with the ingress worker. It is an unexpected issue that happens when the worker attempts to execute a rule but encounters an error during the process.
+
+## 72002: Ingress table is unhealthy
+
+This error occurs when the rule worker is unable to access or retrieve data from either the [outbox](/docs/livesync/postgres#outbox-table) or [nodes](/docs/livesync/postgres#nodes-table) table in the database as expected.
+
+An example of this error is misconfigurations in the database setup or inconsistencies between the provided configuration and the actual database schema or table names.
+
+**Resolution:** The following steps can help resolve this issue:
+* Verify the configuration of the outbox and nodes tables in the database to ensure they are correctly set up and match the rule definition.
+* Check for database connectivity issues and confirm that the database is accessible.
+* Ensure that the schema and table names align with the expected configuration.
+
+## 72004: Ingress cannot identify channel, no _ablyChannel field
+
+This error occurs when a [MongoDB Change Stream](https://www.mongodb.com/docs/manual/changeStreams/#change-streams) event does not contain the required `_ablyChannel` field after being processed through the Change Stream pipeline. This field is essential for identifying the channel where the change event message will be published.
+
+**Resolution:** The following steps can help resolve this issue:
+* Ensure that the `_ablyChannel` field is present at the root level of the change event.
+* Avoid nesting it inside other sections, such as `$fullDocument._ablyChannel`.
+* The field must be part of the main structure of the change event to allow proper identification.
+
+## 72005: Ingress invalid pipeline
+
+This error occurs when the [MongoDB Change Stream](https://www.mongodb.com/docs/manual/changeStreams/#change-streams) fails to start due to an invalid pipeline. An example of this error is when the pipeline syntax does not conform to MongoDB's requirements or contains unrecognized operators.
+
+**Resolution:** The following steps can help resolve this issue:
+* Review the pipeline syntax for errors and ensure all operators are valid.
+* Adjust the pipeline to match MongoDB's accepted structure and syntax guidelines.
+
+## 72006: Unable to resume from change stream
+
+This error occurs when the [MongoDB Change Stream](https://www.mongodb.com/docs/manual/changeStreams/#change-streams) cannot be resumed because the resume token document stored in MongoDB is not in the correct format.
+
+**Resolution:** The following steps can help resolve this issue:
+* Verify the format of the stored resume token document in MongoDB.
+* Ensure the token meets the expected structure and format required for MongoDB Change Stream resumption.
+* Refer to the MongoDB documentation for guidelines on properly storing and using resume tokens.
+
+## 72007: Unable to store change stream resume token
+
+This error occurs when the [MongoDB Change Stream](https://www.mongodb.com/docs/manual/changeStreams/#change-streams) resume token cannot be stored in the `ably` collection of the database.
+
+**Resolution:** The following steps can help resolve this issue:
+* Verify that the integration rule and MongoDB connection string are correctly configured.
+* Ensure the database user has the necessary read and write permissions for the `ably` collection.
+* Adjust permissions if needed to allow the token to be successfully stored.
+
+## 80000: Connection failed
+
+This error occurs when the SDK is having trouble [connecting](/docs/connect/states#connection-states) to Ably, likely due to client-side network connectivity issues. Note: The SDK will automatically retry the connection after 30 seconds.
+
+## 80002: Connection suspended
+
+This error occurs when the SDK is having trouble [connecting](/docs/connect/states#connection-states) to Ably. This is likely due to client-side network connectivity issues, and has failed to establish a connection within 2 minutes. Note: The SDK will automatically retry the connection after 15 seconds.
+
+## 80003: Generic disconnection error
+
+This error occurs when the SDK is having trouble [connecting](/docs/connect/states#connection-states) to Ably, likely due to client-side network connectivity issues. Note: The SDK will automatically retry the connection after 15 seconds.
+
+## 80008: Unable to recover connection (connection expired)
+
+This error occurs when a [connection](/docs/connect/states#connection-states) resume attempt fails because the original connection has expired. This typically happens when the [`resume`](/docs/connect/states#resume) attempt occurs after the two-minute window has passed.
+
+If this error occurs, the client establishes a new connection instead of resuming the old one. Any messages sent during the gap will be missed, unless channel persistence is enabled.
+
+**Resolution:** Ensure that resume attempts occur within the two-minute window to successfully recover a connection. If message loss is a concern, use [history](/docs/api/realtime-sdk/history) to retrieve missed messages.
+
+## 80014: Connection timed out
+
+This error occurs when a realtime [connection](/docs/connect/states#connection-states) times out after waiting for the default 10-second `realtimeRequestTimeout` in certain Ably SDKs.
+
+The request will be automatically retried by the SDK.
+
+**Resolution:** If the client never connects to the [primary or fallback endpoints](https://faqs.ably.com/routing-around-network-and-dns-issues), check any firewall rules that may be blocking access to Ably's [endpoints](https://faqs.ably.com/if-i-need-to-whitelist-ablys-servers-from-a-firewall-which-ports-ips-and/or-domains-should-i-add).
+
+## 80016: Operation on superseded connection
+
+This error occurs when a browser [connection](/docs/connect/states#connection-states) upgrades from an HTTP (Comet) transport to WebSockets. It is logged by the client library when operations are performed on the older transport.
+
+**Resolution:** the following steps can help resolve this issue:
+* If this error only appears in logs, it is harmless and does not affect your application. No action is needed.
+* If you receive this error as a response to a request, contact Ably support with relevant logs and details, and they will investigate the issue.
+
+## 80017: Connection closed
+
+This error occurs when a [connection](/docs/connect/states#connection-states) has been closed and an operation is attempted on it, such as calling a channel or presence method, for example, `channel.presence.update` while the connection is still in a closed state.
+
+**Resolution:** The following steps can help resolve this issue:
+* Check the client's connection state before performing operations to ensure the connection is active.
+* If the connection is closed, reconnect before making requests to avoid this error.
+
+## 80018: Invalid connection ID (invalid format)
+
+This error occurs when an invalid `connectionId` is supplied.
+
+**Resolution:** If you are seeing resumes failing in ably-js, this was a known bug in ably-js versions 1.2.30 through 1.2.33. Upgrading to the latest version of ably-js should resolve the issue.
+
+## 80019: Auth server rejecting request
+
+This error occurs when the client library fails to obtain a token using the client-supplied [`authUrl`](/docs/auth/token#auth-url) or [`authCallback`](/docs/auth/token#auth-callback). It is raised when the request to the authentication server fails due to an error or exception in the callback.
+
+## 80020: Continuity loss due to maximum subscribe message rate exceeded
+
+This error occurs when a client exceeds the [outbound](/docs/platform/pricing/limits#connection) subscribe message rate on a realtime connection.
+
+**Resolution:** The subscriber will receive an `UPDATE` [channel state change](/docs/api/realtime-sdk/channels#channel-state-change) event, indicating that continuity is lost. Use the [`resume`](/docs/connect/states#resume) flag to determine whether to recover missing messages or handle the failure accordingly.
+
+## 80021: Max new connections rate exceeded
+
+This error occurs when the maximum allowed rate of new connections for an account has been [exceeded](/docs/platform/pricing/limits#hitting).
+
+## 80022: Unable to find connection
+
+This error can occur when using the Comet transport, where a `send` or `recv` request is sent to the system but reaches a different frontend instance than the one hosting the connection. This can happen due to a disruption on a frontend instance.
+
+**Resolution:** This is a non-fatal error, and no action is required. The transport will automatically drop and be re-initiated without any need for manual intervention.
+
+## 80023: Unable to resume connection from a different site
+
+This error occurs when a disconnected client attempts to resume a [connection](/docs/connect) from a different site than the original connection. This typically happens when a client tries to [`resume`](/docs/connect/states#resume) via a fallback host.
+
+**Resolution:** Channel message continuity will not be possible in this scenario. Any messages sent while the client was disconnected will need to be retrieved using [history](/docs/storage-history/history).
+
+## 90001: Channel operation failed (invalid channel state)
+
+This error occurs when an application attempts to perform an operation on a channel that is in a [state](/docs/channels/states#connection-state) that does not permit it.
+
+An example of this error is when an application tries to [publish](/docs/pub-sub#publish) a message or attach to a channel that is in a failed state due to a prior error. As a result, the operation fails because actions cannot be performed on a channel in this state.
+
+**Resolution:** The following steps can help resolve this issue:
+* Ensure the channel is in an appropriate state before performing any operations.
+* Use an Ably SDK to listen for channel state changes and handle operations accordingly.
+* Implement state change callbacks to trigger the intended operation when the channel is in a valid [state](/docs/channels/states).
+
+## 90004: Unable to recover channel (message limit exceeded)
+
+This error occurs when using the rewind feature with a specified time period, and the total number of messages within the selected timeframe exceeds the maximum [limit](/docs/channels/options/rewind#limits) that can be retrieved in a single request.
+
+## 90007: Channel didn't attach within 00:00:10
+
+This error occurs when a channel fails to [attach](/docs/channels/states#attach) within the default 10-second timeout. It is most commonly encountered by clients with poor internet connections, where the `ACK` response to an `ATTACH` request does not return within the expected timeframe.
+
+Note: In older versions of the ably-java SDK, this error was incorrectly assigned to error code `91200`.
+
+**Resolution:** Adjust the `realtimeRequestTimeout` or `channelRetryTimeout` (depending on the SDK) to a higher value to allow more time for the attachment process.
+
+## 90010: Maximum number of channels per connection exceeded
+
+This error occurs when a Realtime client [attaches](/docs/channels/states#attach) to more channels than the account allows on a single connection. This happens when channels are attached but never explicitly detached, causing the limit to be reached.
+
+**Resolution:** Review your channel [limits](/docs/platform/pricing/limits#channel) and ensure that channels are explicitly detached when no longer needed.
+
+## 90021: Max channel creation rate exceeded
+
+This error occurs when the [maximum](/docs/platform/pricing/limits#channel) rate of channel creation has been exceeded, across an account. Until the rate returns below the limit, new channels may not be created immediately. The Ably SDK will automatically retry every 10 seconds until the request succeeds.
+
+## 91000: Unable to enter presence channel (no clientId)
+
+This error occurs when a client attempts to [enter](/docs/chat/rooms/presence#set) the [presence](/docs/presence-occupancy/presence) set of a channel without specifying a `clientId`.
+
+A client can be identified in several ways:
+* If using [token](/docs/auth/token) authentication, ensure the token is associated with a `clientId` by setting the `clientId` field in `tokenParams` when creating a token request or requesting a token.
+* If using basic authentication or token authentication with a wildcard `clientId`, set the `clientId` in the client options when initializing the Ably SDK.
+* Specify a `clientId` at the time of entering presence using [`enterClient()`](/docs/api/realtime-sdk/presence#enterclient).
+
+## 91003: Maximum member limit exceeded
+
+This error occurs when the [maximum](/docs/platform/pricing/limits#hitting) number of clients in the [presence](/docs/presence-occupancy/presence) set for a channel has been reached, preventing additional clients from joining.
+
+## 91005: Presence state is out of sync
+
+This is a client-side issue that occurs when an up-to-date [presence](/docs/presence-occupancy/presence) set cannot be retrieved due to connection issues. It typically happens when calling `presence.get()` while the channel is in a suspended state, often caused by an interruption in the client's internet connection.
+
+**Resolution:** The following steps can help resolve this issue:
+* Ensure the client has an active connection before calling `presence.get()`.
+* If an outdated presence set is acceptable, set `waitForSync` to `false` to retrieve the presence data even when out of sync.
+
+## 92000: Invalid object message
+
+This error occurs when an object message used to represent [operations](/docs/liveobjects/concepts/operations) and [objects](/docs/liveobjects/concepts/objects) is malformed or contains invalid data that cannot be processed.
+
+* If this error occurs when using the REST API, the error response will include additional details about how to correctly construct your request.
+* If this error occurs when using a Realtime SDK, it likely indicates a bug in the client. Please raise an issue in the GitHub repository for the SDK you are using with relevant logs and details.
+
+## 92001: Objects limit exceeded
+
+This error occurs when the maximum number of [objects](/docs/liveobjects) on the channel has exceeded the allowed [limit](/docs/platform/pricing/limits#channel) for the account or application.
+
+**Resolution:**
+* Remove any unnecessary objects from the channel to free up space, for example by [removing](/docs/liveobjects/map#remove) any references to them.
+* [Upgrade](/docs/pricing) your package to increase the [limit](/docs/platform/pricing/limits#channel) on the allowed number of objects on the channel.
+
+## 92002: Unable to submit operation on tombstone object
+
+This error occurs when attempting to perform an [operation](/docs/liveobjects/concepts/operations) on a [tombstone](/docs/liveobjects/concepts/objects#tombstones) object (an object that has been marked as deleted).
+
+**Resolution:**
+* Retry the operation on an object that is not a tombstone and is [reachable](/docs/liveobjects/concepts/objects#reachability) from the [root object](/docs/liveobjects/concepts/objects#root-object) .
+
+## 92003: Unable to fetch object tree with tombstone object as root
+
+This error occurs when attempting to fetch an [object](/docs/liveobjects/concepts/objects) tree where the specified object is a [tombstone](/docs/liveobjects/concepts/objects#tombstones) object (an object that has been marked as deleted).
+
+You may encounter this error when [fetching objects](/docs/liveobjects/rest-api-usage#fetching-objects-get-children) via the REST API using the `children` query parameter, or if using the [compact](/docs/liveobjects/rest-api-usage#fetching-objects-compact) endpoint.
+
+**Resolution:**
+* Retry the operation on an object that is not a tombstone and is [reachable](/docs/liveobjects/concepts/objects#reachability) from the [root object](/docs/liveobjects/concepts/objects#root-object) .
+
+## 92004: Object not found
+
+This error occurs when attempting to access an [object](/docs/liveobjects/concepts/objects) that does not exist.
+
+You may encounter this error when using the [REST API](/docs/liveobjects/rest-api-usage) or if calling methods on a [LiveMap](/docs/liveobjects/map) or [LiveCounter](/docs/liveobjects/map) instance that has been deleted.
+
+**Resolution:**
+* Listen for [lifecycle events](/docs/liveobjects/lifecycle) on object instances to be notified when an object is deleted.
+* Retry the REST API request with a valid [object ID](/docs/liveobjects/rest-api-usage#updating-objects-by-id) or [path](/docs/liveobjects/rest-api-usage#updating-objects-by-path) that corresponds to an existing object.
+
+## 92005: No objects found matching operation path
+
+This error occurs when no objects are found that match the specified [path](/docs/liveobjects/rest-api-usage#updating-objects-by-path) when using the REST API.
+
+**Resolution:**
+* Ensure that the `path` is correctly specified and corresponds to an existing object.
+
+## 92006: Unable to perform operation without objectId or path
+
+This error occurs when attempting to perform an operation without providing either an [object ID](/docs/liveobjects/rest-api-usage#updating-objects-by-id) or [path](/docs/liveobjects/rest-api-usage#updating-objects-by-path) to identify the target object when using the REST API.
+
+**Resolution:**
+* Ensure that the request includes either an `objectId` or a `path` parameter to specify the target object for the operation.
+
+## 92007: Operation not processable on path
+
+This error occurs when the requested operation cannot be processed for the object located at the specified [path](/docs/liveobjects/rest-api-usage#updating-objects-by-path) when using the REST API.
+
+You may encounter this error when the type of the object located at the specified path does not support the specified operation (e.g. publishing a `COUNTER_INC` operation on a [LiveMap](/docs/liveobjects/map) instance).
+
+**Resolution:**
+* Ensure that the operation is valid for the type of object at the specified path.
+
+## 101000: Space name missing
+
+This error occurs when calling [`spaces.get()`](/docs/spaces/space#options) without specifying a space name. The name parameter is required to retrieve a space.
+
+**Resolution:** Ensure that a valid space name is provided when calling `spaces.get()`:
+
+
+```javascript
+const space = await spaces.get('mySpaceName');
+```
+
+
+## 101001: Not entered space
+
+This error occurs when calling a function that requires the client to be [entered](/docs/spaces/space#enter) into a space, but the client has not yet done so.
+
+**Resolution:** Ensure that `space.enter()` is called before performing operations that require the client to be inside the space:
+
+
+```javascript
+const space = await spaces.get('mySpace');
+space.enter({
+ username: 'Claire Lemons',
+ avatar: 'https://slides-internal.com/users/clemons.png',
+});
+```
+
+
+## 101002: Lock request exists
+
+This error occurs when an existing [lock request](/docs/spaces/locking#states) is still pending or locked. Nested locks are not supported, so a new lock cannot be requested until the previous one is resolved.
+
+## 101003: Lock is locked
+
+This error occurs when a lock is already in the [locked state](/docs/spaces/locking#states), and a pending request did not override or release the lock.
+
+## 101004: Lock invalidated
+
+This error occurs when a [lock request](/docs/spaces/locking#states) invalidates an existing lock that was already in the locked state.
diff --git a/src/pages/docs/platform/errors/index.mdx b/src/pages/docs/platform/errors/index.mdx
new file mode 100644
index 0000000000..1747e54eee
--- /dev/null
+++ b/src/pages/docs/platform/errors/index.mdx
@@ -0,0 +1,142 @@
+---
+title: Debugging
+meta_description: "Debugging in Ably supported apps, including troubleshooting techniques, logging options, and tools for error analysis."
+redirect_from:
+ - /docs/errors/
+---
+
+Errors can occur in various scenarios when using Ably, such as invalid inputs in requests, authentication issues, or connection problems caused by network disruptions. Proper debugging is essential for building a reliable application and troubleshooting.
+
+You can debug issues in your Ably-supported app using the following:
+
+* Set up a custom log handler to capture and manage errors in a way that suits your requirements.
+* Meta channels allow you to monitor errors that might not otherwise be visible to clients, providing additional insights into issues.
+* The [Dev console](https://ably.com/accounts/any/apps/any/console) in your Ably dashboard is a quick and easy way to inspect errors and events, especially during development or debugging.
+
+## Error info
+
+All errors returned by Ably are standardized and use the [`ErrorInfo`](/docs/api/rest-sdk/types#error-info) object:
+
+
+```json
+{
+ "code": 40005,
+ "statusCode": 400,
+ "cause": "Authentication",
+ "nonfatal": false,
+ "href": "https://help.ably.io/error/40005"
+}
+```
+
+
+The following explains each property of an `ErrorInfo` object:
+
+* `code` := Ably-specific numeric code indicating the error type.
+* `statusCode` := An HTTP status code providing broader context, such as 400 for a bad request.
+* `cause` := A brief description of the issue.
+* `nonfatal` := A boolean indicating whether the error is critical.
+* `href` := A direct link to Ably's documentation or for quick troubleshooting references.
+
+## Logging
+
+Ably SDKs allow you to customize the function that handles logging. This function is usually set in the options when configuring a client, such as the `ClientOptions` object for Pub/Sub.
+
+Two separate properties can be set:
+
+* `logHandler` := Provides a custom function for each line of log output.
+* `logLevel` := The verbosity of the logging output, from silent to trace. In some SDKs this is numeric, and in others string.
+
+The following table explains the `logLevel` setting for the Ably client, which controls how much logging output is shown. Higher levels include more detailed information:
+
+| Level | Description |
+| ----- | ----------- |
+| `0` | No logs |
+| `1` | Errors only |
+| `2` | Errors plus connection and channel state changes |
+| `3` | Abbreviated debug output |
+| `4` | Full debug output |
+
+The following example configures the Ably client to log only error messages using `logLevel:1` and processes them with the function `logWriteFun()`:
+
+
+```javascript
+const ablyClient = new Ably.Realtime({
+ key: {{API_KEY}},
+ logHandler: logWriteFunc,
+ logLevel: 1 // Errors only
+});
+```
+
+
+The following example is a log output for an Ably client configured to log messages using `logLevel:1`:
+
+
+```text
+LOG [Level 1]: Ably: ConnectionManager.failQueuedMessages(): failing 1 queued messages, err = [_ErrorInfo: Application Ptz0jg disabled.
+(See https://help.ably.io/error/40300 for help.); statusCode=403; code=40300]
+```
+
+
+## Metachannels
+
+Ably provides a set of [metachannels](/docs/metadata-stats/metadata/subscribe#metachannels) that expose internal events from the Ably system. These metachannels are be useful for debugging and monitoring, especially when investigating issues not surfaced directly to clients.
+
+
+```javascript
+const channel = realtime.channels.get('[meta]log');
+channel.subscribe((msg) => {
+ console.log(msg);
+});
+```
+
+
+The following is an example event published to the `[meta]log` channel as an [`ErrorInfo`](#format) object:
+
+
+```json
+{
+ "code": 40005,
+ "statusCode": 400,
+ "cause": "Authentication",
+ "nonfatal": false,
+ "href": "https://help.ably.io/error/40005"
+}
+```
+
+
+## Dev console
+
+The [Dev console](https://ably.com/accounts/any/apps/any/console) in your Ably dashboard is a quick and easy way to inspect errors. It provides a live stream of all events in your application, which is especially useful during early-stage development or low-traffic periods when events are easier to track:
+
+* Monitor all live events in your application for detailed insights.
+* Test publishing and subscribing to channels to identify and resolve issues with these functions.
+
+If you have an "Enterprise package":/docs/pricing/enterprise with Ably, then contact your Customer Success Manager to discuss any details or queries you may have regarding your package.
-*the maximum rate at which messages can be published and received across your account each second*
| 500 | 2,500 | 10,000 | Unlimited | +| Messages (per month)*the maximum number of messages that can be sent and received across your account each month*
| 6,000,000 | Unlimited | Unlimited | Unlimited | +| Concurrent channels*the maximum number of channels that are active simultaneously at any point*
| 200 | 10,000 | 50,000 | Unlimited | +| Concurrent connections*the maximum number of realtime clients connected to Ably simultaneously at any point*
| 200 | 10,000 | 50,000 | Unlimited | + +### Bandwidth + +There is also a charge on additional bandwidth consumed. + +This is worked out based on the average message size of 5KiB multiplied by the number of messages consumed in the month. If your total bandwidth for the month is less than this value then there is no charge for bandwidth. Anything over this value is charged at $0.25 per GiB. + +## Packages + +Ably offers four different package types so that you can choose the one that best suits your needs: + +* [Free:](/docs/platform/pricing/free) for experimenting with Ably, or building a proof of concept. No credit card required. +* [Standard:](/docs/platform/pricing/standard) for when you're ready to roll out into production. +* [Pro:](/docs/platform/pricing/pro) higher limits than the standard package to accommodate a growing business. +* [Enterprise:](/docs/platform/pricing/enterprise) create a custom package to meet all of your business needs. + +## Pricing + +Each package has a default base price. You are then charged for the amount of messages, and channel and connection time that you consume. The cost of each of these units decreases as you consume more. + +### Base package price + +Packages have a monthly base package price: + +| Free | Standard | Pro | Enterprise | +| ---- | -------- | --- | ---------- | +| N/A | $39 | $399 | Custom | + +### Message cost + +Messages are charged per million messages consumed: + +| Number of messages | Cost (per million) | +| ------------------ | ------------------ | +| First 50 million | $2.50 | +| Next 450 million | $2.25 | +| Next 4.5 billion | $1.95 | +| Next 15 billion | $1.65 | +| Next 30 billion | $1.40 | +| Over 50 billion | $1.25 | + +For example: + +* if you use 49 million messages in a month, this would cost $122.50 (49 x 2.50). +* if you use 120 million messages in a month, this would cost $282.50 ((50 x 2.50) + (70 x 2.25)) + +### Channel minutes cost + +Channels are charged for every million minutes of activity: + +| Channel time (minutes) | Price (per million minutes) | +| ---------------------- | ---------------------------- | +| First 10 million | $1.00 | +| Next 90 million | $0.95 | +| Next 900 million | $0.85 | +| Next 4 billion | $0.75 | +| Next 10 billion | $0.65 | +| Over 15 billion | $0.60 | + +For example: + +* if you use 8 million minutes of channel time, this would cost $8.00 (8 x 1.00). +* if you use 140 million minutes of channel time, this would cost $129.50 ((10 x 1.00) + (90 x 0.95) + (40 x 0.85)). + +### Connection minutes cost + +Connections are charged for every million minutes of activity: + +| Connection time (minutes) | Price (per million minutes) | +| ------------------------- | ---------------------------- | +| First 10 million | $1.00 | +| Next 90 million | $0.95 | +| Next 900 million | $0.85 | +| Next 4 billion | $0.75 | +| Next 10 billion | $0.65 | +| Over 15 billion | $0.60 | + +For example: + +* if you use 7 million minutes of connection time, this would cost $8.00 (7 x 1.00). +* if you use 130 million minutes of connection time, this would cost $121 ((10 x 1.00) + (90 x 0.95) + (30 x 0.85)). + +## Limits + +There are limits on certain operations within Ably. This is to protect against deliberate or accidental abuse of your application, and to provide a level of protection on your consumption costs if abuse does occur. + +Whilst hitting a limit should be an infrequent occurrence if you're on the correct package, it's important to be aware of the different types of limits that exist. + +Find out more about [limits](/docs/platform/pricing/limits). + +## Billing + +It's important to understand how, and when, you're billed. + +Invoices are issued in arrears on the first of each month. They include your base package price, plus your consumption of messages, and channel and connection minutes used in the previous month. + +Find out more about [billing](/docs/platform/pricing/billing). diff --git a/src/pages/docs/platform/pricing/limits.mdx b/src/pages/docs/platform/pricing/limits.mdx new file mode 100644 index 0000000000..6bb97dcc81 --- /dev/null +++ b/src/pages/docs/platform/pricing/limits.mdx @@ -0,0 +1,131 @@ +--- +title: Limits +meta_description: "The limits associated with each Ably package." +redirect_from: + - /docs/general/limits + - /docs/pricing/limits +--- + +Ably can scale effortlessly as your business grows. + +Limits exist in order to minimize the impact on service due to accidental or deliberate abuse of your applications. They also provide a level of protection to your consumption rates if abuse does occur. If you're on the correct package for your applications and use case, then hitting a limit should be an infrequent occurrence. + +## Limit types + +Some limits are tied to a package type. For example, the length of time that you can store messages for is dictated by which package you are on, from 1 day on a Free package up to 1 year on an Enterprise package. + +Other limits are more technical in nature. For example, the number of channels that a single realtime connection can be attached to, or the rate at which a single connection can publish messages. + +Others still are precautions against high message consumption. For example, the number of clients that can be [present](/docs/presence-occupancy/presence) on a single channel. This is because clients can change state very rapidly and the number of messages generated can be high. An example of this would be 200 clients subscribed to presence events on a channel and all of them join and leave the presence set within a few minutes. This would result in the following messages: + +* 200 presence messages published for the enter event. +* 200 x 200 (40,000) messages subscribed to for the enter events. +* 200 presence messages published for the leave event. +* 200 x 200 (40,000) presence messages subscribed to for the leave event. + +This highlights the potential for 80,400 messages to be sent in a very short space of time on a single channel. There are options for [mitigating](/docs/presence-occupancy/presence#present-no-subscribe) this such as utilizing [server-side batching](/docs/channels#server-side-batching). Contact Ably to discuss increasing this limit if you think it's necessary for your use case. + +### View limits + +1. Log in to your [account](https://ably.com/login). +2. Select **Limits** from the **Account** menu. + +To view any limits that you have previously hit, click **view recent limits notifications**. + +## Exceeding a limit + +If you exceed the limits of your package then it likely means that your app is performing well, and Ably won't penalize your success by blocking usage for the majority of limits. Normal service will continue to function beyond the limit, up to a point, for certain limits. However, Ably will contact you to let you know that you need to upgrade your package to accommodate your increased usage. + +Limits will come into force either because there isn't any buffer on them, or because you have exceeded the buffer. Exceeding the limit depends on the limit: + +* **Count-based limits**: only a set amount of resources can be in use simultaneously. This means that any usage in excess of that limit will be restricted until existing resources are removed, such as the number of concurrent connections, or concurrent channels. +* **Rate-based limits**: the rate at which resources can be used, expressed as their frequency per second. Usage in excess of a rate limit can be rejected locally, such as a publisher trying to publish at a rate in excess of the publish rate per channel. The publisher will have any publish attempts in excess of this rate rejected and have an error code returned. Other rate limits apply rate suppression across your account when exceeded. For example, if the limit for publishing messages into a queue is exceeded by twice the rate, then each message will have a 50% chance of being rejected. The suppression probability is continuously updated based on the publishing rate. + +*the maximum number of applications that can be created per account*
| 100 | 100 | 100 | 100 | +| **Number of API keys (per account)***the maximum number of API keys that can be created per account*
| 100 | 100 | 100 | 100 | +| **Number of rules (per account)***the maximum number of channel rules that can be created per account*
| 100 | 100 | 100 | 100 | +| **Number of namespaces (per account)***the maximum number of namespaces that can be created per account*
| 100 | 100 | 100 | 100 | + +## Message limits + +Message limits relate to the number, rate and bandwidth of messages consumed across you account. + +| Message limit | Free | Standard | Pro | Enterprise | +| ------------- | ---- | -------- | --- | ---------- | +| **Message rate (per second)***the maximum rate at which messages can be published and received across your account each second*
| 500 | 2,500 | 10,000 | Unlimited | +| **Messages (per month)***the maximum number of messages that can be sent and received across your account each month*
| 6,000,000 | Unlimited | Unlimited | Unlimited | +| **Message count (per hour)***the total number of messages that can be sent across an account per hour*
| 250,000 | 5,208,000 | 20,833,000 | Unlimited | +| **Message bandwidth rate (per second, KiB)***the maximum rate at which data can be transferred through messages each second, in KiB*
| 2,384 | 11,921 | 47,684 | Unlimited | +| **Message bandwidth (hourly, GiB)***the maximum amount of data that can be transferred through messages each hour, in GiB*
| 1.2 | 24.8 | 99.3 | Unlimited | +| **Message bandwidth (monthly, GiB)***the maximum amount of data that can be transferred through messages each month, in GiB*
| 28.6 | 1,192 | 4,768 | Unlimited | +| **Max message size (KiB)***the maximum size of a single published message*
| 64 | 64 | 256 | 256 | +| **Default history TTL (hours)***the default time that a message or presence message can be retrieved from history*
| 24 | 72 | 72 | 72 | +| **Max history / storage TTL (days)***the maximum time that a message or presence message can be retrieved from history*
| 1 | 30 | 365 | 365 | + +## Channel limits + +Channel limits relate to the number, rate and membership of [channels](/docs/channels) on your account. + +| Channel limit | Free | Standard | Pro | Enterprise | +| ------------- | ---- | -------- | --- | ---------- | +| **Concurrent channels***the maximum number of channels that are active simultaneously at any point*
| 200 | 10,000 | 50,000 | Unlimited | +| **Default last message on channel TTL (days)***the default period that the last message on a channel is stored for, when enabled*
| 1 | 30 | 365 | 365 | +| **Channel creation rate (per second)***the maximum rate at which channels can be created across an account*
| 42 | 250 | 500 | Custom | +| **Message publish rate per channel (per second)***the maximum rate at which messages can be published for each channel*
| 50 | 50 | 50 | 50 | +| **Presence members per channel***the maximum number of clients that can be simultaneously present on a channel*
| 200 | 200 | 200 | 200 | +| **Presence members per channel with [server-side batching](/docs/messages/batch#server-side) enabled***the maximum number of clients that can be simultaneously present on a channel when server-side batching is enabled*
| 200 | 5,000 | 10,000 | 20,000 | +| **Objects per channel***the maximum number of objects that can be stored on a channel*
| 100 | 100 | 100 | 100 | + +## Connection limits + +Connection limits relate to the realtime [connections](/docs/connect) made to Ably from your account. + +| Connection limit | Free | Standard | Pro | Enterprise | +| ---------------- | ---- | -------- | --- | ---------- | +| **Concurrent connections***the maximum number of realtime clients connected to Ably simultaneously at any point*
| 200 | 10,000 | 50,000 | Unlimited | +| **New connection rate (per second)***the maximum rate at which new realtime connections can be made to Ably across an account*
| 42 | 250 | 500 | Custom | +| **Inbound message rate (per second)***the maximum rate at which messages can be published by a realtime connection*
| 50 | 50 | 50 | 50 | +| **Outbound message rate (per second)***the maximum rate at which messages can be received by a realtime connection*
| 50 | 50 | 50 | 50 | +| **Number of channels per connection***the maximum number of channels that each connection can be attached to*
| 200 | 200 | 200 | 200 | +| **Connection state TTL***the maximum duration that Ably will preserve the state of a dropped connection for*
| 2 mins | 2 mins | 2 mins | 2 mins | + +## Integration limits + +Integration limits relate to the rate and concurrency of [webhooks](/docs/integrations/webhooks), [queues](/docs/integrations/queues) and [Firehose](/docs/integrations/streaming). + +| Integration limit | Free | Standard | Pro | Enterprise | +| ----------------- | ---- | -------- | --- | ---------- | +| **Integration rate (per second)***the maximum rate at which integrations can be executed, or streamed*
| 250 | 250 | 1,000 | Custom | +| **Integration concurrency (Google Functions and Azure)***the maximum number of integrations that can run at the same time*
| 25 | 25 | 100 | Custom | +| **Webhook batch size***the maximum number of webhook events that can be sent per batch*
| 50 | 100 | 100 | 100 | +| **Webhook batch concurrency***the maximum number of webhook batches that can be processed at the same time*
| 1 | 1 | 1 | 1 | +| **Max number of queues (per account)***the maximum number of queues that can be created per account*
| 5 | 10 | 50 | 100+ | +| **Max queue length***the maximum number of messages that can be stored in queues whilst waiting to be consumed. This value is shared between all queues in an account*
| 50,000 | 50,000 | 50,000 | 50,000 | +| **Queue publish rate (per second)***the maximum rate at which messages can be published to a queue*
| 250 | 250 | 1,000 | Custom | +| **Queue TTL (hours)***the maximum time that a message is stored in a queue for, before being transferred to the dead letter queue*
| 24 | 24 | 24 | 24 | + +## API limits + +API request limits are the maximum number of [REST API](/docs/api/rest-api) requests, [Control API](/docs/platform/account/control-api) requests and [token requests](/docs/auth/token) that can be made to Ably. + +| API request limit | Free | Standard | Pro | Enterprise | +| ----------------- | ---- | -------- | --- | ---------- | +| **HTTP API requests (per hour)***the maximum number of HTTP API requests that can be made to Ably per hour, excluding token requests*
| 25,000 | 521,000 | 2,083,300 | Custom | +| **HTTP API request rate (per second)***the maximum rate at which HTTP API requests can be made to Ably*
| 50 | 362 | 1,447 | Custom | +| **Token requests (per hour)***the maximum number of token requests that can be made to Ably per hour*
| 60,000 | 360,000 | 720,000 | Custom | +| **Token request rate (per second)***the maximum rate at which token requests can be made*
| 50 | 250 | 500 | Custom | +| **Control API: authenticated account requests (per hour)***the maximum number of requests that can be made to the Control API, per hour, from authenticated users*
| 4000 | 4000 | 4000 | 4000 | +| **Control API: authenticated access token requests (per hour)***the maximum number of requests that can be made to the Control API, per hour, for each access token*
| 2000 | 2000 | 2000 | 2000 | +| **Control API: unauthenticated requests (per hour)***the maximum number of requests that can be made to the Control API, per hour, from unauthenticated users*
| 60 | 60 | 60 | 60 | diff --git a/src/pages/docs/platform/pricing/pro.mdx b/src/pages/docs/platform/pricing/pro.mdx new file mode 100644 index 0000000000..2095105cc5 --- /dev/null +++ b/src/pages/docs/platform/pricing/pro.mdx @@ -0,0 +1,84 @@ +--- +title: Pro package +meta_description: "Explore the features and cost of Ably's Pro package." +redirect_from: + - /docs/pricing/pro +--- + +The Pro package is for when your business is growing and you need higher limits to accommodate this. + +## Features + +The Pro package includes the following limits on the key units of consumption: + +| Limit | Pro | +| ----- | --- | +| Message rate (per second) | 10,000 | +| Messages (per month) | Unlimited | +| Concurrent channels | 50,000 | +| Concurrent connections | 50,000 | + +Pro package users also have access to the following features: + +* Google and GitHub SSO +* [DataDog Lite](/docs/integrations/streaming/datadog#lite) + +## Pricing and billing + +The Pro package has a monthly fee of $399 plus the number of messages, and channel and connection minutes that you use on top of that. You will be billed for the previous month's consumption. + +Note that volume discounts reset every month. + +## Limits + +[Compare the limits](/docs/platform/pricing/limits) associated with each package to see those available on the Pro package. + +## Support + +Standard package support includes access to Ably support via email with a Service Level Agreement (SLA) of less than 1 business day for general guidance and less than 2 business hours for system impediments or system down. + +## Upgrade from Free to Pro + +To upgrade your account from a Free package to a Pro package: + +1. Ensure you are the [account owner](/docs/platform/account/users). +2. Log in to your [account](https://ably.com/login) and select **Billing** from the **Account** menu. +3. Choose the plan you wish to upgrade to and follow the instructions. Upgrades take effect immediately. + +Note that your first invoice will be issued at the start of the following calendar month. It covers consumption from the point of upgrade up until the end of that month. All subsequent invoices will follow the same pattern of billing for the previous month's consumption. The base package price will be charged pro-rata from the point in the month that you upgraded. + +Once you upgrade to a Pro, your consumption is counted from that point onwards. For example, if you upgrade in the middle of the month, you are charged for the first message you send after upgrading, not after the 6,000,000 messages allowed on the Free package. + +## Upgrade from Standard to Pro + +To upgrade your account from a Standard package to a Pro package: + +1. Ensure you are the [account owner](/docs/platform/account/users). +2. Log in to your [account](https://ably.com/login) and select **Billing** from the **Account** menu. +3. Choose the plan you wish to upgrade to and follow the instructions. Upgrades take effect immediately. + +The base package price will be charged pro-rata from the point in the month that you upgraded. This is true for the current Standard package base price, as well as the upgraded Pro package base price. + +## Upgrade from Pro to Enterprise + +To upgrade your account from a Pro package, [contact us](https://ably.com/contact?cta=enterprise_package) to discuss [Enterprise package](/docs/platform/pricing/enterprise) options. + +## Downgrade + +To downgrade your account from a Pro package: + +1. Ensure you are the [account owner](/docs/platform/account/users). +2. Log in to your [account](https://ably.com/login) and select **Billing** from the **Account** menu. +3. Click the **Downgrade** button. + +If you downgrade to the [Free package](/docs/platform/pricing/free), you will remain on the Pro package with its limits and benefits until the end of your billing cycle (on the 1st of the month). At the start of the following month, you will receive a final invoice that includes the full package fee for the previous month. + +If you downgrade to the [Standard package](/docs/platform/pricing/standard), you will remain on the Pro package with its limits and benefits until the end of your billing cycle (on the 1st of the month). At the start of the following month, you will receive a final invoice that includes the full package fee for the previous month. + +## Close your account + +You can [close your account](/docs/platform/account/users#close) at any time by first downgrading to the Free package. + +Be aware that this will permanently delete all information associated with your account.
-