How Workspace Invitations and Member Onboarding Work in Plane

Plane manages workspace invitations through the WorkspaceInvitationService class, which provides methods to invite users via email, list pending invitations for both admins and invitees, and accept invitations individually or in bulk through a RESTful API.

Plane (makeplane/plane) handles member onboarding through a dedicated invitation system that bridges project administrators and new collaborators. The system centers on the WorkspaceInvitationService, a TypeScript service class that extends the generic APIService to manage the full lifecycle of workspace invitations—from creation to acceptance.

The Core Service Architecture

The invitation logic lives in packages/services/src/workspace/invitation.service.ts. This service extends APIService (from packages/services/src/api.service.ts) and automatically reads the API_BASE_URL from @plane/constants to communicate with Plane’s backend. It wraps HTTP requests to the /api/workspaces/:slug/invitations/ endpoints, handling authentication headers and response parsing transparently.

Sending Workspace Invitations

Administrators (or users with appropriate permissions) initiate onboarding by calling the invite method. This method accepts a workspace slug and an IWorkspaceBulkInviteFormData payload containing email addresses and the desired role for each invitee.

According to the source code at invitation.service.ts#L55-L60, the service POSTs this data to the backend, which creates IWorkspaceMemberInvitation records and dispatches email links to the specified addresses.

const invitationSvc = new WorkspaceInvitationService();

// Invite multiple users with a specific role
await invitationSvc.invite("engineering", {
  emails: ["alice@example.com", "bob@example.com"],
  role: "member",
});

Listing Pending Invitations

The service distinguishes between administrative oversight and personal invitation management through two distinct methods.

Administrative View

Admins retrieve all pending invitations for a specific workspace using workspaceInvitations(workspaceSlug). As implemented in invitation.service.ts#L40-L45, this returns an array of invitation objects visible only to workspace administrators.

User View

Authenticated users check their own pending invitations via userInvitations(), defined at invitation.service.ts#L26-L31. This method returns IWorkspaceMemberInvitation[], allowing the frontend to display a "Join Workspace" interface for the current user.

Accepting Invitations and Completing Onboarding

When an invitee follows an email link, the client completes onboarding by accepting the invitation through one of two methods.

Single Acceptance

The join method handles individual workspace entry. Located at invitation.service.ts#L100-L107, it accepts the workspace slug, invitation ID, and optional data (such as a password or SSO token). The backend validates the token, creates a WorkspaceMember record, and marks the invitation as accepted.

// Accept a specific invitation
await invitationSvc.join("engineering", invitationId, { password: "secure123" });

Bulk Acceptance

Users with multiple pending invitations can batch-accept them using joinMany, implemented at invitation.service.ts#L16-L21. This method accepts an object containing an array of invitation_ids, minimizing API round-trips during initial user setup.

// Accept all pending invitations at once
const pending = await invitationSvc.userInvitations();
await invitationSvc.joinMany({
  invitation_ids: pending.map(i => i.id),
});

Updating and Revoking Invitations

Administrators maintain invitation hygiene through modification and deletion endpoints.

The update method (invitation.service.ts#L70-L75) allows editing an invitation’s role or email address before acceptance. To remove stale invitations, admins call destroy (invitation.service.ts#L84-L89), which permanently deletes the invitation record.

Key Types and Supporting Files

The invitation system relies on several core files within the Plane monorepo:

Summary

  • WorkspaceInvitationService extends APIService to manage the full invitation lifecycle in packages/services/src/workspace/invitation.service.ts.
  • Creating invitations uses invite() with IWorkspaceBulkInviteFormData to send email invites to multiple users simultaneously.
  • Listing invitations separates concerns: workspaceInvitations() for admins and userInvitations() for individual users.
  • Accepting invitations supports both individual entry via join() and bulk onboarding via joinMany().
  • Lifecycle management includes update() for modifying invitation details and destroy() for revocation before acceptance.

Frequently Asked Questions

How do I invite multiple users to a Plane workspace simultaneously?

Use the invite method with an IWorkspaceBulkInviteFormData payload containing an array of email addresses. The service handles batch creation of invitation records and email dispatch automatically, as implemented in invitation.service.ts#L55-L60.

The client application extracts the invitation token and calls the join method (or joinMany for multiple invites). The backend validates the token, creates a WorkspaceMember record linking the user to the workspace, and marks the corresponding IWorkspaceMemberInvitation as accepted, completing the onboarding flow.

Can a user accept multiple workspace invitations at once?

Yes. The joinMany method (invitation.service.ts#L16-L21) accepts an array of invitation IDs, allowing new users to join multiple workspaces in a single API call rather than processing each invitation individually.

How do I revoke a pending invitation before it is accepted?

Administrators can call the destroy method with the workspace slug and invitation ID. This endpoint, located at invitation.service.ts#L84-L89, permanently removes the invitation record from the database and invalidates the email link.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →