Invite users
Build applications that enable organization owners to invite users to join their organization. Scalekit takes care of sending the invite emails, verifying their email addresses, and creating the user accounts end to end.
Invite-only access is ideal for the following scenarios:
- Enterprise applications: Organization admins need to invite team members to join their workspace.
- B2B SaaS platforms: You want to restrict access to invited users only
- Exclusive communities: Applications that require invitation-based membership.
Scalekit helps you implement invite-only access while handling the complexity of user management and authentication.
For applications where you want to build custom invitation flows in your own UI, Scalekit provides APIs to programmatically invite users. This is ideal when organization admins or workspace owners need to invite team members directly from your application’s dashboard.
Common use cases include:
- Admin dashboards: Organization admins can invite users from a settings or team management page.
- Bulk invitations: Import and invite multiple users at once from CSV files or directory systems.
- Custom workflows: Implement approval processes or conditional invitations based on business logic.
- Integration with existing systems: Connect invitation flows with your CRM, HR systems, or user directories.
Use the dashboard to invite users
Section titled “Use the dashboard to invite users”The quickest way to get started with user invitations is through the Scalekit Dashboard. Navigate to the Users section and click the “Add User” button to invite new members to your organization. You can specify their email address, assign roles, and customize the invitation settings directly from the UI.
Build custom invitation flows with the SDK
Section titled “Build custom invitation flows with the SDK”For applications that require custom invitation flows or automated user management, Scalekit provides a comprehensive SDK. This allows you to programmatically invite users, manage invitations, and integrate with your existing systems.
-
Create user invitations
Section titled “Create user invitations”To invite a user to an organization, create a user membership with their email address and the target organization ID. Scalekit handles sending the invitation email and managing the invitation process.
const newUser = await scalekit.user.createUserAndMembership('org_xxxxxxxxxxxx', {email: "user@example.com",externalId: "crm-user-87425",userProfile: {firstName: "John",lastName: "Doe"},metadata: {plan: "free",department: "Engineering"},sendInvitationEmail: true});from scalekit import ScalekitClientfrom scalekit.v1.users.users_pb2 import CreateUser, CreateUserProfile# Initialize scalekit clientscalekit = ScalekitClient(<'SCALEKIT_ENV_URL'>,<'SCALEKIT_CLIENT_ID'>,<'SCALEKIT_CLIENT_SECRET'>)# Create user objectuser = CreateUser(email="user@example.com",external_id="crm-user-87425",user_profile=CreateUserProfile(first_name="John",last_name="Doe"),metadata={"plan": "free","department": "Engineering"})# Create the usernew_user = scalekit.users.create_user_and_membership(organization_id='org_xxxxxxxxxxxx', user=user)import ("context"usersv1 "github.com/scalekit-inc/scalekit-sdk-go/pkg/grpc/scalekit/v1/users")user := &usersv1.CreateUser{Email: "user@example.com",ExternalId: "crm-user-87425",UserProfile: &usersv1.CreateUserProfile{FirstName: "John",LastName: "Doe",},Metadata: map[string]string{"plan": "free","department": "Engineering",},}newUser, err := scalekit.User().CreateUserAndMembership(context.Background(),"org_xxxxxxxxxxxx", // The ID of the organization the user belongs touser,false, // sendInvitationEmail)if err != nil {// handle error appropriatelyreturn err}import com.scalekit.grpc.scalekit.v1.users.*;CreateUserAndMembershipRequest request = CreateUserAndMembershipRequest.newBuilder().setUser(CreateUser.newBuilder().setEmail("user@example.com").setExternalId("crm-user-87425").setUserProfile(CreateUserProfile.newBuilder().setFirstName("John").setLastName("Doe").build()).putMetadata("plan", "free").putMetadata("department", "Engineering").build()).build();CreateUserAndMembershipResponse newUser = scalekit.users().createUserAndMembership("org_xxxxxxxxxxxx", request); // The ID of the organization the user belongs toKey parameters:
email
: The email address of the user to invite (required)organization_id
: The ID of the organization they’re joining (required)sendActivationEmail
: Set totrue
to automatically send invitation emails (recommended)roles
: Optional array of roles to assign to the invited usermetadata
: Optional custom data to associate with the membership
-
View invitation response
Section titled “View invitation response”When a user is successfully invited, Scalekit returns a user object with membership details. The membership status will be
PENDING_INVITE
until the user accepts the invitation.Example invitation response {"user": {"id": "usr_01HTR0ABCXYZ","environmentId": "env_01HTQZ99MMNZ","createTime": "2025-06-19T15:41:22Z","updateTime": "2025-06-19T15:41:22Z","email": "user@example.com","externalId": "crm-user-87425","memberships": [{"organizationId": "org_xxxxxxxxxxxx","joinTime": "2025-06-19T15:41:22Z","membershipStatus": "ACTIVE","roles": [{"id": "role_admin","name": "admin"}],"primaryIdentityProvider": "IDENTITY_PROVIDER_UNSPECIFIED","metadata": {"plan": "free","department": "Engineering"}}],"userProfile": {"id": "prof_01HTR0PQRMNO","firstName": "John","lastName": "Doe","name": "John Doe","locale": "en","emailVerified": false,"phoneNumber": "","metadata": {},"customAttributes": {}},"metadata": {"plan": "free","department": "Engineering"},"lastLogin": null}} -
Resend user invitation
Section titled “Resend user invitation”Resend invitation emails to users who have pending or expired invitations. If the invitation has expired, a new one is automatically created and sent. If still valid, a reminder email is sent instead.
When to resend invitations:
- Users haven’t responded to their initial invitation
- Original invitations have expired
- Users request a new invitation link
- Users can’t find the original email
The invitation email includes a secure magic link that allows the user to complete their account setup and join the organization. Each resend operation increments the resend counter. The expiration time stamp is updated if a resend is requested upon the expiry, if not previous expiry timestamp remains.
Resend invitation curl 'https://$SCALEKIT_ENVIRONMENT_URL/api/v1/invites/organizations/{organization_id}/users/{id}/resend' \--request PATCH \--header 'Content-Type: application/json' \--data 'null'Express.js // Example Node.js implementation coming soonFlask # Example Python implementation coming soonParameters:
Parameter Description organization_id
Unique identifier of the organization (starts with ‘org_‘) id
System-generated user ID of the user with a pending invitation (starts with ‘usr_’) Response:
200 {"invite": {"created_at": "2025-07-10T08:00:00Z","expires_at": "2025-12-31T23:59:59Z","invited_by": "admin_998877","organization_id": "org_987654321","resent_at": "2025-07-15T09:30:00Z","resent_count": 2,"status": "pending_invite","user_id": "usr_123456"}} -
Handle user invitation acceptance
Section titled “Handle user invitation acceptance”When invited users click the invitation link in their email, Scalekit redirects them to your application’s registered initiate login endpoint. Your application then completes the authentication flow.
Set up the initiate login endpoint:
-
Register your endpoint in the Scalekit dashboard (for example,
https://your-app.com/auth/login/initiate
) -
Handle the redirect by constructing an authorization URL and redirecting the user to Scalekit’s hosted login page
-
Complete authentication when the user returns to your callback URL
Example endpoint implementation:
Express.js app.get('/auth/login/initiate', (req, res) => {const redirectUri = 'http://localhost:3000/api/callback';const options = {scopes: ['openid', 'profile', 'email', 'offline_access']};const authorizationUrl = scalekit.getAuthorizationUrl(redirectUri, options);res.redirect(authorizationUrl);});Flask @app.route('/auth/login/initiate')def initiate_login():redirect_uri = 'http://localhost:3000/api/callback'options = AuthorizationUrlOptions()options.scopes = ['openid', 'profile', 'email', 'offline_access']authorization_url = scalekit.get_authorization_url(redirect_uri, options)return redirect(authorization_url)Gin func initiateLogin(c *gin.Context) {redirectUri := "http://localhost:3000/api/callback"options := scalekit.AuthorizationUrlOptions{Scopes: []string{"openid", "profile", "email", "offline_access"}}authorizationUrl, err := scalekit.GetAuthorizationUrl(redirectUri, options)if err != nil {c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})return}c.Redirect(http.StatusFound, authorizationUrl.String())}Spring @GetMapping("/auth/login/initiate")public ResponseEntity<Void> initiateLogin() {String redirectUri = "http://localhost:3000/api/callback";AuthorizationUrlOptions options = new AuthorizationUrlOptions();options.setScopes(Arrays.asList("openid", "profile", "email", "offline_access"));URL authorizationUrl = scalekit.authentication().getAuthorizationUrl(redirectUri, options);return ResponseEntity.status(HttpStatus.FOUND).header("Location", authorizationUrl.toString()).build();}Authentication flow:
When a user accepts an invitation, Scalekit handles the authentication process automatically:
- User clicks invitation link → Scalekit redirects to your initiate login endpoint
- Your app redirects to Scalekit → Your initiate login endpoint creates an authorization URL and redirects to Scalekit’s login page
- User completes authentication → Scalekit processes the login and redirects back to your callback URL with an authorization code
- Your app exchanges code for user details → Your callback endpoint exchanges the authorization code for ID Token and redirects the user to your dashboard
- Decode ID Token for user profile → Decode the JWT ID Token to access user information like email, name and verification status
-