> ## Documentation Index
> Fetch the complete documentation index at: https://wallet-docs.iexexchanger.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Ошибки

> Единый формат ответа, маппинг HTTP-статусов и полный справочник кодов ошибок

Все ответы API возвращаются в едином конверте (envelope). Ошибки имеют машинно-читаемый
`error.code` — именно на него опирайтесь в коде интеграции, а не на текст `message`.

## Формат конверта

<CodeGroup>
  ```json Успех theme={null}
  {
    "ok": true,
    "data": { /* полезная нагрузка эндпоинта */ }
  }
  ```

  ```json Ошибка theme={null}
  {
    "ok": false,
    "error": {
      "code": "INVALID_SIGNATURE",
      "message": "X-Signature mismatch",
      "details": { /* опционально, доп. контекст */ },
      "traceId": "8f3c2a1e-..."
    }
  }
  ```
</CodeGroup>

<ResponseField name="ok" type="boolean">
  `false` для любой ошибки. Проверяйте это поле перед чтением `data`.
</ResponseField>

<ResponseField name="error.code" type="string">
  Стабильный машинно-читаемый код. Ветвите логику обработки по нему.
</ResponseField>

<ResponseField name="error.message" type="string">
  Человекочитаемое пояснение. Текст может меняться между релизами — не парсите его.
</ResponseField>

<ResponseField name="error.details" type="object">
  Опциональный объект с контекстом. Например, для `STATUS_TRANSITION_NOT_ALLOWED` —
  `{ entity, from, to }`; для `VALIDATION_FAILED` — `{ errors: [...] }`.
</ResponseField>

<ResponseField name="error.traceId" type="string">
  Идентификатор трассировки. Присутствует, когда запрос дошёл до платформы. Указывайте его
  при обращении в поддержку — по нему оператор найдёт запрос в логах.
</ResponseField>

<Warning>
  Для ошибок `5xx` в production-режиме платформа намеренно скрывает внутренний `message`
  (`"Internal server error"`) и не возвращает `details` — это защита от утечки внутренней
  информации. Опирайтесь на `error.code` и `traceId`.
</Warning>

## HTTP-статус и код ошибки

HTTP-статус задаёт семейство ошибки, а `error.code` уточняет причину. Базовый маппинг,
когда конкретный код не выставлен явно:

| HTTP                        | Код по умолчанию    | Семантика                            |
| --------------------------- | ------------------- | ------------------------------------ |
| `400 Bad Request`           | `VALIDATION_FAILED` | запрос некорректен                   |
| `401 Unauthorized`          | `UNAUTHORIZED`      | не аутентифицирован                  |
| `403 Forbidden`             | `PERMISSION_DENIED` | аутентифицирован, но доступ запрещён |
| `404 Not Found`             | `NOT_FOUND`         | ресурс не найден                     |
| `409 Conflict`              | `ALREADY_PROCESSED` | конфликт состояния                   |
| `422 Unprocessable Entity`  | `VALIDATION_FAILED` | бизнес-правило не выполнено          |
| `429 Too Many Requests`     | `RATE_LIMITED`      | превышен лимит запросов              |
| `503 Service Unavailable`   | `MAINTENANCE_MODE`  | сервис временно недоступен           |
| `500 Internal Server Error` | `INTERNAL_ERROR`    | внутренняя ошибка                    |

## Справочник кодов

Ниже — полный каталог кодов, которые может вернуть Public API, сгруппированный по семейству.

### Аутентификация и подпись (400 / 401 / 403)

| Код                  | HTTP | Значение                                                                                                 | Как устранить                                                                            |
| -------------------- | ---- | -------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- |
| `UNAUTHORIZED`       | 401  | Нет `X-Api-Id` / `X-Signature` / `X-Timestamp`, ключ не найден, неактивен или сайт не в статусе `active` | Проверьте, что присланы все три заголовка и ключ активен в личном кабинете               |
| `INVALID_SIGNATURE`  | 401  | `X-Signature` не совпала с ожидаемой                                                                     | Чаще всего подписаны не те байты тела. См. [Аутентификация](/authentication)             |
| `TIMESTAMP_SKEW`     | 401  | `X-Timestamp` вне диапазона ±300 секунд от времени сервера                                               | Синхронизируйте часы (NTP) и берите время непосредственно перед запросом                 |
| `IP_NOT_WHITELISTED` | 403  | IP запроса не входит в белый список сайта                                                                | Добавьте исходящий IP сервера обменника в whitelist                                      |
| `API_KEY_REVOKED`    | 403  | Ключ отозван оператором                                                                                  | Выпустите новый ключ в личном кабинете                                                   |
| `PERMISSION_DENIED`  | 403  | У ключа недостаточно прав для операции (например, ключ со scope `deposit_only` пытается создать выплату) | Используйте ключ с подходящим scope                                                      |
| `LICENSE_REQUIRED`   | 403  | Лицензия инстанса не активирована                                                                        | Обратитесь к оператору инстанса (затрагивает создание сущностей, не уже идущие операции) |

### Идемпотентность и конфликты (409)

| Код                             | HTTP | Значение                                                                                                                                                                                                                                       | Как устранить                                                                                                                     |
| ------------------------------- | ---- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- |
| `DUPLICATE_ORDER_ID`            | 409  | `order_id` уже использован в рамках сайта (строгий режим по умолчанию)                                                                                                                                                                         | Используйте новый `order_id` для новой заявки; для безопасных повторов — `X-Idempotency-Key`. См. [Идемпотентность](/idempotency) |
| `IDEMPOTENCY_CONFLICT`          | 409  | Конфликт идемпотентного ключа (зарезервированный код). На стандартном создании депозита/выплаты НЕ возникает: повтор с тем же `X-Idempotency-Key` возвращает первый сохранённый результат без сверки тела. См. [Идемпотентность](/idempotency) | Не переиспользуйте один ключ для разных запросов                                                                                  |
| `ALREADY_PROCESSED`             | 409  | Операция уже обработана / ресурс уже существует                                                                                                                                                                                                | Запросите текущее состояние ресурса и не повторяйте операцию                                                                      |
| `STATUS_TRANSITION_NOT_ALLOWED` | 409  | Недопустимый переход статуса (`details: { entity, from, to }`)                                                                                                                                                                                 | Сверьтесь со схемой статусов депозита/выплаты                                                                                     |
| `ROTATION_IN_PROGRESS`          | 409  | Идёт ротация ключа/секрета                                                                                                                                                                                                                     | Повторите запрос после завершения ротации                                                                                         |
| `APPROVAL_QUORUM_NOT_MET`       | 409  | Не набран кворум подтверждений (внутренний апрув выплаты)                                                                                                                                                                                      | Дождитесь подтверждения операторами на стороне инстанса                                                                           |

### Не найдено (404)

| Код                  | HTTP | Значение                                               | Как устранить                                           |
| -------------------- | ---- | ------------------------------------------------------ | ------------------------------------------------------- |
| `NOT_FOUND`          | 404  | Ресурс не найден                                       | Проверьте `uuid` / путь                                 |
| `DEPOSIT_NOT_FOUND`  | 404  | Депозит не найден (в т.ч. принадлежащий другому сайту) | Проверьте `uuid` депозита и что он создан этим сайтом   |
| `PAYOUT_NOT_FOUND`   | 404  | Выплата не найдена                                     | Проверьте `uuid` выплаты                                |
| `SITE_NOT_FOUND`     | 404  | Сайт не найден                                         | Сверьтесь с оператором                                  |
| `PROVIDER_NOT_FOUND` | 404  | Провайдер не найден                                    | Внутренняя ошибка конфигурации — обратитесь к оператору |
| `SECRET_NOT_FOUND`   | 404  | Секрет/ключ не найден                                  | Проверьте конфигурацию ключа                            |

### Валидация входных данных (400 / 404 / 422)

| Код                        | HTTP    | Значение                                                                  | Как устранить                                                             |
| -------------------------- | ------- | ------------------------------------------------------------------------- | ------------------------------------------------------------------------- |
| `VALIDATION_FAILED`        | 400/422 | Тело запроса не прошло валидацию (`details.errors` содержит список полей) | Исправьте перечисленные поля                                              |
| `INVALID_AMOUNT`           | 400     | Некорректная сумма (нечисловая, отрицательная, ноль)                      | Передавайте сумму строкой, положительным числом                           |
| `AMOUNT_TOO_MANY_DECIMALS` | 400     | Знаков после запятой больше, чем поддерживает актив (`asset.decimals`)    | Округлите до точности актива (например, 6 для USDT\_TRC20, 8 для BTC/LTC) |
| `INVALID_ADDRESS`          | 400     | Некорректный адрес получателя для выбранной сети                          | Проверьте формат адреса сети                                              |
| `INVALID_MEMO`             | 400     | Некорректный memo/comment (memo-based сети, например TON)                 | Проверьте формат memo                                                     |
| `INVALID_NETWORK`          | 400     | Неизвестная или отключённая сеть                                          | Берите `code` сети из `GET /v1/public/networks`                           |
| `INVALID_ASSET`            | 404     | Неизвестный актив (не найден в каталоге)                                  | Берите `code` актива из `GET /v1/public/assets`                           |
| `INVALID_SYSTEM_WALLET`    | 400     | Некорректная ссылка на системный кошелёк                                  | Внутренняя ошибка конфигурации — к оператору                              |

### Бизнес-лимиты: суммы, баланс, комиссии (409 / 422)

| Код                               | HTTP | Значение                                              | Как устранить                                                              |
| --------------------------------- | ---- | ----------------------------------------------------- | -------------------------------------------------------------------------- |
| `AMOUNT_BELOW_MINIMUM`            | 409  | Сумма меньше минимума по активу                       | Сверьтесь с `minDeposit` / `minPayout` из `GET /v1/public/assets`          |
| `AMOUNT_ABOVE_MAXIMUM`            | 422  | Сумма больше максимума                                | Уменьшите сумму или разбейте на несколько операций                         |
| `INSUFFICIENT_HOT_WALLET_BALANCE` | 422  | Не хватает средств на hot-кошельке для выплаты        | Сверьтесь с `GET /v1/public/balances` перед выплатой                       |
| `INSUFFICIENT_NETWORK_FEE_BUDGET` | 422  | Не хватает нативной валюты на комиссию сети           | Пополните бюджет комиссии (на стороне инстанса)                            |
| `INSUFFICIENT_TRON_ENERGY`        | 422  | Не хватает energy для TRC-20 перевода                 | Платформа управляет energy сама; при повторе обратитесь к оператору        |
| `FEE_EXCEEDS_CEILING`             | 422  | Оценённая комиссия сети превысила настроенный потолок | Повторите позже (комиссия сети спадёт) или согласуйте потолок с оператором |

### Политики выплат (400 / 422)

| Код                              | HTTP | Значение                                                                                                        | Как устранить                                                                 |
| -------------------------------- | ---- | --------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------- |
| `PAYOUT_NOT_ALLOWED`             | 422  | Выплата запрещена политикой инстанса                                                                            | Уточните политику выплат у оператора                                          |
| `PAYOUT_DESTINATION_BLACKLISTED` | 400  | Адрес получателя в чёрном списке (санкции/мошенничество) — выплата запрещена                                    | Адрес заблокирован оператором; используйте другой адрес получателя            |
| `PAYOUT_WHITELIST_REJECT`        | 400  | Адрес получателя не в whitelist выплат (режим enforced)                                                         | Добавьте адрес в whitelist выплат (если он используется)                      |
| `PAYOUT_VELOCITY_REJECT`         | 400  | Сработал лимит частоты/объёма выплат                                                                            | Снизьте темп; повторите позже                                                 |
| `PAYOUT_DUPLICATE_SUSPECTED`     | 422  | Похоже на случайный дубль выплаты (та же пара адрес+сумма+актив за короткое окно) без согласованного `order_id` | Для намеренного повтора задайте уникальный `order_id` или `X-Idempotency-Key` |

### Платформа и доступность (429 / 503 / 5xx)

| Код                    | HTTP | Значение                                                     | Как устранить                                                                   |
| ---------------------- | ---- | ------------------------------------------------------------ | ------------------------------------------------------------------------------- |
| `RATE_LIMITED`         | 429  | Превышен лимит запросов                                      | Уважайте `Retry-After`, применяйте backoff. См. [Лимиты запросов](/rate-limits) |
| `MAINTENANCE_MODE`     | 503  | Инстанс на обслуживании                                      | Повторите позже                                                                 |
| `READ_ONLY_MODE`       | 422  | Включён режим «только чтение» (write-операции заблокированы) | Повторите создание позже; чтение доступно                                       |
| `NETWORK_DISABLED`     | 409  | Сеть временно отключена оператором                           | Выберите другую сеть/актив или дождитесь включения                              |
| `NO_ACTIVE_PROVIDERS`  | 422  | Нет доступных блокчейн-провайдеров для сети                  | Повторите позже; при стойком повторе — к оператору                              |
| `KEYSTORE_LOCKED`      | 503  | Keystore временно заперт (ожидает разблокировки оператором)  | Повторите позже                                                                 |
| `PROVIDER_UNAVAILABLE` | 5xx  | Блокчейн-провайдер недоступен                                | Повторите с backoff                                                             |
| `PROVIDER_DEGRADED`    | 5xx  | Провайдер деградировал                                       | Повторите позже                                                                 |
| `ALL_PROVIDERS_FAILED` | 5xx  | Все провайдеры сети недоступны                               | Повторите позже; при стойком повторе — к оператору                              |
| `INTERNAL_ERROR`       | 500  | Внутренняя ошибка                                            | Повторите позже, сохраните `traceId` для поддержки                              |
| `DATABASE_ERROR`       | 500  | Ошибка БД                                                    | Повторите позже, сохраните `traceId`                                            |
| `KEYSTORE_ERROR`       | 500  | Ошибка keystore                                              | Повторите позже, сохраните `traceId`                                            |

## Обработка ошибок в коде

Ветвитесь по `error.code`, а 5xx и 429 — повторяйте с экспоненциальным backoff.

<CodeGroup>
  ```javascript Node.js theme={null}
  async function callApi(req) {
    const res = await fetch(req.url, req.options);
    const env = await res.json();

    if (env.ok) return env.data;

    const { code, message, traceId } = env.error;
    switch (code) {
      case 'TIMESTAMP_SKEW':
        throw new Error('Часы рассинхронизированы — синхронизируйте NTP');
      case 'DUPLICATE_ORDER_ID':
        // Заявка с таким order_id уже создана — найдите её
        return findByOrderId(req.orderId);
      case 'RATE_LIMITED':
        // Уважаем Retry-After и повторяем
        await sleep(Number(res.headers.get('Retry-After') ?? 1) * 1000);
        return callApi(req);
      case 'INTERNAL_ERROR':
      case 'DATABASE_ERROR':
      case 'PROVIDER_UNAVAILABLE':
      case 'ALL_PROVIDERS_FAILED':
        // Транзиентные — повтор с backoff (см. ниже)
        throw new RetryableError(code, traceId);
      default:
        // Клиентские ошибки — чинить запрос, не повторять
        throw new Error(`${code}: ${message}`);
    }
  }
  ```

  ```bash cURL theme={null}
  # Любой ответ — это конверт; парсите .ok и .error.code
  curl -sS https://wallet.your-exchange.com/v1/public/deposits/by-order-id/ord-20260626-0042 \
    -H "X-Api-Id: $API_ID" -H "X-Timestamp: $TS" -H "X-Signature: $SIG" \
    | jq 'if .ok then .data else .error.code end'
  ```
</CodeGroup>

<Note>
  Транзиентные коды (`INTERNAL_ERROR`, `DATABASE_ERROR`, `PROVIDER_UNAVAILABLE`,
  `PROVIDER_DEGRADED`, `ALL_PROVIDERS_FAILED`, `RATE_LIMITED`, `MAINTENANCE_MODE`) безопасно
  повторять — особенно если вы прислали `X-Idempotency-Key`, повтор не создаст дубликат.
  Клиентские коды (`VALIDATION_FAILED`, `INVALID_*`, `DUPLICATE_ORDER_ID`,
  `AMOUNT_*`) повторять бессмысленно — сначала исправьте запрос.
</Note>

## Частые вопросы

<AccordionGroup>
  <Accordion title="Почему всё время INVALID_SIGNATURE, хотя секрет верный?" icon="signature">
    Подписывается **сырое тело** запроса — ровно те байты, что уходят на сервер. Если вы
    сериализуете JSON один раз для подписи, а второй раз (с другими пробелами/порядком ключей)
    для отправки — подпись не сойдётся. Сериализуйте один раз и подписывайте именно эту строку.
    Подробнее — [Аутентификация](/authentication).
  </Accordion>

  <Accordion title="В чём разница между DUPLICATE_ORDER_ID и IDEMPOTENCY_CONFLICT?" icon="copy">
    `DUPLICATE_ORDER_ID` — вы повторно использовали `order_id`, уже занятый другой заявкой
    (строгий режим). `IDEMPOTENCY_CONFLICT` — вы прислали тот же `X-Idempotency-Key`, но с
    другим телом запроса. Первое лечится новым `order_id`, второе — новым ключом либо повтором
    ровно того же тела. См. [Идемпотентность](/idempotency).
  </Accordion>

  <Accordion title="Что делать при 5xx?" icon="rotate">
    Повторяйте с экспоненциальным backoff. Если вы прислали `X-Idempotency-Key`, повтор не
    создаст дубликат. Сохраните `error.traceId` — по нему оператор найдёт запрос в логах инстанса.
  </Accordion>

  <Accordion title="Можно ли полагаться на текст error.message?" icon="text">
    Нет. `message` предназначен для людей и может меняться. Ветвите логику только по
    `error.code` — он стабилен.
  </Accordion>
</AccordionGroup>

<Tip>
  Связанные страницы: [Аутентификация](/authentication), [Идемпотентность](/idempotency),
  [Лимиты запросов](/rate-limits), [Частые вопросы](/faq).
</Tip>
