Subscription Freeze and Vacation Mode
The customer goes on vacation, doesn't need VPN for now, and the paid days melt away — so they either ask for a refund or cancel auto-pay and often don't return. A freeze puts the days in a bank instead of churn. I show how to assemble it in the bot — with real mechanics from production. Practice.
This material is about engineering your own infrastructure and is educational in nature. The laws and taxes of your own jurisdiction are on you.
What it is and why
The customer taps "❄️ Freeze" — the subscription pauses, the paid days don't burn but go into a "bank." Back from vacation → "▶️ Unfreeze" → the days keep counting from exactly where they stopped.
Instead of "give me my money back, I'm not using it," you get "okay, I'll freeze and come back." It's cheaper than a refund, removes the reason for a dispute, and noticeably reduces churn during seasonal dips — summer, New Year holidays. The tactic is assembled in the bot — the Remnawave panel itself has no freeze.
Fields in the subscription
Storage — four fields in the subscription/key row:
frozen # 0/1 — is the subscription frozen
frozen_at # when it was frozen
banked_days # how many days were "put in the bank" (the remainder at the moment of freezing)
last_freeze_at # marker for the "once per 30 days" limitTwo operations
Freeze (on the customer's button):
if frozen → "already frozen"
if (now - last_freeze_at) < 30 days → "freeze is once a month, wait N days"
days_left = expireAt - now
if days_left < 2 → "less than 2 days left — not allowed"
Remnawave PATCH /api/users { status: DISABLED }
frozen = 1, frozen_at = now, banked_days = days_left, last_freeze_at = nowUnfreeze (on the customer's button or auto after 30 days):
Remnawave PATCH /api/users { status: ACTIVE, expireAt: now + banked_days }
frozen = 0, frozen_at = NULL, expireAt = now + banked_daysThe key point: while the subscription is frozen, expireAt doesn't decrease — the clock is stopped. On unfreeze the term is recalculated as now + banked_days, so not a single paid day is lost. The DISABLED status simply turns off access while preserving the squads, traffic limit, HWID, and Telegram binding — after unfreeze the client connects with the same key, re-registering nothing.
Mandatory restrictions
Without them, the freeze turns into free parking where the customer lives forever.
- Once per 30 days. Without a limit, the customer will freeze/unfreeze a day at a time and live forever. We check
last_freeze_at. - Remainder ≥ 2 days. Freezing a "stub" is pointless and breeds bugs at the term boundary.
- Auto-unfreeze after 30 days. A frozen account must not hang forever — the scheduler unfreezes it on its own after 30 days (
expireAt = now + banked_days) and sends a notification: "❄️➡️☀️ The subscription was automatically unfrozen — 30 days have passed, the term resumed counting." That way you don't hold a slot under dead pauses. - Don't nag the frozen. "Subscription ending" reminders and auto-renewal in the scheduler must skip
frozenkeys — otherwise a customer on vacation gets "renew" spam for a frozen subscription.
What to set up in the bot
Essentially it's a modest set:
- 4 fields in the database (above).
- Two handlers (
/freeze,/unfreeze), each — one limit check + one PATCH to Remnawave. - A pair of buttons "❄️ Freeze / ▶️ Unfreeze" in the bot or miniapp.
- A scheduler tweak: skip
frozenkeys in reminders/auto-renewal + add auto-unfreeze after 30 days.
It's simpler to assemble than it seems. Before enabling it for everyone, run it on yourself: froze → days stopped → unfroze → term continued exactly from the remainder; and check that reminders don't touch a frozen one.
A vacation bonus: access to Russian services
Vacation spawns a second request from the same customer: abroad they want to log into a Russian bank or Gosuslugi, but the app complains "turn off VPN" — and that doesn't help, because it's not about VPN but about their IP not being Russian. This is cured by a separate Russian node (stealth entry, white IP) that you hand the client as a "🇷🇺 Russia" server or via auto-routing of Russian services. But that's already about infrastructure and routing — a separate big topic; here what matters is that both "vacation" requests are closed and both work for retention.
Checklist
- [ ] ❄️ Freeze / ▶️ Unfreeze buttons in the bot/miniapp.
- [ ] 4 fields:
frozen,frozen_at,banked_days,last_freeze_at. - [ ] Limits: once per 30 days, remainder ≥ 2 days, auto-unfreeze after 30 days.
- [ ] The reminder/auto-renewal scheduler skips
frozenkeys. - [ ] Run on yourself: froze → unfroze → days weren't lost.
The freeze is one of three anti-churn tactics alongside the lifeline (grace) and auto-renewal; see the general retention logic in the retention theory.
Next guide Why CDN Fronting: Working Under Whitelists → ↗ Article unclear or something off? Message me and I will help or fix it. @notrealvpn →