Teams
SaaSyBase supports team subscriptions that provision managed organizations, sync with billing status, and give members shared access to features and token pools. This guide covers the full team lifecycle, including personal-versus-team workspace switching.
How Team Plans Work
A team plan is a subscription plan with scope: "TEAM" and supportsOrganizations: true. When a user subscribes to a team plan, the system automatically:
- Creates or updates an organization for the subscriber.
- Assigns a deterministic slug based on the user's name or email.
- Mirrors organization metadata to the active auth provider when that provider supports organization primitives, notably Clerk and Better Auth.
- Sets up the token strategy defined in the plan.
This provisioning only happens when the plan has supportsOrganizations: true and the subscription is active (not in a proration-pending state).
When the buyer already has a local workspace, provisioning updates that organization in place instead of deleting and recreating it. That preserves the workspace row, member assignments, and related metadata while bringing the plan-backed fields back into sync.
Tip
Multiple Workspaces and Switching
Users can operate in more than one workspace context. There is always a personal workspace, and there can also be one or more team workspaces owned by or shared with the user.
| Workspace type | What it means | How users switch |
|---|---|---|
| Personal workspace | The user is acting on their own subscription, balances, and features | Select the personal context in the sidebar switcher or clear the active org cookie |
| Team workspace | The user is acting inside an organization with its own plan context and token strategy | Use the sidebar workspace switcher or app-managed active-org API |
The dashboard sidebar footer renders the workspace switcher through AuthOrganizationSwitcher. For app-managed switching, the client calls POST /api/user/active-org and stores the active organization in an httpOnly cookie.
Note
If you are using Clerk-backed organizations, the relevant upstream docs are Clerk Organizations.
Organization Provisioning
The ensureTeamOrganization helper handles creating and updating organizations when subscriptions activate. It runs automatically during:
- Checkout completion
- Subscription activation
- Webhook events
- Admin overrides
When a subscription lapses, the companion helper syncOrganizationEligibilityForUserapplies the configured organization-expiry policy and clears member access. The shipped default is to suspend workspace access while preserving the local organization row so reactivation can provision it again cleanly. Admins can switch this to full dismantling through ORGANIZATION_EXPIRY_MODE.
Admins can also manually suspend a workspace from /admin/organizations. That keeps the local workspace row, expires pending invites, and surfaces a notice whenever a user is inside the suspended workspace. The same admin screen can restore that workspace later without creating a brand-new local record.
If provisioning ever drifts from billing state, the dashboard and admin tooling both expose a provisioning refresh path backed by /api/team/provision. Use that before making direct database edits.
Organization expiry modes
ORGANIZATION_EXPIRY_MODE controls what happens when a workspace owner falls outside the configured token-expiry grace window.
| Mode | What happens |
|---|---|
| SUSPEND | Keep the local workspace, expire invites, remove provider-side org linkage when applicable, and show a dashboard notice until access is restored. |
| DISMANTLE | Remove the workspace access path entirely instead of leaving a suspended shell behind. |
The grace window before either mode is applied is controlled by TOKENS_NATURAL_EXPIRY_GRACE_HOURS.
Token Strategies
Team plans support two distinct approaches to distributing tokens among members. See the Tokens & Features page for detailed field descriptions.
| Strategy | How tokens work |
|---|---|
| SHARED_FOR_ORG | One shared pool for the whole team. Optional per-member caps prevent overuse. |
| ALLOCATED_PER_MEMBER | Each member gets their own balance. Renewals reset individual balances. |
The effective strategy is set on the plan (organizationTokenPoolStrategy). The dashboard UI adapts automatically — shared-pool cap controls only appear when the workspace uses SHARED_FOR_ORG.
Tip
SHARED_FOR_ORG when the team should spend from one common pool. Choose ALLOCATED_PER_MEMBER when each member needs their own predictable allowance.Member Management
Inviting members
Team owners invite members through the /dashboard/team page. Invites generate a unique token and send an email notification. Invited users accept via /invite/[token].
The invite flow works for both existing users and new sign-ups — new users can accept the invite after creating their account.
Member entitlements
When a workspace uses ALLOCATED_PER_MEMBER, joining members receive the plan's token allowance in their membership balance. Renewals reset those balances, and top-ups credit each active member instead of the org pool.
The initial allowance is granted when the invite is accepted and the membership becomes active. Renewal resets happen on the organization subscription lifecycle, not on an individual member anniversary.
Seat limits
Plans can define seat constraints to control team size:
| Field | Purpose |
|---|---|
| organizationSeatLimit | Maximum number of members |
| minSeats / maxSeats | Seat range for seat-based pricing |
| seatPriceCents | Per-seat price for seat-based billing |
Treat the seat-pricing fields as advanced plan metadata. The schema and provider abstractions understand them, but you should verify your checkout and admin flows before treating seat-count selection as a finished end-user feature.
Plan Schema for Teams
Plan {
scope String @default("INDIVIDUAL") // "INDIVIDUAL" or "TEAM"
supportsOrganizations Boolean @default(false)
organizationSeatLimit Int?
organizationTokenPoolStrategy String? @default("SHARED_FOR_ORG")
minSeats Int?
maxSeats Int?
seatPriceCents Int?
}Dashboard & API
The team management UI is at /dashboard/team and includes:
- Invite management (send, resend, revoke)
- Member list with removal
- Per-member cap override controls for shared token workspaces
- Provisioning refresh
- Owner-only organization deletion with active-plan checks in the confirmation modal
- Strategy-aware balance labels
- Shared-pool cap controls (only visible for
SHARED_FOR_ORGworkspaces)
Deleting a workspace safely
Workspace deletion is intentionally owner-only and is triggered from the /dashboard/team header actions beside the refresh control. The dashboard first checks deletion eligibility, then opens a confirmation modal that explains whether an active team plan still blocks deletion.
The confirm action stays disabled while the workspace still has an active team subscription attached. That prevents accidental removal of an organization that billing still considers live.
When deletion succeeds, the client clears the active workspace by posting { orgId: null } to /api/user/active-org so the user returns to their personal workspace cleanly.
Note
Team API routes
| Route | Purpose |
|---|---|
| /api/user/active-org | Switch between the personal workspace and a selected organization workspace |
| /api/organization/check-deletion-eligibility | Check whether the current or requested workspace still has an active team plan that blocks deletion |
| /api/organization/delete | Delete a workspace owned by the current user once no active team plan remains |
| /api/team/invite | Create team invitations |
| /api/team/invite/revoke | Revoke a pending invite |
| /api/team/invite/accept | Accept a team invite |
| /api/team/invite/decline | Decline a team invite |
| /api/team/invite/resend | Resend an invite email |
| /api/team/members/remove | Remove a team member |
| /api/team/members/cap-override | Set or clear a per-member cap override |
| /api/team/summary | Get team summary data |
| /api/team/provision | Trigger organization provisioning |
| /api/team/settings | Update team settings |
Support and recovery flows
If a workspace owner needs help with invites, provisioning drift, billing confusion, or member access issues, the built-in support center is already wired into the dashboard.
Users can open tickets at /dashboard/support, and admins handle them from /admin/support. Invite acceptance also tries to switch the user directly into the organization workspace after success so the team dashboard opens in the correct context.
When no custom organization billing email exists, admin tooling falls back to the owner's email so the workspace still has a default billing contact.
If a workspace is suspended manually or by expiry policy, users see a workspace notice in the dashboard so they understand why team actions are blocked.
Clerk Webhook Sync
When using Clerk as the auth provider, organization and membership events are automatically synced:
organization.*— upserts organizations from Clerk into the local database.organizationMembership.*— syncs member roles and status.organizationInvitation.*— tracks invite state (pending, accepted, revoked).
Note
If a Clerk webhook delivery fails, Clerk retries according to its own webhook policy. For stubborn drift or missed backfills, rerun provisioning from the team dashboard or the organizations admin view rather than assuming the provider retry already repaired everything.
For the auth-provider tradeoffs behind that choice, see Authentication.

