Ошибки
Успешный ответ всегда имеет статус 200. Ошибка приходит с кодом 4xx или 5xx и телом в формате RFC 9457.
#Формат
Ошибка возвращается с заголовком Content-Type: application/problem+json и телом из восьми полей:
HTTP/1.1 400 Bad Request
Content-Type: application/problem+json; charset=utf-8
Request-Id: 0f3c7a95-2e8b-4d16-b9a4-6c5e1d8f7b20
Cache-Control: no-store
{
"type": "urn:meliora:problem:invalid_parameter",
"title": "Invalid parameter",
"status": 400,
"detail": "Проверьте значение параметра",
"instance": "urn:request:0f3c7a95-2e8b-4d16-b9a4-6c5e1d8f7b20",
"code": "invalid_parameter",
"param": "limit",
"request_id": "0f3c7a95-2e8b-4d16-b9a4-6c5e1d8f7b20"
}| Поле | Описание |
|---|---|
type | URI типа ошибки: urn:meliora:problem: и код. |
title | Короткое название на английском. |
status | HTTP-статус, тот же, что у ответа. |
detail | Пояснение для человека. Язык зависит от заголовка Accept-Language. |
instance | URI запроса: urn:request: и идентификатор запроса. |
code | Машинный код ошибки. |
param | Параметр, к которому относится ошибка, или null. |
request_id | Идентификатор запроса, тот же, что в заголовке Request-Id. |
#Отказы до проверки ключа
Часть запросов отклоняется еще до проверки ключа: превышен лимит с одного IP-адреса, неизвестный путь, тело в запросе, перегрузка. У таких ответов те же поля status, code, param и request_id, но type равен about:blank, а title и detail совпадают с code:
{
"type": "about:blank",
"title": "rate_limit_exceeded",
"status": 429,
"code": "rate_limit_exceeded",
"detail": "rate_limit_exceeded",
"instance": "urn:request:0f3c7a95-2e8b-4d16-b9a4-6c5e1d8f7b20",
"request_id": "0f3c7a95-2e8b-4d16-b9a4-6c5e1d8f7b20",
"param": null
}Поэтому опирайтесь на status и code, а не на type и title.
#Как обрабатывать
- Ветвите логику по
statusиcode. Текстdetailможет меняться, не разбирайте его в коде. - Если пришел незнакомый
code, обработайте ошибку по HTTP-статусу: 4xx означает проблему в запросе или доступе, 5xx временную проблему на нашей стороне. - При ошибке в параметре
paramсодержит его имя:limit,status,cursor,include_textи так далее. - Ошибка никогда не продвигает курсор. После повтора запрос с тем же курсором вернет те же данные.
#Язык пояснения
По умолчанию detail на русском. Чтобы получать английский текст, передайте заголовок Accept-Language: en. Поля code и title от языка не зависят.
#Request-Id
Каждый ответ, включая ошибки, содержит заголовок Request-Id с UUID запроса. Записывайте его в журнал рядом с маршрутом и временем. В обращении в поддержку достаточно Request-Id: по нему мы найдем запрос. Сам ключ не присылайте.
#Коды ошибок
| Статус | Код | Что случилось |
|---|---|---|
400 | invalid_parameter | Значение параметра не подходит по формату, диапазону или сочетанию. Имя параметра в param. |
400 | unknown_parameter | Маршрут не принимает такой параметр. Ключ API в адресе тоже дает эту ошибку. |
400 | cursor_mismatch | Курсор поврежден, выдан для другого маршрута или фильтров, либо права и охват ключа изменились. |
401 | invalid_api_key | Ключа нет, он неверен, отозван или истек его срок. |
403 | scope_required | Ключ не имеет права на это чтение. Для текстов нужен также включенный «Текст сообщений». |
403 | api_disabled | Доступ по API выключен в настройках кабинета. |
403 | api_not_available | Тариф кабинета не включает API. Чтение доступно с тарифа Pro. |
403 | subscription_inactive | Подписка кабинета не действует. |
403 | module_not_available | В кабинете недоступен модуль рассылок. |
403 | organization_suspended | Доступ кабинета приостановлен. |
403 | ip_not_allowed | Запрос пришел с IP-адреса, которого нет в списке разрешенных у ключа. |
404 | not_found | Объект не найден или находится вне охвата ключа. Неизвестный путь тоже дает 404. |
405 | method_not_allowed | Разрешен только метод GET. Внешний адрес отвечает на другие методы 404 без тела, поэтому этот код снаружи не встречается. |
410 | cursor_expired | Срок курсора истек: 15 минут для списков, 30 суток для ленты событий. |
429 | rate_limit_exceeded | Исчерпан лимит запросов ключа, организации или IP-адреса. Повторите через Retry-After секунд. |
503 | service_unavailable | Данные временно не прочитаны. Повторите позже. |
503 | server_busy | Сервис перегружен. Повторите через Retry-After секунд. |
503 | integration_initializing | Новый ключ еще готовится. Повторите позже. |
#Что повторять
| Статус | Повторять? | Как |
|---|---|---|
| 400 | Нет | Исправьте параметр из param. Для cursor_mismatch начните список заново. |
| 401, 403 | Нет | Проверьте ключ, права и настройки кабинета. |
| 404 | Нет | Объект не существует или вне охвата ключа. |
| 410 | Нет | Курсор истек: начните список заново или восстановите ленту. |
| 429 | Да | Подождите Retry-After секунд, добавьте случайный разброс. |
| 503 | Да | Подождите Retry-After секунд, при повторных отказах увеличивайте паузу. |
Подробнее о паузах между повторами в руководстве Лимиты и повторы.
#Особые случаи
- Неизвестный путь и объект с идентификатором не в формате UUID дают 404
not_found. Путь пишется точно как в справочнике: завершающий/или закодированные символы в пути тоже дают 404. - Методы кроме GET, включая
HEADиOPTIONS, и адреса вне/v1/получают 404 без тела. Кодmethod_not_allowedснаружи не встречается. - Тело в GET-запросе, адрес длиннее 8 КиБ или заголовки больше 8 КиБ дают 400
invalid_parameterсparamравнымbody,uriилиheaders. - Повторенный параметр (
?status=new&status=replied) и пустое значение (?status=) дают 400invalid_parameter. - Долгий запрос прерывается через 10 секунд с ответом 503
service_unavailable.