Skip to content

Invitations

The invitation system allows adding users to organizations and teams.

Model

Invitation
├── email (invited user)
├── roleId (role to be assigned)
├── organizationId? (optional)
├── teamId? (optional)
├── token (unique JWT token)
├── status: pending | accepted | declined | cancelled | expired
└── expiresAt (expiration date)

API Endpoints

MethodPathAuthDescription
POST/api/invitationsYesCreate invitation
GET/api/invitations/myYesMy pending invitations
GET/api/invitations/pendingNoFind pending (?teamSlug=&orgSlug=)
POST/api/invitations/:id/acceptYesAccept invitation
POST/api/invitations/:id/declineYesDecline invitation
DELETE/api/invitations/:id/cancelYesCancel invitation

Invitation Flow

  1. Creation: A user with members.invite permission creates an invitation by email
  2. Delivery: If a user with that email already exists — they receive a notification. If not — an email with a link is sent
  3. Anonymous flow: An unauthenticated user follows the link → sees invitation data via GET /invitations/pending/:token → registers → invitation is auto-accepted
  4. Acceptance: The user is added to the org/team with the specified role, added to the team chat
  5. Notifications: The inviter receives a notification on acceptance

Frontend

Invitations Store

typescript
const store = useInvitationsStore()
const { myInvitations } = storeToRefs(store)

await store.fetchMy()
await store.create({ email, roleId, organizationId?, teamId? })
await store.accept(id)
await store.decline(id)
await store.cancel(id)

Key Implementation Details

  • Invitations use JWT tokens for secure anonymous links
  • On user registration, all pending invitations for their email are auto-accepted
  • Cannot invite a user who is already a member
  • Invitations have an expiration date (expiresAt)