Skip to content

Billing & Plans

Plans

Hierarchy: SIMPLE (0) → VIP (1) → PRO (2) → PERS (3). There is also an administrative role GLAVA outside the plan ladder (platform staff, not sold).

Feature SIMPLE (free) VIP (~$3/30 days) PRO (~$5/30 days) PERS (~$9/30 days)
HTTP/HTTPS tunnel, profile card
Public catalog listing
SSH tunnel (TCP 22) + SFTP
Security section — attack logs + email alerts
RDP, VNC tunnel
Traffic analytics (visits, UTM, geo, Excel export)
PostgreSQL, MySQL, Redis, MongoDB tunnel

Sources of truth for this table (update both code and this table when a plan changes):

  • TCP ports — TcpPortController.SYSTEM_PORTS (minRole per port) + dixu_proxy/README.md.
  • Security/incidents — IncidentsController.MIN_ROLE, InternalController.ATTACK_NOTIFY_MIN_ROLE (both "VIP").
  • Analytics — AnalyticsController.MIN_ROLE ("PRO").
  • Prices/descriptions — BillingController.TARIFFS.

Smart Billing

Instead of a fixed expiry date, each plan has a remaining-days counter (user_tariffs.remaining_days). A user can hold multiple plans simultaneously: one active, the rest frozen; switching is instant.

  • Deduction: 1 day per day for whichever plan was active that day — regardless of how many times plans were switched within the day (lazy-deduction via last_deducted_date).
  • Switching (POST /api/billing/switch): unlimited per day; downgrading to a lower-tier plan is blocked while a higher-tier plan is active.
  • Auto-switch on expiry (SmartBillingScheduler, daily at 00:05): when remaining_days = 0 on the active plan, looks for the next-highest frozen plan (PERS(3) > PRO(2) > VIP(1)), activates it, sends email; if none remain — falls back to SIMPLE.
  • Tunnel freeze: while tunnel_frozen_by != 'none', all plan counters stop decrementing.

Days stack, not reset: adding 30 days to a plan with 5 remaining gives you 35 days.

Payment providers

Lemon Squeezy (international — card payments)

For users outside Russia. Checkout URL is built client-side via POST /api/billing/init-ls; webhook handler at POST /api/billing/notify-ls credits 30 days on subscription_created / subscription_payment_success.

Current status: code is fully deployed and ready. The dixsu.lemonsqueezy.com store is not yet activated — Stripe Connect onboarding requires a non-Russian bank account (IBAN/ routing number). Once the store is activated through Stripe Connect, card payments will work without any code changes.

Setup guide: guides/lemon-squeezy.md

Tinkoff / T-Bank (Russia only)

For Russian users. Balance top-up + deduction. Endpoints: /api/billing/pay, /topup, /notify, /payment-status/{id}, /history.

Private mode

A separate axis of the account (combined with the plan ladder, not a parallel ladder): on first login at /auth/account-type-setup the user makes a permanent, irreversible choice between public and private account. Stored in users.private_mode.

  • Public — profile card, catalog, authored short links, weighted reviews.
  • Private — none of the above; tunnel accessible only to the owner via their dix.su session. On the free SIMPLE plan — 14-day trial (users.private_trial_expires_at), after which the tunnel is frozen until a paid plan (VIP+) is activated.

Verification before granting private mode — a one-time 1 ₽ payment through Tinkoff (POST /api/billing/verify-private) plus a self-entered full name. Payment confirmation in /notify sets private_mode=true and private_trial_expires_at=NOW()+14 days.

Invited users (PRO and above) — a private account owner on PRO or higher can invite other registered dix.su users by their slug; invitees pass the access gate the same way as the owner. Limits by owner's plan (PrivateInviteController.MAX_INVITES): PRO — up to 10, PERS — up to 100.

End-to-end encryption (Phase 2, deployed) — a separate entry point e2e-<token>.{BASE_DOMAIN} without TLS termination on the server (POST /api/private/e2e/mint, PrivateE2eController). The private key never leaves the device. Verified on production in Chrome and Firefox. Details — Security.

Database schema

user_tariffs (migration V28) — role, remaining_days, status (active/frozen/expired), last_deducted_date. Fields role/role_expires_at in users — cached current active plan for fast access, updated on every switch.

Where to find the code

  • modulauth/.../billing/BillingController.java — all HTTP endpoints.
  • modulauth/.../billing/TariffService.java — lazy-deduction, sync users.role.
  • modulauth/.../billing/SmartBillingScheduler.java — daily auto-switcher (@Scheduled).
  • modulauth/.../billing/TinkoffService.java — Tinkoff integration (RU).
  • modulauth/.../billing/LemonSqueezyService.java — Lemon Squeezy integration (international).