LangSmith 的 API 通过 API 密钥支持对 UI 中可用的所有操作的编程访问,只有一些例外情况在仅用户端点中注明。
在深入了解此内容之前,阅读以下内容可能会有所帮助:
有几个限制将很快取消:
  • LangSmith SDK 尚不支持这些组织管理操作。
  • 具有组织管理员权限的组织范围服务密钥可用于这些操作。
使用 X-Tenant-Id 标头指定要定位的工作区。如果标头不存在,如果不是组织范围的,操作将默认为 API 密钥最初创建的工作区。如果在使用组织范围的 API 密钥访问工作区范围的资源时未指定 X-Tenant-Id,请求将失败并显示 403 Forbidden
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: Workspace level:
These params should be omitted: read_only (deprecated), password and full_name (basic auth only)

API keys

Security settings

Organization Admin permissions are required to make these changes.
“Shared resources” in this context refer to public prompts, shared runs, and shared datasets.
Updating these settings affects all resources in the organization.
You can update these settings under the Settings > Shared tab for a workspace, or via API: These settings are only editable via API:
  • Disable/enable PAT creation (for self-hosted, available in Helm chart version 0.11.25+)
    • Use pat_creation_disabled to disable PAT creation for the entire organization.
    • See the admin guide for information about the Organization Viewer role, which cannot create PATs.

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["LANGSMITH_API_KEY"]
    # LANGSMITH_ORGANIZATION_ID is not a standard environment variable in the SDK, just used for this example
    organization_id = os.environ["LANGSMITH_ORGANIZATION_ID"]
    base_url = os.environ.get("LANGSMITH_ENDPOINT")  # or "https://api.smith.langchain.com". Update appropriately for self-hosted installations or the EU region
    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"
    api_keys_path = f"{base_url}/api/v1/api-key"

    # 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"]
    new_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=new_workspace_headers,
    )
    existing_user_res.raise_for_status()

    # List all members of the workspace
    members_res = session.get(f"{workspaces_path}/current/members", headers=new_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=new_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()

    # Create a new Service key
    api_key_res = session.post(
        api_keys_path,
        json={"description": "my key"},
        headers=new_workspace_headers,
    )
    api_key_res.raise_for_status()
    api_key_json = api_key_res.json()
    api_key = api_key_json["key"]

if __name__ == "__main__":
    main()

Connect these docs programmatically to Claude, VSCode, and more via MCP for real-time answers.