# Rate Limits

Rate limit mechanics are shared by every Stream product and documented on [Rate limits](https://getstream.io/docs/platform/rate-limits/): how limits are counted, the `X-RateLimit-*` headers, inspecting your quotas, catching 429s, and enabling automatic retries in the server SDKs. This page lists the chat endpoint limits and chat-specific practices.

## Rate Limits by Endpoint

Default rate limits for self-serve plans (per minute, per platform).

| API Request            | Limit/min |
| ---------------------- | --------- |
| Connect                | 10,000    |
| Get or Create Channel  | 10,000    |
| Get App                | 10,000    |
| Mark All Read          | 10,000    |
| Mark Read              | 10,000    |
| Query Channels         | 10,000    |
| Send Event             | 10,000    |
| Create Guest           | 1,000     |
| Delete Message         | 1,000     |
| Delete Reaction        | 1,000     |
| Get Message            | 1,000     |
| Get Reactions          | 1,000     |
| Get Replies            | 1,000     |
| Query Users            | 1,000     |
| Run Message Action     | 1,000     |
| Send Message           | 1,000     |
| Send Reaction          | 1,000     |
| Stop Watching Channel  | 1,000     |
| Update Message         | 1,000     |
| Upload File            | 1,000     |
| Upload Image           | 1,000     |
| Ban                    | 300       |
| Create Device          | 300       |
| Edit Users             | 300       |
| Flag                   | 300       |
| Hide Channel           | 300       |
| Mute                   | 300       |
| Query Members          | 300       |
| Search                 | 300       |
| Show Channel           | 300       |
| Unban                  | 300       |
| Unflag                 | 300       |
| Unmute                 | 300       |
| Update Channel         | 300       |
| Update Users           | 300       |
| Update Users (Partial) | 300       |
| Activate User          | 60        |
| Check Push             | 60        |
| Create Channel Type    | 60        |
| Deactivate User        | 60        |
| Delete Channel         | 60        |
| Delete Channel Type    | 60        |
| Delete Device          | 60        |
| Delete File            | 60        |
| Delete User            | 60        |
| Export Channel         | 60        |
| Export User            | 60        |
| Get Channel Type       | 60        |
| List Channel Types     | 60        |
| List Devices           | 60        |
| Truncate Channel       | 60        |
| Update App             | 60        |
| Update Channel Type    | 60        |

<Admonition type="info">

All endpoints also enforce the user rate limit of 60 requests per minute per user. Rate limits can be adjusted based on your use case and plan.

</Admonition>

## Avoiding Rate Limits in Chat

In addition to the [general practices](https://getstream.io/docs/platform/rate-limits/#avoiding-rate-limits), chat integrations should:

1. **Avoid redundant queries** - Channel creation is an upsert operation. Do not call `QueryChannels` to check if a channel exists before creating it. See [Query Channels](https://getstream.io/chat/docs/unreal/query-channels/).

2. **Use one WebSocket per user** - Multiple WebSocket connections per user cause performance issues, billing problems, and unexpected behavior. See [Initialization & Users](https://getstream.io/chat/docs/javascript/init-and-users/).

3. **Follow livestream best practices** - High-volume messaging scenarios require additional optimization. See [Livestream Best Practices](https://getstream.io/chat/docs/unreal/livestream-best-practices/).

## Handling 429s in the Unity SDK

The Unity SDK surfaces rate limits and other API errors through `StreamApiException`. The exception classes are documented in [Error handling](https://getstream.io/docs/platform/error-handling/), and the full list of codes in [API error codes](https://getstream.io/docs/platform/api-error-codes/):

```csharp
// Example 1 — single catch + switch on the numeric error code.
try
{
    await channel.SendNewMessageAsync("Hello");
}
catch (StreamApiException ex)
{
    // ex.Code / ex.StatusCode / ex.ErrorMessage / ex.ExceptionFields / ex.MoreInfo
    // are all available for inspection. See the API Error Codes docs page
    // for the full list.
    switch (ex.Code)
    {
        case StreamApiException.RateLimitErrorStreamCode:
            // HTTP 429 — back off with exponential delay before retrying.
            await Task.Delay(TimeSpan.FromSeconds(1));
            break;
        case StreamApiException.CooldownErrorStreamCode:
            // HTTP 403 — slow-mode cooldown. Gate the send UI for `channel.Cooldown` seconds.
            break;
        case StreamApiException.PermissionDeniedErrorStreamCode:
            // HTTP 403 — user lacks permission. Hide / disable the control.
            break;
        default:
            Debug.LogError($"Stream API error {ex.Code} (HTTP {ex.StatusCode}): {ex.ErrorMessage}");
            break;
    }
}

// Alternatively, use the `when` syntax combined with our dedicated
// error-checking extensions.
try
{
    await channel.SendNewMessageAsync("Hello");
}
catch (StreamApiException ex) when (ex.IsRateLimitExceededError())
{
    // HTTP 429 / Stream code 9 — back off before retrying.
    await Task.Delay(TimeSpan.FromSeconds(1));
}

// Most common error cases have a dedicated extension method on StreamApiException.
// Pick the helper that matches your branch instead of comparing `ex.Code` by hand:
//   IsRateLimitExceededError       (429 / 9)     — back off and retry
//   IsCooldownError                (403 / 60)    — gate UI for `channel.Cooldown` seconds
//   IsPermissionDeniedError        (403 / 17)    — hide the UI control
//   IsNoAccessToChannelsError      (403 / 70)    — drop the channel locally
//   IsAppSuspendedError            (403 / 99)    — show service-unavailable UI
//   IsAuthenticationError          (401 / 5)     — send the user back to sign-in
//   IsTokenExpiredError            (401 / 40)    — refresh the token
//   IsTokenError                   (401 / 40-43) — any token-related failure
//   IsDoesNotExistError            (404 / 16)    — refresh the local view
//   IsInputError                   (400 / 4)     — inspect `ex.ExceptionFields`
//   IsMessageTooLongError          (400 / 20)    — show character-limit error
//   IsMessageModerationFailedError (400 / 73)    — show "filtered" UI
//   IsPayloadTooBigError           (413 / 22)    — ask for a smaller file
//   IsInternalSystemError          (500 / -1)    — retry, then surface a transient-failure UI
//
// The general guidance: wrap a call in try/catch where you want to react
// specifically (rate-limit back-off, cooldown UI, validation feedback,
// permission gating). For everything else, let the exception propagate to
// your global error handler — every SDK call already throws StreamApiException
// on server-rejected requests, so a single boundary catch is enough.
```


---

This page was last updated at 2026-08-11T12:49:41.907Z.

For the most recent version of this documentation, visit [https://getstream.io/chat/docs/unreal/rate-limits/](https://getstream.io/chat/docs/unreal/rate-limits/).