Лимиты и ошибки
Для разработчиков

Лимиты и ошибки

HTTP-коды

КодКогда
200Успех: чтение, PATCH, закрытие / переоткрытие / оценка тикета, POST /messages, тест webhook
201Создано: POST /tickets, POST /tickets/{id}/messages, POST /contacts (даже если контакт уже был), POST /webhooks, POST /media/upload
204Успех без тела: DELETE /webhooks/{id}
302GET /media/{id}, когда файлы проекта лежат в его S3-бакете: переадресация на объект
400POST /tickets или POST /contacts без telegram_id и email
401Нет заголовка Authorization, ключ неверный, отключён или удалён, либо проект заблокирован. В ответе есть заголовок WWW-Authenticate: Bearer
403TICKET_LIMIT_REACHED: исчерпан месячный лимит тикетов тарифа; PLAN_FEATURE_UNAVAILABLE: база знаний не входит в тариф; POST /tickets для заблокированного контакта
404Тикет, контакт, сообщение, webhook, файл или статья не найдены
409TICKET_ALREADY_CLOSED: закрытие уже закрытого тикета
413MEDIA_TOO_LARGE: файл больше 200 МБ
422Тело или параметры не прошли проверку (например, неизвестный status или priority), VALIDATION_ERROR (файл не из этого проекта в media_ids, неизвестное событие webhook, правка системного сообщения), MESSAGE_EMPTY, TICKET_INVALID_STATUS_TRANSITION
429RATE_LIMIT_EXCEEDED: превышен лимит запросов, заголовок Retry-After говорит, через сколько секунд повторить
500Непредвиденная ошибка сервера
502MEDIA_UPLOAD_FAILED: не удалось записать файл в хранилище
503MAINTENANCE_MODE: на платформе идут технические работы

Формат ошибки

Тело ошибки бывает трёх видов. Ошибки бизнес-логики (не найден тикет, лимит тарифа, пустое сообщение, лимит запросов) приходят в общем конверте:

HTTP 404
{
  "error_code": "TICKET_NOT_FOUND",
  "error_message": "Ticket not found",
  "detail": { "ticket_id": "8a3f..." },
  "request_id": "0b5c..."
}
  • error_code — стабильная строка в UPPER_SNAKE_CASE, по ней удобно ветвиться в коде.
  • error_message — короткое описание на английском.
  • detail — контекст, свой у каждой ошибки, например {"field": "contact", "reason": "at least one of telegram_id, email is required"}, или null.
  • request_id — идентификатор запроса, тот же, что в заголовке ответа X-Request-ID.

Проверки на уровне API (ключ, обязательные идентификаторы контакта, не найден webhook или файл) отвечают коротко, без request_id в теле:

HTTP 400
{ "detail": "contact must include at least one of telegram_id, email" }

А если тело или параметры не совпадают со схемой (нет обязательного поля, неверный тип, page_size больше максимума, неизвестный status или priority), FastAPI возвращает 422 со списком проблем:

HTTP 422
{
  "detail": [
    { "type": "missing", "loc": ["body", "contact"], "msg": "Field required", ... }
  ]
}
Разбирайте ответ так: есть error_code — ветвитесь по нему; иначе смотрите detail (строка или список). В ответах есть заголовок X-Request-ID (его может не быть только у 500 и у 503 во время технических работ). Своё значение можно передать в запросе: до 200 видимых ASCII-символов без пробелов, иначе сервер выдаст новое. Этот id указывайте, когда пишете в поддержку.

Лимит запросов

Лимит считается на клиента и общий для всего API, а не для отдельного пути или эндпоинта:

  • 20 000 запросов в минуту на API-ключ — для запросов с рабочим ключом. Все серверы вашей интеграции с одним ключом делят этот бюджет.
  • 1000 запросов в минуту на IP-адрес клиента — для остальных: без ключа, с неверным или отключённым ключом. Сюда же засчитывается первый запрос нового ключа в каждом процессе API, пока ключ там ещё не проверен.

Окно фиксированное, одна минута с первого запроса в нём. При превышении приходит 429 с RATE_LIMIT_EXCEEDED в общем конверте и заголовком Retry-After — через сколько секунд окно откроется. Заголовков X-RateLimit-* нет.

Запрос к /api/v1/updates считается один раз, сколько бы он ни ждал событий.

Счётчики хранятся в Redis и общие для всех серверов API. Если Redis недоступен, запросы не ограничиваются.

Когда повторять запрос

  • 429 — через столько секунд, сколько указано в Retry-After.
  • 500, 502, 503 — с растущей паузой (например, 1, 2, 4, 8 секунд).
  • Остальные 4xx повтор не исправит: нужно поменять запрос.

Во время технических работ API отвечает 503 с телом {"error_code": "MAINTENANCE_MODE", "error_message": "Platform is under maintenance"}.

Была ли страница полезной?