--- title: "Teams Management" description: "Learn how to implement team functionality in your Python application using Stack Auth's REST API" --- After setting up your [Stack Auth helper function](../getting-started/setup.mdx), you can implement comprehensive team functionality in your Python application. ## Team Management Stack Auth provides full team management capabilities including: - **Team Creation & Management** - Create and update teams with metadata - **Team Memberships** - Add and remove users from teams - **Team Invitations** - Send email invitations to join teams - **Team Permissions** - Control what team members can do - **Team Profiles** - Manage user profiles within team context ### Creating a Team To create a new team: ```python def create_team(access_token, display_name, creator_user_id=None): """ Create a new team Returns the created team data """ body = { 'display_name': display_name } # Optionally specify a creator (only on server) if creator_user_id: body['creator_user_id'] = creator_user_id response = stack_auth_request('POST', 'api/v1/teams', headers={'x-stack-access-token': access_token}, json=body ) return { 'id': response['id'], 'display_name': response['display_name'], 'profile_image_url': response['profile_image_url'], 'client_metadata': response['client_metadata'], 'client_read_only_metadata': response['client_read_only_metadata'], 'created_at_millis': response.get('created_at_millis') # Server only } # Example usage team_data = create_team( access_token=access_token, display_name="Engineering Team" ) team_id = team_data['id'] print(f"Created team: {team_data['display_name']}") ``` ### Listing Teams Get all teams for the current user: ```python def list_user_teams(access_token): """ List all teams that the current user is a member of """ response = stack_auth_request('GET', 'api/v1/teams?user_id=me', headers={'x-stack-access-token': access_token} ) return response['items'] def list_all_teams(): """ List all teams in the project (server access only) """ response = stack_auth_request('GET', 'api/v1/teams') return response['items'] # Example usage user_teams = list_user_teams(access_token) print(f"User is member of {len(user_teams)} teams") # Server-side: list all teams all_teams = list_all_teams() print(f"Total teams in project: {len(all_teams)}") ``` ### Getting Team Information Retrieve details about a specific team: ```python def get_team(access_token, team_id): """ Get information about a specific team """ response = stack_auth_request('GET', f'api/v1/teams/{team_id}', headers={'x-stack-access-token': access_token} ) return { 'id': response['id'], 'display_name': response['display_name'], 'profile_image_url': response['profile_image_url'], 'client_metadata': response['client_metadata'], 'client_read_only_metadata': response['client_read_only_metadata'] } # Example usage team_info = get_team(access_token, team_id) print(f"Team: {team_info['display_name']}") ``` ### Updating Team Information Update team details (requires `$update_team` permission): ```python def update_team(access_token, team_id, **updates): """ Update team information Requires $update_team permission """ # Filter out None values body = {k: v for k, v in updates.items() if v is not None} response = stack_auth_request('PATCH', f'api/v1/teams/{team_id}', headers={'x-stack-access-token': access_token}, json=body ) return response # Example usage updated_team = update_team( access_token=access_token, team_id=team_id, display_name="Updated Engineering Team", profile_image_url="https://example.com/team-logo.png", client_metadata={ "department": "Engineering", "location": "San Francisco" } ) ``` ## Team Membership Management ### Adding Members to a Team Add users to a team (server access required): ```python def add_team_member(team_id, user_id): """ Add a user to a team (server access only) """ response = stack_auth_request('POST', f'api/v1/team-memberships/{team_id}/{user_id}', json={} ) return response # Example usage add_team_member(team_id, user_id) print(f"Added user {user_id} to team {team_id}") ``` ### Removing Members from a Team Remove users from a team (requires `$remove_members` permission): ```python def remove_team_member(access_token, team_id, user_id): """ Remove a user from a team Requires $remove_members permission """ stack_auth_request('DELETE', f'api/v1/team-memberships/{team_id}/{user_id}', headers={'x-stack-access-token': access_token} ) # Example usage remove_team_member(access_token, team_id, user_id) print(f"Removed user {user_id} from team {team_id}") ``` ### Getting Team Members List all members of a team: ```python def get_team_members(access_token, team_id): """ Get all members of a team with their profiles Requires $read_members permission """ response = stack_auth_request('GET', f'api/v1/team-member-profiles?team_id={team_id}', headers={'x-stack-access-token': access_token} ) return response['items'] # Example usage members = get_team_members(access_token, team_id) for member in members: print(f"Member: {member['display_name']} ({member['user_id']})") ``` ## Team Invitations ### Sending Team Invitations Invite users to join a team via email: ```python def send_team_invitation(access_token, team_id, email, callback_url): """ Send an invitation to join a team Requires $invite_members permission """ response = stack_auth_request('POST', 'api/v1/team-invitations/send-code', headers={'x-stack-access-token': access_token}, json={ 'email': email, 'team_id': team_id, 'callback_url': callback_url } ) return { 'success': response['success'], 'invitation_id': response['id'] } # Example usage invitation_result = send_team_invitation( access_token=access_token, team_id=team_id, email="newmember@example.com", callback_url="https://yourapp.com/join-team" ) print(f"Invitation sent: {invitation_result['invitation_id']}") ``` ### Accepting Team Invitations Complete the invitation process when a user clicks the invitation link: ```python def accept_team_invitation(code): """ Accept a team invitation using the code from the invitation email """ response = stack_auth_request('POST', 'api/v1/team-invitations/accept', json={'code': code} ) return response # Example usage (when user clicks invitation link) accept_team_invitation(invitation_code) print("User successfully joined the team!") ``` ### Listing Team Invitations Get pending invitations for a team: ```python def list_team_invitations(access_token, team_id): """ List pending invitations for a team Requires $invite_members permission """ response = stack_auth_request('GET', f'api/v1/team-invitations?team_id={team_id}', headers={'x-stack-access-token': access_token} ) return response['items'] # Example usage invitations = list_team_invitations(access_token, team_id) for invitation in invitations: print(f"Pending invitation for: {invitation['recipient_email']}") ``` ## Team Permissions Management ### Granting Team Permissions Give specific permissions to team members: ```python def grant_team_permission(team_id, user_id, permission_id): """ Grant a permission to a user in a team (server access only) """ response = stack_auth_request('POST', f'api/v1/team-permissions/{team_id}/{user_id}/{permission_id}', json={} ) return response # Example usage grant_team_permission(team_id, user_id, "$update_team") grant_team_permission(team_id, user_id, "$invite_members") print(f"Granted permissions to user {user_id}") ``` ### Revoking Team Permissions Remove permissions from team members: ```python def revoke_team_permission(team_id, user_id, permission_id): """ Revoke a permission from a user in a team (server access only) """ stack_auth_request('DELETE', f'api/v1/team-permissions/{team_id}/{user_id}/{permission_id}') # Example usage revoke_team_permission(team_id, user_id, "$update_team") print(f"Revoked permission from user {user_id}") ``` ### Checking Team Permissions Check if a user has specific permissions in a team: ```python def check_team_permission(access_token, team_id, user_id, permission_id): """ Check if a user has a specific permission in a team """ try: response = stack_auth_request('GET', f'api/v1/team-permissions/{team_id}/{user_id}/{permission_id}', headers={'x-stack-access-token': access_token} ) return True except Exception as e: if "TEAM_PERMISSION_NOT_FOUND" in str(e): return False raise e # Example usage can_update = check_team_permission(access_token, team_id, user_id, "$update_team") if can_update: print("User can update the team") else: print("User cannot update the team") ``` ### Listing User Permissions Get all permissions a user has in a team: ```python def list_user_team_permissions(access_token, team_id, user_id="me"): """ List all permissions a user has in a team """ response = stack_auth_request('GET', f'api/v1/team-permissions/{team_id}/{user_id}', headers={'x-stack-access-token': access_token} ) return response['items'] # Example usage permissions = list_user_team_permissions(access_token, team_id) permission_ids = [p['id'] for p in permissions] print(f"User permissions: {permission_ids}") ``` ## Team Member Profiles ### Managing Team Member Profiles Users can have different display names and profile information within each team: ```python def update_team_member_profile(access_token, team_id, user_id="me", **profile_data): """ Update a user's profile within a team context """ response = stack_auth_request('PATCH', f'api/v1/team-member-profiles/{team_id}/{user_id}', headers={'x-stack-access-token': access_token}, json=profile_data ) return response def get_team_member_profile(access_token, team_id, user_id="me"): """ Get a user's profile within a team context """ response = stack_auth_request('GET', f'api/v1/team-member-profiles/{team_id}/{user_id}', headers={'x-stack-access-token': access_token} ) return response # Example usage # Update current user's profile in the team updated_profile = update_team_member_profile( access_token=access_token, team_id=team_id, display_name="John Doe (Engineering Lead)", profile_image_url="https://example.com/john-avatar.png" ) # Get the updated profile profile = get_team_member_profile(access_token, team_id) print(f"Team profile: {profile['display_name']}") ``` ### Deleting Teams Remove a team entirely (requires `$delete_team` permission): ```python def delete_team(access_token, team_id): """ Delete a team (requires $delete_team permission) """ response = stack_auth_request('DELETE', f'api/v1/teams/{team_id}', headers={'x-stack-access-token': access_token} ) return response # Example usage delete_team(access_token, team_id) print(f"Team {team_id} deleted successfully") ``` ## Complete Team Management Example Here's a comprehensive example that demonstrates a full team management workflow: ```python import os import requests # Setup (from setup guide) stack_project_id = os.getenv("STACK_PROJECT_ID") stack_publishable_client_key = os.getenv("STACK_PUBLISHABLE_CLIENT_KEY") stack_secret_server_key = os.getenv("STACK_SECRET_SERVER_KEY") def stack_auth_request(method, endpoint, **kwargs): res = requests.request( method, f'https://api.stack-auth.com/{endpoint}', headers={ 'x-stack-access-type': 'server', # or 'client' if you're only accessing the client API 'x-stack-project-id': stack_project_id, 'x-stack-publishable-client-key': stack_publishable_client_key, 'x-stack-secret-server-key': stack_secret_server_key, # not necessary if access type is 'client' **kwargs.pop('headers', {}), }, **kwargs, ) if res.status_code >= 400: raise Exception(f"Stack Auth API request failed with {res.status_code}: {res.text}") return res.json() class TeamManager: def __init__(self, access_token): self.access_token = access_token def create_and_setup_team(self, name, member_emails): """Create a team and invite members""" # Create the team team = create_team(self.access_token, name) team_id = team['id'] print(f"Created team: {name} (ID: {team_id})") # Send invitations to members invitation_results = [] for email in member_emails: try: result = send_team_invitation( self.access_token, team_id, email, "https://yourapp.com/join-team" ) invitation_results.append((email, result['invitation_id'])) print(f"Invited {email}") except Exception as e: print(f"Failed to invite {email}: {e}") return team, invitation_results def manage_team_permissions(self, team_id, admin_user_ids): """Grant admin permissions to specific users""" admin_permissions = ["$update_team", "$invite_members", "$remove_members"] for user_id in admin_user_ids: for permission in admin_permissions: try: grant_team_permission(team_id, user_id, permission) print(f"Granted {permission} to {user_id}") except Exception as e: print(f"Failed to grant {permission} to {user_id}: {e}") def get_team_overview(self, team_id): """Get complete team information""" # Get team details team_info = get_team(self.access_token, team_id) # Get team members try: members = get_team_members(self.access_token, team_id) except Exception: members = [] # User might not have read_members permission # Get pending invitations try: invitations = list_team_invitations(self.access_token, team_id) except Exception: invitations = [] # User might not have invite_members permission return { 'team': team_info, 'members': members, 'pending_invitations': invitations } # Example usage team_manager = TeamManager(access_token) # Create a new team with initial members team, invitations = team_manager.create_and_setup_team( name="Product Team", member_emails=["alice@example.com", "bob@example.com", "charlie@example.com"] ) # Make some users team admins (server-side operation) admin_users = ["user-id-1", "user-id-2"] team_manager.manage_team_permissions(team['id'], admin_users) # Get team overview overview = team_manager.get_team_overview(team['id']) print(f"\nTeam Overview:") print(f"Name: {overview['team']['display_name']}") print(f"Members: {len(overview['members'])}") print(f"Pending Invitations: {len(overview['pending_invitations'])}") ``` ## Error Handling Common team-related errors you might encounter: ```python def handle_team_errors(func): """Decorator to handle common team operation errors""" def wrapper(*args, **kwargs): try: return func(*args, **kwargs) except Exception as e: error_message = str(e) if "TEAM_PERMISSION_REQUIRED" in error_message: print("Insufficient permissions for this team operation") elif "TEAM_MEMBERSHIP_NOT_FOUND" in error_message: print("User is not a member of this team") elif "TEAM_NOT_FOUND" in error_message: print("Team not found") elif "TEAM_MEMBERSHIP_ALREADY_EXISTS" in error_message: print("User is already a member of this team") elif "USER_NOT_FOUND" in error_message: print("User not found") else: print(f"Team operation error: {error_message}") raise e return wrapper @handle_team_errors def safe_add_member(team_id, user_id): return add_team_member(team_id, user_id) @handle_team_errors def safe_send_invitation(access_token, team_id, email, callback_url): return send_team_invitation(access_token, team_id, email, callback_url) ``` ## Common Team Permission IDs Stack Auth includes several built-in team permissions: - **`$update_team`** - Edit team information and metadata - **`$delete_team`** - Delete the entire team - **`$invite_members`** - Send invitations to new members - **`$remove_members`** - Remove members from the team - **`$read_members`** - View team member list - **`team_member`** - Basic team membership (automatically granted) For more advanced team features, check out the [REST API documentation](../rest-api/overview.mdx).