> ## Documentation Index
> Fetch the complete documentation index at: https://oblodai.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Что делать, если не работает — диагностика

Единая точка входа, когда «что‑то пошло не так». Найдите свой **симптом** в таблице и переходите к
разделу с пошаговой диагностикой. Короткие ответы на частые вопросы — в [FAQ](/guides/faq-troubleshooting);
здесь — подробнее и по шагам.

<Note>
  **Первое правило диагностики:** ветвитесь по **коду** ошибки (`error.code`), а не по тексту. Полный
  список кодов с расшифровкой и что делать — [Справочник кодов ошибок](/reference/errors-catalog).
</Note>

***

## Быстрая навигация по симптому

| Симптом                                  | Куда                                                                   |
| ---------------------------------------- | ---------------------------------------------------------------------- |
| Каждый запрос отдаёт `401`               | [Ошибки аутентификации](#ошибки-аутентификации-401/403)                |
| `429` / «rate limit»                     | [Превышен лимит частоты](#превышен-лимит-частоты-429)                  |
| Платёж создался, но `address` пустой     | [Платёж: пустой адрес](#платёж-создался-но-address-пустой)             |
| Покупатель оплатил, а статус не меняется | [Диагностика: платёж «застрял»](#диагностика-платёж-«застрял»)         |
| Вебхук вообще не приходит                | [Диагностика: вебхук не приходит](#диагностика-вебхук-не-приходит)     |
| Вебхук приходит, но подпись не сходится  | [Вебхук: подпись не сходится](#вебхук-приходит-но-подпись-не-сходится) |
| Выплата не проходит (`payout.*`)         | [Выплаты не проходят](#выплаты-не-проходят)                            |
| В магазине (CMS) заказ не оплачивается   | [Модули CMS](#модули-cms-заказ-не-меняет-статус)                       |
| Запрос завис / таймаут / `5xx`           | [Таймауты и недоступность API](#таймауты-и-недоступность-api)          |

***

## Сначала — 5 быстрых проверок

Прежде чем углубляться, проверьте базовое (это закрывает большинство проблем на старте):

1. **Ключи вставлены без пробелов** по краям (частая причина `401`).
2. **Секрет — это секрет, а не public\_id** (их легко перепутать местами).
3. **Сумма — строкой** (`"10.00"`), а не числом.
4. **Сайт доступен из интернета** (для вебхуков — `localhost` не подойдёт).
5. **Вы на боевом URL** API, а не на плейсхолдере из документации.

***

## Ошибки аутентификации (401/403)

**Симптом:** любой запрос отдаёт `401`.

Проверьте по порядку:

1. **`X-Public-Id` и `secret`.** Скопируйте заново, без пробелов. Секрет — тот, что подписывает, а не
   `public_id`.
2. **Строка для подписи.** Подписывается ровно `"{timestamp}\n{METHOD}\n{path}\n{body}"`, а
   `X-Signature = hex(HMAC‑SHA256(secret, строка))`. Тело подписи должно **побайтно** совпадать с
   отправляемым телом — не пересериализуйте JSON после подписи. Разбор — [Как подписать запрос](/guides/signing-requests).
3. **Часы сервера.** `timestamp` — в **unix‑секундах**, окно ±5 минут. Разъехались часы → синхронизируйте
   NTP. Симптом окна — код `merchant.bad_signature` (а не `auth.bad_timestamp`).
4. **`merchant.wrong_key_kind` (403)** — ключ не подходит для этого эндпоинта. **Второго ключа искать
   не надо:** в Oblodai **один API‑ключ на всё** — и приём, и выплаты (раздельных ключей «для приёма» и
   «для выплат» не существует). На практике этот код означает, что вы предъявляете **легаси‑ключ**
   старого формата (`pk_…` / `wk_…`). Выпустите в кабинете актуальный ключ `oblodai_…` и используйте
   его везде. → [Регистрация и ключи](/guides/get-keys)
5. **`401 auth.ip_not_allowed`** — включён [IP‑allowlist](/reference/api-allowlist), а запрос идёт с
   адреса вне списка. Добавьте IP или временно выключите контроль.

<Tip>
  Проще всего — не подписывать вручную, а взять [SDK](/sdk/overview): он не ошибётся в подписи.
</Tip>

***

## Превышен лимит частоты (429)

**Симптом:** `429` с телом `{"state":1,"message":"rate limit exceeded"}`.

* Лимит считается **на IP** (по умолчанию 120 запросов/мин). Подробнее — [Ограничение частоты](/reference/basics-ratelimit).
* **Что делать:** прочитать заголовок `Retry-After` (секунды), подождать и повторить (повтор безопасен
  благодаря идемпотентности: тот же `Idempotency-Key` + тот же `order_id`). SDK делают это сами.
* **Как не упираться:**

  * **Массовые операции отправляйте батчем** — [`/v1/payment/batch`](/reference/payment-batch),
    `/v1/refund/batch`, `/v1/payout/batch`: до **5000** операций **одним** запросом вместо 5000 запросов.
    Это штатный способ вообще не встречаться с `429`. → [Массовые операции](/guides/batch-operations)
  * Не поллите `/payment/info` — статус придёт вебхуком.
  * Кэшируйте `services`/`currencies`/курсы.

  См. [best‑practices](/reference/basics-ratelimit#как-не-упереться-в-лимит).

***

## Платёж: создался, но `address` пустой

Это **нормально** для валюто‑агностичного счёта (`is_multi: true`): валюту и сеть выбирает покупатель
на [hosted‑странице](/reference/pay-select), и адрес выделяется в момент выбора.

* Хотите адрес сразу — задайте `to_currency` **и** `network` при создании (одновалютный режим). Разбор
  режимов — [Три режима создания счёта](/guides/payment-modes).

***

## Платёж не создаётся

| Код                                | Что значит                                                                                       | Что делать                                                                                                                                     |
| ---------------------------------- | ------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------- |
| `400 payment.to_currency_required` | Цена в **фиате**, задан `network`, но не `to_currency` — монету расчёта вывести нельзя.          | Укажите `to_currency` или уберите `network`. → [Три режима создания счёта](/guides/payment-modes#частая-ошибка-цена-в-фиате-и-сеть-без-монеты) |
| `400 payment.network_required`     | У монеты несколько сетей, а `network` не задан.                                                  | Укажите `network` явно.                                                                                                                        |
| `400 payment.unknown_currency`     | Валюта не поддерживается (частый случай — фиат вне списка: **KZT, KGS, UZS не поддерживаются**). | Сверьтесь с `pricing_currencies` в [`GET /v1/currencies`](/reference/currencies).                                                              |
| `400 payment.below_minimum`        | Сумма ниже минимума сети (Ethereum, Bitcoin).                                                    | Увеличьте сумму или возьмите дешёвую сеть.                                                                                                     |
| `503 invoice.fee_quote_failed`     | **Временная** ошибка: не удалось получить котировку курса/комиссии.                              | Повторите с backoff (тот же `Idempotency-Key`) — это не ошибка вашего запроса. → [Устойчивый клиент](/guides/resilient-client)                 |

***

## Диагностика: платёж «застрял»

**Симптом:** покупатель говорит, что оплатил, а статус заказа не стал `paid`.

Идите по шагам:

1. **Запросите факт.** Вызовите [`/v1/payment/info`](/reference/payment-info) по `uuid`/`order_id` и
   посмотрите `payment_status`:
   * `check` / `select` — оплаты ещё **не видели** на блокчейне. Ждём или платёж не отправлен.
   * `confirm_check` — транзакцию **видим, ждём подтверждений сети** (это нормально, подождите).
   * `wrong_amount_waiting` — пришла **недоплата**, покупатель может **докинуть остаток** (см.
     [Недоплата/переплата](/guides/under-overpayment)).
   * `paid` / `paid_over` — оплата **прошла**. Значит проблема на вашей стороне: не пришёл/не
     обработался вебхук → см. [следующий раздел](#диагностика-вебхук-не-приходит).
   * `wrong_amount` — недоплата, срок вышел. `cancel` — счёт истёк/отменён.
2. **Если `paid`, а заказ не обновился** — проблема в доставке/обработке вебхука. Проверьте
   [журнал доставок](/reference/webhooks-deliveries) и раздел ниже.
3. **Разовая ручная синхронизация:** можно [переотправить вебхук](/reference/payment-resend) или
   обновить заказ по результату `/payment/info` вручную.

***

## Диагностика: вебхук не приходит

**Симптом:** оплата в статусе `paid`, но уведомление на ваш сервер не пришло.

Пройдите по цепочке — уведомление рвётся в одном из звеньев:

1. **Endpoint зарегистрирован?** Oblodai шлёт вебхуки **только** если вы вызвали
   [`POST /v1/webhooks`](/reference/webhooks-register) и получили `secret`. Без регистрации
   доставок нет вовсе — даже per‑объектный `url_callback` игнорируется (без секрета endpoint
   подписывать нечем, доставка не создаётся). (Модули CMS делают это автоматически при сохранении
   настроек.)
2. **URL доступен снаружи?** Адрес должен открываться из интернета (не `localhost`, не за VPN, не за
   Basic‑Auth). Проверьте, что на ваш `url_callback` можно сделать `POST` извне.
3. **Ваш сервер отвечает `2xx`?** Если обработчик возвращает не‑2xx (или падает) — Oblodai считает
   доставку неуспешной и будет **повторять** (до 12 попыток, \~3,5 часа), затем статус `dead`.
4. **Смотрите журнал доставок:** [`POST /v1/webhooks/deliveries`](/reference/webhooks-deliveries) —
   там видно `status` (`pending`/`delivered`/`dead`), число попыток и текст последней ошибки.
   Учтите: журнал хранит только **50 последних** доставок и не имеет фильтров (тело запроса — пустой
   `{}`) — на бойком магазине нужная запись могла выпасть из окна, и её отсутствие **не** означает,
   что вебхук не отправлялся. В этом случае сверьте статус платежа через
   [`/v1/payment/info`](/reference/payment-info) и при необходимости
   [переотправьте вебхук](/reference/payment-resend).
5. **Проверьте вручную:** [тестовый вебхук](/reference/webhooks-test) отправит событие на ваш URL —
   так можно отделить «Oblodai не шлёт» от «мой сервер не принимает».

Подробная отладка — [Отладка вебхуков](/guides/webhooks-debug).

***

## Вебхук приходит, но подпись не сходится

Частые причины (по убыванию частоты):

1. **Проверяете не тем секретом.** Вебхуки подписываются секретом из
   [`POST /v1/webhooks`](/reference/webhooks-register), а **не** вашим API‑секретом.
2. **Не сырое тело.** Подпись считается по **сырым байтам** запроса. Если фреймворк распарсил JSON, а вы
   пересобрали его в строку — подпись не сойдётся. Берите `php://input` / `express.raw` / `request.get_data()`.
3. **Другой алгоритм.** Подпись вебхука — это `hex(HMAC‑SHA256(secret, "{timestamp}." + сырое_тело))` по
   заголовкам `X-Webhook-Timestamp` / `X-Webhook-Signature`. Это **не** тот же алгоритм, что у подписи
   запроса. Формат — [Объект вебхука](/reference/webhook-object).
4. **Пробный вебхук.** События с `"is_test": true` **не подписаны** — их не нужно проверять, просто
   отвечайте `200`.

***

## Выплаты не проходят

| Код                                            | Что значит                                 | Что делать                                                                                                                                          |
| ---------------------------------------------- | ------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------- |
| `payout.insufficient_funds` (409)              | Не хватает **доступного** баланса          | Денег реально нет: пополните баланс. Повтор **не** поможет. Часть средств может быть заморожена/дозревает — проверьте [баланс](/reference/balance). |
| `payout.funds_maturing` (409)                  | Средства ещё **дозревают** (maturity‑холд) | **ПОВТОРИТЕ ПОЗЖЕ.** Это временная ошибка, а не отказ — когда депозит наберёт подтверждения, выплата пройдёт. Не отменяйте выплату из-за неё.       |
| `payout.frozen` (409)                          | Выплаты **заморожены** (kill‑switch)       | Временная защита; **повторите позже**.                                                                                                              |
| `payout.no_destination` / `payout.bad_address` | Пустой/некорректный адрес                  | Проверьте адрес получателя.                                                                                                                         |
| `payout.address_network_mismatch`              | Адрес не соответствует сети                | Сверьте адрес и `network`.                                                                                                                          |
| `payout.order_id_required`                     | Не передан `order_id`                      | Для выплаты `order_id` **обязателен** — это ваш бизнес‑ключ дедупликации (дополняющий заголовок `Idempotency-Key`).                                 |

<Warning>
  **Не все `409` финальны.** Частая и дорогая ошибка — считать любой `409` конечным («уже
  обработано») и бросить операцию. `payout.funds_maturing`, `payout.frozen` и `idempotency.in_progress`
  **надо повторять позже** — иначе вы потеряете законную выплату. →
  [Устойчивый клиент](/guides/resilient-client#не-все-409-финальны)
</Warning>

Полный список — [Справочник кодов ошибок](/reference/errors-catalog), раздел `payout`.

***

## Модули CMS: заказ не меняет статус

1. Убедитесь, что способ оплаты **включён** и виден на оформлении заказа.
2. **Сохраните настройки способа оплаты ещё раз** — так модуль перерегистрирует вебхук.
3. Сайт должен быть **доступен из интернета** (иначе вебхуки не дойдут).
4. Проверьте, что **Public ID** и **API secret** вставлены без пробелов.

***

## Таймауты и недоступность API

Сеть моргнула, запрос завис или пришёл `5xx`/`503` — это ожидаемая ситуация, к ней надо быть готовым.

* **Таймаут ≠ «не прошло».** Ответ мог потеряться уже после того, как операция выполнилась на сервере.
  Поэтому **не создавайте вторую операцию вслепую** — повторите **тот же** запрос: с тем же
  HTTP‑заголовком `Idempotency-Key` и тем же `order_id`. Идемпотентность вернёт уже созданный объект
  (с заголовком `Idempotent-Replayed: true`), а не сделает дубль.
* **`5xx` / `503`** — временная недоступность зависимости (например, оракула курсов). Повторяйте с
  **экспоненциальным backoff** (0.5с → 1с → 2с …), а не в плотном цикле.
* **`409 idempotency.in_progress`** — не ошибка: ваш предыдущий запрос с этим `Idempotency-Key` ещё
  выполняется. Подождите и повторите — получите его результат.
* **Что повторять безопасно:** запросы с `Idempotency-Key` и/или `order_id`/`reference` (создание
  платежа, выплаты, возврата) — идемпотентны. Чтения (`info`, `balance`, `services`) безопасны всегда.
* **Готовый рецепт клиента** (таймауты, ретраи, backoff, идемпотентность) — [Устойчивый клиент](/guides/resilient-client).
  Все [SDK](/sdk/overview) реализуют это из коробки.

***

## Не нашли решение?

* Быстрые вопросы‑ответы — [FAQ](/guides/faq-troubleshooting).
* Все коды ошибок и что делать — [Справочник кодов ошибок](/reference/errors-catalog).
* Как это устроено «под капотом» — [Диаграммы жизненных циклов](/reference/diagrams).
* Незнакомый термин — [Глоссарий](/reference/glossary).
* Ничего не помогло — создайте тикет в поддержку в кабинете [my.oblodai.com](https://my.oblodai.com)
  (раздел **«Поддержка»**). Приложите ваш `public_id`, `uuid` платежа/выплаты и строки лога с
  префиксом `oblodai:` (в SDK включаются переменной `OBLODAI_LOG`, в модулях CMS — галочкой
  **Debug log**); `secret` **не** прикладывайте.
