Для разработчиков

Лимиты

Мы следим за стабильностью API, поэтому есть лимиты на запросы (rate limiting). Они гибкие, зависят от нагрузки, но мы сделали их комфортными — должно хватить для любых ваших задач.

Входящие вебхуки

Входящие вебхуки
Лимит привязан к идентификатору вебхука в пути.
Например, для /webhooks/user123 считаем по user123
Лимит
~10 запросов
Период
1 секунда

Если за секунду отправите больше указанного количества запросов на один идентификатор, лишние получат 429 Too Many Requests. В заголовке Retry-After мы укажем, через сколько секунд можно попробовать снова. Тело такого ответа — короткий текст с Content-Type: text/plain, а не JSON.

API

Отправка сообщений
Действует на POST /messages. Считаем по токену авторизации (заголовок HTTP_AUTHORIZATION), отдельно по каждому entity_id из тела запроса — то есть по беседе, треду или собеседнику, кому пишете. Дополнительно действует общий предел по всем адресатам сразу — 30 запросов за 5 секунд: он допускает короткие ускорения выше посекундного лимита, но не даёт держать такой темп долго. Изменение и удаление сообщений под этот лимит не подпадают и работают в рамках общего.
Лимит
~4 запроса
Период
1 секунда
Сущность
entity_id
Чтение сообщений
Действует на методы чтения, путь которых начинается с /messages: список сообщений, отдельное сообщение, его реакции и список прочитавших. Считаем по токену авторизации (заголовок HTTP_AUTHORIZATION). Один токен — один лимит.
Лимит
~10 запросов
Период
1 секунда
Остальные методы API
Считаем по токену авторизации (заголовок HTTP_AUTHORIZATION). Один токен — один лимит.
Лимит
~50 запросов
Период
1 секунда
Чтение истории событий бота
Действует на GET /webhooks/events. Считаем по токену авторизации.
Лимит
~5 запросов
Период
2 секунды
Инвентаризация пространства
Действует на GET /company/chats и GET /company/bots. Считаем по токену авторизации. Лимит заметно строже общего: при странице в 50 записей за минуту получится обойти около 1500 чатов или ботов.
Лимит
~30 запросов
Период
1 минута
Обмен кода на токен
Действует на POST /oauth/token — обмен кода на токен при авторизации от имени сотрудника. Считаем по адресу, с которого пришёл запрос, и client_id: у одного бота с одного сервера один лимит.
Лимит
~30 запросов
Период
1 минута
Сообщения в один чат за сутки
Действует на POST /messages. Считаем по паре «отправитель и чат» за последние 24 часа. Сообщения в тред засчитываются в чат, которому принадлежит родительское сообщение. Квоту расходуют только созданные сообщения: запрос, отклонённый проверкой, её не тратит.
Лимит
7 500 сообщений
Период
Скользящие 24 часа
Сущность
chat_id
Письма-приглашения за сутки
Действует в бесплатном пространстве, в том числе на пробном периоде: на POST /users и на смену почты в PUT /users/{id}. Считаем все письма пространства вместе — приглашения и письма о смене почты, отправленные и из интерфейса, и через API. Смена почты отправляет два письма: на прежний и на новый адрес. Сотрудник, созданный с skip_email_notify: true, квоту не тратит.
Лимит
50 писем
Период
Скользящие 24 часа

Если за секунду будет больше указанных запросов с одним токеном, API вернёт 429 Too Many Requests. В заголовке Retry-After мы укажем, через сколько секунд можно попробовать снова. В теле придёт обычный ответ об ошибке: код rate_limit в errors[].code и причина в message.

Превышение суточного предела отвечает так же — 429 с кодом rate_limit в errors[].code и заголовком Retry-After. Отправка в этот чат приостанавливается на час, и каждая следующая попытка во время паузы удваивает её: 1, 2, 4, 8, 16 и до 24 часов. Дождитесь срока из Retry-After — он учитывает и паузу, и момент, когда в окне освободится место. Отправка, прошедшая после паузы, возвращает шкалу к началу.

Лимит писем-приглашений отвечает иначе: 422 с кодом daily_invites_limit, а остаток и время, когда в окне освободится место, приходят в payload. Запрос при этом не применяется: сотрудник не создаётся, почта не меняется. В платном пространстве этого лимита нет.

  • Лимиты гибкие: они ориентировочные и могут меняться, чтобы всё работало гладко;
  • Должно хватать на всё: мы настроили их так, чтобы вам было комфортно в любых сценариях;
  • Если упёрлись в лимит: при ошибке 429 смотрите заголовок Retry-After — он подскажет, через сколько секунд повторить запрос (или используйте экспоненциальный backoff, если хотите перестраховаться).

Защита от перегрузки

Если приложение продолжает отправлять сообщения выше лимитов даже после 429, отправку с этого токена могут временно заблокировать — это защита от сбойных циклов и случайной перегрузки. Порог высокий, в обычной работе до него не доходит: около 22 000 запросов на отправку сообщений за час с одним токеном. Дальше отправка сообщений с этим токеном на час блокируется, а остальные методы продолжают работать. Ответ — тот же 429 с кодом rate_limit, а в Retry-After приходит, сколько секунд осталось до снятия блокировки: сразу после неё около часа, потом меньше. Чтобы этого избежать:

  • Соблюдайте Retry-After — он указывает, через сколько секунд имеет смысл повторить
  • Используйте экспоненциальный backoff с jitter — готовые примеры ниже в разделе Повторные запросы
  • Если ваш сервис не успевает обрабатывать ответы, приостановите запросы, а не ускоряйте retry

Повторные запросы (Retry)

SDK (TypeScript, Python), CLI и нода n8n повторяют запрос сами. Ниже — реализация для кастомных HTTP-клиентов.

Если пишете свой клиент, соблюдайте два правила.

Не ждите меньше, чем сказано в Retry-After. Это минимум ожидания, а не оценка: срок уже округлён вверх, чтобы клиент, выждавший его честно, не пришёл в ещё закрытое окно. Джиттер добавляйте вверх, а не вниз.

Не повторяйте долгие паузы. Retry-After дольше минуты приходит только там, где повтор не поможет: суточный предел сообщений в чат и блокировка отправки при перегрузке. Повтор внутри такой паузы бесполезен, а у суточного предела ещё и продлевает её: каждая попытка удваивает срок, от часа до суток. Отдайте ошибку вызывающему коду вместе с Retry-After, и пусть он вернётся к работе позже. Наши клиенты так и делают.

TypeScript

async function withRetry<T>(  fn: () => Promise<T>,  maxRetries = 3): Promise<T> {  for (let attempt = 0; attempt <= maxRetries; attempt++) {    try {      return await fn()    } catch (error: any) {      // 429 Too Many Requests — ждём Retry-After или backoff      if (error.status === 429) {        const retryAfter = error.headers?.["retry-after"]        const delay = retryAfter          ? parseInt(retryAfter) * 1000          : Math.pow(2, attempt) * 1000 * (0.5 + Math.random())        await new Promise(r => setTimeout(r, delay))        continue      }      // 5xx — серверная ошибка, backoff с jitter      if (error.status >= 500 && attempt < maxRetries) {        const delay = Math.pow(2, attempt) * 1000 * (0.5 + Math.random())        await new Promise(r => setTimeout(r, delay))        continue      }      // 4xx (кроме 429) — не повторяем      throw error    }  }  throw new Error("Max retries exceeded")} // Использованиеconst users = await withRetry(() => client.users.listUsers())

Python

import time, random async def with_retry(fn, max_retries=3):    for attempt in range(max_retries + 1):        try:            return await fn()        except Exception as e:            status = getattr(e, "status_code", getattr(e, "status", 0))            headers = getattr(e, "headers", {})            # 429 Too Many Requests            if status == 429:                retry_after = headers.get("Retry-After")                delay = int(retry_after) if retry_after else (2 ** attempt) * (0.5 + random.random())                time.sleep(delay)                continue            # 5xx — серверная ошибка            if status >= 500 and attempt < max_retries:                time.sleep((2 ** attempt) * (0.5 + random.random()))                continue            raise    raise Exception("Max retries exceeded") # Использованиеusers = await with_retry(lambda: client.users.list_users())

Стратегия повторов

КодДействиеЗадержка
429ПовторитьRetry-After header или exponential backoff: 1с, 2с, 4с × jitter
500, 502, 503, 504ПовторитьExponential backoff с jitter: ~1с, ~2с, ~4с
400, 401, 403, 404, 422Не повторятьОшибка клиента — нужно исправить запрос
Максимум 3 повтора на каждый запрос. Jitter (случайный множитель 0.5–1.5) предотвращает «thundering herd» при массовых 429.