Обработка ошибок

Формат ответа при ошибках, типовые HTTP-статусы и их значения.

Два уровня ошибок

Ошибки приходят двумя разными путями. Их нельзя путать. Правило общее для DBS, FBS и FBO — как в DBS.

Что случилосьHTTPЧто в телеПример в работе
Запрос сломан: не JSON, нет токена, слишком часто, сбой витрины400, 401, 429, 500ApiErrorПродавец не дошёл до заказа
Запрос принят, но заказ / товар / заявка отклонены200errors[] и/или 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_UNAUTHORIZED401
ERROR_TYPE_RATE_LIMIT429
ERROR_TYPE_INTERNAL500
ERROR_TYPE_BAD_REQUEST400 — запрос целиком

Для разбора 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Число меньше или больше допустимого

У метода свой короткий список. Не подставлять коды из чужого метода.