Get started
BETA
Browse docs
Account & Billing

Upgrade and downgrade

How to change plans, what happens at the moment of upgrade, and what happens when a downgrade takes effect.

JustTunnel uses Stripe's hosted Checkout and Customer Portal for all subscription changes. There is no JustTunnel-built billing UI to learn — you do everything from the dashboard, and Stripe handles cards, invoices, tax, and proration.

Where to change your plan

  • From Free → Starter or Pro: sign in to the dashboard and start a Stripe Checkout session. The server creates the session and redirects you to Stripe; on success Stripe redirects you back to /dashboard?billing=success.
  • Changing between Starter and Pro, or cancelling: open the Stripe Customer Portal from the dashboard. The portal is the canonical surface for plan changes, payment-method updates, invoices, and cancellation.
  • Pro → Team: this is a separate flow because Team is a per-seat subscription rather than a single-user one. Create a team from the dashboard; the upgrade orchestrator cancels your Pro subscription with proration and provisions the Team subscription against the same Stripe customer.

What happens on upgrade

For an individual upgrade (Free → Starter, Free → Pro, Starter → Pro):

  • Access is immediate. The Stripe webhook updates your plan in our database the moment the subscription is created. The new tier's limits apply on the next API call.
  • Proration is handled by Stripe. When you upgrade mid-cycle, Stripe credits the unused portion of your old plan and bills the prorated cost of the new one.
  • Existing tunnels keep running. Limits being raised never disrupts an active session.

For a Pro → Team upgrade, the orchestrator (internal/teams/service.go) does three things in order:

  1. Creates the Team subscription against your existing Stripe customer with a deterministic idempotency key (team-upgrade-<user_id>-<slug>). Retries are safe — Stripe returns the original subscription for 24h.
  2. Cancels the Pro subscription with prorate=true and at_period_end=false. You receive a credit for the unused portion of the Pro period; you are not double-charged.
  3. Inserts the team and your owner-membership row.

If step 1 succeeds and a later step fails, the team is marked provisioning_failed and you can resume via the retry endpoint surfaced in the dashboard. The team doesn't appear in your team list until provisioning is complete (internal/teams/service.go:330 returns 409 for a half-provisioned team).

What happens on downgrade

The downgrade path is asymmetric: most downgrades are scheduled, but a payment failure can trigger an immediate downgrade after a grace period.

Voluntary downgrade (you initiate it)

Voluntary downgrade goes through the Stripe Customer Portal. Stripe schedules the change for the end of the current billing period — you keep the higher tier's limits and reserved subdomains until then. When the period ends:

  • Excess tunnels are killed oldest-first until you're at the new tier's cap (internal/billing/downgrade.go:39).
  • If you're dropping away from Pro, reserved subdomains are released (internal/billing/downgrade.go:60). The names go back into the pool — the next requester can claim them.
  • Workers and other resources that exceed the new caps are quarantined per the worker reaper.

Involuntary downgrade (payment fails)

If your card fails and the failure is not resolved, you enter a grace period of 5 days (internal/billing/grace.go:13). During grace:

  • Your plan stays at its current tier and limits are unchanged.
  • Stripe retries the payment on its standard schedule.
  • You receive payment-failed emails from Stripe.

When the grace period expires without a successful retry:

  • Your plan is set to free and the Stripe subscription ID is cleared (internal/billing/grace.go:67).
  • Excess tunnels are killed oldest-first.
  • Reserved subdomains are released (you were Pro, you're now Free).
  • You receive a "plan downgraded" email (internal/billing/grace.go:110).

You can re-subscribe at any time from the dashboard; see Cancelling.

Verifying your active plan

After a plan change, confirm the new tier is live before you depend on it:

justtunnel status

status prints the plan the API resolves you to right now, including any gifted plan that overrides the Stripe plan. If the dashboard says "Pro" but status says "Free", the webhook hasn't applied yet — wait a few seconds and retry. If it still doesn't match, contact support.

Edge cases

  • Mid-upgrade page reload. The Pro→Team upgrade is crash-recoverable. If you close the tab during the upgrade, the team is in provisioning or provisioning_failed and the dashboard offers a "Retry provisioning" action that calls POST /api/teams/{id}/retry-provisioning. Stripe's idempotency keys guarantee the retry doesn't create a second subscription.
  • Gifted plans. If a JustTunnel admin has gifted you a plan, the gift overrides your Stripe plan whenever the gift is higher (internal/plan/enforcer.goEffectivePlan). Cancelling your Stripe subscription does not cancel a gifted plan.
  • Plan rank guard. The checkout endpoint refuses to "upgrade" you to a plan you already have or to a lower tier (internal/billing/handlers.go:47). Use the Stripe portal for downgrades.

On this page