# Чек-лист выхода в прод

> Двенадцать пунктов, которые нужно закрыть перед переходом в боевой режим: кассир, боевой ключ, вебхук, подпись, идемпотентность, поздняя оплата, обработка ошибок, логи, тариф и лимиты, уведомления, возвраты, первый реальный платёж.

## Коротко

Пройдите двенадцать пунктов по порядку. У каждого написано, **куда нажать** и **как проверить**. Если все зелёные — переход в боевой режим безопасен.

Две самые частые ошибки: ключ остался в виде `qp_test_…` и адрес вебхука не подключён для боевого режима. Пункты 2 и 3 именно про это.

## 1. Кассир активен

**Куда нажать:** Кабинет → раздел **Kaspi**. Статус привязки должен быть «активна».

**Как проверить:** если статус серый или «оборвалась» — переподключите. Код из SMS придёт на номер кассира, весь процесс проходит в одном окне и занимает около десяти минут.

Помните: Kaspi разрешает одно активное устройство на кассира. После привязки не входите с этого номера в приложение Kaspi Pay — сессия оборвётся.

Если что-то не так: [Привязка кассира оборвалась](/kb/ru/connection-lost), [Кассир Kaspi не подключается](/kb/ru/cashier-not-connecting).

## 2. Ключ боевой

**Куда нажать:** Кабинет → **Интеграции** → API-ключи. Создайте ключ `qp_live_…` и подмените его на сервере в `.env`.

**Как проверить:** посмотрите на сервере **первые семь символов** ключа: должно быть `qp_live_`, а не `qp_test_`.

Это самый забываемый шаг. Если ключ остался тестовым, счета создаются, но реального платежа покупатель не получает. Признаки: [Забыли выключить тестовый режим](/kb/ru/test-mode-forgotten).

## 3. Вебхук публичный и на https

**Куда нажать:** Кабинет → **Интеграции** → адрес вебхука. Адрес должен быть на постоянном домене и на `https`.

**Как проверить:** отправьте `POST` на свой адрес из внешней сети (например, с мобильного интернета телефона, не из офисного Wi-Fi). Ответ должен прийти. Возможные отказы при добавлении адреса:

- IP-адрес вместо домена — `webhook_url_requires_domain`
- `http://` — `webhook_url_requires_https`
- Туннельный адрес — `webhook_url_tunnel_forbidden`

Адрес должен быть **открыт без авторизации**: Basic Auth, фильтр по IP или «защита от ботов» Cloudflare заблокируют доставку. Редиректы тоже не отслеживаются, кроме 307/308 на тот же самый адрес.

Если не приходит: [Вебхук не приходит](/kb/ru/webhook-not-arriving).

## 4. Подпись действительно проверяется

**Что сделать:** убедитесь, что в коде проверяется `X-Webhook-Signature`: `sha256=` + `HMAC-SHA256(secret, timestamp + "." + rawBody)`.

**Как проверить:** отправьте на свой адрес запрос с заведомо испорченной подписью. Сервер обязан **ответить 401 и не тронуть заказ**. Если заказ всё равно стал оплаченным — проверки нет или она не работает.

Дополнительно: запросы с `X-Webhook-Timestamp` старше 5 минут принимать нельзя. Подробно: [Безопасность вебхуков](/kb/ru/webhook-security).

## 5. Идемпотентность на месте

**Что сделать:** в двух местах.

1. **При создании счёта** — передавайте заголовок `Idempotency-Key`. Если связь оборвалась и запрос повторился, новый счёт не создастся
2. **При обработке вебхука** — по паре `(invoice.id, status)`. Пришла та же пара второй раз — заказ повторно не обрабатывается

**Как проверить:** в песочнице создайте счёт дважды с одним `Idempotency-Key` — во второй раз должен прийти HTTP 200 и `idempotentReplay: true`. Для вебхука: отправьте одно и то же тело дважды, товар не должен уехать повторно.

Подробно: [Идемпотентность](/kb/ru/idempotency).

## 6. Готовность к поздней оплате

**Что сделать:** в обработчике `invoice.paid` предусмотрите ветку на признак **`late: true`**. Это означает, что деньги пришли по уже закрытому (`cancelled` или `expired`) счёту.

**Как проверить:** в песочнице отмените счёт, затем отправьте `simulate {"status":"paid"}` — придёт `late: true`. Что дальше сделает ваша система?

Вариантов два, выберите заранее: выдать услугу или вернуть деньги. Третий — отправить уведомление на ручной разбор. Подробно: [Поздняя оплата](/kb/ru/late-payment).

## 7. Обработка ошибок

**Что сделать:** писать интеграцию по коду `error`, а не по тексту `message`. Как минимум обработайте:

| Код | Что делать |
|---|---|
| `kaspi_session_expired` | Уведомить ответственного, приостановить выставление счетов |
| `tariff_limit_reached` | Уведомить, повысить тариф |
| `tariff_daily_burst` | Проверить, нет ли цикла в коде |
| `rate_limited`, `429` | Подождать по `Retry-After` и повторить |
| `502`, `503` | Повторять с нарастающей паузой (1, 2, 4, 8 секунд) |
| `refund_unknown` | **Не повторять**, прочитать статус счёта |

**Как проверить:** в песочнице отправьте заведомо некорректные запросы. Все коды: [Каталог ошибок](/kb/ru/error-catalog).

## 8. Ведутся логи

**Что сделать:** записывайте каждое создание счёта и каждый входящий вебхук: время, `invoice.id`, `externalOrderId`, статус, HTTP-код, `X-Webhook-Delivery`.

**Не пишите в лог:** сам API-ключ и секрет вебхука.

**Как проверить:** проведите тестовый платёж и найдите его в логах. Без логов первый же инцидент разобрать не получится.

## 9. Тариф активен и лимита хватает

**Куда нажать:** Кабинет → **Тариф**. Тариф активен? Месячного лимита хватает на планируемое число счетов?

| Тариф | Счетов в месяц | Суточная защита |
|---|---|---|
| Старт | 800 | 200 |
| Бизнес | 4 000 | 1 500 |
| Про | 15 000 | 5 000 |

**Суточное число — не бизнес-лимит**, а защита от интеграции, ушедшей в цикл. Если вы планируете больше 200 счетов в день, подбирайте тариф соответственно.

Пробный период — 7 дней и 50 счетов в сутки, он стартует **с первого боевого счёта**. Подробно: [Тарифы и лимиты](/kb/ru/tariff-limits).

## 10. Уведомления в Telegram включены

**Куда нажать:** Кабинет → **Настройки** → код привязки Telegram. Привяжите бота.

**Зачем:** об обрыве привязки кассира вы узнаете из сообщения, а не из логов на следующее утро. Если связь оборвалась ночью, вы увидите это сразу.

Как подключить: [Подключить Telegram-бота](/kb/ru/telegram-connect).

## 11. Порядок возвратов продуман

**Что сделать:** у вас должны быть ответы на три вопроса.

- Кто делает возврат: оператор руками из кабинета или ваша система через API?
- Нужны ли частичные возвраты?
- Что вы делаете при `refund_unknown` или `refund_pending_unknown`? (Ответ: не повторяете, читаете статус счёта)

**Как проверить:** прогоните в песочнице полный и частичный возврат. Подробно: [API возвратов](/kb/ru/refunds-api), [Как не вернуть деньги дважды](/kb/ru/double-refund).

## 12. Первый реальный платёж — на маленькую сумму

**Что сделать:** после перехода в боевой режим выставьте счёт на **минимальную сумму** (например, 100 ₸) и оплатите его со своего телефона.

**Что при этом проверяется:** сразу всё — ключ, кассир, QR, вебхук, смена статуса в вашей системе, поступление денег на счёт Kaspi.

Затем сделайте по этому счёту возврат — так вы проверите и путь возврата. Эти пять минут находят проблемы до того, как в них упрётся первый живой клиент.

Если не прошло: [Перешёл в боевой режим — не работает](/kb/ru/after-live-not-working).

## Список одним взглядом

1. Кассир активен
2. Ключ `qp_live_…`
3. Вебхук публичный, `https`, постоянный домен
4. Подпись проверяется, timestamp не старше 5 минут
5. Передаётся `Idempotency-Key`, обработчик вебхука идемпотентен
6. Обрабатывается `late: true`
7. Обрабатываются коды ошибок
8. Есть логи, без ключей
9. Тариф активен, лимита хватает
10. Уведомления в Telegram включены
11. Порядок возвратов определён
12. Первый реальный платёж на маленькую сумму прошёл

## Вопросы и ответы

**Что будет со счетами песочницы после перехода?** Они остаются, но не показываются в боевом списке и не попадают в лимит.

**Будет ли тестовый ключ работать в боевом режиме?** Нет. Режим и ключ должны совпадать, иначе вы получите 401.

**Когда нужно оплачивать тариф?** Пробный период стартует с первого боевого счёта и длится 7 дней — за это время выбираете и оплачиваете: [Как оплатить тариф](/kb/ru/tariff-payment).

**Какой пункт можно пропустить?** Ни один. Порядок менять можно, но пункт 12 должен оставаться последним: он разом проверяет всё остальное.
