Тарифы
Бот поддерживает два способа описания продаж:
- JSON-каталог тарифов из
TARIFFS_CONFIG_PATH(по умолчаниюdata/tariffs.json); - конфигурация через переменные
.env, если JSON-файл отсутствует.
JSON-каталог может содержать несколько тарифов разных моделей: подписки на срок, пакеты трафика без срока действия, разные наборы Internal Squads, лимиты устройств и пакеты докупки. Пример формата: data/tariffs.example.json.
Коротко по моделям:
period- подписка на срок с месячным лимитом трафика и опциональной докупкой GB поверх месячного лимита;traffic- покупка пакетов GB без пользовательского срока действия, где повторная покупка добавляет трафик к текущему остатку;- premium-сквады - дополнительный набор Internal Squads внутри любого тарифа, с отдельным названием, счетчиком, месячным лимитом и отдельными пакетами докупки.
Управление через админку
Заголовок раздела «Управление через админку»Каталог тарифов можно настраивать из Web App админки: раздел Система → Тарифы. Админка читает и сохраняет файл из TARIFFS_CONFIG_PATH, валидирует данные той же моделью TariffsConfig, что и бот, и атомарно перезаписывает JSON только после успешной проверки.
В интерфейсе доступны:
- добавление, редактирование и удаление тарифов;
- включение и выключение тарифа на витрине;
- выбор тарифа по умолчанию;
- настройка
period-тарифов: месячный лимит, периоды, RUB/Stars цены, пакеты докупки трафика; - настройка
traffic-тарифов: пакеты GB, RUB/Stars цены, курс конвертации; - настройка базовых Internal Squads из списка Remnawave;
- настройка premium-раздела: названия RU/EN, premium Internal Squads, месячный premium-лимит и RUB/Stars пакеты докупки premium-трафика;
- настройка базового HWID-лимита и пакетов докупки устройств.
После сохранения изменения применяются к новым запросам Web App сразу, потому что конфиг тарифов загружается из JSON при обращении. Уже созданные подписки сохраняют свой tariff_key; при удалении или отключении тарифа проверьте, что активные подписки с этим ключом не требуют дальнейшего продления или смены.
Подробности по админ-панели, правам доступа, сохранению настроек и списку разделов есть в админ-панели.
Как выбирается режим
Заголовок раздела «Как выбирается режим»Если файл из TARIFFS_CONFIG_PATH существует и проходит валидацию, используется каталог тарифов. В этом режиме TRAFFIC_PACKAGES и цены подписок из .env не формируют витрину продаж, потому что цены и пакеты берутся из JSON.
Если JSON-файл отсутствует, бот использует значения .env:
RUB_PRICE_*,STARS_PRICE_*и*_MONTHS_ENABLEDдля подписок на срок;TRAFFIC_PACKAGESиSTARS_TRAFFIC_PACKAGESдля продажи пакетов трафика;USER_TRAFFIC_LIMIT_GB,USER_TRAFFIC_STRATEGY,USER_SQUAD_UUIDS,USER_HWID_DEVICE_LIMITдля пользователей Remnawave.
В режиме без JSON-каталога наличие TRAFFIC_PACKAGES или STARS_TRAFFIC_PACKAGES переключает витрину на продажу трафика вместо подписок на срок.
Структура JSON-каталога
Заголовок раздела «Структура JSON-каталога»Минимальная структура:
Основные поля:
| Поле | Назначение |
|---|---|
default_tariff | Тариф по умолчанию для первичного выбора и привязки активных подписок без tariff_key. |
tariffs[].key | Стабильный ключ тарифа. Используется в платежах, подписках и смене тарифа. |
tariffs[].names | Названия тарифа по языкам. |
tariffs[].descriptions | Описания тарифа по языкам. |
tariffs[].enabled | Доступность тарифа на витрине. |
tariffs[].squad_uuids | Internal Squads Remnawave для пользователей тарифа. |
tariffs[].premium_names | Название premium-раздела по языкам. Используется в карточке лимита, модалке докупки premium-трафика и предупреждениях. Если поле не задано, используется Premium-серверы / Premium servers. |
tariffs[].premium_squad_uuids | Internal Squads с отдельным premium-лимитом. Ноды для учета берутся автоматически из accessible nodes этих сквадов через API панели. |
tariffs[].premium_monthly_gb | Отдельный месячный лимит трафика по premium-сквадам. 0 или отсутствие поля отключает отдельное ограничение. |
tariffs[].premium_topup_packages | Пакеты докупки premium-трафика в формате { "rub": [{ "gb": 10, "price": 99 }], "stars": [...] }. Требуют premium_squad_uuids. |
tariffs[].billing_model | Модель тарифа: period или traffic. |
tariffs[].hwid_device_limit | Базовый лимит HWID-устройств. 0 означает безлимит, отсутствие поля использует USER_HWID_DEVICE_LIMIT. |
tariffs[].hwid_device_packages | Пакеты докупки устройств. price — legacy/monthly fallback, prices задаёт полную цену пакета для периодов тарифа ("1", "3", "6", "12"), min_price задаёт минимальную цену prorate-докупки. |
Для period-тарифа также используются:
| Поле | Назначение |
|---|---|
monthly_gb | Базовый месячный лимит трафика тарифа. 0 означает безлимит. |
prices_rub | Цены периодов в рублях, ключ - количество месяцев. |
prices_stars | Цены периодов в Telegram Stars. |
enabled_periods | Периоды, доступные для покупки. |
topup_packages | Пакеты докупки трафика именно для этого тарифа. Если поле не задано или списки пустые, докупка для тарифа не показывается в Web App и Telegram-боте. |
Для traffic-тарифа используются:
| Поле | Назначение |
|---|---|
traffic_packages | Пакеты трафика в GB для рублей и Telegram Stars. |
conversion_rate_rub_per_gb | Курс для конвертации оставшихся дней period-тарифа в GB при смене на traffic-тариф. |
Если у traffic-тарифа нет RUB-пакетов, conversion_rate_rub_per_gb обязателен.
Period-тарифы
Заголовок раздела «Period-тарифы»period продает доступ на срок с месячным лимитом трафика.
При покупке или продлении:
- дата начала берется от текущей активной подписки, если она еще действует, иначе от текущего времени;
- срок считается календарными месяцами через
add_months; - промокод может добавить бонусные дни к рассчитанному сроку;
tier_baseline_bytesполучает значениеmonthly_gb;topup_balance_bytesсохраняется из текущей активной подписки;traffic_limit_bytesстановитсяtier_baseline_bytes + topup_balance_bytes;- в Remnawave отправляется
trafficLimitStrategy = MONTH; - в Remnawave отправляются Internal Squads из тарифа;
- в Remnawave отправляется эффективный HWID-лимит тарифа.
MONTH означает, что сброс использованного трафика выполняет Remnawave. Бот не рассчитывает дату сброса самостоятельно и не хранит отдельный период сброса для period-тарифов.
Докупка трафика для period-тарифа увеличивает topup_balance_bytes и общий traffic_limit_bytes. Этот баланс сохраняется в подписке и учитывается при продлении period-тарифа. В панель отправляется актуальный лимит, а доступ переводится в ACTIVE.
Premium-сквады и отдельный лимит
Заголовок раздела «Premium-сквады и отдельный лимит»Тариф может включать дополнительный набор Internal Squads с отдельным лимитом трафика. Это удобно для сценария “обычные серверы без изменений, premium-серверы ограничены отдельно”.
Правила:
- обычный лимит тарифа продолжает работать через
trafficLimitBytesRemnawave; - premium-трафик считается отдельно по нодам, доступным из
premium_squad_uuids; - список UUID нод не хранится в тарифе: бот запрашивает accessible nodes каждого premium-сквада у Remnawave и кеширует результат;
- пока premium-лимит не исчерпан, пользователь получает
squad_uuids + premium_squad_uuids; - при исчерпании premium-лимита бот убирает только premium-сквады, обычный доступ остается;
- после докупки premium-трафика бот возвращает premium-сквады, если новый лимит снова больше использованного premium-трафика.
- докупленный premium-трафик не сгорает в конце месяца: каждый месяц сначала расходуется
premium_monthly_gb, а докупленный остаток уменьшается только на трафик сверх месячного лимита; - при новом календарном месяце счетчик premium-трафика и
premium_topup_used_bytesсбрасываются, ноpremium_topup_balance_bytesпереносится дальше.
Если premium_squad_uuids заданы, но premium_monthly_gb пустой или 0 и нет premium_topup_packages, premium-сквады работают как дополнительный доступ без отдельного ограничения. Если заданы premium_topup_packages или положительный premium_monthly_gb, premium_squad_uuids обязательны.
Состояние хранится в подписке:
premium_baseline_bytes- базовый premium-лимит тарифа;premium_topup_balance_bytes- оставшийся докупленный premium-трафик;premium_topup_used_bytes- часть докупленного premium-трафика, уже потраченная в текущем месяце;premium_used_bytes- использованный premium-трафик за текущий календарный месяц;premium_period_start_at- месяц, к которому относитсяpremium_used_bytes;premium_is_limited- признак, что premium-сквад временно снят.
В пользовательском Web App premium-лимит показывается отдельной карточкой: использовано, лимит, остаток, докупленный переносимый остаток и список серверов/сквадов, на которые действует отдельное ограничение. В Telegram-разделе “Моя подписка” выводится тот же блок.
Обычная докупка и premium-докупка показываются отдельно. Обычная докупка использует topup_packages у period-тарифа или traffic_packages у traffic-тарифа. Premium-докупка использует только premium_topup_packages, получает sale_mode=premium_topup и в заголовке показывает premium_names, а не название обычной докупки.
Предупреждения по premium-лимиту отправляются отдельно от обычного трафика на тех же процентах TARIFF_TRAFFIC_WARNING_LEVELS. Сообщение использует название из premium_names, перечисляет серверы/сквады и ведет пользователя в докупку premium-трафика.
В Web App админке premium-сквады можно выбрать из выпадающего списка на вкладке Premium в редакторе тарифа. Список берется из API Remnawave (/api/admin/panel/internal-squads), поэтому UUID обычно не нужно копировать вручную.
Traffic-тарифы
Заголовок раздела «Traffic-тарифы»traffic продает объем трафика без пользовательского срока действия.
При покупке:
end_dateставится в дальнюю дату2099-01-01 UTC, если у активной подписки нет более поздней даты;duration_months = 0;period_start_at = NULL;tier_baseline_bytes = 0;topup_balance_bytesхранит доступный остаток трафика;- в Remnawave отправляется
trafficLimitStrategy = NO_RESET; - автопродление и уведомления о скором окончании срока отключаются для такой подписки.
Очередная покупка добавляет GB к фактическому остатку:
Так пользователь не теряет уже оплаченный остаток, а Remnawave продолжает считать общий лимит от текущего использованного трафика.
Если докупка трафика вызывается для traffic-тарифа, она обрабатывается как покупка очередного пакета этого же traffic-тарифа.
HWID-устройства
Заголовок раздела «HWID-устройства»Тариф может задавать базовый лимит устройств и пакеты докупки:
Правила:
hwid_device_limitхранит базовый лимит тарифа;extra_hwid_devicesхранит только текущую активную сумму докупленных устройств;- срок действия каждой докупки хранится в
hwid_device_purchases.valid_from/valid_until; - эффективный лимит равен
hwid_device_limit + active extra_hwid_devices; - базовый лимит
0означает безлимит, в Remnawave отправляетсяhwidDeviceLimit = 0; - при безлимитном базовом лимите докупка устройств не применяется;
- полная цена HWID-пакета берется из
prices[duration_months]; если периода нет, используется fallbackprice * duration_months; - фактическая цена докупки считается пропорционально оплачиваемому окну
valid_from -> valid_untilотносительно периода подписки и фиксируется в платежe; - для Telegram Stars цена округляется вверх до целого Stars, для RUB — вверх до копеек;
min_priceзащищает от микроплатежей в конце периода; - при продлении подписки докупленные устройства не продлеваются автоматически: старая докупка действует до прежнего
end_date, а для нового срока создается отдельнаяhwid_devices_renewal-покупка; traffic-тарифы не показывают и не принимают докупку HWID-устройств, потому что у них нет срока подписки;- при смене тарифа базовый лимит берется из целевого тарифа, а неиспользованная RUB-стоимость HWID-докупок конвертируется в дни нового period-тарифа или GB traffic-тарифа; XTR/Stars-докупки не конвертируются без явного курса и продолжают жить по своему
valid_until; - история докупок пишется в
hwid_device_purchases; - платеж хранит количество устройств в
payments.purchased_hwid_devices.
Докупка устройств доступна в Web App через /api/devices/topup-options и /api/payments, а также в Telegram-боте из раздела устройств.
Смена тарифа
Заголовок раздела «Смена тарифа»Смена тарифа доступна для активных подписок с tariff_key и записывается в таблицу tariff_changes.
Варианты расчета:
| Переход | Поведение |
|---|---|
period -> period | Остаток оплаченных дней оценивается по effective_monthly_price_rub, затем пересчитывается в дни целевого тарифа через месячную цену целевого тарифа. Неиспользованная RUB-стоимость HWID-докупок добавляется к этому расчету как дополнительные дни. Количество дней округляется вниз. |
period -> period с доплатой | Если целевой тариф дороже, может быть создан платеж tariff_upgrade; неиспользованная RUB-стоимость HWID-докупок уменьшает сумму доплаты. После оплаты применяется целевой тариф, а конвертированные HWID-окна закрываются. |
period -> traffic | Остаток оплаченных дней и неиспользованная RUB-стоимость HWID-докупок конвертируются в GB по conversion_rate_rub_per_gb или минимальной RUB-цене GB из пакетов целевого тарифа. |
traffic -> period | Пользователь выбирает и оплачивает период целевого тарифа; остаток GB сохраняется как topup_balance_bytes поверх лимита period-тарифа. |
При смене тарифа бот меняет:
tariff_key;- Internal Squads в Remnawave;
trafficLimitBytes;trafficLimitStrategy;- базовый HWID-лимит;
effective_monthly_price_rubдля period-тарифов;auto_renew_enabledи уведомления для traffic-тарифов.
Платежи
Заголовок раздела «Платежи»В платежах используются поля:
| Поле | Назначение |
|---|---|
sale_mode | Тип продажи: subscription, traffic_package, topup, premium_topup, tariff_upgrade, hwid_devices. |
tariff_key | Ключ тарифа, к которому относится платеж. |
purchased_gb | Купленный объем GB для traffic-пакетов и докупки трафика. |
purchased_hwid_devices | Количество устройств при докупке HWID. |
hwid_valid_from, hwid_valid_until | Зафиксированное окно действия HWID-докупки на момент создания платежа. |
hwid_pricing_period_months, hwid_proration_ratio, hwid_full_price | Метаданные расчета цены HWID-докупки: период тарифа, коэффициент prorate и полная цена пакета для периода. |
subscription_duration_months | Количество месяцев для подписки на срок; также используется платежными обработчиками как числовое поле покупки. |
В callback и metadata платежных провайдеров sale_mode может передаваться с суффиксом тарифа, например subscription@standard или topup@standard. При активации платежа тариф сохраняется отдельно в tariff_key.
Предупреждения и исчерпание трафика
Заголовок раздела «Предупреждения и исчерпание трафика»Remnawave ограничивает доступ при достижении trafficLimitBytes, переводя пользователя в статус LIMITED. Бот не удаляет пользователя из Internal Squads при 100% использования трафика.
TariffTrafficWorker запускается, когда активен JSON-каталог тарифов. Раз в 300 секунд он:
- синхронизирует из панели
status,trafficLimitBytes,usedTrafficBytesиtrafficLimitStrategy; - для period-тарифов выставляет
trafficLimitStrategy = MONTH, если панель еще показывает другую стратегию; - отправляет предупреждения на уровнях из
TARIFF_TRAFFIC_WARNING_LEVELS(по умолчанию85,90,95); - не отправляет
status=ACTIVEпри простой синхронизации стратегии, чтобы не снять статусLIMITED, выставленный Remnawave; - дедуплицирует предупреждения через
traffic_warnings.
Для period-тарифов дедупликация предупреждений привязана к началу текущего месяца. Для traffic-тарифов она учитывает текущий trafficLimitBytes, чтобы после покупки очередного пакета пользователь мог получить следующий набор предупреждений.
Подписки, которые были ограничены логикой предыдущих запусков бота (is_throttled=True), восстанавливаются воркером только когда лимит снова больше использованного трафика.
Автопродление, пробный период и бонусы
Заголовок раздела «Автопродление, пробный период и бонусы»Автопродление через YooKassa применяется к подпискам на срок. Для режима продажи трафика без JSON-каталога автопродление пропускается. Для traffic-тарифов JSON-каталога покупка является пакетом трафика, а не периодической подпиской.
Пробный период использует настройки TRIAL_DURATION_DAYS, TRIAL_TRAFFIC_LIMIT_GB, TRIAL_TRAFFIC_STRATEGY и TRIAL_SQUAD_UUIDS. Он не выбирает тариф из JSON-каталога, но его можно настроить на странице Система → Тарифы рядом с каталогом продаж. Если TRIAL_SQUAD_UUIDS пустой, для trial применяются squads из USER_SQUAD_UUIDS.
Промокоды с бонусными днями применяются к покупке period-подписки. Реферальные бонусы по периодам также относятся к подпискам на срок; в режиме продажи трафика без JSON-каталога Web App не показывает детализацию бонусов по месяцам.
Привязка существующих подписок
Заголовок раздела «Привязка существующих подписок»При запуске с активным JSON-каталогом бот заполняет активные подписки без tariff_key:
tariff_keyполучаетdefault_tariff;tier_baseline_bytesберется из текущего лимита подписки или изmonthly_gbтарифа по умолчанию;topup_balance_bytesстановится0, если значение отсутствовало;period_start_atочищается;effective_monthly_price_rubберется из последнего успешного платежа или из цены тарифа по умолчанию.
Это позволяет существующим активным подпискам отображаться и управляться в интерфейсах тарифов.