Обработка ошибок
Формат ответа при ошибках, типовые HTTP-статусы и их значения.
Два уровня ошибок
Ошибки приходят двумя разными путями. Их нельзя путать. Правило общее для DBS, FBS и FBO — как в DBS.
| Что случилось | HTTP | Что в теле | Пример в работе |
|---|---|---|---|
| Запрос сломан: не JSON, нет токена, слишком часто, сбой витрины | 400, 401, 429, 500 | ApiError | Продавец не дошёл до заказа |
| Запрос принят, но заказ / товар / заявка отклонены | 200 | errors[] и/или failed[] | Статус не сменился; остаток по одной позиции не записался |
ApiError — только про сам запрос (HTTP 4xx/5xx). Отклонение заказа, поля или строки списка — в HTTP 200 (errors / failed).
У методов в ответе бывают 200, 400 («Некорректный запрос»), 401 («Ошибка авторизации»), 429 («Превышен лимит запросов»), 500 («Внутренняя ошибка сервера»). Тело 4xx/5xx — ApiError.
HTTP 200 не значит, что всё прошло. Смотрите errors и failed в теле.
Сейчас в OpenAPI FBS/FBO в ApiError нет ERROR_TYPE_BAD_REQUEST, а у FBO для code указано только OPERATION_NOT_SUPPORTED. Это расхождение с DBS, его поправят. Тестируйте по правилу ниже.
Поля ApiError
В контракте у ApiError нет обязательных полей. Обычно приходят:
| Поле | Зачем |
|---|---|
error_type | Класс ошибки запроса. Сюда не кладут ошибку конкретного заказа |
code | Уточнение к error_type. Список значений для ApiError не задан |
message | Текст для человека |
details | Дополнительные строки ключ–значение |
error_type:
| Значение | HTTP |
|---|---|
ERROR_TYPE_UNSPECIFIED | не используется |
ERROR_TYPE_UNAUTHORIZED | 401 |
ERROR_TYPE_RATE_LIMIT | 429 |
ERROR_TYPE_INTERNAL | 500 |
ERROR_TYPE_BAD_REQUEST | 400 — запрос целиком |
Для разбора JSON в контракте отдельно указан код FAIL_JSON_PARSE («не получилось разобрать JSON») при error_type ERROR_TYPE_BAD_REQUEST. В ответах методов тело всё равно описано как ApiError.
HTTP 400 — сломанный запрос
Сюда попадает тело, которое витрина не может разобрать. Не сюда: «заказ не найден», «нельзя сменить статус», «витрина отклонила правило». Это HTTP 200 + errors / failed.
Пример (FAIL_JSON_PARSE — код разбора JSON):
{
"error_type": "ERROR_TYPE_BAD_REQUEST",
"code": "FAIL_JSON_PARSE",
"message": "не получилось разобрать JSON",
"details": {}
}
HTTP 401 / 429 / 500
Конкретные значения code для этих статусов в ApiError не перечислены.
{
"error_type": "ERROR_TYPE_UNAUTHORIZED",
"code": "string",
"message": "Ошибка авторизации",
"details": {}
}
{
"error_type": "ERROR_TYPE_RATE_LIMIT",
"code": "string",
"message": "Превышен лимит запросов",
"details": {}
}
{
"error_type": "ERROR_TYPE_INTERNAL",
"code": "string",
"message": "Внутренняя ошибка сервера",
"details": {}
}
Сколько запросов в секунду можно слать, в контракте не сказано.
HTTP 200: errors[] по одному объекту
Так отвечают методы, которые меняют один заказ, заявку на отмену или локацию. Идентификатор в ответе есть всегда. Если операция не прошла, прикладного поля (status и т.п.) нет — есть errors.
У каждой строки в errors обязательны field, code, message. Берите code только из списка этого метода. Общий каталог кодов в ответы не подставлять.
Если витрина отклонила своим правилом: code = STOREFRONT_RULE_VIOLATION, подробности — в message.
Успех (пустой errors)
В ответе архива локации обязателен location_id. Пустой errors — операция прошла.
{
"location_id": "wh-msk-dbs-01",
"errors": []
}
Ошибка по заявке или заказу
В ответе на решение по отмене обязателен cancellation_id. При ошибке приходят только cancellation_id и errors; поля status нет. В errors обязательны field, code, message.
{
"cancellation_id": 10042,
"errors": [
{
"field": "cancellation_id",
"code": "NOT_FOUND",
"message": "Заявка на отмену не найдена"
}
]
}
В ответе на смену статуса заказа обязателен merchant_order_id. При ошибке — только он и errors; поля status нет.
{
"merchant_order_id": "ORD-DBS-2026-301",
"errors": [
{
"field": "status",
"code": "INVALID_ENUM",
"message": "Значение не из допустимого набора"
}
]
}
Пустой errors и отсутствие поля — не одно и то же. Для отмены и смены статуса errors описаны «только при неуспехе». Для архива локации и привязки полигона — «пустой массив при успехе». Не копировать одно правило на все методы.
HTTP 200: список failed[]
Так отвечают загрузка остатков, цен, архива товаров и код вручения (handover-code/set): сколько обработали (processed) и что не прошло (failed). У ответа остатков и цен обязательных полей нет.
Для кода вручения: пустой или отсутствующий failed — все строки прошли. Для цен и остатков написано только «элементы, по которым возникла ошибка»; про пустой failed отдельно не сказано.
В строке failed по остаткам обязательных полей нет. Вложенные errors снова с обязательными field, code, message. Если в строке есть и product_id, и offer_id, витрина смотрит на product_id. Поле error_message — совместимость; смотрите errors.
{
"processed": 1,
"failed": [
{
"product_id": "PRD-PHONE-01",
"offer_id": "PHONE-001",
"location_id": "wh-msk-dbs-01",
"error_message": "Остаток не может быть отрицательным",
"errors": [
{
"field": "count",
"code": "NEGATIVE_VALUE",
"message": "Остаток не может быть отрицательным"
}
]
}
]
}
В запросе остатков обязателен массив items, максимум 200 позиций. В каждой позиции обязательны location_id и count.
У FBO нет метода stock/update — продавец не загружает остатки на склад маркетплейса. Это не ошибка контракта, а схема работы FBO.
Коды в errors
Набор зависит от метода. Ниже — частые значения. В ответ ставьте код, только если он есть у этого метода.
| Код | Что это значит для продавца |
|---|---|
REQUIRED | Поле нет или оно пустое, а без него нельзя |
REQUIRED_ONE_OF | Нужно хотя бы одно поле из набора (например артикул или id товара) |
CONDITIONALLY_REQUIRED | Поле нужно только при условии |
INVALID_TYPE | Неверный тип JSON |
INVALID_ENUM | Значение не из допустимого набора (статус, тип доставки) |
INVALID_FORMAT | Неверный формат |
INVALID_DATE_TIME | Дата не RFC3339 или без часового пояса |
NOT_FOUND | Объект не найден; какое именно — в field |
CONFLICT | Конфликт состояния |
INVALID_STATUS_TRANSITION | Такой переход статуса нельзя |
STATUS_NOT_ALLOWED | В текущем статусе заказа операция недоступна |
STOREFRONT_RULE_VIOLATION | Витрина отклонила своим правилом; текст в message |
TOO_MANY_ITEMS | Слишком много элементов в одном запросе |
NEGATIVE_VALUE / MIN_VALUE / MAX_VALUE | Число меньше или больше допустимого |
У метода свой короткий список. Не подставлять коды из чужого метода.