ДОКУМЕНТАЦИЯ
ПЛАТЕЖИ · § 012
FreshDonate из коробки умеет работать с шестью шлюзами: ЮKassa, Heleket, CryptoBot, Wata, Robokassa и Tebex. Получаешь ключи у провайдера, вписываешь в админ-панель, прописываешь webhook - готово.
§ 012.01
Жизненный цикл платежа от клика по кнопке до выдачи товара
Игрок выбрал товар на витрине, нажал "Оплатить" → shop отправляет POST /payments в backend с productId, ником, email и id метода оплаты.
Backend создаёт запись payment, идёт в API провайдера (например YooKassa) и получает confirmation_url - ссылку, куда отправить игрока.
Игрок попадает на страницу провайдера, вводит карту/крипту/СБП и оплачивает. По результату его редиректит на PAYMENT_RETURN_URL магазина.
Параллельно провайдер шлёт серверный вебхук на WEBHOOK_BASE_URL/webhooks/<provider>. Backend проверяет подпись/IP, помечает платёж paid и кладёт его в очередь доставки.
Плагин или RCON забирает покупку из очереди и выдаёт её игроку. Покупателю на почту уходит email-чек.
§ 012.02
Каждый можно включить независимо и подключить хоть все шесть одновременно
ЮKassa
Карты РФ, СБП, ЮMoney, SberPay, T-Pay
RUB
~2%
РФ
Heleket
Криптовалюта: BTC, ETH, USDT и другие
USD
~0.5%
Весь мир
CryptoBot
Криптоплатежи через Telegram @CryptoBot
USD
~3%
Весь мир
Wata
Карты, СБП. Имеет вывод дохода в крипту
RUB
~10%
РФ + СНГ
Robokassa
Карты, СБП, электронные кошельки
RUB
~3%
РФ
Tebex
Visa, MasterCard, Google/Apple pay, Revolut.. Через Headless API
USD / EUR
~5%
Весь мир
※ Комиссии указаны ориентировочно - реальный процент зависит от твоего договора с провайдером.
§ 012.03
Минимальный набор перед началом
ДОМЕН
Публичный HTTPS-адрес backend
WEBHOOK_BASE_URL
АККАУНТ
Активный аккаунт у провайдера
с подтверждением личности
ПАНЕЛЬ
Доступ к админ-панели FreshDonate
panel.your-domain.com
ДОКУМЕНТЫ
Вероятно нужно будет изменить документы на странице магазина
зависит от платёжки
Важно
Все провайдеры требуют публичный HTTPS-URL для приёма вебхуков. localhost или http:// работать не будут. Если ты тестируешь локально - подними туннель через cloudflared, ngrok или localhost.run и подставь его в WEBHOOK_BASE_URL.
§ 012.04
Всё подключение делается через UI, ничего трогать в .env не надо
В админ-панели открой Магазин → Платёжные системы. Слева - форма провайдера, справа - список всех доступных шлюзов. Выбери нужный и переключи "Включить" наверху страницы.
После сохранения настройки лежат в БД (payment_providers), backend не нужно перезапускать - изменения подхватятся на следующем запросе.
※ Бекенд при старте делает seed - создаёт все 6 шлюзов с пустыми credentials в выключенном состоянии. Если в базе уже есть запись с твоими ключами, повторный seed её не затрёт.
§ 012.05
Карты, СБП, ЮMoney, SberPay, T-Pay. Только RUB
В личном кабинете yookassa.ru зайди в Интеграция → Ключи API. Тебе нужны:
shopId
Идентификатор магазина (число в правом верхнем углу личного кабинета и на странице ключей).
secretKey
Секретный ключ. Бывает test_* и live_* - используй тот, который соответствует режиму магазина в кабинете.
Затем настрой webhook: Интеграция → HTTP-уведомления → Добавить. Адрес:
WEBHOOK URL
https://api.your-domain.com/webhooks/yookassa
Подпиши уведомления на события: payment.succeeded, payment.canceled, refund.succeeded.
※ ЮKassa не подписывает вебхуки - аутентификация по списку IP. Backend проверяет, что вебхук пришёл с 185.71.76/77.*, 77.75.153/156/157.* или 2a02:5180:*. Если ты за прокси без x-forwarded-for - поставь в .env YOOKASSA_SKIP_IP_CHECK=true, но только в тестовом режиме.
§ 012.06
Криптовалютные платежи. BTC, ETH, USDT и десятки других монет
В личном кабинете heleket.com создай мерчанта и забери:
merchantId
UUID мерчанта из карточки в кабинете.
apiKey
Payment API Key. Используется и для подписи запросов в Heleket, и для проверки подписи вебхука.
При создании мерчанта (или в его настройках) укажи URL вебхука:
WEBHOOK URL
https://api.your-domain.com/webhooks/heleket
Валюта аккаунта - в карточке провайдера выбери одну из: USD, EUR, RUB. Если товары в другой валюте, сумма пересчитается по курсам из общих настроек магазина.
※ Heleket дополнительно проверяет IP-источник (31.133.220.*) И MD5-подпись каждого webhook. Подпись считается как md5(base64(json_body) + apiKey).
§ 012.07
Криптоплатежи через Telegram-бота @CryptoBot. USDT, TON, BTC и другие
Открой в Telegram бота @CryptoBot (или @CryptoTestnetBot для песочницы) → Crypto Pay (/pay) → Create App. Получишь:
apiToken
Токен приложения, выглядит как 12345:AAaaBbCc.... Вставь его в поле API Token в админ-панели.
В том же приложении CryptoBot включи Webhooks и укажи URL:
WEBHOOK URL
https://api.your-domain.com/webhooks/cryptobot
Включи тестовый режим в админке, если используешь токен от @CryptoTestnetBot - тогда backend будет ходить в testnet-pay.crypt.bot вместо боевого pay.crypt.bot.
※ CryptoBot подписывает вебхук HMAC-SHA256 от сырого тела, ключ - sha256(apiToken), заголовок - crypto-pay-api-signature. Подпись считается по байтам, которые приходят в запросе.
§ 012.08
Карты, СБП. Вывод дохода в крипту
Для подключения подайте заявку на сайте wata.pro, при подаче укажите тип верификации "Рекомендация" и введите FreshDonate
В кабинете wata.pro (или api-sandbox.wata.pro для теста) выпусти Access Token. Это JWT - подпиши его в кабинете и сразу скопируй (после закрытия модалки токен будет недоступен).
apiKey
JWT-токен. Один токен работает либо в prod, либо в sandbox - не оба сразу. Тестовый режим в админке переключает базовый URL Wata.
В терминале Wata укажи URL для уведомлений (Предварительно включите "Вебхук оплаты"):
WEBHOOK URL
https://api.your-domain.com/webhooks/wata
※ Wata подписывает вебхуки RSA-SHA512 по сырому телу, подпись приходит в заголовке X-Signature в base64. Публичный ключ backend сам подтягивает с /api/h2h/public-key и кеширует на время жизни процесса.
§ 012.09
Карты, СБП, электронные кошельки. Redirect-only API
В кабинете robokassa.ru зайди в Технические настройки → Технические настройки магазина и забери:
merchantLogin
Идентификатор магазина (логин). Используется в подписи и в редиректе.
password1
Пароль #1 - подписывает редирект на оплату (что мы отправляем покупателю).
password2
Пароль #2 - подписывает ResultURL-уведомление (что приходит к нам от Robokassa). Никогда не путай: пароль #2 ушёл в редирект = подделка.
В тех. настройках укажи ResultURL и метод POST:
WEBHOOK URL
https://api.your-domain.com/webhooks/robokassa
В админ-панели выбери алгоритм подписи (SHA256 по умолчанию, либо MD5) - он должен совпадать с настройкой в кабинете Robokassa, иначе все вебхуки будут отбиваться 403.
※ Robokassa требует, чтобы InvId был положительным 32-битным числом, а у нас платежи - UUID. Backend хеширует UUID в 31-битный int и передаёт оригинал UUID в Shp_paymentId - именно по нему ResultURL находит платёж и завершает его. На ResultURL обязательно нужно ответить телом OK<InvId>, иначе Robokassa будет долбить вебхук снова и снова.
§ 012.10
Headless API. Только премиум-ники Mojang. Платежи через Tebex Checkout
В Tebex Dashboard создай Webstore типа Minecraft. Далее Webstore Builder → API Keys, забери:
webstoreToken
Публичный токен витрины (Public Token).
privateKey
Приватный ключ. Используется как пароль для HTTP Basic к Headless API.
webhookSecret
Developers → Webhooks → Endpoints. Создай endpoint, скопируй секрет.
URL вебхука для Tebex:
WEBHOOK URL
https://api.your-domain.com/webhooks/tebex
После добавления endpoint Tebex пришлёт validation.webhook с уникальным id - backend сам ответит этим же id, и endpoint в Tebex перейдёт в "Validated".
Coin-пакеты: обязательны
Tebex Headless API не позволяет передать произвольную сумму - корзина собирается из заранее созданных пакетов фиксированного номинала. В Tebex Dashboard → Packages создай 6 пакетов с ценами 1000, 100, 10, 1, 0.1, 0.01 в валюте аккаунта (USD/EUR). Тип - Single Payment, имя любое ("Coin 1000", "Coin 10" и т.д.). Скопируй Package ID каждого и вставь в админ-панели в раздел "Coin-пакеты Tebex". Без них checkout вернёт TEBEX_COINS_NOT_CONFIGURED.
Tebex также валидирует ник игрока через Mojang. На offline-mode серверах и для пиратских ников Tebex отвечает 404 "Invalid Username". Backend в этом случае подставляет известный премиум-ник из fallback-списка, чтобы корзина создалась - реальный ник игрока всё равно лежит в basket.custom.payment_id и используется при доставке.
§ 012.11
Все URL и способы проверки подлинности в одном месте
yookassa
/webhooks/yookassa
IP-allowlist (185.71.76/77.*, 77.75.153/156/157.*)
heleket
/webhooks/heleket
IP 31.133.220.* + MD5 подпись
cryptobot
/webhooks/cryptobot
HMAC-SHA256 по сырым байтам
wata
/webhooks/wata
RSA-SHA512 по сырым байтам
robokassa
/webhooks/robokassa
SHA256/MD5 от Password2 + InvId + OutSum
tebex
/webhooks/tebex
HMAC-SHA256(sha256(body)) + handshake
※ Базовый URL берётся из WEBHOOK_BASE_URL в .env бекенда. На проде это https://api.your-domain.com, локально - твой ngrok/cloudflared-туннель.
※ Каждый /webhooks/* endpoint защищён rate-limit (200 req/min). Если провайдер ретраит вебхуки часто - повысь RATE_LIMIT_MAX в .env.
§ 012.12
Кто платит комиссию платёжной системы - ты или покупатель
В карточке провайдера есть две связанные настройки: commissionPercent (сколько процентов берёт провайдер) и commissionRule (на кого вешать эту комиссию).
Продавец оплачивает
Комиссия вычитается из суммы платежа. Покупатель видит цену товара, вы получаете меньше.
Покупатель оплачивает
Комиссия добавляется к цене товара. Покупатель видит цену + комиссию, вы получаете полную цену товара.
Поровну (50/50)
Комиссия делится пополам. Покупатель доплачивает половину, вы недополучаете половину.
Пример: товар 100 ₽, комиссия 2.8%.
ПРИМЕР
seller: покупатель платит 100₽ → ты получаешь 97.20₽
buyer: цена 100₽ → покупатель платит 102.80₽ → ты получаешь 100₽
split: покупатель платит 101.40₽ → ты получаешь 98.60₽
※ Комиссия из настроек используется только для предварительного расчёта при создании платежа. Когда платёж проходит, backend перезаписывает её из реального ответа провайдера (income_amount у YooKassa, commission у Heleket и т.п.). Так что в статистике панели цифры будут точными, даже если ты в админке указал чуть-чуть не ту ставку.
§ 012.13
В какой валюте провайдер принимает деньги и от какой суммы
У каждого провайдера в админке два важных поля:
Валюта аккаунта
В какой валюте у тебя настроен аккаунт у провайдера. Если товар в магазине в другой валюте - сумма пересчитается по курсам из общих настроек магазина перед отправкой провайдеру. Для ЮKassa и Robokassa зашито в RUB, у Heleket / Wata / Tebex выбирается в дропдауне.
Минимальная сумма
Платежи на сумму меньше этой не будут отправляться через этого провайдера. Полезно если у YooKassa лимит 1₽, а ты не хочешь дёргать API из-за грошей. Диапазон 0.01 .. 10000.
§ 012.14
То, что увидит игрок на витрине
Провайдер - это бекенд-сущность. Чтобы игрок увидел его в магазине, нужно создать платёжный метод - кнопку с названием, иконкой и привязкой к провайдеру.
В админ-панели открой Магазин → Методы оплаты → Добавить и заполни:
Название
Текст на кнопке. Например "Российские карты и СБП" или "Telegram CryptoBot".
Иконка
Имя Lucide-иконки (i-lucide-credit-card, i-lucide-bitcoin, i-lucide-bot, ...). Все доступные иконки - на lucide.dev/icons.
Тип обработки
provider - оплата через подключённый шлюз. redirect - просто редирект по произвольной ссылке с плейсхолдерами {nickname}, {amount}, {email}, {product} и т.п. Полезно для интеграции с самописными платёжками или Telegram-ботами.
※ Можно создать несколько методов на одного провайдера - например "Карты РФ" и "СБП" оба на YooKassa, с разными иконками. Покупатель видит только включённые методы.
§ 012.15
Как погонять платежи без настоящих денег
У некоторых провайдеров в карточке есть тумблер testMode. Что он делает:
CryptoBot
Backend ходит в testnet-pay.crypt.bot. Нужен токен от @CryptoTestnetBot, не от боевого.
Wata
Backend ходит в api-sandbox.wata.pro. Токен sandbox != prod.
Robokassa
В редирект добавляется IsTest=1 - Robokassa открывает тестовую страницу без реального списания.
YooKassa, Heleket, Tebex
У этих провайдеров нет отдельного sandbox - тестовый режим включается в самом кабинете провайдера (отдельный test_* shopId/secretKey у YooKassa, тестовый мерчант у Heleket).
Демо-платежи (созданные через кнопку "Тест" в админке, без реального захода в API) не шлют email-чеки покупателю и не попадают в очередь доставки - чтобы не спамить плагин при отладке.
※ В NODE_ENV=development backend пропускает проверку IP/подписи для всех вебхуков. На проде такого делать нельзя - иначе любой сможет послать фейковый "оплачено" и забрать товар.
§ 012.16
Самые частые проблемы при первой настройке
Платёж создаётся, но вебхук не приходит
Проверь, что WEBHOOK_BASE_URL в .env действительно публичный HTTPS, что в кабинете провайдера прописан правильный URL и что nginx пробрасывает /webhooks/* на backend без редиректов. Логи: docker compose logs backend -f.
403 Forbidden в логах на /webhooks/yookassa
Backend не видит реальный IP клиента из-за прокси. В nginx-конфиге обязательно proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for. Для отладки можно временно поставить YOOKASSA_SKIP_IP_CHECK=true - но только в тестовом режиме.
403 Invalid signature
Не тот ключ. У Heleket apiKey должен быть Payment API Key (не General). У CryptoBot - apiToken от того же приложения, чьи ключи в кабинете. У Robokassa password2 в админке должен совпадать с тем, что в кабинете Robokassa.
TEBEX_INVALID_USERNAME
Mojang не знает такого ника. Сервер в offline-mode или игрок указал ник с опечаткой. Backend сам подставит fallback-ник, чтобы checkout прошёл - но если хочется убрать ворнинги, переходи на онлайн-сервер или используй другой шлюз.
TEBEX_COINS_NOT_CONFIGURED
Не заполнены Package ID для 6 coin-номиналов. Создай в Tebex Dashboard пакеты 1000 / 100 / 10 / 1 / 0.1 / 0.01 и вставь их ID в админке.
Robokassa ретраит вебхук бесконечно
ResultURL должен возвращать OK<InvId> в текстовом виде. Backend это уже делает, но если nginx переписывает Content-Type или ответ - Robokassa считает доставку неуспешной. Проверь, что nginx не вмешивается в тело ответа.
Платёж "висит" в статусе pending
Backend каждые несколько минут сам ходит в API провайдера и обновляет статус (см. payment-expiration плагин Fastify). Если за paymentLifetime игрок не оплатил - платёж помечается как expired и удаляется из очереди.
§ 012.17
Деньги принимаются - осталось доставлять покупки