Ошибки¶
Любой отказ API Ziex Try-On имеет одну и ту же форму, с какого бы эндпоинта он ни пришёл:
{
"error": {
"code": "RATE_LIMITED",
"message": "Too many requests. Please slow down.",
"details": []
}
}
code— стабильная машиночитаемая строка. Все коды перечислены ниже.message— английская фраза для строки в логе. Она может измениться в любой момент.detailsесть только у422 VALIDATION_ERRORпри неверном теле запроса. Каждый элемент -{"loc": [...], "msg": "...", "type": "..."};locназывает поле.
Идентификатор запроса ответа, который сформировало приложение, лежит в заголовке X-Request-ID. Назовите его, когда
обращаетесь за помощью (см. Контакты). У ответов краевого слоя перед приложением (413, 429, 502, 503,
504 — см. Ошибки краевого слоя) и у собственного 500 INTERNAL_ERROR приложения идентификатора запроса нет.
Правила обработки ошибок¶
- Решайте по
codeи HTTP-статусу, а не по текстуmessage. Тексты не входят в контракт. - Не показывайте покупателю текст сервера. Сопоставьте код со своей формулировкой. В таблицах ниже для каждого кода есть короткое предложение. Виджет и плагины делают именно так.
- Читайте
Retry-After. Каждый429,409и503, которые формирует API, несёт его в целых секундах. Подождите не меньше этого времени до следующего запроса. Что означает каждое значение — на странице Лимиты. - Статус — это класс (4xx: ваш запрос или ваш аккаунт; 5xx: наша сторона), код — это условие.
Повторы и неопределённые ответы¶
Примерка стоит денег, поэтому главное — знать, что делать, когда неизвестно, создана ли задача. Отправляйте
Idempotency-Key с каждым POST /api/v1/tryon (от 22 до 64 символов из A-Z a-z 0-9 _ -; хороший ключ — UUID без
дефисов). Ключ действует в пределах вашего API-ключа и его вида (секретный или publishable). Один ключ создаёт не
больше одной задачи.
| Ответ на POST | Что это значит | Что делать |
|---|---|---|
201 |
Задача есть и находится в pending. |
Следите за ней: GET /api/v1/tryon/status/{job_id}. |
200 с заголовком Idempotent-Replayed: true |
Вы повторили ключ, который уже создал задачу. Второго списания нет. | Берите задачу из ответа. Её status — текущий статус задачи (она уже может быть completed или failed). Браузерная страница этот заголовок прочитать не может (его нет в Access-Control-Expose-Headers): там повтор видно по самому 200. |
409 IDEMPOTENT_IN_PROGRESS |
Первый запрос с этим ключом ещё обрабатывается. | Повторите тот же запрос с тем же ключом через Retry-After (2 с). |
503 OVERLOADED + Retry-After: 5, без X-Job-Id |
Все слоты обработки изображений остались заняты. Задачи нет, списания нет. | Повторите с тем же ключом через Retry-After. Это новая попытка: одна задача и одно списание. Достаточно нескольких повторов; виджет делает не больше 3 повторов за 60 секунд. |
503 SUBMIT_UNCONFIRMED + X-Job-Id + Retry-After: 2 |
Задача записана, но подтвердить постановку в очередь не удалось. Она может быть в очереди. | Опрашивайте GET /api/v1/tryon/status/{job_id} по id из X-Job-Id либо GET /api/v1/tryon/attempts/{idempotency_key}. Никогда не отправляйте заново под новым ключом — так можно создать и списать вторую задачу. |
500 INTERNAL_ERROR |
Финальный ответ этой попытки. Если задача уже была записана, она существует и помечена failed; её единица тарифа вернётся автоматически. |
Не повторяйте в цикле. Повтор с тем же ключом ответит 200 с этой проваленной задачей (а если задача записана не была — начнёт новую попытку). Чтобы попробовать снова, возьмите новый Idempotency-Key. |
502, 504, 503 SERVICE_UNAVAILABLE, оборванное соединение, таймаут |
Неизвестно, дошёл ли запрос до обработчика. | Найдите попытку: GET /api/v1/tryon/attempts/{idempotency_key}. 200: задача есть, следите за ней. 409 IDEMPOTENT_IN_PROGRESS: спросите снова через Retry-After. 404 NOT_FOUND: спрашивайте снова примерно две минуты (запрос ещё может быть в пути); если и после этого 404, задачи нет, и можно отправлять заново с новым ключом. 503 ATTEMPT_LOOKUP_UNAVAILABLE: спросите снова через Retry-After. |
Любой другой 4xx |
Запрос отклонён, задачи нет. | Устраните причину (см. таблицы). Тот же запрос будет отклонён так же. |
Запрос, отклонённый до появления задачи, ничего не берёт из тарифа: ни генерации, ни счётчиков, ни маркера. Повтор того же ключа после такого отказа — просто новая попытка.
Ключ помнится, пока существует задача (не меньше 24 часов): повтор с тем же ключом всегда отвечает той задачей, которую он создал, — никогда не используйте ключ повторно для новой примерки. GET /api/v1/tryon/attempts/{idempotency_key} отвечает как эндпоинт статуса (плюс заголовки
X-Job-Id и Location) и действует в пределах вашего API-ключа и его вида.
Вебхуки — best effort¶
Вебхук может опоздать, прийти дважды или потеряться (ваш адрес был недоступен, сбой сети, или задачу завершило собственное восстановление платформы). Никогда не полагайтесь только на вебхук. Сверяйтесь опросом:
GET /api/v1/tryon/status/{job_id}для известной задачи;GET /api/v1/tryon/jobs?since=...для задач секретного ключа (список ваших задач;since— время в формате ISO 8601), например раз в минуту для задач, которые ещёpendingилиprocessing.
Каждая задача приходит в финальное состояние (completed, failed или interrupted) не позже чем через 45
минут. Задача, которая ждёт в pending дольше 30 минут или выполняется в processing дольше 15 минут, закрывается
платформой как проваленная. По такой задаче вебхук может не прийти, поэтому через 45 минут перестаньте ждать и
прочитайте статус.
Аутентификация и доступ¶
Эти ошибки идут от ключа и от страницы, с которой он используется. Это проблемы настройки: не повторяйте их в цикле. Покажите покупателю нейтральное сообщение, а владельца магазина известите отдельно.
| Код | HTTP | Когда | Что делать | Что показать покупателю |
|---|---|---|---|---|
INVALID_API_KEY |
401 | Нет заголовка X-API-Key или он пустой, ключ неизвестен, секрет неверный, ключ длиннее 72 байт, либо тестовый ключ при выключенных тестовых ключах. |
Не повторять. Проверьте отправляемый ключ. Отсутствие заголовка — это именно этот код, а не ошибка валидации. | «Примерка сейчас недоступна.» |
KEY_EXPIRED |
401 | У ключа истёк срок действия. | Не повторять. Выпустите новый ключ в клиентском портале и замените его. | «Примерка сейчас недоступна.» |
KEY_SUSPENDED |
403 | Ключ выключен. | Не повторять. Включите ключ в клиентском портале или выпустите новый. | «Примерка сейчас недоступна.» |
CLIENT_SUSPENDED |
403 | Весь аккаунт не активен. | Не повторять. Напишите нам (см. Контакты). | «Примерка сейчас недоступна.» |
ORIGIN_REQUIRED |
403 | Publishable-ключ использован без Origin и Referer, то есть не со страницы браузера. |
Не повторять. Publishable-ключ работает только со страницы; с сервера вызывайте секретным ключом. | «Примерка сейчас недоступна.» |
KEY_NOT_BOUND |
403 | У боевого publishable-ключа нет привязанного домена. | Не повторять. Привяжите домен магазина к ключу в клиентском портале. | «Примерка сейчас недоступна.» |
DOMAIN_NOT_ALLOWED |
403 | Хост из Origin — не домен ключа (и не www., и не его поддомен). Боевой ключ на хосте разработки вроде localhost получает тот же код. |
Не повторять. Используйте ключ на привязанном домене либо тестовый ключ на хосте разработки (см. Локальная разработка). | «На этом сайте примерка недоступна.» |
SECRET_KEY_REQUIRED |
403 | Publishable-ключ вызвал эндпоинт, которому нужен секретный (GET /api/v1/tryon/integration, GET /api/v1/tryon/jobs). |
Не повторять. Вызывайте с сервера секретным ключом. | Ничего: это не вызов от покупателя. |
WEBHOOK_NOT_ALLOWED |
403 | Publishable-ключ прислал webhook_url. |
Не повторять. Уберите webhook_url или отправляйте с сервера секретным ключом. |
Ничего: страница не должна его слать. |
Ошибки запроса¶
| Код | HTTP | Когда | Что делать | Что показать покупателю |
|---|---|---|---|---|
VALIDATION_ERROR |
422 | Тело или параметр неверны (поле названо в details); неверный Idempotency-Key; фото отклонено: неподдерживаемый формат (допустимы JPEG, PNG, WebP, HEIC, AVIF), нечитаемый файл, больше 10 МБ, больше 16 мегапикселей (4096 x 4096) или меньше 256 x 256 пикселей; webhook_url не является публичным адресом. |
Не повторять тот же запрос. Исправьте поле из details или попросите покупателя выбрать другое фото. |
Для фото: «Не удаётся использовать это фото. Выберите другое.» В остальных случаях: «Что-то пошло не так. Попробуйте ещё раз.» |
INVALID_REQUEST |
400 | Запрос искажён так, что схема не может назвать поле: сломанный data URI или base64, либо job_id не является корректным идентификатором. |
Не повторять тот же запрос. Исправьте его. | «Не удаётся использовать это фото. Выберите другое.» |
PHOTO_UPLOAD_REQUIRED |
422 | Publishable-ключ или тестовый ключ прислал фото покупателя (model_image) ссылкой. Нужна загрузка (data URI data:). Одежда может остаться ссылкой. |
Не повторять. Отправьте фото загрузкой. | Ничего: страница должна слать загрузку. |
CATEGORY_UNSUPPORTED |
422 | category неизвестна, или сейчас ни одна модель её не покрывает. |
Не повторять. Актуальные категории — в GET /api/v1/tryon/capabilities. |
«Эту вещь пока нельзя примерить.» |
NOT_FOUND |
404 | Нет такой задачи у этого ключа (задача чужого ключа выглядит так же), нет результата или нет попытки с этим Idempotency-Key. |
Для поиска попытки — таблица повторов выше. Иначе не повторять. | «Не удалось найти эту примерку.» |
Лимиты и квота¶
У всех есть Retry-After. Числа — на странице Лимиты. Отказы этой группы случаются до появления задачи,
поэтому ничего не берут, и после ожидания повтор с тем же Idempotency-Key безопасен.
| Код | HTTP | Когда | Что делать | Что показать покупателю |
|---|---|---|---|---|
RATE_LIMITED |
429 | Достигнут лимит на IP, на пару «ключ и IP» или почасовой лимит ключа, либо лимит GET /api/v1/tryon/jobs на ключ (60 в минуту). |
Подождите Retry-After секунд и повторите. Снизьте частоту, не повторяйте сразу. |
«Слишком много примерок. Подождите немного и попробуйте снова.» |
LIMIT_EXCEEDED |
429 | Генерации тарифа за расчётный период израсходованы (с допуском 10 %). | Повтор до сброса не поможет: Retry-After — время до сброса (не меньше 60 с; сутки, если даты сброса нет). Повысьте тариф или подождите. Известите владельца магазина. |
«Примерка сейчас недоступна.» |
DAILY_CAP_REACHED |
429 | Достигнут дневной потолок платформы или доля потолка, доступная этому ключу. | Retry-After — время до ближайшей полуночи UTC. Не повторять в цикле. Известите владельца магазина. |
«Примерка сейчас недоступна. Попробуйте завтра.» |
OVERLOADED |
503 | Все слоты обработки изображений были заняты 10 секунд. Задачи нет. | См. таблицу повторов: повторить с тем же ключом через Retry-After (5 с). |
«Сейчас много запросов. Подождите несколько секунд.» |
Повторы и состояния сервера¶
| Код | HTTP | Когда | Что делать | Что показать покупателю |
|---|---|---|---|---|
IDEMPOTENT_IN_PROGRESS |
409 | Запрос с этим ключом ещё обрабатывается (на POST /api/v1/tryon или при поиске попытки). |
Повторить с тем же ключом через Retry-After (2 с). |
Продолжайте показывать «Обрабатываем». |
SUBMIT_UNCONFIRMED |
503 | Задача записана; постановка в очередь не подтверждена. В ответе X-Job-Id и Retry-After: 2. |
Опрашивайте задачу или ищите попытку. Не отправляйте заново под новым ключом. | Продолжайте показывать «Обрабатываем». |
ATTEMPT_LOOKUP_UNAVAILABLE |
503 | GET /api/v1/tryon/attempts/{idempotency_key} не может сказать, выполняется ли попытка или её нет. |
Спросите снова через Retry-After (2 с). Не делайте вывод, что задачи нет. |
Продолжайте показывать «Обрабатываем». |
INTERNAL_ERROR |
500 | Непредвиденная ошибка. См. таблицу повторов: для этой попытки ответ финальный. | Новая попытка — только с новым Idempotency-Key. |
«Что-то пошло не так. Попробуйте ещё раз.» |
SERVICE_UNAVAILABLE |
502, 503, 504 | Сервис перезапускается или не ответил вовремя. Этот код формирует краевой слой (см. ниже). | Перед повторной отправкой найдите попытку. Делайте паузы: несколько секунд, затем вдвое и вчетверо больше. | «Сервис занят. Попробуйте через минуту.» |
Коды, зависящие от статуса¶
Несколько кодов появляются только тогда, когда API отвечает простым статусом без конкретного условия. Публичные эндпоинты примерки везде, где есть более точный код, используют его, поэтому эти вы увидите там редко; они перечислены, чтобы клиент умел их обработать.
| Код | HTTP | Значение | Что делать | Что показать покупателю |
|---|---|---|---|---|
AUTHENTICATION_ERROR |
401 | Вызывающий не аутентифицирован. | Не повторять. Исправьте учётные данные. | «Примерка сейчас недоступна.» |
AUTHORIZATION_ERROR |
403 | Вызывающему это не разрешено. | Не повторять. | «Примерка сейчас недоступна.» |
CONFLICT |
409 | Запрос конфликтует с текущим состоянием. | Не повторять тот же запрос. | «Что-то пошло не так. Попробуйте ещё раз.» |
Тестовые ключи и клиентский портал¶
Эти коды относятся к клиентскому порталу и инструментам тестовых ключей и вебхуков, а не к эндпоинтам примерки.
| Код | HTTP | Когда | Что делать |
|---|---|---|---|
TEST_KEY_NOT_ALLOWED |
401 | Тестовый ключ попытался войти в клиентский портал (или использован сеанс портала тестового ключа). Тестовый ключ портал не открывает. | Войдите боевым секретным ключом. |
TEST_KEY_LIMIT |
409 | У аккаунта уже максимальное число тестовых ключей (3). Retry-After нет: ожидание не поможет. |
Удалите тестовый ключ, затем создайте новый. |
WEBHOOK_LIMIT |
409 | У аккаунта уже максимальное число эндпоинтов вебхуков (10, live и test вместе); это 11-й. Retry-After нет: ожидание не поможет. |
Удалите неиспользуемый эндпоинт, затем создайте новый. Это не для покупателя: покажите владельцу магазина «Удалите неиспользуемый эндпоинт вебхука». |
Ошибки краевого слоя¶
Краевой слой перед API отвечает на эти случаи до того, как запрос увидит приложение. Конверт тот же, с
Access-Control-Allow-Origin: *, без X-Request-ID.
| Код | HTTP | Когда | Что делать | Что показать покупателю |
|---|---|---|---|---|
PAYLOAD_TOO_LARGE |
413 | Тело запроса больше 12 МБ. | Не повторять. Отправляйте фото поменьше (виджет сжимает длинную сторону примерно до 1600 px; делайте так же). | «Это фото слишком большое. Выберите поменьше.» |
RATE_LIMITED |
429 | Частота запросов с вашего адреса выше лимита на адрес. Retry-After: 1. |
Подождите секунды из Retry-After и повторите. Если все покупатели идут через один сервер, снизьте частоту: см. Лимиты. |
«Слишком много примерок. Подождите немного и попробуйте снова.» |
SERVICE_UNAVAILABLE |
502, 503, 504 | Сервис перезапускается или не ответил вовремя. | См. таблицу повторов: перед повторной отправкой найдите попытку. | «Сервис занят. Попробуйте через минуту.» |
Ошибки задачи¶
У задачи, которая закончилась failed или interrupted, в ответе статуса (GET /api/v1/tryon/status/{job_id}) есть
error_code и безопасный error_message. В них нет подробностей о провайдере. Это не коды HTTP-ошибок: сам запрос
статуса отвечает 200.
error_code |
Значение | Что делать | Что показать покупателю |
|---|---|---|---|
GENERATION_FAILED |
Результат не удалось получить. Значение по умолчанию для всего, что не перечислено ниже. | Предложите повторить. Это новая задача, поэтому нужен новый Idempotency-Key. Единица тарифа проваленной задачи вернётся автоматически. |
«Не удалось сделать эту примерку. Попробуйте ещё раз.» |
INVALID_IMAGE |
Одно из фото не удалось обработать. | Повтор с тем же фото снова провалится. Попросите другое фото. | «Одно из фото не удалось обработать. Попробуйте другое фото.» |
CONTENT_BLOCKED |
Это изображение нельзя использовать для примерки. | Не повторять с тем же фото. | «Это изображение нельзя использовать для примерки. Выберите другое фото.» |
TIMEOUT |
Заняло дольше ожидаемого, либо исполнитель потерян. | Предложите повторить с новым Idempotency-Key. |
«Это заняло больше времени, чем ожидалось. Попробуйте ещё раз.» |
INTERRUPTED |
Примерка прервана (например, перезапуском). | Предложите повторить с новым Idempotency-Key. |
«Примерка была прервана. Попробуйте ещё раз.» |
Генерация проваленной (failed или interrupted) задачи возвращается в тариф. Завершённая (completed) задача не
возвращается никогда.
site.reason и коды¶
GET /api/v1/tryon/integration?site_url=... (секретный ключ) сообщает, можно ли использовать ключ на сайте: site.allowed
и, если нельзя, site.reason. Причины — слова в нижнем регистре, и они соответствуют кодам, которые этот же сайт
получил бы на настоящем запросе:
site.reason |
Код на настоящем запросе | Значение |
|---|---|---|
key_not_bound |
KEY_NOT_BOUND |
У боевого ключа нет привязанного домена. |
domain_mismatch |
DOMAIN_NOT_ALLOWED |
Сайт — не домен ключа. |
dev_host |
DOMAIN_NOT_ALLOWED |
Боевой ключ на хосте разработки (localhost, *.test, частный IP). Там используйте тестовый ключ. |
Что читать дальше¶
- Числа за каждым
429и503: Лимиты. - Каждый эндпоинт с документированными ответами: Справочник API.
- Первый вызов с сервера: Быстрый старт B.