--- title: "Коды ошибок" url: "https://docs.x-hub.online/reference/errors/" description: "Коды ошибок API и что делать по каждому." relatedDocuments: - "https://docs.x-hub.online/reference/nodejs/" - "https://docs.x-hub.online/reference/python/" - "https://docs.x-hub.online/reference/faq/" - "https://docs.x-hub.online/payments/" - "https://docs.x-hub.online/exchange/kyc/" - "https://docs.x-hub.online/money/withdrawals/" - "https://docs.x-hub.online/exchange-terminal/" - "https://docs.x-hub.online/subscriptions/" - "https://docs.x-hub.online/start/auth/" - "https://docs.x-hub.online/subscriptions/api/" - "https://docs.x-hub.online/payments/refunds/" --- # Ошибки ## Формат ```json { "error": { "code": "PAYMENT_NOT_FOUND", "message": "Payment with id 'pay_xxx' not found", "details": {} } } ``` ## Таблица | HTTP | Code | Когда | Что делать | |---|---|---|---| | 400 | `VALIDATION_ERROR` | Невалидные параметры запроса. Отдельный случай с HTTP `422` — `client_phone` в `POST /payments` не в формате E.164: ожидается «+» и 10–15 цифр после него. Ещё один случай с `422` — значение в объекте `payer` не прошло правила полей, `path` вида `payer.full_name`; форма самого объекта (не объект, нет обязательного поля, лишний ключ) — обычный `400`, см. [объект `payer`](../payments/index.md#payer-object) | Проверь `details`, исправь запрос. Для телефона — приведи его к E.164 и повтори запрос | | 400 | `INVALID_JSON` | Тело запроса — не валидный JSON. Проверка тела идёт до авторизации, поэтому код приходит и на невалидных ключах | Пошли корректный JSON с заголовком `Content-Type: application/json` | | 400 | `MISSING_IDEMPOTENCY_KEY` | Нет заголовка `Idempotency-Key` на POST | Добавь UUID | | 400 | `KYC_REQUIRED` | Клиент не прошёл KYC (если для аккаунта настроена KYC-проверка) | Отправь клиента на KYC-верификацию | | 400 | `KYC_PROCESSING` | KYC-верификация ещё обрабатывается | Повтори через несколько минут | | 400 | `KYC_FAILED` | KYC-верификация отклонена | Клиент должен пройти KYC заново | | 400 | `KYC_NOT_REQUIRED` | Вызов KYC-эндпоинта, когда KYC не настроен для аккаунта | KYC не нужен, просто создавай платёж | | 502 | `KYC_PROVIDER_ERROR` | Проверяющая сторона не ответила при **создании платежа** (не при вызове `/kyc/*`) | Временная ошибка. Ретрай через 30–60 сек с тем же `Idempotency-Key` | | 403 | `PROVIDER_DISABLED` | KYC для твоего аккаунта отключён. Возвращают **все** `/kyc/*` — до любых других проверок | Ретрай не поможет — свяжись с X-Hub. См. [Ошибки KYC](../exchange/kyc.md#kyc-errors) | | 403 | `QR_PAYMENTS_DISABLED` | Аккаунт настроен **только на рекуррентные списания** — разовые платежи по QR ему запрещены | Не создавай `POST /payments`; работай через `/subscriptions`. Нужен приём разовых — напиши в X-Hub | | 400 | `CARD_NOT_SUPPORTED` | Запрошен `payment_method: "card"`, а приём карт твоему аккаунту не подключён. Платёж не создаётся | Создавай платёж с `payment_method: "sbp"`. Нужен приём карт — напиши в X-Hub, это настройка аккаунта, флагом в запросе не включается. Подробнее — [оплата картой](../payments/index.md#card-payment) | | 400 | `PAYMENT_ROUTE_UNAVAILABLE` | На `POST /payments`: для запрошенного способа оплаты у твоего аккаунта нет рабочего маршрута — например, способу оплаты не назначен терминал. Платёж не создаётся. Редкий вариант — тот же код с HTTP `503`: маршрут не удалось проверить из-за временного сбоя на нашей стороне | `400` — ретрай не поможет, пока не изменится настройка аккаунта: напиши в X-Hub. `503` — временный сбой: ретрай через 30–60 сек с тем же `Idempotency-Key`. Подробнее — [отказы при создании платежа](../payments/index.md#create-refusals) | | 422 | `PAYMENT_UNAVAILABLE` | На `POST /payments`: приём по этому способу оплаты для твоего аккаунта сейчас недоступен. Платёж не создаётся. Слово «temporarily» в `message` значит «до изменения настройки на стороне X-Hub», а не «через минуту» | Ретрай не поможет — повтор получит тот же ответ. Напиши в X-Hub. Подробнее — [отказы при создании платежа](../payments/index.md#create-refusals) | | 400 | `SANDBOX_NOT_SUPPORTED` | Эндпоинт отключён в sandbox для твоего аккаунта (у части конфигураций — `/kyc/*`) | Тестируй этот флоу в боевом режиме или свяжись с X-Hub | | 400 | `AMOUNT_BELOW_MINIMUM` | Сумма разового платежа (`POST /payments`) ниже минимума — 30 ₽, одинаково для всех аккаунтов. Списания по уже выданному мандату подписки порогу не подчиняются | Увеличь сумму — точное значение минимума приходит в `message` | | 400 | `AMOUNT_TOO_LOW` | Сумма меньше минимальной для операции (пример: обмен < 1000 ₽) | Увеличь сумму | | 400 | `AMOUNT_TOO_HIGH` | Сумма превышает максимум | Разбей на несколько операций или свяжись с X-Hub | | 422 | `CLIENT_NOT_REGISTERED` | Клиент не прошёл KYC-регистрацию для USDT→RUB | Сначала зарегистрируй клиента через `/kyc/register` | | 403 | `CLIENT_BLOCKED` | Аккаунт клиента заблокирован | Свяжись с X-Hub | | 401 | `UNAUTHORIZED` | Неверные `X-Api-Key` / `X-Api-Secret` | Проверь ключи | | 401 | `MODE_MISMATCH` | Ключ не-активного режима (test/live) — активен другой режим | Переключи режим в кабинете или используй ключи активного режима | | 403 | `IP_NOT_WHITELISTED` | IP-адрес не в whitelist мерчанта | Добавь IP в настройках или свяжись с X-Hub | | 404 | `PAYMENT_NOT_FOUND` | Платёж не существует / чужой | Проверь ID | | 404 | `NOT_FOUND` | Обмен не существует / чужой; или такого пути в `/api/v1` нет | Проверь ID и путь | | 410 | `WITHDRAWAL_DISCONTINUED` | Запрос к выведенным из эксплуатации эндпоинтам `/withdrawals` | Ничего не делать — выплаты происходят автоматически, см. [Выплаты](../money/withdrawals.md#vyplaty-avtomaticheskie) | | 409 | `DELIVERY_PROOF_LOCKED` | `POST /payments/:id/delivery-proof`: хэш по платежу уже подтверждён, заменить его через API нельзя | Если хэш передан по ошибке, напиши в X-Hub. См. [хэш перевода клиенту](../exchange-terminal/index.md#step-delivery-proof) | | 409 | `DELIVERY_PROOF_CONFLICT` | `POST /payments/:id/delivery-proof`: хэш изменён параллельным запросом | Прочитай состояние запросом `GET /payments/:id/delivery-proof` и повтори запрос | | 409 | `EXCHANGE_IN_PROGRESS` | Обмен уже в обработке | Дождись финального статуса | | 409 | `INVALID_STATUS` | Операция невалидна для текущего статуса (напр. попытка отменить уже завершённый обмен; хэш перевода клиенту по платежу не в статусе `paid` или `settled`) | Проверь статус перед действием | | 409 | `IDEMPOTENCY_TERMINAL` | Повтор запроса с тем же `idempotency_key` после финального статуса | Используй новый ключ | | 502 | `RATE_INVALID` | Временная ошибка получения курса для обмена | Ретрай через 30-60 сек | | 503 | `PROVIDER_UNAVAILABLE` | Внешняя платёжная система временно недоступна. **Операция могла пройти** — мы не увидели ответ | Ретрай **с тем же `Idempotency-Key`** через 30-60 сек. Второй платёж не создастся | | 503 | `PROVIDER_NOT_CONFIGURED` | Операция для твоего аккаунта сейчас недоступна на стороне X-Hub. Так же сейчас отвечают списания по подпискам в боевом режиме — см. [Подписки](../subscriptions/index.md#subscriptions) | Свяжись с X-Hub. На списаниях по подпискам повтор ответ не изменит | | 503 | `KYC_UNAVAILABLE` | На `/kyc/*`: аккаунту положен KYC, но проверка сейчас недоступна на нашей стороне. Это **не** «KYC не нужен» — не пропускай верификацию клиента | Ретрай через 1–2 мин; если долго — напиши в X-Hub | | 500 | `KYC_PERSIST_FAILED` | На `POST /kyc/register`: проверяющая сторона клиента приняла, но у нас не сохранилась запись об этом (сбой на нашей стороне уже ПОСЛЕ успешного ответа проверяющей стороны) | **Не повторяй запрос с теми же данными** — клиент мог быть создан у проверяющей стороны, повтор для части конфигураций навсегда ломает повторную регистрацию по тому же e-mail/телефону. Напиши в X-Hub с временем запроса и телефоном/e-mail клиента — восстановим вручную | | 503 | `RATE_UNAVAILABLE` | `GET /rates`: источник курса временно недоступен | Ретрай через 30-60 сек | | 404 | `EXCHANGE_RATE_NOT_SUPPORTED` | Запрос курса по способу оплаты: курс не отдаётся ни для одного терминала | Не запрашивай курс — повтор ответ не изменит | | 400 | `FEATURE_NOT_ENABLED` | Опция не подключена **на твоём аккаунте** (например USDT→RUB или KYC; хэш перевода клиенту — по платежу, по которому он не принимается, в том числе в тестовом режиме) | Свяжись с X-Hub для подключения | | 503 | `FEATURE_DISABLED` | Направление временно недоступно **у всех** мерчантов. Твоя интеграция исправна | Подожди и ретрай. В поддержку — если держится долго | | 429 | `RATE_LIMIT_EXCEEDED` | Превышен лимит. Создание платежа: 120 req/min на ключ **или** 120 req/min на IP. Остальные вызовы: 60 req/min на ключ **или** 300 req/min на IP | Жди `Retry-After` секунд, см. [Rate Limiting](../start/auth.md#rate-limiting) | | 500 | `INTERNAL_ERROR` | Серверная ошибка | Ретрай через 30 сек, если повторяется — пиши команде | | 404 | `SUBSCRIPTION_NOT_FOUND` | Подписка не существует / чужая / другого режима | Проверь ID | | 409 | `CHARGE_MANDATE_INACTIVE` | Списание по неактивному мандату (подписка не `active`) | Дождись активации / возобнови подписку | | 409 | `CAP_EXCEEDED` | Списание превышает `cap_amount_rub` или `cap_window_rub` | Уменьши сумму или измени потолки (PATCH) | | 409 | `INVALID_STATE` | Недопустимый lifecycle-переход подписки (pause/resume/cancel) | Проверь текущий `status` | | 501 | `RECURRING_NOT_SUPPORTED` | Подписки недоступны для твоего аккаунта: подписка или списание не создаются | Ретрай не поможет — напиши в X-Hub. См. [Подписки](../subscriptions/index.md#subscriptions) | | 502 | `PROVIDER_ERROR` | Операция отклонена платёжной системой. На `POST /subscriptions` — не удалось инициировать привязку мандата; на `POST /:id/charges` — **отказ по списанию, включая отказ банка**; на `/kyc/*` — проверяющая сторона не ответила | Для привязки и KYC — повтори через 30–60 сек. Для списания это чаще окончательный отказ, см. [Ошибки списания](../subscriptions/api.md#charge-errors) | | 404 | `REFUND_NOT_FOUND` | Заявка на возврат не существует / чужая / из другой среды. Приходит на чтение и на отмену | Проверь ID и режим (test/live) | | 413 | `PAYLOAD_TOO_LARGE` | Тело запроса больше лимита (100 КБ). Проверка тела идёт до авторизации | Уменьши тело запроса, например `metadata` | | 400 | `NOT_REFUNDABLE` | Платёж не в возвратном статусе | Возврат возможен только по оплаченному платежу, см. [Возвраты](../payments/refunds.md#refunds) | | 409 | `CANNOT_CANCEL` | Заявку уже взяли в работу или закрыли | Отменить нельзя — деньги могли уйти. Дождись финального статуса | | 400 | `PARTIAL_DISABLED` | Прислана `amount_rub`, а частичные возвраты выключены | Не присылай сумму — вернётся весь остаток | | 400 | `PARTIAL_BEFORE_SETTLEMENT` | Частичный возврат до ежедневного расчёта по способу оплаты, где начисление идёт по фактическому поступлению | Вернуть полностью или частично после расчёта | | 400 | `OVER_REMAINING` | Сумма больше остатка по платежу | Остаток смотри в `remaining_rub` через `GET /refunds/:id` | | 400 | `INVALID_AMOUNT` | Сумма нулевая или отрицательная | Исправь сумму | | 409 | `LIMIT_PER_PAYMENT` | Больше 10 заявок на один платёж | Разбирайся с уже созданными или пиши команде | | 400 | `SHOP_NOT_FOUND` | Магазина с таким `shop_id` нет в твоём аккаунте (ответ один и для чужого, и для несуществующего) | Проверь `shop_id` в кабинете | | 403 | `SHOP_DISABLED` | Магазин выключен | Включи магазин в кабинете или передай другой | | 422 | `SHOP_MARKUP_NOT_SET` | Магазину ещё не назначена ставка | Напиши в X-Hub | | 422 | `PAYER_DATA_REQUIRED` | На `POST /payments`: выбранный способ оплаты требует данные плательщика (`client_phone` / `client_email` / `description` / `payer`), которых нет в запросе. В `details.missing_fields` — имена недостающих полей; `payer` в списке значит, что объекта `payer` в запросе нет вовсе. Платёж не создаётся. Если `payer` передан, но не прошёл проверку, ответ — `VALIDATION_ERROR` (`400` — форма объекта, `422` — значения полей), а не этот код | Повтори запрос **с тем же `Idempotency-Key`**, добавив недостающие поля: неудачная попытка ключ не расходует. Подробнее — [данные плательщика](../payments/index.md#body) и [объект `payer`](../payments/index.md#payer-object) | | 409 | `IDEMPOTENCY_KEY_REUSED` | Тот же `Idempotency-Key` с другими параметрами. Другой `shop_id` в `POST /subscriptions` даёт этот ответ всегда. На возвратах (`POST /refunds`) действует всегда. На `POST /payments`, `POST /exchanges` и `POST /subscriptions` этот ответ пока не включён: повтор с другими параметрами возвращает исходную операцию. О включении объявим отдельно | Это не ретрай, а ошибка — новая операция требует нового ключа. Используй новый `Idempotency-Key` для каждой новой операции | ## Validation errors При `400 VALIDATION_ERROR` в `details` — массив проблем: ```json { "error": { "code": "VALIDATION_ERROR", "message": "Invalid request body", "details": [ {"path": "amount_rub", "message": "Must be a decimal string with up to 2 decimal places"}, {"path": "payment_method", "message": "Must be 'sbp' or 'card'"} ] } } ``` ## Retry-стратегия | Код | Retry? | Как | |---|---|---| | 4xx | нет | Fix запрос, ретрай не поможет. Исключения — `429` ниже и `403 PROVIDER_DISABLED` / `403 QR_PAYMENTS_DISABLED` (их лечит не ретрай, а обращение в X-Hub) | | 429 | да | Жди `Retry-After` / `X-RateLimit-Reset` | | 500 | да | Exponential backoff: 1s, 2s, 4s, 8s, max 5 попыток. Исключение — `KYC_PERSIST_FAILED`: не повторяй с теми же данными, пиши в поддержку | | 501 | нет | Возможность не подключена — ретрай ничего не изменит | | 502 | зависит | `PROVIDER_ERROR` на привязке мандата и на KYC — ретрай (5s, 15s, 60s). `PROVIDER_ERROR` на **списании** — это отказ, а не сбой: ретрай даст то же самое | | 503 | да | `PROVIDER_UNAVAILABLE` / `PROVIDER_NOT_CONFIGURED` / `FEATURE_DISABLED` / `RATE_UNAVAILABLE` / `PAYMENT_ROUTE_UNAVAILABLE` — backoff 30–60 сек, **обязательно с тем же `Idempotency-Key`**. Исключение — `PROVIDER_NOT_CONFIGURED` на списаниях по подпискам: повтор ответ не изменит, см. [Подписки](../subscriptions/index.md#subscriptions). `KYC_UNAVAILABLE` — backoff 1–2 мин, идемпотентность не нужна (`/kyc/*` без побочных эффектов) | !!! tip "Tip" **Всегда используй Idempotency-Key на ретраях POST** — иначе можно создать дубль платежа. ---