Invitations
Add people to your team by inviting them with their email address and a role. The invitee receives a secure link and joins once they accept while logged in as the invited address.
Who can invite
Inviting requires the manage_team capability, so only the owner and admins can send invitations. See Roles & Permissions.
Sending an invitation
Dashboard β Settings β Team (/dashboard/settings?tab=team)
- Enter the invitee's email address.
- Choose a role:
admin,member, orviewer. (owneris never assignable; an invalid value falls back tomember.) - Send the invitation.
What happens on the backend:
- The email is normalized (trimmed, lowercased) and validated.
- If that person is already a member of the team, the invite is rejected with an error.
- The seat limit is checked: active members plus pending invitations must be below the owner's plan limit (
max_team_members). If the team is full, you are asked to upgrade. See Seats & Billing. - A pending invitation is created (or refreshed) for the
(team, email)pair, and an email with a unique link is sent.
Invitations are upserted per email: re-inviting the same address refreshes the token, role, and expiry and resets the invite to pending β you never accumulate duplicate invites for one person.
Invitation lifecycle
| State | Meaning |
|---|---|
pending |
Sent, not yet accepted or declined, and not expired |
accepted |
The invitee joined the team |
declined |
The invitee declined the link |
| expired | The link's expiry (default 7 days / 168 hours) has passed |
Only invitations that are pending and unexpired can be accepted. Expired or already-actioned links show "This invitation is invalid or has expired."
Token security
- The invitation link carries a secret token; the database stores only its SHA-256 hash, so a leaked database row cannot be turned back into a working link.
- Accepting requires being logged in as the invited email. A link forwarded to or stolen by someone else cannot be redeemed β acceptance checks that your session email matches the invited address.
- Tokens expire after 7 days by default.
The accept flow
- The invitee clicks the link:
GET /team/invite/{token}. - The invitation page shows the team name and the invite details.
- If the invitee is not logged in, they are prompted to log in (or register) with the invited email first.
- If they are logged in but with a different email, acceptance is refused with a message naming the correct address.
- The invitee accepts:
POST /team/invite/{token}/accept. - Inside a single transaction:
- The team is confirmed to still exist.
- The seat limit is re-checked (guards against the team filling up between send and accept).
- The membership row is created with the invited role (clamped to admin/member/viewer).
- The user's active team switches to this team.
- The invitation is marked
accepted.
- The invitee lands on the dashboard, now operating inside the new team.
If the team is full at accept time, the invitee sees: "This team has reached its member limit. Ask the owner to upgrade the plan."
Declining
The invitee can decline from the invitation page: POST /team/invite/{token}/decline. This marks the invitation declined and does not require login.
Managing members after they join
Owners and admins can manage members from Dashboard β Settings β Team:
- Change role β Set a member to admin, member, or viewer. You cannot change your own role, and the owner's role cannot be changed here (use ownership transfer).
- Remove member β Remove a non-owner member. They are automatically re-pointed to their own personal team so they are never locked out. You cannot remove yourself this way (use "Leave team"); the owner cannot be removed.
Leaving and transferring
- Leave team β Any non-owner member can leave (
POST /dashboard/settings/team/leave); their active team reverts to their personal team. The owner cannot leave β they must transfer ownership first. - Transfer ownership β The owner hands ownership to an existing member (
POST /dashboard/settings/team/transfer, requirestransfer_ownership). In one transaction, the new owner becomesownerand the previous owner becomesadmin, preserving the exactly-one-owner invariant. The target must already be a member of the team.
Next Steps
- Roles & Permissions - What each role can do
- Seats & Billing - How seat limits and plans work
- Teams Overview - Company sub-accounts concept