Перейти к содержимому

API

На странице

Коды ошибок

Обрабатывайте ошибки Merchant API по стабильным машинным кодам, деталям валидации полей и документированным сценариям восстановления.

Каталог кодов

Стабильные машинно-читаемые идентификаторы возвращаются в code (а при ошибке по конкретному полю — в errors[].code). Список — фактически выдаваемый набор: каждый код ниже реально отдаёт хотя бы один обработчик, валидатор или middleware в API. Семантика существующих кодов не меняется, новые коды добавляются под новые сценарии. Переименование кода — редкий случай, и о каждом мы пишем в чейнджлоге.

Используйте code для программной обработки. detail приходит только на английском — для логов и запасного UI; локализуйте на клиенте по code.

401 и 403 — не две ступени одной ошибки. 401 значит, что запрос не прошёл проверку учётных данных: заголовка нет, он повреждён, подпись сделана не тем секретом или слишком давно. Повторить тот же запрос — получить тот же ответ. Чинить нужно на стороне ключа: сам ключ, его настройки в дашборде или часы, по которым вы подписываете.

403 значит, что ключ приняли, а дальше запрос не пропустили. Под одним статусом живут две несвязанные ситуации:

  • Ключ не тотforbidden, payment_key_required, payout_key_required. Это настройка интеграции: подпишите запрос ключом нужного типа и окружения, и вызов пройдёт.
  • Ключ в порядке, дело в состоянии аккаунта или проектаwhitelist_required, merchant_suspended, widget_inactive, terminal_not_enabled, embed_not_enabled, not_sandbox, payment_channel_simulation_sandbox_only. Ключ исправен, менять его бесполезно. Самый частый случай — whitelist_required: адрес получателя ещё не добавлен в белый список для выводов. Покажите это тому, кто ждёт вывод, вместо того чтобы поднимать дежурного из-за рабочего ключа.

HTTP-статус говорит только о том, на каком уровне запрос остановили. Что делать — смотрите в code: ни он сам, ни класс ошибки из вашего SDK этого не скажут.

Коды поля

Возвращаются при валидации запроса. У кодов уровня поля (ниже) field содержит имя поля, не прошедшего проверку, в snake_case. Когда сразу несколько полей не проходят проверку, код верхнего уровня — validation_failed, а разбивка по полям лежит в errors[].

Code Когда Что делать
validation_failed Сразу несколько полей не прошли валидацию. Это код верхнего уровня; разбивка по полям — у каждого свой code и field — лежит в errors[]. Разберите errors[] и поправьте каждое перечисленное field.
field_required Обязательное поле пустое, null или состоит только из пробелов. Передайте значение в field.
field_too_long Поле длиннее допустимого максимума. Обрежьте до лимита, указанного для этого эндпоинта.
field_out_of_range Числовое значение вне допустимого диапазона. Приведите значение к документированному диапазону.
field_invalid_enum Значение не входит в набор допустимых значений enum (например, незнакомая currency / network, или токен не включён в проекте). Сверьтесь со справочником допустимых значений; для токенов — убедитесь, что пара токен+сеть включена в проекте.
field_invalid_format Значение не соответствует формату поля: либо не разбирается как id (например, invoice_id без префикса inv_…), либо amount передан не простой decimal-строкой вида "10.00". Передавайте поле в документированном формате; id — ровно в том виде, в каком их вернул API.
entity_id_empty Переданный id — это нулевой (пустой) GUID (00000000-0000-…). field указывает на конкретный id — например, invoice_id или withdrawal_id. Передавайте id ровно в том виде, в каком его вернул API; не отправляйте пустой или обнулённый id.
field_must_be_positive Десятичное или целое число должно быть больше 0. Передайте положительное значение.
field_percentage_out_of_range Процент должен быть в диапазоне [0, 100] включительно. Приведите значение к диапазону [0, 100].
query_parameter_unknown В запросе списка передан параметр строки запроса, которого нет у этого эндпоинта. Удалите параметр или используйте его документированное имя в snake_case.
pagination_cursor_invalid Курсор повреждён, истёк, подделан, относится к другому ресурсу или совмещён с другими фильтрами. Начните пагинацию без cursor, затем сохраняйте фильтры при переходе по next_cursor.
amount_too_many_decimals Для инвойса с суммой в фиатной валюте amount содержит больше знаков после запятой, чем допускает минимальная единица валюты (например, 23.345 для USD, 23.01 для JPY). Округлите до минимальной единицы валюты.
amount_too_large amount при создании инвойса или вывода выходит за поддерживаемый диапазон — выше потолка в 20 целых знаков, который хранит API. Передайте сумму в пределах поддерживаемого диапазона.

Резервные коды по HTTP-статусу

Возвращаются, когда у ошибки нет своего бизнес-кода. Каждый код — резервный вариант для HTTP-статуса: запрос не прошёл, а описать причину точнее было нечем.

Code HTTP Когда Что делать
forbidden 403 Аутентификация прошла, но этому ключу операция не разрешена: не хватает возможностей (scope) или не то окружение — например, тестовый ключ на эндпоинте только для рабочего режима. Используйте ключ с нужными возможностями и в нужном окружении. Владение никогда не даёт 403: чужой ресурс возвращает not_found (404), а не forbidden.
payment_key_required 403 Эндпоинту нужен Payment-ключ (pk_), а запрос пришёл с Payout-ключом (rk_) — например, получение списка инвойсов. Вызовите его Payment-ключом.
payout_key_required 403 Эндпоинту нужен Payout-ключ (rk_), а запрос пришёл с Payment-ключом (pk_). Так отвечает любая операция с выводами и чтение балансов. Вызовите его Payout-ключом. Учтите: Payout-ключу нужен ещё и белый список IP, иначе он не работает.
internal_error 500 Непредвиденная ошибка или баг на нашей стороне. Повторите один раз. Если не проходит — обратитесь в поддержку и укажите время ответа.
validation_failed 400 Запрос не прошёл валидацию, но кода под конкретное поле не нашлось. Смотрите поле detail — там написано, что отклонено.

Аутентификация

Возвращается только на 401 Unauthorized от обработчика HMAC. Каждый код указывает на конкретную точку отказа — клиент может показать осмысленное сообщение вместо общего «auth failed».

Code HTTP Когда Что делать
unauthorized 401 Запасной код, когда не подошёл ни один из кодов ниже — обычно запрос к эндпоинту с обязательной аутентификацией без заголовка Authorization (или с нераспознанной схемой). Отправьте корректный заголовок HMAC Authorization; проверьте всю сборку подписи.
authorization_missing 401 Заголовок Authorization есть, но его значение пустое. Отправьте полный заголовок Authorization: HMAC-SHA256 {apiKeyId}:{base64signature}.
authorization_malformed 401 Заголовок есть, но его формат нарушен: схема распознана, но в учётных данных нет двоеточия, не разбирается id API-ключа или пустая подпись. Соберите заголовок по разделу «Аутентификация»; чаще всего — опечатка в id API-ключа.
timestamp_missing 401 Заголовок X-Request-Timestamp отсутствует или не разбирается как положительное целое. Передайте текущую Unix-метку в секундах.
timestamp_expired 401 Метка вышла за допустимое окно расхождения часов (по умолчанию ±5 минут — слишком в прошлом или слишком в будущем). Синхронизируйте часы по NTP; пересчитайте подпись со свежей меткой.
invalid_credentials 401 Ключ использовать нельзя: id не найден, ключ отозван, префикс окружения или типа не совпадает с сохранённым ключом либо подпись не сходится. Один код на все четыре случая — намеренно: разные ответы позволили бы тому, у кого нет секрета, выяснить, какие id ключей существуют. Проверьте, что id ключа верный и ключ активен, а подпись считается секретом того же ключа. Чаще всего причина в подписи: сверьте сборку строки для подписи ({ts}\n{METHOD}\n{path}\n{query}\n{bodyHash}) и то, что для пустого тела bodyHash — пустая строка (не хешируйте пустую строку).
ip_not_allowed 401 Для Payout-ключа задан белый список IP, и адрес клиента в него не входит. Проверка по IP есть только у Payout-ключей — Payment-ключи вызываются с любого адреса. Идёт после успешной подписи, поэтому корректная подпись с «не той» сети всё равно вернёт 401. Добавьте IP клиента (или его CIDR-блок) в белый список Payout-ключа в дашборде.
payout_whitelist_required 401 У только что созданного Payout-ключа ещё не задан белый список IP. Payout-ключи остаются неактивными, пока мерчант не добавит хотя бы один разрешённый IP — код отделён от ip_not_allowed, чтобы клиент мог отличить «не настроены параметры в дашборде» от «не тот адрес-источник». Откройте дашборд, перейдите на страницу API-ключей и добавьте хотя бы один IP или CIDR в белый список Payout-ключа.

Лимит запросов

Возвращается при 429 Too Many Requests, когда запрос превышает лимит для мерчанта. Окно — одна секунда, и лимит общий для всех ваших API-ключей: своего бюджета у ключа нет. Перед API работает ещё одно ограничение, по IP-адресу; здесь описан лимит мерчанта.

Code HTTP Когда Что делать
rate_limited 429 Превышен лимит запросов для мерчанта. Действуют два лимита: общий на все эндпоинты (по умолчанию 30 запросов в секунду) и строже — на создание инвойса, POST /v1/invoices (по умолчанию 5 запросов в секунду). Какой из двух лимитов сработал, ответ не сообщает — в нём приходит только пауза до следующей попытки. Прочитайте заголовок Retry-After (пауза в секундах) и повторите запрос после неё. Большинство HTTP-клиентов с повторами учитывают Retry-After автоматически.

Транспорт и системные ошибки

Возвращаются системным обработчиком ошибок, когда запрос не дошёл до обработчика самого эндпоинта.

Code HTTP Когда Что делать
malformed_request 400 Тело запроса не удалось разобрать — повреждённый JSON. Проверьте, что тело — валидный JSON.
payload_too_large 413 Тело запроса превышает лимит в 1 MiB. Отправьте тело меньшего размера; разбейте крупные объёмы на отдельные запросы.
unsupported_media_type 415 Content-Type не application/json. Выставьте Content-Type: application/json.
method_not_allowed 405 Путь существует, но не для этого HTTP-метода. Используйте метод, указанный для эндпоинта (например, POST для создания).
route_not_found 404 Ни один эндпоинт не подходит под этот путь. Сверьте URL со справочником API.

Инвойсы

Code HTTP Когда Что делать
invoice_not_found 404 Инвойс с таким id не существует или принадлежит другому мерчанту. Используйте id, возвращённый POST /v1/invoices, без изменений.
project_not_found 404 project_id в запросе на создание инвойса не существует или не виден вызывающему. Используйте project id из дашборда (проект должен быть активен и принадлежать тому же мерчанту, что и API-ключ).
invoice_terminal 410 confirm-payment вызван на инвойсе со статусом expired или cancelled. (Инвойс paid возвращает invoice_not_awaiting_client, 409, а не этот код.) Обновите статус инвойса; делать больше нечего.
invoice_deadline_passed 410 confirm-payment вызван после истечения срока инвойса. Создайте новый инвойс.
requested_amount_invalid 400 amount в запросе на создание инвойса отсутствует, не разбирается, выходит за поддерживаемый диапазон десятичных значений или не положителен. Передайте amount положительной десятичной строкой вместе с выбранной currency и при необходимости — network.
invoice_amount_below_minimum 400 USD-эквивалент инвойса ниже минимума для токена/сети из каталога. Увеличьте сумму выше минимума, возвращённого для выбранного токена.
deposit_amount_exceeds_limit 400 Сумма превышает максимум, допустимый для этого платежа. Проверяется рассчитанная сумма инвойса в момент подтверждения токена и сети, а не фактический приход в блокчейне. Уменьшите сумму инвойса; если так задача не решается, напишите в поддержку.
currency_not_enabled_for_project 400 Запрошенная криптовалюта не входит в enabled_tokens проекта (ни в одной сети). Включите валюту в проекте либо выберите из enabled_tokens.
tokens_required 409 Создание инвойса или подтверждение платежа для проекта, где не включён ни один токен. Включите в проекте хотя бы один токен через дашборд.
acceptance_disabled 503 Запрошенный токен сейчас не принимается. Используйте другой токен или попробуйте позже.
exchange_rate_unavailable 503 Нет свежего курса для пары токен/фиат. Повторите запрос; курсы обновляются часто.
network_unavailable 503 При автоподтверждении не удалось использовать выбранную сеть. Откажитесь от автоподтверждения; дайте клиенту выбрать токен на странице оплаты Paymos.
payment_method_unavailable 503 Выбранный токен или сеть сейчас не принимают платёж. С 23.08.2026 заменяет no_available_address, address_lease_failed и bridge_unavailable. Повторите запрос или дайте клиенту выбрать другой токен либо сеть.
client_confirmation_failed 409 Подтверждение со стороны клиента (выбор токена, автоподтверждение) отклонено. detail содержит причину. Смотрите detail; типично — инвойс уже не в awaiting_client или токен не разрешён.
invoice_not_awaiting_client 409 confirm-payment вызван на инвойсе, уже вышедшем из awaiting_client. Обновите статус инвойса; клиент уже прошёл выбор.
invoice_cannot_be_cancelled 409 Инвойс уже не в awaiting_client — клиент выбрал токен либо инвойс уже paid или expired. Повторная отмена уже отменённого инвойса возвращает 200, а не эту ошибку. Проверьте статус; отмена работает только в awaiting_client.
simulate_payment_failed 409 Вызов simulate_payment для тестового режима отклонён. Смотрите detail; обычно — несоответствие статуса или суммы.
not_sandbox 403 simulate-payment вызван для инвойса рабочего режима. Симуляция доступна только для тестового инвойса. По рабочему отправьте реальный перевод в выбранной сети.

Инвойсы через виджет

Эти коды возвращает эндпоинт POST /public/v1/sdk — создание инвойса через Low-Code SDK.

Code HTTP Когда Что делать
widget_key_missing 401 Заголовок X-Sdk-Key отсутствует или пуст на эндпоинте, где нужна авторизация виджета. Передайте публичный SDK-ключ в заголовке X-Sdk-Key.
widget_key_invalid 401 X-Sdk-Key передан, но не распознаётся как идентификатор ключа Paymos. Скопируйте ключ из дашборда; проверьте префикс и что в значение не попали лишние пробелы или URL-кодирование.
widget_key_not_found 401 Ключ распознан, но активной записи за ним нет: он отозван, удалён или это не Payment-ключ (ключи Payout виджетом не управляют). Возьмите активный Payment-ключ из дашборда.
widget_inactive 403 Виджет проекта выключен или ещё ни разу не был инициализирован. Включите виджет в настройках проекта.
terminal_not_enabled 403 Запрос пришёл с source=terminal, но способ подключения проекта — не «Терминал». Создайте проект типа «Терминал» либо передавайте source=embed из Low-Code-проекта.
embed_not_enabled 403 Запрос пришёл с source=embed, но способ подключения проекта — не Low-Code. Используйте способ подключения самого проекта либо создайте Low-Code-проект.
origin_not_allowed 401 Браузерный Origin не входит в список разрешённых доменов. Проверок две — на уровне авторизации origin сверяется с объединённым списком всех проектов ключа с активным виджетом, затем обработчик сверяет его с конкретным проектом запроса, — и обе отвечают одинаково: тот же 401, тот же код, тот же detail. Это сделано намеренно. Другой статус на второй проверке подсказал бы владельцу ключа pk_ (он публичный, его нетрудно вытащить со страницы), что домен зарегистрирован в другом проекте того же мерчанта, и тестовые хосты и невыпущенные бренды можно было бы перебрать по одному запросу за раз. Впишите домен в поле Разрешённый origin проекта. Значение одно, не список: под второй домен нужен второй проект. Запросы с того же домена, откуда отдаётся платёжная страница — например, с POS-терминала на том же хосте, — проверку пропускают.

Платёжные каналы

Code HTTP Когда Что делать
payment_channels_disabled 503 Платёжные каналы не включены для вашего аккаунта в этой среде. Так отвечают все методы каналов и депозитов, включая симулятор песочницы. Обратитесь в поддержку для подключения. Повтор запроса ответ не изменит.
payment_channel_not_found 404 Идентификатор pc_ не соответствует ничему, доступному этому ключу: канала нет, он принадлежит другому мерчанту, находится в другой среде или в проекте вне области видимости ключа. Все четыре случая намеренно неразличимы. Используйте id, возвращённый POST /v1/payment-channels, без изменений и подписывайте ключом той же среды и того же проекта.
payment_channel_deposit_not_found 404 Идентификатор pcd_ не соответствует ничему, доступному этому ключу. Причины те же четыре. Используйте id из payload вебхука или из ленты без изменений.
payment_channel_external_id_invalid 400 external_id пуст, состоит из пробелов или длиннее 128 символов — при создании либо как фильтр списка. Передайте непустой идентификатор длиной не более 128 символов.
payment_channel_project_has_no_supported_tokens 409 В проекте не включён ни один токен, который платёжный канал мог бы принимать, поэтому у канала не будет ни одного маршрута. Включите в проекте хотя бы один поддерживаемый токен и создайте канал заново.
payment_channel_simulation_sandbox_only 403 simulate-deposit вызван для канала рабочей среды. Симуляция существует только для каналов песочницы. Канал рабочей среды проверяется настоящим переводом.
payment_key_required 403 Запрос подписан ключом выплат (rk_). Доступ к каналам даёт ключ Payment — так же, как выплаты работают через ключ Payout. Подпишите запрос ключом pk_ той же среды.
pagination_cursor_invalid 400 Курсор списка или ленты повреждён, старше 24 часов или выдан для других фильтров; для ленты — также для другого мерчанта, среды или набора проектов. Начните с первой страницы. Дедупликация по pcd_ делает полную пересинхронизацию безвредной.
currency_not_enabled_for_project 400 Токен, переданный в simulate-deposit, не включён в проекте. Включите его в проекте или выберите тот, который канал уже возвращает в networks[].tokens.
acceptance_disabled 503 Приём указанного токена сейчас отключён на уровне платформы. Используйте другой токен или дождитесь включения приёма.
amount_too_many_decimals 400 В сумме симуляции больше знаков после запятой, чем поддерживает токен. Деньги мерчанта не округляются молча до другого числа. Округлите сумму до точности токена перед отправкой.

Выводы

Code HTTP Когда Что делать
withdrawal_not_found 404 Вывода с таким id нет либо он принадлежит другому мерчанту. Используйте id, который вернул POST /v1/withdrawals, без изменений.
insufficient_balance 409 Доступный баланс мерчанта ниже amount + fee. Пополните баланс или уменьшите сумму вывода.
whitelist_required 403 Адрес назначения не добавлен в белый список для выбранной сети. (Сеть белый список поддерживает — просто этот адрес ещё не внесён.) Добавьте адрес в белый список и повторите запрос.
destination_address_invalid 400 Адрес не проходит проверку формата или контрольной суммы для этой сети. Сверьте адрес со спецификацией сети.
withdrawal_amount_below_minimum 400 Сумма ниже минимума для выбранного токена. Увеличьте сумму выше минимума (возвращается в detail).
withdrawal_quota_exceeded 409 Достигнут лимит активных выводов. Дождитесь завершения текущих или запросите повышение лимита.
withdrawal_amount_exceeds_limit 400 USD-эквивалент тела вывода превышает лимит на одну выплату по вашему аккаунту. Считается по телу вывода, комиссия сети в эту сумму не входит. Уменьшите сумму или запросите повышение лимита в поддержке.
exchange_rate_unavailable 503 Чтобы сверить сумму вывода с лимитом аккаунта, нужен свежий курс токен/USD, а его в этот момент нет. Лимит не подтвердить, поэтому запрос отклоняется. Повторите запрос; курсы обновляются часто.
withdrawal_not_enabled 400 Paymos не выводит запрошенную пару токен/сеть. Пара названа в detail — например Withdrawals are not available for USDT on TRC20. Набор пар, доступных для вывода, задаётся на стороне Paymos. Выведите токен в сети, по которой Paymos делает выплаты, либо спросите в поддержке про нужную пару.
withdrawal_cannot_be_cancelled 409 Вывод уже вышел из состояния, в котором его можно отменить. Проверьте текущий статус. Окно закрывается, когда начинается исполнение, — ещё внутри created, до всякого подписания.
withdrawal_simulation_failed 409 Вызов simulate_completion для тестового режима отклонён. Смотрите detail.
merchant_suspended 403 Мерчант приостановлен для исходящих операций, поэтому создать вывод нельзя. Обратитесь в поддержку, чтобы снять приостановку.
outbound_frozen 503 Исходящие операции заморожены — либо на всей платформе, либо для той сети и токена, в которых вы выводите. Дождитесь снятия, попробуйте другую сеть или токен либо обратитесь в поддержку.
withdrawal_network_unavailable 503 Вывод этого токена в этой сети сейчас провести нельзя. Попробуйте другую сеть назначения или повторите позже.

Состояние проекта

Возвращается при создании инвойса или подтверждении платежа, если статус проекта не позволяет их выпускать.

Code HTTP Когда Что делать
project_state_invalid 409 Проект не в статусе Active — он Suspended или Archived. Какой именно, ответ не сообщает. Посмотрите статус проекта в дашборде: архивный — восстановите, приостановленный — активируйте. Либо отправьте запрос в уже активный проект.