Manage your organization using the API
LangSmith's API supports programmatic access via API key to all of the actions available in the UI, with only a few exceptions that are noted below.
Before diving into this content, it might be helpful to read the following:
There are a few limitations that will be lifted soon:
- The LangSmith SDKs do not support these organization management actions yet.
- Service Keys don't have access to newly-added workspaces yet (we're adding support soon). We recommend using a PAT of an Organization Admin for now, which by default has the required permissions for these actions.
Some commonly-used endpoints and use cases are listed below. For a complete list of available endpoints, see the API docs.
The X-Organization-Id
header should be present on all requests, and X-Tenant-Id
header should be present on requests that are scoped to a particular workspace.
Workspacesโ
User managementโ
RBACโ
Membership managementโ
List roles
under RBAC should be used for retrieving role IDs of these operations.
List [organization|workspace] members
endpoints (below) response "id"
s should be used as identity_id
in these operations.
Organization level:
- List organization members
- Invite a user to the organization and one or more workspaces. This should be used when the user is not already a member in the organization.
- Update a userโs organization role
- Remove someone from the organization
Workspace level:
- List workspace members
- Add a member to a workspace that is already part of the organization
- Update a userโs workspace role
- Remove someone from a workspace
These params should be omitted: read_only
(deprecated), password
and full_name
(basic auth only)
User-Only Endpointsโ
These endpoints are user-scoped and require a logged-in user's JWT, so they should only be executed through the UI.
/api-key/current
endpoints: these are related a user's PATs/sso/email-verification/send
(Cloud-only): this endpoint is related to SAML SSO
Sample Codeโ
The sample code below goes through a few common workflows related to organization management.
Make sure to make necessary replacements wherever <replace_me>
is in the code.
import os
import requests
def main():
api_key = os.environ["LANGCHAIN_API_KEY"]
# LANGCHAIN_ORGANIZATION_ID is not a standard environment variable in the SDK, just used for this example
organization_id = os.environ["LANGCHAIN_ORGANIZATION_ID"]
base_url = os.environ.get("LANGCHAIN_ENDPOINT") or "https://api.smith.langchain.com"
headers = {
"Content-Type": "application/json",
"X-API-Key": api_key,
"X-Organization-Id": organization_id,
}
session = requests.Session()
session.headers.update(headers)
workspaces_path = f"{base_url}/api/v1/workspaces"
orgs_path = f"{base_url}/api/v1/orgs/current"
# Create a workspace
workspace_res = session.post(workspaces_path, json={"display_name": "My Workspace"})
workspace_res.raise_for_status()
workspace = workspace_res.json()
workspace_id = workspace["id"]
workspace_headers = {
"X-Tenant-Id": workspace_id,
}
# Grab roles - this includes both organization and workspace roles
roles_res = session.get(f"{orgs_path}/roles")
roles_res.raise_for_status()
roles = roles_res.json()
# system org roles are 'Organization Admin', 'Organization User'
# system workspace roles are 'Admin', 'Editor', 'Viewer'
org_roles_by_name = {role["display_name"]: role for role in roles if role["access_scope"] == "organization"}
ws_roles_by_name = {role["display_name"]: role for role in roles if role["access_scope"] == "workspace"}
# Invite a user to the org and the new workspace, as an Editor.
# workspace_role_id is only allowed if RBAC is enabled (an enterprise feature).
new_user_email = "<replace_me>"
new_user_res = session.post(
f"{orgs_path}/members",
json={
"email": new_user_email,
"role_id": org_roles_by_name["Organization User"]["id"],
"workspace_ids": [workspace_id],
"workspace_role_id": ws_roles_by_name["Editor"]["id"],
},
)
new_user_res.raise_for_status()
# Add a user that already exists in the org to the new workspace, as a Viewer.
# workspace_role_id is only allowed if RBAC is enabled (an enterprise feature).
existing_user_email = "<replace_me>"
org_members_res = session.get(f"{orgs_path}/members")
org_members_res.raise_for_status()
org_members = org_members_res.json()
existing_org_member = next(
(member for member in org_members["members"] if member["email"] == existing_user_email), None
)
existing_user_res = session.post(
f"{workspaces_path}/current/members",
json={
"user_id": existing_org_member["user_id"],
"workspace_ids": [workspace_id],
"workspace_role_id": ws_roles_by_name["Viewer"]["id"],
},
headers=workspace_headers,
)
existing_user_res.raise_for_status()
# List all members of the workspace
members_res = session.get(f"{workspaces_path}/current/members", headers=workspace_headers)
members_res.raise_for_status()
members = members_res.json()
workspace_member = next(
(member for member in members["members"] if member["email"] == existing_user_email), None
)
# Update the user's workspace role to Admin (enterprise-only)
existing_user_id = workspace_member["id"]
update_res = session.patch(
f"{workspaces_path}/current/members/{existing_user_id}",
json={"role_id": ws_roles_by_name["Admin"]["id"]},
headers=workspace_headers,
)
update_res.raise_for_status()
# Update the user's organization role to Organization Admin
update_res = session.patch(
f"{orgs_path}/members/{existing_org_member['id']}",
json={"role_id": org_roles_by_name["Organization Admin"]["id"]},
)
update_res.raise_for_status()
if __name__ == "__main__":
main()