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
ownerrole 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:
| Role | Granted to | Powers |
|---|---|---|
| Owner | The team creator | Full 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. |
| Admin | Anyone who accepts an invitation, plus the owner | Can invite teammates, remove members, manage workers and reserved subdomains. |
| Billing admin | Tracked by Team.BillingAdminUserID | The 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
retiredstate (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:
- Promote another member to admin (or confirm they already are).
- Open the team's settings in the dashboard and choose "Transfer ownership" → select the new owner.
- 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.
Related
- Plans — Team-plan features
- Plans and limits — Team-tier numeric limits
- Contexts — switching identities at the CLI
- Worker tunnels — long-lived team-scoped tunnels
justtunnel context— CLI for context management