Team seats & invites
How seat quota is counted, how invites consume it, and how the gate re-checks at accept time to handle plan changes mid-flow.
Seats are the unit of team access: each plan caps how many members a tenant can hold, and the cap is re-checked when an invite is accepted, so plan changes mid-flow cannot overshoot the count.
This page documents the caps, the invite lifecycle states, and the two details teams ask about most — custom entitlements and member removal.
Key points
- A seat is one active user (User.isActive=true) on the tenant. Soft-deleted users free the seat instantly.
- Issuing an invite does not consume a seat — only the accept does. Admins can have any number of pending invites.
- The seat gate fires at two moments: when the admin sends the invite, and again when the invitee clicks accept.
- If the tenant downgraded between invite and accept, the accept returns 402 and the invite is marked expired.
Plan caps
- Free: 1 seat. Starter: 3 seats. Pro: 10 seats. Enterprise: as defined in your contract.
- Sales can hand-grant a custom seat count via TenantEntitlement; the override wins over the catalogue.
- Removing a member is a soft-delete (isActive=false); the audit chain stays intact.
Caps are Free 1, Starter 3, Pro 10, and Enterprise per contract. A sales-granted TenantEntitlement overrides the plan cap explicitly. Removing a member is a soft delete: the member is deactivated and the audit chain stays intact.
Invite lifecycle
- Pending: token generated, email dispatched, expires_at = now + 7d.
- Accepted: user created, session issued, invite row updated; new user lands on /dashboard authenticated.
- Expired / revoked: terminal states. A new invite for the same email starts a new lifecycle.
An invite is a lifecycle, not a flag: pending with a token and a seven-day expiry, accepted with the user and session created, then the terminal expired or revoked states. A fresh invite for the same email starts a new lifecycle rather than resurrecting the old one.
Related resources