Get started
BETA
Browse docs
Account & Billing

Teams

Inviting teammates, the billing-admin role, transferring ownership, and deleting a team.

A team is a shared identity multiple people can open tunnels under. Tunnels, reserved subdomains, and worker tunnels created in a team context belong to the team — not to whoever opened them — so they survive offboarding and onboarding.

Teams are different from the Team plan. You can create a team on any tier, including Free; you only need a Team subscription if you want the higher per-seat limits. See Plans and limits → Team contexts vs Team plan.

Creating a team

From the dashboard, pick a slug (3-32 characters, lowercase alphanumerics and hyphens) and a display name. The slug becomes the team:<slug> you pass to the CLI (Contexts).

Behind the scenes (internal/teams/service.go:84):

  • Slug uniqueness is enforced by the database — duplicates return 409.
  • The creator is inserted with the owner role and is recorded as the billing admin.
  • A team Stripe subscription is created against your Stripe customer if you have one. (For Pro→Team upgrades the orchestrator also cancels your existing Pro subscription with proration — see Upgrade and downgrade.)

If billing setup fails partway through, the team lands in provisioning_failed status and the dashboard surfaces a "Retry provisioning" action that calls POST /api/teams/{id}/retry-provisioning (internal/teams/handler.go:118). The retry is idempotent — Stripe's idempotency key ensures it doesn't double-charge.

Inviting teammates

Team admins create invitations from the dashboard. Each invitation:

  • Is identified by a 32-byte URL-safe token (internal/teams/service.go:363).
  • Has a 7-day TTL (internal/teams/service.go:28).
  • Counts against a cap of 20 pending invitations per team (internal/teams/service.go:359).

The invitee receives an email; clicking the accept link calls GET /api/invitations/{token}/accept. The server validates the token, inserts an admin-role TeamMembership, and bumps the team's Stripe subscription seat count if the team is on the Team plan.

Roles inserted from invitation acceptance default to admin — there is currently one effective role tier above member (the billing_admin flag on the team itself, see below). The owner role is reserved for the team creator.

Roles

Three role concepts exist on a team:

RoleGranted toPowers
OwnerThe team creatorFull admin powers. The owner role is set at creation and is currently changed only via the (separate) transfer-ownership flow. See internal/teams/membership.go:22.
AdminAnyone who accepts an invitation, plus the ownerCan invite teammates, remove members, manage workers and reserved subdomains.
Billing adminTracked by Team.BillingAdminUserIDThe user who owns the Stripe customer the team is billed against. Only one per team. The billing admin cannot be removed until the role is transferred to another teammate (internal/teams/service.go:522).

In practice this means a team always has at least one human who can pay the bill, and that person can't be accidentally removed.

Transferring billing-admin

The billing-admin flag is what determines whose Stripe customer the team is billed against. Transferring it is what you do before removing the current billing admin from the team.

The transfer flow is exposed via the dashboard. The Next.js proxy lives at POST /api/teams/{slug}/billing-admin/transfer (src/app/api/teams/[slug]/billing-admin/transfer/route.ts). Server-side wiring for the transfer endpoint is part of the team admin lifecycle work — if the dashboard action returns 404 or 502, contact support for help completing the transfer manually.

Removing a member

Admins can remove any member except the billing admin. From RemoveMember (internal/teams/service.go:499):

  • Requires an active admin/owner membership for the actor.
  • Refuses to remove the billing admin (you must transfer first — see above).
  • Refuses self-removal of the sole admin (you'd leave the team without a leader).
  • Soft-deletes the membership row.
  • Auto-retires the removed teammate's team-scoped workers so their CI workers stop accepting traffic against the team's namespace immediately. The 14-day worker reaper finishes the transition to terminal retired state (internal/teams/service.go:598).

Personal workers (workers the user owns outside this team) are not touched.

Transferring ownership

Ownership is the owner role on the founding TeamMembership. The transfer flow exists in the dashboard UI; if you don't see a "Transfer ownership" action on your team page, the server-side endpoint may not yet be wired in your environment — contact support.

When transfer-ownership is available, the typical motion is:

  1. Promote another member to admin (or confirm they already are).
  2. Open the team's settings in the dashboard and choose "Transfer ownership" → select the new owner.
  3. The new owner can then transfer billing-admin to themselves if they also want to take over billing.

Until ownership is transferred, the original owner is the only user who can dissolve the team.

Deleting a team

Deletion ends the Team subscription and removes all team data. The dashboard exposes a "Delete team" action; the Next.js proxy is at DELETE /api/teams/{slug} (src/app/api/teams/[slug]/route.ts). Server-side wiring for the delete endpoint is part of the same admin lifecycle work — if the dashboard action returns an upstream error, contact support to complete deletion.

When deletion is fully wired, the typical guarantees are:

  • Active tunnels in the team context are closed.
  • Reserved subdomains held by the team are released back to the pool.
  • Team-scoped workers are retired.
  • The Stripe subscription is cancelled.
  • Membership rows are soft-deleted (audit history preserved).

Members do not lose their personal accounts — only the team relationship is removed.

CLI usage

Once invited and accepted, switch into the team to open tunnels under it:

justtunnel context use team:acme
justtunnel http 3000

The tunnel now counts against the team's limits, and reserved subdomains stay with the team rather than your personal account. See Contexts and justtunnel context.

On this page