> ## 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.

# Безопасность в проде

Oblodai построен на модели «один API‑ключ на весь функционал». Это удобно, но повышает цену утечки:
тем же ключом, которым вы принимаете платежи, можно и выводить средства. Эта инструкция — про то, как
снизить риски перед боевым запуском.

***

## Модель ключа

* **Один ключ — и приём, и выплаты.** Отдельных ключей нет.
* **Радиус поражения ограничен одним вашим мерчантом.** Утёкший ключ не трогает чужие данные и баланс,
  но со **своим** балансом может сделать всё, включая вывод.
* **За хранение ключа отвечаете вы.**

Отсюда три опоры защиты: хранить секрет правильно, ограничить, откуда им можно пользоваться, и знать,
как его сменить.

***

## 1. Хранение секрета

* Секрет живёт **только на сервере**, в секрет‑хранилище (Vault, KMS, зашифрованные переменные
  окружения) — не в коде, не в репозитории, не в браузере, не в мобильном приложении.

<Note>
  **Что за Vault/KMS?** Это специальные хранилища секретов (например HashiCorp Vault или облачный
  Key Management Service), которые держат ключи отдельно от кода и выдают их приложению по запросу.
  **На старте достаточно переменных окружения** сервера — Vault/KMS подключают по мере роста, когда
  секретов и людей становится больше.
</Note>

* Подпись считается на бэкенде. Клиент никогда не видит `secret`.
* Секрет вебхука (`secret` из [`/v1/webhooks`](/reference/webhooks-register)) — тоже секрет:
  храните так же.

***

## 2. IP‑allowlist

Ограничьте, с каких IP принимаются подписанные запросы. Когда список включён, запрос с чужого IP
получает `401 auth.ip_not_allowed`, даже если подпись верна.

<CodeGroup>
  ```python Python theme={null}
  # 1) Сначала добавьте IP вашего backend
  call("/v1/api-allowlist/add", {"cidr": "203.0.113.10"})
  # 2) Только потом включайте контроль
  call("/v1/api-allowlist/enable", {"enabled": True})
  ```

  ```js Node.js theme={null}
  // 1) Сначала добавьте IP вашего backend
  await call("/v1/api-allowlist/add", { cidr: "203.0.113.10" });
  // 2) Только потом включайте контроль
  await call("/v1/api-allowlist/enable", { enabled: true });
  ```
</CodeGroup>

<Warning>
  **Порядок важен.** Нельзя включить контроль с пустым списком (`apiallow.empty`) — иначе рискуете
  заблокировать сами себя. Сначала добавьте IP, потом включайте.
</Warning>

Управление списком — [`POST /v1/api-allowlist/*`](/reference/api-allowlist).

***

## 3. Ротация ключа

<Note>
  **Ротация ключа не входит в публичный API.** По подписанному запросу ключ ротировать нельзя — это
  сделано специально, чтобы утёкший ключ не мог сам себя сменить и заблокировать владельца.
</Note>

Смена ключа выполняется **только в личном кабинете на сайте**:

1. Владелец мерчанта заходит в кабинет.
2. Проходит подтверждение (2FA — двухфакторная аутентификация: помимо пароля вводится одноразовый код,
   например из приложения‑аутентификатора).
3. Получает новый `public_id` + `secret` (секрет показывается один раз).

Старый секрет перестаёт работать сразу. **Заморозки выплат при ротации нет** — приём и выплаты
продолжают работать без паузы.

***

## Особенности денежных операций

* **Выплаты по API‑ключу авто‑одобряются и уходят сразу** — без белых списков и периодов выдержки, и
  они необратимы. Валидируйте адрес получателя на своей стороне до вызова
  [`/v1/payout`](/reference/payout-create).
* **Вывод из личного кошелька — только в кабинете под 2FA.** На API‑ключе доступен лишь ввод средств В
  личный кошелёк ([`/v1/transfer/to-personal`](/reference/transfer-to-personal)); вывод оттуда
  через API намеренно закрыт.
* **Идемпотентность обязательна.** Отправляйте денежные запросы с HTTP‑заголовком **`Idempotency-Key`**
  (одно значение на действие, неизменное во всех попытках) и задавайте **`order_id`/`reference`** (для
  выплат он обязателен). Это два независимых механизма защиты от дублей при ретраях: заголовок — на
  уровне транспорта, `order_id` — на уровне вашей бизнес‑логики. См.
  [Идемпотентность](/reference/basics-idempotency).

***

## Дополнительно

* **Rate limit.** При превышении — `429` с телом `{"state":1,"message":"rate limit exceeded"}` и заголовком `Retry-After`; подождите и повторяйте с backoff. → [Ограничение частоты](/reference/basics-ratelimit)
* **Часы сервера.** Держите время синхронизированным (NTP): подпись живёт в окне ±5 минут, при
  расхождении сверка подписи не пройдёт и придёт `merchant.bad_signature` (окно проверяется внутри
  проверки подписи). Код `auth.bad_timestamp` — это только про отсутствующий или нечисловой
  `X-Timestamp`.
* **Мониторинг.** Следите за балансом и статусами выплат; храните сопоставление `order_id` ↔ ваш заказ.

***

## Связанные страницы

<CardGroup cols={2}>
  <Card title="IP‑allowlist" href="/reference/api-allowlist" icon="arrow-right" horizontal />

  <Card title="Идемпотентность" href="/reference/basics-idempotency" icon="arrow-right" horizontal />

  <Card title="POST /v1/transfer/to-personal" href="/reference/transfer-to-personal" icon="arrow-right" horizontal />

  <Card title="Чек‑лист перед запуском" href="/guides/production-checklist" icon="arrow-right" horizontal />
</CardGroup>
