Ошибки
Единый конверт на всё: {"error": {"code", "message", "request_id"}}.
code — машинный и стабильный, ветвитесь в коде по нему;
message — по-русски для человека и может меняться без анонса;
request_id совпадает с заголовком X-Request-Id —
присылайте его в поддержку.
{ "error": { "code": "key_revoked", "message": "Ключ отозван 14.08.2026.", "request_id": "a1b2c3d4-5e6f-7890-abcd-ef1234567890" } }
Коды ошибок
| HTTP | code | Что значит | Что делать |
|---|---|---|---|
| 401 | unauthorized |
Ключ не передан ни в одном из двух заголовков, либо такого ключа не существует. | Передайте ключ в "Authorization: Bearer <ключ>" или "X-Api-Key". Проверьте, что ключ скопирован целиком. |
| 401 | key_revoked |
Ключ существует, но отозван. | Попросите менеджера ПерфектПак выпустить новый ключ для этой интеграции. |
| 429 | rate_limited |
Превышен лимит запросов: 60 в минуту на ключ, всплеск 20. | Подождите время из заголовка Retry-After и повторите. Для регулярного опроса ориентируйтесь на средний темп 60/мин, а не на всплеск. |
| 404 | not_found |
Объекта с таким идентификатором нет — либо он есть, но принадлежит не вашему client_id (эти два случая неразличимы намеренно). | Проверьте идентификатор. Если уверены, что объект должен существовать и быть вашим, напишите в поддержку с request_id. |
| 400 | bad_request |
Параметр запроса не прошёл валидацию: нечисловой limit, недопустимое значение перечисления, нераспознанная дата, некорректный период from/to. | Текст message называет конкретный параметр и допустимые значения — исправьте запрос по нему. |
| 400 | bad_cursor |
Параметр cursor не наш или испорчен. | Запросите первую страницу заново без параметра cursor. Не пытайтесь исправить или собрать курсор самостоятельно. |
| 500 | internal |
Ошибка на нашей стороне. | Повторите запрос; если повторяется — напишите в поддержку с request_id из тела ответа или заголовка X-Request-Id. |
| 400 | validation_error |
Поле тела запроса не прошло валидацию (например, POST /v1/receipts: пустой items, qty вне диапазона 1…100000, отсутствует barcode). | Текст message называет конкретное поле — исправьте тело запроса по нему. |
| 400 | cabinet_required |
У клиента больше одного кабинета маркетплейса, а cabinet_id в запросе не передан. | Передайте cabinet_id — идентификатор нужного кабинета из GET /v1/me. |
| 400 | mixed_marking |
В одной заявке POST /v1/receipts перемешаны позиции с honest_mark:true и honest_mark:false — склад принимает задание только целиком по кодам маркировки либо целиком по штрихкодам. | Разделите заявку на две — по одной на каждое значение honest_mark. |
| 503 | write_disabled |
Заявки через API (POST /v1/receipts) ещё не включены для вашего ключа. | Обратитесь к менеджеру ПерфектПак, чтобы включить приём заявок через API для вашего ключа. |
| 502 | warehouse_unavailable |
Склад временно не принял заявку. Заявка не создана. | Повторите запрос через минуту — это временный сбой, а не ошибка в теле запроса. |
| 400 | webhook_url_unverified |
При регистрации вебхука URL не ответил 2xx на webhook.ping за 10 секунд. | Проверьте, что URL общедоступен, отвечает 2xx и укладывается в 10 секунд, затем повторите регистрацию. |
| 400 | webhook_limit |
У клиента уже 10 подписок — максимум на клиента. | Удалите неиспользуемую подписку (DELETE /v1/webhooks/{id}) или переиспользуйте существующую. |
| 503 | webhooks_unavailable |
Вебхуки временно выключены на нашей стороне. | Повторите позже; события за это время не теряются — доставка возобновится, когда вебхуки снова заработают. |
| 403 | sandbox_only |
Операция доступна только тестовому ключу (pp_test_), а запрос пришёл с боевым ключом (pp_live_). | Используйте тестовый ключ песочницы для песочничных операций (например, POST /v1/sandbox/reset) — они не действуют на боевые ключи. |
Почему 404, а не 403, если объект не мой
Осознанное решение об изоляции. Если бы «объект существует, но не ваш»
отвечало 403, а «объекта нет вовсе» — 404, по
разнице кодов можно было бы перебором выяснять, какие идентификаторы вообще
существуют у других селлеров. Поэтому оба случая отвечают одинаково —
404 not_found.
Заголовки лимита запросов
| Заголовок | Смысл |
|---|---|
X-RateLimit-Limit | Ёмкость всплеска — 20. Не то же самое, что средний лимит 60 в минуту. |
X-RateLimit-Remaining | Сколько запросов из текущего всплеска ещё доступно. |
X-RateLimit-Reset | Unix-время полного восстановления всплеска. |
Retry-After | Только на 429: через сколько секунд имеет смысл повторить. |
Заголовки X-RateLimit-* есть на любом ответе /v1/*, кроме 401 — ключ ещё не проверен, лимит считать не по чему.