Коды ошибок
Этот документ перечисляет все error.code, которые возвращают публичные маршруты /v1 и /checkout/v1, с HTTP-статусом, который использует сервис, и тем, что делать клиенту. Прочитайте его, когда пишете обработку ошибок интеграции.
Тело ошибки
Любой ответ API с ошибкой имеет одно и то же тело:
{ "error": { "code": "route_not_found", "message": "Route not found" } }
| Поле | Тип | Смысл |
|---|---|---|
error.code |
string | Машиночитаемый код из перечня. Сервис не переименовывает и не удаляет коды; новые коды появляются в журнале изменений |
error.message |
string | Пояснение для человека на английском. Текст может меняться: не разбирайте его в коде |
error.details |
array | Есть, только если запрос не прошёл проверку по схеме: по элементу на каждую проблему, с path — где проблема (body.amount, params.id или body для лишнего поля) — и message. У validation_failed из более поздней проверки, например числа знаков суммы, details нет; её message начинается с имени поля |
Каждый ответ, включая ошибки, содержит заголовок X-Request-Id. Сообщайте его значение оператору, когда сообщаете о проблеме: по нему находится запрос в логах. Если клиент сам передал X-Request-Id из 1–128 латинских букв, цифр и символов ., _, :, -, сервис использует его, иначе генерирует UUID.
Описание OpenAPI, GET /v1/openapi.json, объявляет один список кодов для всех маршрутов сервиса, включая внутренние. Публичный маршрут возвращает только коды из перечня ниже.
Два вида ответов такого тела не имеют:
- HTTPS-прокси отвечает на путь вне
/v1/кодом404с пустым телом; - во время остановки API отвечает
503с телом в другом формате.
Ответ, тело которого не в формате выше, обрабатывайте по HTTP-статусу.
Как обрабатывать ошибки
400,413,415— запрос неверный. Исправьте его: тот же запрос получит ту же ошибку.401— проверьте ключ и имя заголовка.403— мерчант отключён или не одобрен. Запросы будут отклоняться, пока это не изменит владелец или оператор.404— проверьте путь и идентификатор.409— запрос конфликтует с существующим объектом: ключ идемпотентности (order_id,reference) использован повторно с другими данными, или выбор токена на странице оплаты уже сделан либо уже невозможен. Не повторяйте тот же запрос.422— запрос корректен, но его отклоняет бизнес-правило; код называет правило. Тот же запрос получит ту же ошибку, пока не изменится настройка, стоящая за правилом.429— повторите через число секунд из заголовкаretry-after.500,503— проблема сервиса. Повторите позже с растущей задержкой и тем же ключом идемпотентности:order_idдля инвойса,referenceдля выплаты. Повтор не создаёт второй объект.- Кода нет в перечне — обработайте ответ по классу HTTP-статуса:
4xx— ошибка в запросе,5xx— проблема сервиса.
Перечень
| HTTP | error.code |
Маршруты | Когда | Что делать клиенту |
|---|---|---|---|---|
| 400 | validation_failed |
все | Тело, путь или параметры не проходят проверку: поле отсутствует, лишнее, null или неверного формата. Или не проходит более поздняя проверка поля: формат или число знаков суммы, точность цены, external_user_id в режиме per_user |
Исправить поле, названное в details или в начале message |
| 400, 413, 415 | bad_request |
маршруты с телом запроса | Тело — не JSON или пустое при Content-Type: application/json (400), больше 16 КиБ (413) или с неподдерживаемым Content-Type (415) |
Отправлять JSON-объект с Content-Type: application/json |
| 401 | unauthorized |
/v1 |
Нет заголовка X-Api-Key, либо ключ неверного формата, неизвестен, отозван или его секрет не совпадает |
Проверить ключ. Причина намеренно не уточняется — см. аутентификацию |
| 403 | merchant_disabled |
/v1 |
Мерчант отключён — оператором или владельцем в кабинете | Включить проект в кабинете. Если проект выключил оператор, включить его может только оператор |
| 403 | merchant_not_approved |
POST /v1/invoices, POST /v1/addresses, POST /checkout/v1/invoices/{id}/select |
Мерчант ещё не одобрен после проверки или отклонён | Дождаться проверки. Причину отклонения владелец видит в кабинете и может исправить заявку и отправить её снова. Повтор с order_id существующего инвойса возвращает этот инвойс |
| 404 | route_not_found |
любой путь под /v1 или /checkout/v1 |
Нет маршрута с таким методом и путём | Проверить метод и путь |
| 404 | invoice_not_found |
GET /v1/invoices/{id}, GET /checkout/v1/invoices/{id}, POST /checkout/v1/invoices/{id}/select |
Инвойса нет или он принадлежит другому мерчанту. На маршрутах /checkout/v1 ещё: мерчант отключён |
Проверить идентификатор |
| 404 | payout_not_found |
GET /v1/payouts/{id} |
Выплаты нет или она принадлежит другому мерчанту | Проверить идентификатор |
| 404 | deposit_not_found |
GET /v1/deposits/{tx_hash} |
В транзакции нет перевода на адрес мерчанта: сервис её не знает, она шла только другим мерчантам или её блок ещё не просканирован | Проверить хэш. Для только что отправленной транзакции повторить позже — см. проверку перевода |
| 409 | address_mode_mismatch |
POST /v1/addresses |
Мерчант работает в режиме per_invoice |
Брать адрес из инвойса — см. режимы |
| 409 | order_id_conflict |
POST /v1/invoices |
Инвойс с этим order_id есть с другим активом, суммой, currencies, external_user_id, return_url или cancel_url |
Проверить, не используется ли order_id повторно для другого заказа, — см. идемпотентность |
| 409 | reference_conflict |
POST /v1/payouts |
Выплата с этим reference есть с другим активом, адресом или суммой |
Проверить, не используется ли reference повторно для другой выплаты |
| 409 | asset_already_selected |
POST /checkout/v1/invoices/{id}/select |
У инвойса уже другой актив. Выбор окончательный | Показать покупателю инвойс с его токеном |
| 409 | invoice_expired |
POST /checkout/v1/invoices/{id}/select |
Дедлайн инвойса прошёл или инвойс уже не в статусе created |
Показать покупателю состояние инвойса |
| 422 | address_mode_disabled |
POST /v1/addresses, POST /v1/invoices, POST /checkout/v1/invoices/{id}/select |
Платформа временно приостановила режим адресов мерчанта | Сообщить покупателю, что оплата сейчас недоступна, и повторить позже. Повтор с order_id существующего инвойса возвращает этот инвойс; переводы на уже выданные адреса зачисляются как обычно — см. режим на паузе |
| 422 | mode_not_allowed |
POST /v1/addresses, POST /v1/invoices, POST /checkout/v1/invoices/{id}/select |
Режим адресов этого проекта ему не разрешён: оператор разрешает режим по проектам (ADR-0066) | Обратиться к оператору. Переводы на уже выданные адреса зачисляются как обычно |
| 422 | asset_not_supported |
POST /v1/invoices, POST /checkout/v1/invoices/{id}/select |
Актив неизвестен или не принимается к оплате | Использовать актив из таблицы активов, который оплачивает инвойсы |
| 422 | asset_not_payable |
POST /v1/payouts |
В этом активе сервис не делает выплат: он неизвестен, неактивен или только для приёма | Использовать актив из таблицы активов, в котором есть выплаты |
| 422 | asset_payments_disabled |
POST /v1/invoices, POST /checkout/v1/invoices/{id}/select |
Оператор временно выключил приём в активе | Предложить другой актив или повторить позже. Повтор с order_id существующего инвойса возвращает этот инвойс |
| 422 | asset_disabled_by_merchant |
POST /v1/invoices, POST /checkout/v1/invoices/{id}/select |
Приём в активе выключен в настройках проекта | Предложить другой актив или включить токен в разделе проекта «Токены» в кабинете. Повтор с order_id существующего инвойса возвращает этот инвойс |
| 422 | asset_payouts_disabled |
POST /v1/payouts |
Оператор временно выключил выплаты в активе | Повторить позже с тем же reference. Выплаты, созданные раньше, исполняются как обычно |
| 422 | amount_below_minimum |
POST /v1/invoices, POST /checkout/v1/invoices/{id}/select |
Сумма или цена меньше минимального депозита актива | Увеличить сумму или выбрать другой актив |
| 422 | asset_required |
POST /v1/invoices |
Нет asset, а в установке нет страницы оплаты, где покупатель выбрал бы токен |
Передать asset |
| 422 | no_payable_assets |
POST /v1/invoices |
Нет ни asset, ни currencies, а мерчант сейчас не принимает ни одного актива, у которого есть курс |
Включить токен в настройках проекта или передать asset |
| 422 | asset_not_offered |
POST /v1/invoices, POST /checkout/v1/invoices/{id}/select |
Актив нельзя предложить для цены в долларах США: у сервиса нет для него курса; на маршруте выбора ещё: его нет в currencies инвойса |
Выбрать другой актив |
| 422 | redirect_url_not_allowed |
POST /v1/invoices |
return_url или cancel_url не на сайте мерчанта |
Использовать адрес на сайте проекта или на сайте адреса проекта того же вида — см. адреса возврата |
| 422 | address_not_whitelisted |
POST /v1/payouts |
Адреса нет в вайтлисте мерчанта по этому активу, или задержка перед его первым использованием ещё не прошла. Сообщение называет, какой из двух случаев | См. куда можно платить. Ответ не зависит от суммы |
| 429 | rate_limited |
/v1, /checkout/v1 |
Превышен лимит запросов | Повторить через число секунд из заголовка retry-after — см. лимиты запросов |
| 500 | internal_error |
все | Необработанная ошибка сервиса. Подробности пишутся в лог сервиса, а не в ответ | Повторить позже с тем же ключом идемпотентности. При повторении сообщить X-Request-Id |
| 503 | service_unavailable |
POST /v1/addresses, POST /v1/invoices, POST /checkout/v1/invoices/{id}/select |
Сервис не может вывести новый адрес в текущей конфигурации; сообщение называет причину | Повторить позже. Если не проходит, обратиться к оператору |
| 503 | addresses_exhausted |
POST /v1/addresses, POST /v1/invoices, POST /checkout/v1/invoices/{id}/select |
Закончились индексы деривации адресов: заняты все 2^31. Практически недостижимо | Обратиться к оператору |
| 503 | network_fee_quote_unavailable |
POST /v1/invoices |
У проекта осталась прежняя настройка «комиссию сети платит покупатель», поэтому новый инвойс не создаётся. Повтор с order_id существующего инвойса возвращает этот инвойс |
Владелец сохраняет «Кто платит комиссии» в настройках проекта в кабинете; затем повторить |
| 503 | rate_unavailable |
POST /v1/invoices, POST /checkout/v1/invoices/{id}/select |
Сейчас нет свежего курса: при создании инвойса без asset — ни у одного разрешённого токена, при выборе — у монеты выбранного актива. Ничего не создаётся и не записывается. Повтор с order_id существующего инвойса возвращает этот инвойс |
Повторить позже с растущей задержкой и тем же order_id. На странице оплаты — предложить другой токен или попросить покупателя попробовать позже. Если не проходит, обратиться к оператору |
| 503 | payouts_halted |
POST /v1/payouts |
Выплаты остановлены — по этому активу или целиком; сообщение говорит, какой из двух случаев. Причина не раскрывается | Повторить позже с тем же reference. Повтор существующего reference возвращает эту выплату и во время остановки |
Примеры
Несуществующий путь:
curl -s https://api.stons.io/v1/unknown
404:
{"error":{"code":"route_not_found","message":"Route not found"}}
Запрос к POST /v1/invoices с "expires_in": 60 не проходит проверку по схеме, и details перечисляет все проблемные поля:
{
"error": {
"code": "validation_failed",
"message": "Request validation failed",
"details": [{ "path": "body.expires_in", "message": "Too small: expected number to be >=300" }]
}
}
Запрос с "asset": "USDT_TRON" и "amount": "49.9000001" проходит проверку по схеме, но не проходит проверку числа знаков, поэтому details нет:
{
"error": {
"code": "validation_failed",
"message": "amount: amount has more than 6 digits after the decimal point (USDT_TRON has 6 decimals)"
}
}