AploDelivery Partner API — портал разработчика · v2 (2026-10-16)

Справочник ошибок

Работает

Тело ошибки в общем случае имеет форму {"error":"code"}. Ниже — каждый код, который сервер реально возвращает партнёрскому клиенту (internal/httpapi/server.go, internal/auth/hmac.go), с HTTP-статусом, причиной и рекомендуемым действием.

Ошибки аутентификации (до вызова бизнес-логики)

HTTPerrorПричинаЧто делать
401unauthorizedнеизвестный X-API-Key; отсутствует/пуст один из заголовков X-Timestamp/X-Signature/X-Request-ID; X-Request-ID не валидный UUID; X-Timestamp расходится с временем сервера больше чем на 60 c; подпись не совпала; либо этот X-Request-ID уже был использован этим API-ключом раньшепроверить ключ, синхронизацию времени, формат X-Request-ID, формулу подписи (см. Аутентификацию); секрет никогда не логировать
503authentication_unavailableсервис не смог проверить одноразовость X-Request-ID (временная недоступность зависимости, сам запрос ещё не принят)безопасно повторить тот же запрос с тем же X-Request-ID позже
413 (текст, не JSON)— (request body too large, Content-Type: text/plain)тело запроса больше лимита: 2 MiB для всех обычных маршрутовуменьшить тело; это плагинский лимит для PUT /v1/plugin/streets (8 MiB) партнёра не касается

413 — единственный случай, где ответ не в форме {"error":"code"}: это стандартный текстовый ответ net/http, разбирайте его отдельной веткой, если парсите тело ошибки как JSON.

Ошибки уровня приложения

HTTPerrorПричинаЧто делать
400invalid_requestJSON не прошёл строгий разбор (неизвестное поле, лишнее значение в теле), не прошла валидация домена (например schemaVersion не 1, total не совпадает с суммой позиций, невалидный телефон/ID, currency не RUB), либо id в пути — не UUIDпоправить запрос на своей стороне; не повторять без изменений
403forbiddenточка, источник (source) или scope (organization/terminalGroup — актуально только для плагинских маршрутов) не разрешены вашему credentialне пытаться обойти scope; для партнёра — типичная причина: externalPointId не входит в список externalPoints вашего credential
404not_foundзаказ не существует, либо существует, но вне point-scope вашего credential (сервер намеренно отвечает так же, как на несуществующий объект — не 403 — чтобы не раскрывать чужие заказы через «оракул существования»)не считать это доказательством, что заказа не было — перепроверить externalOrderId/id и scope; гостю показывать нейтральный текст, не раскрывать, какой из двух случаев произошёл

Исключение: GET /v1/orders/{id}?source= (эндпоинт, существовавший ещё до этого раздела спецификации) проверяет только source вашего credential, но не point-scope (AllowsPoint) — это оставлено ради байт-совместимости с уже развёрнутыми интеграциями. Практически это значит, что по UUID чужого заказа в пределах вашего source можно получить 200 вместо 404, если вы каким-то образом узнали его id. Два новых чтения, которые этот портал документирует как основные — GET /v1/orders?externalOrderId= и POST /v1/orders/{id}/cancel — уже проверяют point-scope полностью и отвечают 404 за его пределами. | 409 | idempotency_conflict | тот же externalOrderId отправлен повторно с другим содержимым (создание заказа) | остановить автоматический retry, разобраться, какое содержимое верное — см. Идемпотентность | | 409 | cancel_rejected | предыдущая попытка отмены уже была отклонена плагином (ресторан не смог отменить доставку — она перешла дальше New) | показать гостю «свяжитесь с рестораном», не повторять отмену автоматически — см. Отмену заказа | | 422 | route_mapping_not_found | для этой точки нет активного маршрута (tenantId + source + externalPointId) в delivery_route_mappings | скрыть/заблокировать точку в вашем UI до исправления маршрутизации на стороне AploDelivery | | 422 | product_mapping_not_found | у одной из позиций заказа нет активного товарного маппинга для точки | убрать блюдо без маппинга из checkout (проверяйте заранее через GET /v1/points/{id}/products, см. Быстрый старт) или сообщить об отсутствующем маппинге |

Коды, которые партнёр может увидеть только косвенно (плагинский протокол)

Эти коды принадлежат эндпоинтам /v1/plugin/*, которые партнёрский backend не вызывает напрямую — но они объясняют, почему заказ может «зависнуть» в промежуточном состоянии при поллинге:

HTTPerrorГде возникает
409invalid_or_expired_claimплагин пытается подтвердить заказ по просроченному или неверному claimToken
409invalid_state_transitionплагин пытается перевести заказ в состояние, недопустимое из текущего
409stable_id_mismatchплагин прислал ACK с другими iikoOrderId/iikoDeliveryId, чем у заказа
500scope_violationвнутренняя защитная проверка (заявленный claim оказался вне scope credential) — признак бага, не пользовательская ошибка

Общесистемные ошибки

HTTPerrorПричинаЧто делать
500internal_errorнеобработанная паника на сервере (перехвачена defer-recover)ретраить с новым X-Request-ID по стандартной backoff-политике; если повторяется — обратиться в поддержку с externalOrderId/id и временем запроса

Общее правило

Неизвестный/незнакомый HTTP-статус или код error, которого нет в этой таблице, не считайте успехом: сохраните техническую ошибку без предположений о результате операции и, если операция не идемпотентна по своей природе (см. Идемпотентность), не повторяйте её вслепую. Go SDK (pkg/ingressclient) уже даёт типизированные ошибки ForbiddenError / NotFoundError / ConflictError / UnprocessableError для 403/404/409/422; остальные статусы приходят как HTTPError{StatusCode, Code}.

Связанное