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

