API и надёжная интеграция

Тестовый режим платежей: сценарии проверки интеграции

Тестовый режим полезен только с планом проверок: успешный, отменённый, просроченный, повторный и подписанный неверным секретом сценарии должны иметь ожидаемый результат.

Тестовый режим нужен ради одного: прогнать все ветки оплаты до того, как деньги станут настоящими. Не только «купил — получил доступ», а ещё пять неприятных веток, на которых обычно и ломается интеграция: покупатель передумал, ссылка истекла, колбэк пришёл с чужой подписью, событие пришло дважды, ваш сервер в этот момент лежал.

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

Что тестовый режим проверяет, а что нет

Тестовый режим проверяет ваш код: как вы создаёте платёж, как принимаете колбэк, как меняете статус заказа и что показываете покупателю. Этого достаточно, чтобы поймать 90% ошибок интеграции.

Чего он не проверяет: реальную маршрутизацию до банка, поведение конкретного банковского приложения, скорость зачисления и решение модерации по вашей категории проекта. Доступные методы и условия подтверждает команда при подключении — это отдельный шаг, и никакой sandbox его не заменит.

Практическое правило: после тестов сделайте одну живую оплату на минимальную сумму со своей карты или телефона. Это последняя проверка, которую нельзя подделать.

Разделите ключи и окружения до первой строки кода

Самая частая авария первого дня — тестовый стенд с боевым ключом. Разведите их так, чтобы перепутать было физически трудно.

  1. Две кассы, а не одна. У каждой свой api_key, свой signing_secret и свой callback_url. Секреты выдаются один раз при создании кассы — сохраните их в менеджере секретов сразу.
  2. Ключи только из переменных окружения. ROLLYPAY_API_KEY и ROLLYPAY_SIGNING_SECRET в .env, которого нет в git. Боевой ключ начинается с rpk_live_ — по префиксу в логе видно, куда вы только что сходили.
  3. Разные базы. Тестовые заказы не должны попадать в ту же таблицу orders, из которой вы считаете выручку. Либо отдельная база, либо колонка is_test boolean not null default false и фильтр во всех отчётах.
  4. Проверка на старте приложения. Если APP_ENV=production, а ключ не боевой — падайте с понятной ошибкой, не запускайтесь «как-нибудь».

В колбэке приходит поле test: true для тестовых платежей, false для боевых. Это ваш последний рубеж — обработчик обязан на него смотреть и никогда не выдавать реальный доступ по событию с test: true.

Шесть сценариев до первой реальной продажи

СценарийКак воспроизвестиЧто должно получиться
УспехСоздать платёж и оплатить егоКолбэк payment.paid, заказ переходит в paid, доступ выдан один раз
ОтменаЗакрыть форму оплаты, дождаться payment.canceledЗаказ закрыт как неоплаченный, покупателю предложен повтор
ИстечениеСоздать платёж и не платить до expires_atКолбэк payment.expired, заказ не висит в «ожидании» вечно
Неверная подписьОтправить себе POST с испорченным X-Signature403, тело не разбирается, заказ не меняется, запись в логе
Повтор событияОтправить один и тот же валидный колбэк дважды200 на оба, доступ выдан один раз, письмо отправлено один раз
Недоступный колбэкПогасить обработчик на 10 минут во время оплатыПосле подъёма событие доезжает повтором, заказ закрывается сам

Отдельно проверьте повтор X-Nonce: одно и то же значение во втором запросе даёт 401 "nonce already used". Нонс живёт 10 минут, генерируйте новый UUID на каждый вызов. И проверьте создание платежа с тем же order_id — идемпотентность считается именно по нему, дубля быть не должно.

Как поймать колбэк на ноутбуке

Колбэк идёт на публичный HTTPS-адрес, а ваш обработчик пока живёт на localhost:3000. Поднимите туннель (ngrok, cloudflared, localtunnel — любой), получите адрес вида https://…/webhooks/rollypay и пропишите его в callback_url тестовой кассы.

Дальше — две вещи, которые ломают половину первых попыток. Первая: подпись считается по сырому телу запроса, поэтому в Express нужен express.raw() на этом маршруте, а не express.json() — после разбора JSON байты уже не те. Вторая: адрес туннеля меняется при перезапуске, и вы обновляете callback_url каждый раз. Подробности проверки — в статье про проверку подписи webhook.

Чтобы тесты не попали в отчёты

Бот-магазин пресетов на 40 заказов в месяц за неделю тестов сгенерировал 60 «продаж». Через месяц владелец смотрел на график и не мог понять, почему июнь оказался вдвое лучше июля.

Лечится тремя правилами. Тестовые заказы помечайте флагом при создании и фильтруйте во всех отчётах, а не только на главном дашборде. Событие покупки в аналитику отправляйте только при test == false. Письма, чеки и уведомления в рабочий чат на тестовых платежах не шлите — иначе бухгалтер увидит продажу, которой не было.

Чек-лист перед включением боевого режима

  • Все шесть сценариев выше прошли и результат зафиксирован, а не «вроде работало».
  • В проде подставлены боевые api_key и signing_secret, тестовые из окружения убраны.
  • callback_url указывает на настоящий домен, отвечает 2xx быстрее 10 секунд и доступен снаружи.
  • success_redirect_url и fail_redirect_url ведут на существующие страницы, а не на 404.
  • Обработчик проверяет подпись до разбора JSON и сверяет order_id, сумму и валюту с заказом.
  • Есть журнал входящих событий, по которому можно поднять историю конкретного платежа.
  • Тестовые заказы вычищены из базы или помечены флагом и исключены из отчётов.
  • Сделана одна живая оплата на минимальную сумму и один возврат по ней.

Дальше держите тестовую кассу живой: любое изменение в обработчике колбэков сначала прогоняется на ней. Как вести себя, когда что-то всё-таки сломалось у покупателя, разобрано в статье что делать, если платёж не прошёл, а общая схема подключения — в материале про API приёма платежей. Если вы только выбираете, как встроить оплату в сайт, посмотрите решение для приёма платежей на сайте.

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

Сколько сценариев достаточно прогнать перед запуском?

Минимум шесть: успешная оплата, отмена, истечение срока ссылки, колбэк с неверной подписью, повторная доставка одного события и недоступный обработчик. Каждый из них меняет поведение вашего кода по-своему. После них сделайте одну живую оплату на минимальную сумму.

Как отличить тестовый платёж от боевого в обработчике?

В теле колбэка есть поле test: у тестовых платежей оно равно true, у боевых false. Выдавайте доступ, отправляйте письма и события в аналитику только при test равном false. Дополнительно помогает префикс rpk_live_ у боевого ключа кассы.

Как принять колбэк, пока сервис работает на localhost?

Поднимите HTTPS-туннель (ngrok, cloudflared) и пропишите его адрес в callback_url тестовой кассы. Учтите, что адрес туннеля меняется при перезапуске, а подпись считается по сырому телу запроса — тело нужно сохранить до разбора JSON.

Что делать с тестовыми заказами после запуска?

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

Заменяет ли тестовый режим согласование условий подключения?

Нет. Тесты проверяют ваш код: создание платежа, приём колбэка, смену статуса заказа. Категорию проекта, доступные способы оплаты и условия работы подтверждает модерация при подключении — это отдельный шаг.

Источники и документация