Перейти к содержимому

Платежи

Платежные методы включаются через .env или админ-панель, если параметр добавлен в allowlist настроек. В Mini App способы оплаты по умолчанию собраны в компактный выпадающий список; настройка PAYMENT_METHODS_DISPLAY_MODE=buttons возвращает отдельные кнопки. Telegram-сценарии продолжают использовать кнопки.

  1. Включите нужный провайдер.
  2. Заполните публичные параметры, секреты и URL возврата.
  3. Настройте webhook URL у провайдера, если он используется.
  4. Проверьте порядок способов оплаты в PAYMENT_METHODS_ORDER.
  5. Выберите выпадающий список или отдельные кнопки в Платежи → Оформление оплаты.
  6. Проверьте подписи и иконки способов оплаты.
  7. Выполните тестовый платеж.
  8. Проверьте логи backend.

[!NOTE] Если URL возврата не задан явно, используется ссылка на Telegram-бота.

PAYMENT_METHODS_DISPLAY_MODE=dropdown используется по умолчанию и показывает компактный выпадающий список. Значение buttons возвращает отдельные кнопки. В обоих режимах сохраняются порядок из PAYMENT_METHODS_ORDER, название и иконка провайдера; настройка находится в Платежи → Оформление оплаты.

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

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

Для period-тарифа checkout может включать устройства и гибкие итоговые лимиты обычного и premium-трафика из тарифного каталога. Гибкий лимит действует в каждом периоде сброса оплаченного срока; он не пополняет несгораемый баланс отдельной докупки трафика. Во время перетаскивания слайдера Mini App меняет цену локально, после завершения запрашивает серверную котировку всей корзины, а создание платежа пересчитывает её повторно. Процентная скидка промокода применяется к полному subtotal — базовой подписке и всем выбранным дополнениям, включая пропорциональную доплату за немедленное повышение активной подписки, — и только затем рассчитывается внешняя часть платежа после партнёрского баланса.

При раннем продлении того же тарифа полный выбранный пакет оплачивается на новый срок, а увеличение над уже оплаченными активными устройствами/лимитами рассчитывается пропорционально остатку текущего окна. Понижение не возвращает деньги и применяется со следующей границы подписки. Котировка привязана к ID и дате окончания активной подписки: параллельное продление делает старый счёт неактуальным и не позволяет повторно выдать права. Смена тарифа не маскируется под обычное продление и выполняется отдельным сценарием.

Заказ активируется только по аутентифицированному успешному подтверждению в той же валюте. Подтверждённая сумма, равная цене счёта или больше неё, активирует ровно один исходный заказ: переплата не добавляет месяцы, трафик или устройства. Недоплата и другая валюта не активируют заказ. Ответ webhook отклоняет такое подтверждение; если провайдер уже захватил средства, возврат или отдельная доплата оформляются через этого провайдера, а не выдачей полного заказа за меньшую сумму.

Партнёрский баланс можно применить к покупке полностью или частично. При смешанной оплате провайдеру передаётся только остаток после баланса, а Payment хранит также полный checkout total и сумму внутреннего списания. В денежную выручку попадает только внешний остаток. Полностью покрытая балансом покупка создаёт внутренний Payment для аудита и общей активации, но не увеличивает денежную выручку и не порождает новую комиссию или реферальный бонус. Подробности, ограничения и восстановление отменённых операций описаны в руководстве по партнёрской программе.

[!TIP] Готовый URL вебхука отображается вверху раздела каждого провайдера в админ-панели.

Все платежные webhook URL строятся от WEBHOOK_BASE_URL - публичного HTTPS-адреса backend/webhook-домена. Это должен быть домен, который проксируется на backend-сервер вебхуков (backend:8080), а не SUBSCRIPTION_MINI_APP_URL frontend/Mini App. Если WEBHOOK_BASE_URL=https://bot.example.com, то полный адрес получается как https://bot.example.com + путь из таблицы.

Если у провайдера включена IP-фильтрация (FREEKASSA_TRUSTED_IPS, WATA_TRUSTED_IPS, HELEKET_TRUSTED_IPS, PAYKILLA_TRUSTED_IPS или встроенный allowlist YooKassa), reverse proxy должен прокидывать X-Forwarded-For, а его IP/CIDR должен входить в TRUSTED_PROXIES. Иначе backend увидит IP proxy/Docker gateway и может отклонить валидный webhook с ошибкой 403. Для webhook-домена за Cloudflare backend использует CF-Connecting-IP, предварительно проверив, что ближайший внешний proxy-hop принадлежит официальной сети Cloudflare.

Провайдер Что указать в кабинете провайдера Комментарий
YooKassa WEBHOOK_BASE_URL + /webhook/yookassa Например https://bot.example.com/webhook/yookassa.
FreeKassa WEBHOOK_BASE_URL + /webhook/freekassa Используйте как notification/webhook URL; при IP-фильтрации заполните FREEKASSA_TRUSTED_IPS.
Platega WEBHOOK_BASE_URL + /webhook/platega Один общий webhook для всех разовых методов и рекуррентной подписки Platega.
SeverPay WEBHOOK_BASE_URL + /webhook/severpay Укажите как callback/webhook URL, если поле есть в кабинете мерчанта.
Wata WEBHOOK_BASE_URL + /webhook/wata Если включена проверка подписи, настройте WATA_WEBHOOK_VERIFY_SIGNATURE и WATA_PUBLIC_KEY.
CryptoPay WEBHOOK_BASE_URL + /webhook/cryptopay Указывается в настройках Crypto Bot / CryptoPay webhook.
Heleket WEBHOOK_BASE_URL + /webhook/heleket При необходимости включите HELEKET_VERIFY_WEBHOOK_SIGNATURE и HELEKET_TRUSTED_IPS.
PayKilla WEBHOOK_BASE_URL + /webhook/paykilla Указывается в PayKilla Dashboard -> Settings -> Webhooks; включите события оплаты инвойсов.
LAVA WEBHOOK_BASE_URL + /webhook/lava Передается автоматически как hookUrl при создании счета; можно также указать в кабинете LAVA Business.
Pally WEBHOOK_BASE_URL + /webhook/pally Укажите как Result URL в настройках магазина Pally / PayPalych. Postback приходит в формате application/x-www-form-urlencoded.
CloudPayments WEBHOOK_BASE_URL + /webhook/cloudpayments Укажите как адрес уведомлений Pay и Fail в кабинете CloudPayments. При IP-фильтрации заполните CLOUDPAYMENTS_TRUSTED_IPS.
Overpay WEBHOOK_BASE_URL + /webhook/overpay Укажите как notification URL в кабинете Overpay. Уведомление приходит JSON POST’ом с HTTP Basic auth (Shop ID / Secret Key).
Stripe WEBHOOK_BASE_URL + /webhook/stripe Укажите этот адрес в Stripe Dashboard и включите события checkout.session.completed, checkout.session.expired, payment_intent.succeeded, payment_intent.payment_failed, payment_intent.canceled.
Tribute WEBHOOK_BASE_URL + /webhook/tribute Укажите URL в настройках API Tribute. Подпись проверяется API key по raw body.
Telegram Stars Отдельный платежный webhook не нужен Stars-события приходят через webhook Telegram-бота: WEBHOOK_BASE_URL + /tg/webhook.

После настройки сделайте тестовый платеж и проверьте, что в логах backend видно входящий POST на нужный путь. Если провайдер сообщает, что адрес недоступен, сначала проверьте DNS/HTTPS и reverse proxy для WEBHOOK_BASE_URL, затем убедитесь, что путь начинается ровно с /webhook/... без /api, /auth и frontend-домена.

YooKassa используется для рублевых оплат. Провайдер также может участвовать в сценариях автопродления period-подписок.

  1. Включите YOOKASSA_ENABLED.
  2. Заполните YOOKASSA_SHOP_ID, YOOKASSA_SECRET_KEY и YOOKASSA_RETURN_URL.
  3. Скопируйте URL вебхука из админ-панели и укажите его в кабинете YooKassa.

Каждый цикл продления фиксирует неизменяемые сумму, валюту, карту, версию согласия пользователя и тело запроса. Неопределенный сетевой результат повторяется только с тем же Idempotence-Key и тем же телом в ограниченном 30-минутном окне. Новый ключ создается только после подтвержденного YooKassa статуса canceled, только для разрешенных временных причин (insufficient_funds, issuer_unavailable, internal_timeout) и не более одного раза. permission_revoked, отключение автопродления или смена/удаление карты окончательно останавливают цикл.

Для первого включения задайте AUTO_RENEW_RETRY_ENABLED=True, оставив AUTO_RENEW_RETRY_DRY_RUN=True, и проверьте логи воркера. После этого отдельно переключите dry-run в False. Резервный планировщик AUTO_RENEW_SCHEDULER_ENABLED независим и по умолчанию выключен.

FreeKassa подключается как отдельный платежный метод. Входящие webhook-события обрабатываются через backend.

  1. Включите FREEKASSA_ENABLED.

  2. Заполните FREEKASSA_MERCHANT_ID, FREEKASSA_FIRST_SECRET, FREEKASSA_SECOND_SECRET и FREEKASSA_API_KEY.

  3. В FREEKASSA_PAYMENT_METHOD_ID укажите ID подключённого способа оплаты из кабинета FreeKassa.

  4. Определите публичный исходящий IPv4 контейнера backend:

    docker compose exec backend sh -lc 'curl -4fsS https://api.ipify.org; echo'
  5. Запишите полученный адрес в FREEKASSA_PAYMENT_IP. Если меняете .env, пересоздайте backend; сохранённый через админ-панель override применяется штатным механизмом настроек.

  6. Проверьте настройки подписи.

  7. Скопируйте URL вебхука из админ-панели и укажите его в кабинете FreeKassa.

  8. При необходимости заполните FREEKASSA_TRUSTED_IPS.

Метод FreeKassa POST /v1/orders/create требует поле ip и описывает его как IP покупателя. Telegram Bot API не передаёт боту IP пользователя, поэтому Minishop использует стабильный публичный исходящий IP backend как резервное значение. Это не IP из FREEKASSA_TRUSTED_IPS и не обязательно адрес домена или reverse proxy.

Определяйте адрес именно из контейнера backend: при Docker NAT, VPN, отдельном шлюзе или Kubernetes egress внешний адрес хоста и контейнера может различаться. Не используйте внутренние адреса 10.x.x.x, 172.16-31.x.x или 192.168.x.x. При динамическом адресе обновите настройку после его смены. Для подтверждения допустимости одного серверного IP для всех Telegram-платежей обратитесь в поддержку FreeKassa.

Требование поля ip зафиксировано в официальной документации FreeKassa. Без FREEKASSA_PAYMENT_IP или FREEKASSA_PAYMENT_METHOD_ID провайдер считается не готовым к созданию платежей; при этом webhook и сверка ранее созданных заказов продолжают работать.

Platega подключается как отдельный платежный провайдер. Внутри Minishop он может создавать независимые кнопки: СБП, оплату картой, криптовалюту, международные карты, единую страницу выбора способа и рекуррентную СБП-подписку. Новые варианты выключены по умолчанию и не меняют существующие кнопки после обновления.

  1. Включите PLATEGA_ENABLED.
  2. Укажите PLATEGA_MERCHANT_ID и PLATEGA_SECRET.
  3. Включите нужные кнопки: PLATEGA_SBP_ENABLED, PLATEGA_CARD_ENABLED, PLATEGA_CRYPTO_ENABLED, PLATEGA_INTERNATIONAL_ENABLED, PLATEGA_ALL_METHODS_ENABLED и/или PLATEGA_SUBSCRIPTION_ENABLED.
  4. Скопируйте URL вебхука из админ-панели и укажите его в кабинете Platega. Один и тот же URL принимает и разовые транзакции, и колбэки подписок.
  • PLATEGA_CARD_ENABLED добавляет после СБП отдельную кнопку «Оплата картой» и создаёт транзакцию с paymentMethod: 11. ID можно переопределить через PLATEGA_CARD_METHOD.
  • PLATEGA_INTERNATIONAL_ENABLED создаёт обычную транзакцию с paymentMethod: 12. При изменении ID метода в Platega его можно переопределить через PLATEGA_INTERNATIONAL_METHOD.
  • PLATEGA_ALL_METHODS_ENABLED использует POST /v2/transaction/process без поля paymentMethod. После перехода по ссылке плательщик выбирает среди способов, подключённых для мерчанта в Platega.
  • Обе кнопки используют общие PLATEGA_RETURN_URL, PLATEGA_FAILED_URL, webhook и PLATEGA_SUPPORTED_CURRENCIES. Если у международного метода или страницы выбора другой набор валют, перечислите объединение реально доступных кодов и ограничьте неподходящие кнопки на уровне тарифов.

Кнопка PLATEGA_SUBSCRIPTION_ENABLED продаёт мандат (paymentMethod: 6), а не разовый платёж. Расписание принадлежит Platega: она списывает оплату сама каждый период и присылает результат каждой попытки на тот же вебхук. Локальный воркер автопродления к Platega не обращается — у провайдера нет API списания по сохранённому методу, поэтому провайдер намеренно не объявляет supports_recurring.

Как это выглядит в работе:

  • Первое списание. Колбэк со SubscriptionId подтверждает исходный чекаут; локальный платёж хранит id подписки в provider_payment_id — это единственная долговременная связь будущих списаний с клиентом.
  • Продления. Каждое следующее списание создаёт отдельный платёж с ключом идемпотентности platega-sub:<subscription>:<charge>, так что повтор колбэка не выдаёт подписку второй раз. Сумма и срок берутся из мандата, а не из колбэка.
  • Автопродление в интерфейсе. Флаг «Автопродление» зеркалит состояние Platega. Клиент может его только выключить: выключение отменяет мандат в Platega (POST /subscription/{id}/cancel), и если провайдер отмену не подтвердил, флаг остаётся включённым, а пользователь видит ошибку. Новый мандат оформляется новой покупкой.
  • Сбои. Неуспешное списание без NextChargeAt считается терминальным: мандат помечается отменённым, автопродление выключается. Если NextChargeAt есть — мандат остаётся past_due, Platega повторит попытку.
  • В интервал Platega укладываются только тарифы на 1 и 12 месяцев (месяц/год). Для остальных периодов кнопка скрыта.
  • Кнопка доступна только для периодических подписок: трафик, HWID-устройства и смена тарифа остаются разовыми покупками.
  • Чекаут с промокодом кнопку скрывает: мандат списывает одну и ту же сумму бесконечно, поэтому разовая скидка в нём неприменима.
  • Сумма мандата фиксируется при оформлении. Изменение цены тарифа не меняет уже оформленные подписки — их нужно оформить заново.

SeverPay подключается как отдельный платежный метод с собственным MID, token и сроком жизни платежной ссылки.

  1. Включите SEVERPAY_ENABLED.
  2. Укажите SEVERPAY_BASE_URL.
  3. Заполните SEVERPAY_MID и SEVERPAY_TOKEN.
  4. Скопируйте URL вебхука из админ-панели и укажите его в кабинете SeverPay.
  5. При необходимости задайте SEVERPAY_LIFETIME_MINUTES.

Wata подключается как отдельный провайдер с bearer token, платежными ссылками и опциональной проверкой подписи webhook.

  1. Включите WATA_ENABLED.
  2. Укажите WATA_BASE_URL и WATA_API_TOKEN.
  3. Настройте WATA_LINK_TTL_MINUTES.
  4. Скопируйте URL вебхука из админ-панели и укажите его в кабинете Wata.
  5. При необходимости включите WATA_WEBHOOK_VERIFY_SIGNATURE.
  6. Если используется проверка подписи, задайте WATA_PUBLIC_KEY.
  7. Для IP-фильтрации заполните WATA_TRUSTED_IPS.
  • WATA_LINK_TTL_MINUTES должен быть от 15 до 43200.

CryptoPay используется для криптовалютных платежей через отдельный токен и сеть Crypto Bot API.

  1. Включите CRYPTOPAY_ENABLED.
  2. Укажите CRYPTOPAY_TOKEN.
  3. Выберите CRYPTOPAY_NETWORK: mainnet или testnet.
  4. Задайте CRYPTOPAY_CURRENCY_TYPE: fiat или crypto.
  5. Проверьте CRYPTOPAY_ASSET, например RUB, USDT или BTC.
  6. Скопируйте URL вебхука из админ-панели и укажите его в CryptoPay.
  • Testnet-токен должен использоваться только с testnet.
  • Mainnet-токен должен использоваться только с mainnet.
  • Если сумма или asset выглядят неверно, проверьте сочетание CRYPTOPAY_CURRENCY_TYPE и CRYPTOPAY_ASSET.

Интеграция работает в двух режимах. Если включены TRIBUTE_ENABLED и TRIBUTE_SHOP_ENABLED и указан TRIBUTE_SHOP_ID, Minishop в первую очередь создаёт динамический заказ через Tribute Shop API: сумма и валюта заказа точно соответствуют локальному расчёту Minishop. Заранее опубликованные подписки и Digital Products из Creator API остаются резервным вариантом для неподдерживаемого Shop-сценария или полностью заменяют Shop API, когда TRIBUTE_SHOP_ENABLED=false.

  1. В кабинете Tribute создайте Shop, разрешите recurrent payments, получите API key и скопируйте числовой ID этого Shop.
  2. В Система -> Настройки -> Платежи включите TRIBUTE_ENABLED, сохраните TRIBUTE_API_KEY, укажите TRIBUTE_SHOP_ID и включите TRIBUTE_SHOP_ENABLED.
  3. Добавьте в Tribute webhook WEBHOOK_BASE_URL + /webhook/tribute. Один URL принимает Shop-события и Creator-события; заголовок trbt-signature проверяется HMAC-SHA256 по исходному body с API key.
  4. Если нужен Creator fallback, заранее создайте подписки и Digital Products и заполните их ссылки и ID в редакторе тарифа.
  5. Проверьте тестовый shop_order, рекуррентный shop_order_charge_success и отмену shop_order_cancelled. Для fallback отдельно проверьте new_subscription, renewed_subscription, cancelled_subscription и new_digital_product.
  • Для обычной period-подписки Minishop создаёт рекуррентный Shop Order только на локальные сроки 1, 3, 6 или 12 месяцев (monthly, quarterly, halfyearly, yearly). Другие сроки, включая поддерживаемый самим Tribute weekly, через Shop-интеграцию Minishop не создаются.
  • Одноразовый Shop Order поддерживает обычный и premium-трафик, докупку трафика, отдельную покупку HWID-устройств и рассчитанную Minishop доплату за смену тарифа. В заказ передаётся точная локальная сумма в RUB, EUR или USD; несовпадение суммы, валюты или пользователя в webhook помещает событие в quarantine без выдачи доступа.
  • Каждый заказ создаётся строго для настроенного TRIBUTE_SHOP_ID; Shop webhook с другим ID или без него отклоняется. Допустимая сумма заказа — от 100 до 300000 копеек/центов.
  • Shop API считается настроенным только вместе с TRIBUTE_SHOP_ID. Пока ID не указан, включённый флаг ничего не меняет: провайдер продаёт только настроенные Creator-подписки и Digital Products, а покупка устройств и доплата за смену тарифа через Tribute недоступны — их сумму способен передать только Shop Order.
  • Для этих сценариев поля tribute у тарифа не нужны. Они используются только при переходе на Creator fallback.
  • Для рекуррентной подписки с ценовой скидкой Minishop передаёт полную цену следующих циклов в amount, а скидочную цену первого списания — в firstPeriodAmount. Webhook первого платежа обязан подтвердить обе суммы; все продления учитываются уже по полной цене. Для рекуррентного Shop Order разрешён только промокод со скидкой цены: бонусные дни, множитель срока или трафика отклоняются, поскольку расписанием списаний и авторитетной датой окончания управляет Tribute. Для одноразовых Shop Order это ограничение не применяется. Комбинированный checkout «продление подписки + HWID-устройства» (hwid_renewal) по-прежнему не поддерживается; устройства можно купить отдельным одноразовым заказом.
  • Цена рекуррентного Shop Order фиксируется Tribute при его создании. Последующее изменение цены тарифа в Minishop не меняет уже оформленное списание: такой пользователь остаётся на прежней цене до отмены и новой подписки. Не отключайте, не удаляйте и не переименовывайте тариф, пока к нему привязаны активные рекуррентные заказы. Не меняйте TRIBUTE_SHOP_ID, пока такие заказы активны: сначала отмените их и дождитесь shop_order_cancelled, иначе последующие webhook не пройдут проверку Shop ID.

Minishop не использует Shop-оплату в Telegram Stars, paymentToken/Token Charging или предоплаченный баланс Tribute. Если внешний Creator Digital Product предлагает свои способы оплаты, их выбор и проведение остаются на стороне Tribute.

  • Tribute публикует отдельную подписку под каждое предложение, поэтому ссылка, subscription_id и period_id задаются у каждого локального срока отдельно — в редакторе тарифа, в разделе «Подписка Tribute». Ссылка вида https://t.me/tribute/app?startapp=ep_... должна вести именно на ту подписку, которая продаёт этот срок. Если все сроки продаёт одна подписка, достаточно повторить её ссылку и subscription_id в каждой строке.
  • Числовых ID нет ни в кабинете Tribute, ни в share-ссылке: их выдаёт только Creator API. Поэтому кнопка «Подтянуть из Tribute» в редакторе тарифа читает Subscriptions API и Products API тем же TRIBUTE_API_KEY. Выбор подписки подставляет subscription_id и period_id во все локальные сроки: Tribute-периоды monthly, quarterly, halfyearly и yearly сопоставляются с 1, 3, 6 и 12 месяцами. Периоды, которых нет в подписке, остаются незаполненными и попадают в список расхождений. Share-ссылку API не отдаёт — её по-прежнему копируют из кабинета вручную.
  • Для фиксированных пакетов обычного и premium-трафика можно указать product_id и ссылку заранее созданного Digital Product. После загрузки каталога поле ID товара становится списком, а выбор подставляет ещё и ссылку — её Products API, в отличие от подписок, публикует.
  • Цена и цикл таких подписок/товаров задаются в Tribute. Локальная цена отображается в Minishop, но не отправляется по Creator-ссылке, поэтому администратор должен вручную поддерживать цены одинаковыми. Загруженный каталог сверяется с текущим тарифом: редактор показывает расхождение цены и валюты, а также ID, которых больше нет в Tribute или которые продают другой срок.
  • Не удаляйте и не переиспользуйте subscription_id, period_id и product_id, пока возможна доставка отложенных webhook или возвратов по этим продажам. Сначала уберите ссылку из новых checkout, дождитесь окончания расчётного/возвратного окна Tribute и только затем удаляйте mapping.

Creator donations намеренно не используются для продаж: донатор сам выбирает сумму, а webhook не даёт устойчивой корреляции с конкретным внутренним заказом Minishop. События new_donation и recurrent_donation поэтому не активируют тариф, трафик или устройства.

  • Доступ меняется только после webhook с корректной подписью. Повторные доставки дедуплицируются, а устаревшее событие не может откатить уже обработанное продление.
  • new_subscription/renewed_subscription и shop_order/shop_order_charge_success продлевают доступ по подтверждённому событию. Промежуточные Shop-события shop_order_payment_received и shop_order_prepaid подтверждаются без выдачи доступа: Minishop ждёт финальный shop_order. Creator expires_at считается авторитетной датой; trial и gift поддерживаются без локального реферального бонуса за бесплатный период.
  • Пока у пользователя активно рекуррентное списание Tribute, Minishop не разрешает заменить тариф или оформить другую period-подписку. Сначала пользователь должен отменить рекуррентность в Tribute, а Minishop — получить shop_order_cancelled или cancelled_subscription. Отмена выключает следующие списания, но оплаченный доступ сохраняется до текущей даты окончания.
  • Если два рекуррентных Shop Order всё же были оплачены конкурентно до первого webhook, Minishop отменяет второй заказ, инициирует возврат его первого списания и не выдаёт по нему доступ. Пока Tribute не подтвердит возврат, событие остаётся в quarantine для ручной проверки.
  • shop_order_charge_failed не выдаёт новый срок. Minishop ждёт предусмотренные Tribute повторные попытки и отключает локальное автопродление после третьей неудачи; более поздний успешный charge снова синхронизирует состояние.
  • digital_product_refunded помечает связанный платёж как возвращённый. shop_order_refunded помечает возвращённым завершённый одноразовый платёж, а возврат рекуррентного заказа требует ручной проверки учёта и entitlement. Уже израсходованный трафик и выданные/использованные устройства автоматически не отзываются.

Heleket используется для крипто-инвойсов с merchant ID, ключом платежного API, валютой инвойса и настройками проверки webhook.

  1. Включите HELEKET_ENABLED.
  2. Укажите HELEKET_BASE_URL, HELEKET_MERCHANT_ID и HELEKET_API_KEY.
  3. Настройте HELEKET_CURRENCY.
  4. При необходимости задайте HELEKET_TO_CURRENCY и HELEKET_NETWORK.
  5. Проверьте HELEKET_RETURN_URL и HELEKET_SUCCESS_URL.
  6. Настройте HELEKET_LIFETIME_SECONDS.
  7. Скопируйте URL вебхука из админ-панели и укажите его в кабинете Heleket.
  8. При необходимости включите HELEKET_VERIFY_WEBHOOK_SIGNATURE.
  9. Для IP-фильтрации заполните HELEKET_TRUSTED_IPS.
  • HELEKET_LIFETIME_SECONDS должен быть от 300 до 43200.
  • Заказы со статусами paid и paid_over активируются только при is_final=true. Для paid_over начисляется исходный фиксированный объём заказа, без доплаты за переплату.

PayKilla используется для крипто-инвойсов V2 через hosted checkout https://gopay.paykilla.com/{invoice_id}.

API-запросы подписываются HMAC-SHA256. Webhook проверяется по заголовку X-API-SIGN и raw body.

  • PayKilla строго валидирует текстовые поля invoice.
  • В purpose и description Minishop отправляет простой английский текст <WEBAPP_TITLE> payment <id>.
  • Локализованное описание платежа остается только внутри Minishop.
  • ASCII-safe sanitizer допускает ASCII-буквы, цифры, пробелы, _, ., ,.
  • Минимальная сумма платежа задается настройками PAYKILLA_MIN_PAYMENT_AMOUNT и PAYKILLA_MIN_PAYMENT_CURRENCY; по умолчанию это 10 USD.
  • Если выбранный тариф/пакет ниже этого порога после конвертации, Telegram bot не показывает кнопку PayKilla, WebApp показывает метод неактивным, а API создания платежа возвращает ошибку payment_amount_below_minimum.

Minishop создает invoice в валюте, которую PayKilla принимает в поле currency.

Для fiat-invoice сумма округляется до двух знаков; для криптоактивов сохраняется точная десятичная величина. При успешном webhook Minishop сверяет сумму и валюту с аутентифицированным invoice PayKilla до активации заказа.

Если валюта тарифа входит в PAYKILLA_INVOICE_CURRENCIES, сумма отправляется как есть.

Если валюта тарифа не входит в список, сумма конвертируется в PAYKILLA_CURRENCY. По умолчанию рублевые тарифы конвертируются в USD через ExchangeRate-API с кэшем PAYKILLA_EXCHANGE_RATE_CACHE_SECONDS.

Перед созданием invoice Minishop читает GET /api/v2/currency и проверяет invoiceMin/invoiceMax для валюты инвойса. Этот endpoint также показывает актуальные currency/payment-method ограничения конкретного merchant account.

Payload создания invoice содержит обязательные поля type, purpose, currency, totalPrice и paymentCurrencies.

Дополнительно отправляются clientOrderId, description, expiredAt, userPaysServiceFee и userPaysNetworkFee.

Redirect URLs в PayKilla не отправляются. Завершение платежа обрабатывается через webhook.

  1. В PayKilla Dashboard откройте Settings -> API keys.
  2. Создайте ключ типа HMAC.
  3. Для приема оплат включите permission INVOICE.
  4. Permission WITHDRAWAL не нужен для Minishop-платежей.
  5. Сохраните publicKey в PAYKILLA_API_KEY.
  6. Сохраните secretKey в PAYKILLA_SECRET_KEY.
  1. В PayKilla Dashboard откройте Settings -> Webhooks.
  2. Скопируйте URL вебхука из админ-панели и укажите его в PayKilla.
  3. Включите минимальные события: INVOICE_PAID, INVOICE_EXPIRED.
  4. Для production также включите PAYMENT_COMPLETED, PAYMENT_FAILED, PAYMENT_OVERPAID, PAYMENT_UNDERPAID, PAYMENT_PARTIAL, COMPLIANCE_FAILED.
  5. Если нужны промежуточные статусы в логах, дополнительно включите INVOICE_CREATED, PAYMENT_PENDING, TRANSACTION_CONFIRMED и TRANSACTION_FINAL.
  6. Оставьте PAYKILLA_VERIFY_WEBHOOK_SIGNATURE=True.
  1. Включите PAYKILLA_ENABLED.
  2. Укажите PAYKILLA_API_KEY и PAYKILLA_SECRET_KEY.
  3. Оставьте PAYKILLA_CURRENCY=USD, если PayKilla не принимает валюту тарифов как invoice currency. В PAYKILLA_INVOICE_CURRENCIES укажите валюты, доступные в PayKilla для поля currency, например USD,EUR.
  4. В PAYKILLA_PAYMENT_CURRENCIES оставьте USDTTRC,BTC,ETH,USDTBSC,USDTTON или укажите другой список тикеров, доступных в PayKilla Dashboard; USDTTRC должен идти первым.
  5. Оставьте PAYKILLA_MIN_PAYMENT_AMOUNT=10 и PAYKILLA_MIN_PAYMENT_CURRENCY=USD, если минимальный invoice PayKilla равен 10 USD.
  6. Убедитесь, что webhook /webhook/paykilla настроен в PayKilla: Minishop не отправляет redirect URLs в PayKilla и полагается на webhook для активации платежа.
  7. Добавьте paykilla в PAYMENT_METHODS_ORDER, если хотите задать явный порядок кнопок.

LAVA Business используется для рублевых оплат картами и СБП через счета https://api.lava.ru.

Исходящие API-запросы подписываются HMAC-SHA256 от raw body, подпись передается в заголовке Signature. Webhook проверяется по заголовку Authorization: принимается подпись raw body или sorted-keys JSON (legacy PHP SDK).

  • Счета выставляются только в рублях (RUB).
  • hookUrl передается автоматически при создании счета, если задан WEBHOOK_BASE_URL.
  • LAVA_INCLUDE_SERVICES ограничивает способы оплаты на странице счета, например card,sbp.
  • При успешной оплате сумма из webhook сверяется с суммой платежа; расхождение отклоняется.
  1. Включите LAVA_ENABLED.
  2. Укажите LAVA_SHOP_ID и LAVA_SECRET_KEY из кабинета LAVA Business.
  3. Если магазин использует отдельный дополнительный ключ для вебхуков, задайте LAVA_WEBHOOK_SECRET; пустое значение означает использование LAVA_SECRET_KEY.
  4. При необходимости задайте LAVA_LIFETIME_MINUTES (1..7200) и LAVA_RETURN_URL.
  5. Скопируйте URL вебхука из админ-панели и при необходимости укажите его в кабинете LAVA.

Pally / PayPalych используется для оплат через hosted-страницу счета https://pally.info. Minishop создает счет через POST /api/v1/bill/create, сохраняет bill_id, а завершение платежа обрабатывает через Result URL /webhook/pally.

  • Поддерживаемые валюты счета: RUB, USD, EUR.
  • API-запросы отправляются как form-urlencoded поля с Authorization: Bearer <PALLY_API_TOKEN>.
  • Подпись postback проверяется по формуле strtoupper(md5(OutSum:InvId:token)); token берется из PALLY_SIGNATURE_TOKEN, а если он пустой - из PALLY_API_TOKEN.
  • OutSum входит в подпись postback и строго сверяется с локальным счетом. При PALLY_PAYER_PAYS_COMMISSION=1 допускается только подписанный OutSum больше суммы счета (комиссия сверху); начисление всегда берется из локального заказа.
  • Статусы SUCCESS и OVERPAID активируют покупку, FAIL помечает платеж неуспешным, NEW, PROCESS и UNDERPAID остаются pending.
  1. Включите PALLY_ENABLED.
  2. Укажите PALLY_API_TOKEN, PALLY_SHOP_ID и при необходимости отдельный PALLY_SIGNATURE_TOKEN.
  3. В кабинете Pally укажите Result URL: WEBHOOK_BASE_URL + /webhook/pally.
  4. При необходимости задайте PALLY_RETURN_URL, PALLY_SUCCESS_URL, PALLY_FAIL_URL, PALLY_TTL_SECONDS и PALLY_PAYER_PAYS_COMMISSION. Для рублевых счетов действует минимальная внешняя сумма PALLY_MIN_PAYMENT_AMOUNT_RUB=30: смешанная оплата партнерским балансом оставляет Pally не меньше этого значения. Отдельные лимиты для USD и EUR задаются через PALLY_MIN_PAYMENT_AMOUNT_USD и PALLY_MIN_PAYMENT_AMOUNT_EUR.
  5. Если нужна жесткая кнопка конкретного метода на стороне Pally, задайте PALLY_PAYMENT_METHOD=BANK_CARD или PALLY_PAYMENT_METHOD=SBP.

CloudPayments используется для оплат картами через Orders API https://api.cloudpayments.ru/orders/create.

Исходящие запросы авторизуются HTTP Basic auth: логин — CLOUDPAYMENTS_PUBLIC_ID, пароль — CLOUDPAYMENTS_API_SECRET. Уведомления Pay/Fail приходят как application/x-www-form-urlencoded и подписываются HMAC-SHA256 (base64) от raw body на CLOUDPAYMENTS_API_SECRET в заголовке Content-HMAC (старые интеграции — X-Content-HMAC).

  • Платёж создаётся как заказ (order) со ссылкой https://orders.cloudpayments.ru/...; InvoiceId — это внутренний ID платежа.
  • Поддерживаемые валюты: RUB, USD, EUR, GBP, KZT, UAH, BYN, AZN, AMD, KGS.
  • При успешной оплате сумма из webhook сверяется с суммой платежа; расхождение отклоняется кодом 12.
  • При CLOUDPAYMENTS_RECURRING_ENABLED=true Pay webhook сохраняет CloudPayments Token как способ оплаты пользователя, а автопродление выполняет merchant-initiated запрос /payments/tokens/charge с TrInitiatorCode=0 и PaymentScheduled=1.
  • Встроенные CloudPayments subscriptions не используются: срок подписки, HWID-продления, отмена автопродления и повторная активация остаются в общей логике бота.
  • Backend отвечает CloudPayments телом {"code": 0} при успешной обработке.
  1. Включите CLOUDPAYMENTS_ENABLED.
  2. Укажите CLOUDPAYMENTS_PUBLIC_ID и CLOUDPAYMENTS_API_SECRET из кабинета CloudPayments.
  3. При необходимости задайте CLOUDPAYMENTS_RETURN_URL и CLOUDPAYMENTS_FAILED_URL.
  4. Скопируйте URL вебхука из админ-панели и укажите его в CloudPayments как адрес уведомлений Pay и Fail.
  5. Для автопродления включите получение Token в уведомлении Pay на стороне CloudPayments и задайте CLOUDPAYMENTS_RECURRING_ENABLED=true.
  6. Для IP-фильтрации при необходимости заполните CLOUDPAYMENTS_TRUSTED_IPS.

Overpay построен на платформе BeGateway: платёж создаётся как hosted-checkout через POST https://checkout.overpay.io/ctp/api/checkouts, пользователь перенаправляется на redirect_url, а завершение обрабатывается через notification URL /webhook/overpay.

Исходящие запросы авторизуются HTTP Basic auth: логин — OVERPAY_SHOP_ID, пароль — OVERPAY_SECRET_KEY. Суммы передаются в минимальных единицах валюты (копейки/центы). Уведомления приходят JSON POST’ом и авторизуются теми же HTTP Basic-кредами; tracking_id — это внутренний ID платежа.

  • Checkout создаётся с transaction_type=payment; в ответе сохраняется token, а ссылка redirect_url показывается пользователю.
  • Поддерживаемые валюты: USD, EUR, RUB, GBP и другие в зависимости от контракта магазина.
  • При успешной оплате сумма из webhook (в минимальных единицах) должна покрывать сумму платежа; недоплата отклоняется кодом 400, а переплата активирует исходный фиксированный заказ.
  • При OVERPAY_RECURRING_ENABLED=true checkout создаётся с additional_data.contract=["recurring"]; успешный webhook сохраняет credit_card.token как способ оплаты пользователя, а автопродление выполняет списание POST https://gateway.overpay.io/transactions/payments по сохранённому токену.
  • Встроенные Overpay subscriptions не используются: срок подписки, HWID-продления, отмена автопродления и повторная активация остаются в общей логике бота.
  1. Включите OVERPAY_ENABLED.
  2. Укажите OVERPAY_SHOP_ID и OVERPAY_SECRET_KEY из кабинета Overpay.
  3. При необходимости задайте OVERPAY_RETURN_URL, OVERPAY_SUCCESS_URL, OVERPAY_DECLINE_URL, OVERPAY_FAIL_URL.
  4. Скопируйте URL вебхука (WEBHOOK_BASE_URL + /webhook/overpay) и укажите его в кабинете Overpay как notification URL.
  5. Для автопродления задайте OVERPAY_RECURRING_ENABLED=true.
  6. Для IP-фильтрации при необходимости заполните OVERPAY_TRUSTED_IPS.

Stripe использует Checkout Sessions для hosted-ссылок оплаты и PaymentIntents для автопродления, управляемого приложением.

  • Платёж создаётся как hosted Checkout Session; внутренний ID платежа передаётся в client_reference_id и metadata (payment_db_id).
  • При STRIPE_RECURRING_ENABLED=true Checkout создаётся с payment_intent_data[setup_future_usage]=off_session; успешные webhook сохраняют customer и payment_method, а автопродление создаёт off-session PaymentIntent.
  • Встроенные Stripe Billing Subscriptions не используются: срок подписки, HWID-продления, отмена автопродления и повторные попытки остаются в общей логике бота.
  • STRIPE_SUPPORTED_CURRENCIES ограничивает кнопки оплаты валютами, которые поддерживаются вашим аккаунтом Stripe и включёнными способами оплаты.
  1. Включите STRIPE_ENABLED.
  2. Укажите STRIPE_SECRET_KEY из Stripe Dashboard.
  3. Скопируйте URL вебхука из админ-панели и укажите его в Stripe Dashboard.
  4. Включите события checkout.session.completed, checkout.session.expired, payment_intent.succeeded, payment_intent.payment_failed, payment_intent.canceled.
  5. Задайте STRIPE_WEBHOOK_SECRET из signing secret эндпоинта (whsec_...).
  6. При необходимости задайте STRIPE_RETURN_URL и STRIPE_CANCEL_URL.
  7. Для автопродления включите STRIPE_RECURRING_ENABLED=true.

Telegram Stars используются напрямую и поддерживаются в legacy-ценах и JSON-каталоге тарифов.

  • Цены period-подписок.
  • Пакеты трафика.
  • Premium-докупки.
  • HWID-докупки, если они включены в каталоге тарифов.
  1. Включите STARS_ENABLED.
  2. Проверьте Stars-цены в legacy-настройках или JSON-каталоге.
  3. Убедитесь, что цена округляется до целого количества Stars.
  4. Проверьте сценарии смены тарифа.
  • Отдельный платежный webhook не нужен.
  • Stars-события приходят через webhook Telegram-бота: WEBHOOK_BASE_URL + /tg/webhook.
  • XTR/Stars-докупки не конвертируются без явно заданного курса.