User management
Manage the people in your Claude Enterprise organization with the Admin API: list members and change roles, send and withdraw invites, manage groups, and read custom roles.
This page covers managing the people in your Claude Enterprise (claude.ai) organization programmatically, using the Admin API:
- List members and look them up by email address
- Change a member’s role
- Remove members, or sign them out everywhere without removing them (beta)
- Send and withdraw invites
- Manage your enterprise’s groups and their membership
- Read your organization’s custom roles
For Claude Console (Claude Platform) organizations, see the Admin API guide for Claude Console.
Which endpoints can your organization use?
The Admin API is a single set of endpoints under https://api.anthropic.com/v1/organizations/. Claude Console and Claude Enterprise organizations authenticate with different Admin API keys and each have access to a different subset of the endpoints:
| Endpoints | Claude Console (Claude Platform) | Claude Enterprise (claude.ai) |
|---|---|---|
| Members and invites | Available; see the Admin API guide | Available (this page) |
| Groups | Not available | Available (this page) |
| Custom roles | Not available | Available, read-only (this page) |
| Plugins and Claude Tag | Not available | Available in beta |
| Spend limits | Not available | Available |
| Usage and cost reports | Available; see the Usage and Cost Analytics API | Available through the Usage and Cost Analytics API and the Claude Enterprise Analytics API |
| Workspaces, API keys, rate limits, and the other endpoints in the Admin API guide | Available | Not available |
Members and invites are the same endpoints for both organization types; this page documents their Claude Enterprise behavior, including the Claude Enterprise organization roles. The group and custom-role endpoints exist only for Claude Enterprise.
Overview
This page covers five resources:
| Resource | Endpoints | Use for |
|---|---|---|
| Members | GET /v1/organizations/usersGET /v1/organizations/users/{user_id}POST /v1/organizations/users/{user_id}DELETE /v1/organizations/users/{user_id}POST /v1/organizations/users/{user_id}/sign_out (beta) | List the organization’s members or look one up by email; change a member’s role; remove a member; sign a member out everywhere. |
| Invites | POST /v1/organizations/invitesGET /v1/organizations/invitesGET /v1/organizations/invites/{invite_id}DELETE /v1/organizations/invites/{invite_id} | Invite a person to the organization, track the invitation’s status, and withdraw it before it is accepted. |
| Groups | GET /v1/organizations/rbac_groupsGET /v1/organizations/rbac_groups/{rbac_group_id}POST /v1/organizations/rbac_groupsPOST /v1/organizations/rbac_groups/{rbac_group_id}DELETE /v1/organizations/rbac_groups/{rbac_group_id} | Read your enterprise’s groups and the custom roles attached to each; create, rename, and delete groups. |
| Group members | GET /v1/organizations/rbac_groups/{rbac_group_id}/membersPOST /v1/organizations/rbac_groups/{rbac_group_id}/membersDELETE /v1/organizations/rbac_groups/{rbac_group_id}/members/{user_id} | Read a group’s members; add and remove members. |
| Custom roles | GET /v1/organizations/rbac_rolesGET /v1/organizations/rbac_roles/{rbac_role_id}GET /v1/organizations/rbac_roles/{rbac_role_id}/permissions | Read your organization’s custom roles and the permissions each role grants. |
Custom roles and their group attachments are managed in claude.ai organization settings; the API reads them but cannot change them.
Quick start
Set the ANTHROPIC_API_KEY environment variable to your Admin API key. The examples on this page read the key from it. The SDK and the ant CLI send the Authorization and anthropic-version headers for you.
List the organization’s members, newest first:
client = anthropic.Anthropic()
users = client.organization.users.list(limit=20)
for user in users:
print(f"{user.id}: {user.email} ({user.role})"){
"data": [
{
"type": "user",
"id": "user_01AbCdEfGhIjKlMnOpQrSt",
"email": "jane@example.com",
"name": "Jane Smith",
"role": "user",
"added_at": "2026-06-12T09:14:03Z"
}
],
"has_more": false,
"first_id": "user_01AbCdEfGhIjKlMnOpQrSt",
"last_id": "user_01AbCdEfGhIjKlMnOpQrSt"
}Key concepts
Organization roles
Every member has exactly one organization role. Reads return the member’s role as one of five values:
| Role | Meaning |
|---|---|
user | A standard member. |
managed | A member whose permissions are granted through the custom roles attached to their groups. |
owner | An organization owner. |
membership_admin | A member who can manage the organization’s members. |
primary_owner | The organization’s primary owner. There is exactly one. |
The API can assign only the user and managed roles, on invite creation and on role updates. Assigning managed requires the write:rbac_groups scope in addition to write:members, because a managed member’s permissions come from the custom roles attached to their groups. The administrative roles (owner, membership_admin, and primary_owner) are assigned in claude.ai organization settings, and members holding them cannot be modified or removed through this API.
Members and invites
A person becomes a member by accepting an invite (or through your organization’s single sign-on, where configured). Creating an invite sends an invitation email; the invite then reads as pending until the recipient accepts (accepted) or its server-assigned expires_at passes (expired). Only a pending invite can be withdrawn. To change a pending invitation’s email address or role, withdraw it and create a new one.
If your organization’s plan draws members from a finite pool of purchased seats, a pending invite consumes a seat. The create-invite endpoint does not take a seat or tier parameter: the seat is assigned automatically from the lowest tier that has availability. Creating an invite when no seat is free fails with a 400 error rather than purchasing a seat. Withdrawing the invite, letting it expire, or removing the member later returns the seat to the pool.
Groups and roles
Groups connect members to custom roles (role-based access control, the rbac in the endpoint paths and scope names). Groups belong to your parent organization and every organization under it, not to a single organization. So the group scopes (read:rbac_groups and write:rbac_groups) require a key created for all linked organizations. Each group carries a source_type: direct for groups created in claude.ai, scim for groups provisioned by your identity provider. A group’s role_ids field lists the IDs of the custom roles attached to it. Resolve them to names and permissions with the custom role endpoints. Each organization has its own role catalog, but groups are shared across your parent organization. So fetching a role that belongs to a different organization under your parent organization returns 404 for your key. The role_ids field is null (rather than []) when role data was temporarily unavailable, so retry to distinguish a degraded read from a group with no roles.
Versioning
Send the anthropic-version header on every request; see API versions for the available versions.
Rate limits
Admin API endpoints share a per-organization limit of 100 requests per minute; invite creation has its own limit of 1,200 requests per hour instead. Requests over a limit return 429 Too Many Requests.
Pagination
Member and invite lists use ID-based pagination: pass limit (default 20, maximum 1,000) plus at most one of before_id or after_id, and page using the first_id and last_id fields of each response until has_more is false. Group and custom-role lists use an opaque cursor instead: pass the response’s next_page value unchanged as the page parameter on the next request, until next_page is null.
When you iterate over the results, the SDK fetches more pages for you, so limit sets the page size, not the total. In the CLI, --limit sets the total number of results for member and invite lists. For group and role lists, it sets the page size.
Error responses
Error responses follow the standard shape documented in Claude API errors.
Members
List members
GET /v1/organizations/users returns the organization’s members, most recently added first. Filter by email to look up a specific member; the match is case-insensitive and tolerates common variants of the same address (for example, jane+hiring@example.com matches jane@example.com). Requires the read:members scope.
For complete parameter details and response schemas, see List usersPreview with links to the API reference available — press Tab until focus enters the card, Escape to return. in the API reference.
client = anthropic.Anthropic()
users = client.organization.users.list(email="jane@example.com")
for user in users:
print(f"{user.id}: {user.email} ({user.role})")Get a member
GET /v1/organizations/users/{user_id} returns one member by ID. Requires the read:members scope.
For complete parameter details and response schemas, see Get userPreview with links to the API reference available — press Tab until focus enters the card, Escape to return. in the API reference.
client = anthropic.Anthropic()
user = client.organization.users.retrieve("user_01AbCdEfGhIjKlMnOpQrSt")
print(f"id: {user.id}")
print(f"email: {user.email}")
print(f"role: {user.role}")Change a member’s role
POST /v1/organizations/users/{user_id} sets the member’s role to user or managed. Members holding an administrative role (owner, membership_admin, or primary_owner) cannot be changed through this endpoint, and administrative roles cannot be assigned; both return 400 and are managed in claude.ai organization settings. If your organization’s identity provider manages roles (advanced SSO or advanced SCIM provisioning), role updates return 400. Requires the write:members scope, plus write:rbac_groups when changing the role to managed.
For complete parameter details and response schemas, see Update userPreview with links to the API reference available — press Tab until focus enters the card, Escape to return. in the API reference.
client = anthropic.Anthropic()
user = client.organization.users.update("user_01AbCdEfGhIjKlMnOpQrSt", role="managed")
print(f"id: {user.id}")
print(f"role: {user.role}")Remove a member
DELETE /v1/organizations/users/{user_id} removes the member from the organization, returning any purchased seat they occupied to the organization’s pool. Members holding an administrative role cannot be removed through this endpoint, and if your identity provider manages membership (SCIM), removals return 400. Requires the write:members scope.
For complete parameter details and response schemas, see Remove userPreview with links to the API reference available — press Tab until focus enters the card, Escape to return. in the API reference.
client = anthropic.Anthropic()
removed_user = client.organization.users.remove("user_01AbCdEfGhIjKlMnOpQrSt")
print(f"id: {removed_user.id}"){
"type": "user_deleted",
"id": "user_01AbCdEfGhIjKlMnOpQrSt"
}Sign a member out everywhere
POST /v1/organizations/users/{user_id}/sign_out signs a member out of Claude on every browser and device, without removing them from the organization. Use it when a member’s device is lost or stolen, during a security incident, or while you investigate an account before you decide whether to remove the member. Requires the write:members scope.
The sign-out reaches the person’s whole Claude account, including their sessions in other organizations and on an individual plan. The member keeps their seat and role and can sign in again right away. To keep someone out, remove them or, if your organization requires single sign-on, disable their account in your identity provider. Disabling stops new sign-ins but leaves them in your member list. If you remove someone and leave their identity provider account active, automatic provisioning can add them back at their next sign-in. If your identity provider manages membership, you can remove the member only there.
Create the key before you need it. See Create a key for a Claude Enterprise organization. A write:members key works only in the organization it was created in, so each linked organization needs its own key. That organization’s primary owner creates it. To look members up by email address with the same key, also select the read:members scope.
The request has no body. Pass the member’s id, which List members returns:
client = anthropic.Anthropic()
user = client.beta.organization.users.sign_out("user_01AbCdEfGhIjKlMnOpQrSt")
print(f"id: {user.id}")A successful request returns 200 with the member, whose role and other fields are unchanged:
{
"type": "user",
"id": "user_01AbCdEfGhIjKlMnOpQrSt",
"email": "jane@example.com",
"name": "Jane Smith",
"role": "user",
"added_at": "2026-06-12T09:14:03Z"
}If you have no key yet, an owner can use the Sign out everywhere action on the Members page of claude.ai organization settings instead. It ends the same sessions, trusted devices, and OAuth tokens, and removes the same push-notification registrations. An owner can’t use it on their own account: they sign out their own sessions from their account settings in claude.ai.
What the request ends
The request ends all of the following for the member:
- Sign-in sessions: All of them for the person’s account, on every browser and device.
- Trusted devices: Every browser, computer, or phone that the person registered as trusted for sensitive actions. The person must register each device again.
- OAuth tokens issued for this organization: Whichever app holds them, such as Claude Code or a third-party app. Those apps must sign in again. A token almost always stops working at once, and within an hour at most.
The request also clears the record of browsers on which the person chose to skip Claude’s two-step verification, so that the next sign-in there asks for the second step again. It also removes the push-notification registrations that Claude holds for the person’s phones, desktop apps, and browsers, so that Claude stops sending notifications to them. This removal runs asynchronously: it usually completes within a minute, but in rare cases can take longer. A 200 doesn’t confirm either of these two steps.
Only the OAuth tokens are limited to this organization. Sessions, trusted devices, and push-notification registrations belong to the person’s account, so the sign-out also reaches their other organizations and any individual plan.
The request doesn’t delete anything that is already stored on a device.
What the request doesn’t end
The request doesn’t end any of the following:
- API keys: They keep working, including Admin API keys that the person created. To stop an Admin API key, delete it in the Keys section of claude.ai > Organization settings > API.
- OAuth tokens for other organizations: To end them, send the request in each organization with that organization’s key. The person has the same
idin every organization. OAuth tokens issued to the person’s account and not to an organization also keep working, and this request can’t end them. - Claude Code cloud sessions and routines: Sessions that run on Anthropic’s infrastructure, such as Claude Code on the web, or in one of your self-hosted environments keep running. Work in progress when you send the request, or started soon after, can fail. The session then gets new credentials without the person signing in again, and continues. The person’s routines that run on a schedule or on GitHub events keep starting new sessions. The Sign out everywhere action leaves these running too.
- Computers linked to Cowork: They stay linked.
- A sign-in that is in progress: One that’s already under way can finish during the request, or up to 5 minutes after it. If the audit log export or Activity Feed shows the person signing in after the request, send it again. Sign-ins to apps such as Claude Code aren’t recorded there, so if the person was signing in to one, send it again after 5 minutes.
Who you can’t sign out
The request can’t sign out the organization’s primary owner: it returns 400 with the error code cannot_sign_out_primary_owner. No one in your organization can sign out the primary owner, on the Members page either. The primary owner signs out their own sessions from their account settings in claude.ai.
A key with the write:members scope can sign out everyone else. That includes owners, members whose custom roles include the permission to manage owners, and members with the membership_admin role. Owners and the primary owner can do the same with the Sign out everywhere action on the Members page. Only the member’s role in this organization counts, so you can sign out someone who is the primary owner of a different organization.
The key keeps working after the person who created it changes role or leaves the organization. See What happens to an Admin API key when the person who created it leaves?.
Responses
| Status | Meaning |
|---|---|
| 200 | The sign-out completed. It’s safe to retry: a request that finds nothing left to end also returns 200, and a second request ends any session, trusted device, or OAuth token that the person has gained since the first. |
400 cannot_sign_out_primary_owner | The member is the primary owner, who can’t be signed out. See Who you can’t sign out. |
400 organization_not_enrolled_in_beta | The endpoint isn’t available to your organization. |
| 400 | The request omits the anthropic-beta value, which the message names, or the id in the path doesn’t start with user_. |
| 401 | The key is missing, invalid, or deleted, or it was created for a parent organization and isn’t bound to one organization. |
| 403 | The key lacks the write:members scope. |
| 404 | No member with that ID is in your organization. |
| 429 | The organization is over the rate limit that Admin API endpoints share. The retry-after header says when to retry. Sign-out has no separate limit. |
| 503 | A service that the request needs is temporarily unavailable. What the request already ended stays ended. Send the request again to end the rest. |
Error responses follow the standard shape documented in Claude API errors, with the error code in error.details.error_code:
{
"type": "error",
"error": {
"type": "invalid_request_error",
"message": "...",
"details": {
"error_code": "cannot_sign_out_primary_owner"
}
},
"request_id": "req_018EeWyXxfu5pfWkrYcMdjWG"
}Where the sign-out is recorded
Each sign-out that completes is recorded as org_user_trusted_devices_revoked, the same event that the Sign out everywhere action records. It appears in the audit log export that owners download in claude.ai. If your organization has the Compliance API, it also appears in the Activity Feed, with counts of the trusted devices and sessions that the request ended. A request that stops partway appears in the Activity Feed too, with completed set to false, and not in the audit log.
Invites
Create an invite
POST /v1/organizations/invites sends an invitation email and returns the invite with a server-assigned expires_at. role must be user or managed. If a pending invite already exists for the email address, or the address already belongs to a member, the request returns 400 naming the existing resource. Organizations whose identity provider provisions users automatically (JIT or SCIM) cannot create invites through the API. Requires the write:members scope, plus write:rbac_groups when role is managed.
On plans that draw members from a finite seat pool, the invite automatically takes a seat from the lowest tier that has availability. The API does not take a tier parameter. If no seat is free, the request fails with a 400 error rather than purchasing a seat. Add seats through the organization’s plan management and retry.
The optional rbac_group_ids field lists groups (by rbac_group_-prefixed ID) to assign to the member when they accept. Passing a non-empty rbac_group_ids additionally requires the key to carry the write:rbac_groups scope, because group assignment can grant the permissions attached to the group’s roles.
For complete parameter details and response schemas, see Create invitePreview with links to the API reference available — press Tab until focus enters the card, Escape to return. in the API reference.
client = anthropic.Anthropic()
invite = client.organization.invites.create(
email="newhire@example.com",
role="managed",
rbac_group_ids=["rbac_group_01UvWxYzAbCdEfGhIjKlMn"],
)
print(f"id: {invite.id}")
print(f"email: {invite.email}")
print(f"status: {invite.status}")
print(f"expires_at: {invite.expires_at}"){
"type": "invite",
"id": "invite_01QrStUvWxYzAbCdEfGhIj",
"email": "newhire@example.com",
"role": "managed",
"invited_at": "2026-07-06T16:20:11Z",
"expires_at": "2026-07-27T16:20:11Z",
"accepted_at": null,
"status": "pending",
"rbac_group_ids": ["rbac_group_01UvWxYzAbCdEfGhIjKlMn"]
}List invites
GET /v1/organizations/invites returns the organization’s invites, most recent first, across the pending, accepted, and expired states. To list only invites in certain states, pass statuses[] once for each state, for example statuses[]=pending. Requires the read:members scope.
For complete parameter details and response schemas, see List invitesPreview with links to the API reference available — press Tab until focus enters the card, Escape to return. in the API reference.
client = anthropic.Anthropic()
invites = client.organization.invites.list(limit=20)
for invite in invites:
print(f"{invite.id}: {invite.email} ({invite.status})")Get an invite
GET /v1/organizations/invites/{invite_id} returns one invite by ID. Requires the read:members scope.
For complete parameter details and response schemas, see Get invitePreview with links to the API reference available — press Tab until focus enters the card, Escape to return. in the API reference.
client = anthropic.Anthropic()
invite = client.organization.invites.retrieve("invite_01QrStUvWxYzAbCdEfGhIj")
print(f"id: {invite.id}")
print(f"email: {invite.email}")
print(f"status: {invite.status}")Withdraw an invite
DELETE /v1/organizations/invites/{invite_id} withdraws a pending invite, deactivating the link in the invitation email. Withdrawing an accepted invite returns 400 (remove the member instead); withdrawing an expired invite returns 400. Requires the write:members scope.
For complete parameter details and response schemas, see Delete invitePreview with links to the API reference available — press Tab until focus enters the card, Escape to return. in the API reference.
client = anthropic.Anthropic()
deleted_invite = client.organization.invites.delete("invite_01QrStUvWxYzAbCdEfGhIj")
print(f"id: {deleted_invite.id}")Groups
Groups your enterprise creates directly, in claude.ai organization settings or through this API (source_type: "direct"), support every endpoint in this section. Groups provisioned by your identity provider (source_type: "scim") can be read but not modified: renaming or deleting a SCIM group, or changing its membership, returns 400, because your identity provider owns it.
List groups
GET /v1/organizations/rbac_groups returns your enterprise’s groups, including identity-provider-managed (scim) groups. Requires the read:rbac_groups scope.
For complete parameter details and response schemas, see List groupsPreview with links to the API reference available — press Tab until focus enters the card, Escape to return. in the API reference.
client = anthropic.Anthropic()
groups = client.beta.organization.rbac_groups.list(limit=20)
for group in groups:
print(f"{group.id}: {group.name} ({group.source_type})"){
"data": [
{
"type": "rbac_group",
"id": "rbac_group_01UvWxYzAbCdEfGhIjKlMn",
"name": "Engineering",
"source_type": "direct",
"role_ids": ["rbac_role_01CdEfGhIjKlMnOpQrStUv"],
"created_at": "2026-03-18T10:01:42Z",
"updated_at": "2026-05-02T08:55:09Z"
}
],
"has_more": false,
"next_page": null
}Get a group
GET /v1/organizations/rbac_groups/{rbac_group_id} returns one group by ID. Requires the read:rbac_groups scope.
For complete parameter details and response schemas, see Get groupPreview with links to the API reference available — press Tab until focus enters the card, Escape to return. in the API reference.
client = anthropic.Anthropic()
group = client.beta.organization.rbac_groups.retrieve(
"rbac_group_01UvWxYzAbCdEfGhIjKlMn"
)
print(f"id: {group.id}")
print(f"name: {group.name}")
print(f"source_type: {group.source_type}")Create a group
POST /v1/organizations/rbac_groups creates a group with the given name (1–255 characters) and no roles or members. Requires the write:rbac_groups scope.
For complete parameter details and response schemas, see Create groupPreview with links to the API reference available — press Tab until focus enters the card, Escape to return. in the API reference.
client = anthropic.Anthropic()
group = client.beta.organization.rbac_groups.create(name="Engineering")
print(f"id: {group.id}")
print(f"name: {group.name}"){
"type": "rbac_group",
"id": "rbac_group_01UvWxYzAbCdEfGhIjKlMn",
"name": "Engineering",
"source_type": "direct",
"role_ids": [],
"created_at": "2026-07-09T18:00:00Z",
"updated_at": "2026-07-09T18:00:00Z"
}Rename a group
POST /v1/organizations/rbac_groups/{rbac_group_id} updates the group. name is the only field this endpoint can change. Requires the write:rbac_groups scope.
For complete parameter details and response schemas, see Update groupPreview with links to the API reference available — press Tab until focus enters the card, Escape to return. in the API reference.
client = anthropic.Anthropic()
group = client.beta.organization.rbac_groups.update(
"rbac_group_01UvWxYzAbCdEfGhIjKlMn", name="Platform Engineering"
)
print(f"id: {group.id}")
print(f"name: {group.name}")Delete a group
DELETE /v1/organizations/rbac_groups/{rbac_group_id} deletes the group. Its members remain members of their organizations, but they lose the permissions of its attached roles, and a group spend limit, if one existed, stops applying to them. Requires the write:rbac_groups scope.
For complete parameter details and response schemas, see Delete groupPreview with links to the API reference available — press Tab until focus enters the card, Escape to return. in the API reference.
client = anthropic.Anthropic()
deleted_group = client.beta.organization.rbac_groups.delete(
"rbac_group_01UvWxYzAbCdEfGhIjKlMn"
)
print(f"id: {deleted_group.id}"){
"id": "rbac_group_01UvWxYzAbCdEfGhIjKlMn",
"type": "rbac_group_deleted"
}List a group’s members
GET /v1/organizations/rbac_groups/{rbac_group_id}/members returns the group’s members (each with their user_id and email), oldest first. Only current members of your enterprise’s organizations are returned, so a page might contain fewer than limit entries while has_more is true. Requires the read:rbac_groups scope.
For complete parameter details and response schemas, see List group membersPreview with links to the API reference available — press Tab until focus enters the card, Escape to return. in the API reference.
client = anthropic.Anthropic()
members = client.beta.organization.rbac_groups.members.list(
"rbac_group_01UvWxYzAbCdEfGhIjKlMn", limit=100
)
for member in members:
print(f"{member.user_id}: {member.email}"){
"data": [
{
"type": "rbac_group_member",
"rbac_group_id": "rbac_group_01UvWxYzAbCdEfGhIjKlMn",
"user_id": "user_01AbCdEfGhIjKlMnOpQrSt",
"email": "jane@example.com",
"created_at": "2026-04-07T12:30:00Z"
}
],
"has_more": false,
"next_page": null
}Add a member to a group
POST /v1/organizations/rbac_groups/{rbac_group_id}/members adds an organization member to the group by user_id. The user must already be a member of one of your enterprise’s organizations (the request returns 404 otherwise), and adding someone who is already in the group returns 400. For scim groups, membership is managed in your identity provider and this request returns 400. To assign groups to a person who has not joined yet, use rbac_group_ids on invite creation instead. Requires the write:rbac_groups scope.
For complete parameter details and response schemas, see Add group memberPreview with links to the API reference available — press Tab until focus enters the card, Escape to return. in the API reference.
client = anthropic.Anthropic()
member = client.beta.organization.rbac_groups.members.add(
"rbac_group_01UvWxYzAbCdEfGhIjKlMn", user_id="user_01AbCdEfGhIjKlMnOpQrSt"
)
print(f"user_id: {member.user_id}")
print(f"email: {member.email}"){
"type": "rbac_group_member",
"rbac_group_id": "rbac_group_01UvWxYzAbCdEfGhIjKlMn",
"user_id": "user_01AbCdEfGhIjKlMnOpQrSt",
"email": "jane@example.com",
"created_at": "2026-07-09T18:00:00Z"
}Remove a member from a group
DELETE /v1/organizations/rbac_groups/{rbac_group_id}/members/{user_id} removes the member from the group; they remain a member of their organization. The request returns 404 if the user is not a member of the group, and 400 for scim groups, whose membership is managed in your identity provider. Requires the write:rbac_groups scope.
For complete parameter details and response schemas, see Remove group memberPreview with links to the API reference available — press Tab until focus enters the card, Escape to return. in the API reference.
client = anthropic.Anthropic()
removed_member = client.beta.organization.rbac_groups.members.remove(
"user_01AbCdEfGhIjKlMnOpQrSt", rbac_group_id="rbac_group_01UvWxYzAbCdEfGhIjKlMn"
)
print(f"user_id: {removed_member.user_id}"){
"rbac_group_id": "rbac_group_01UvWxYzAbCdEfGhIjKlMn",
"user_id": "user_01AbCdEfGhIjKlMnOpQrSt",
"type": "rbac_group_member_deleted"
}Custom roles
Custom roles are read-only through the API: these endpoints catalog your organization’s custom roles (defined in claude.ai organization settings or provisioned by Anthropic) and the permissions each role grants. Custom-role reads use the read:members scope (there is no separate role scope) and work with an organization-level key, and the catalog returned is your organization’s own.
Read a role’s name from its display_name field. For a role provisioned by Anthropic, display_name can differ from the label claude.ai shows, and Anthropic might change the name. To keep a lasting reference to a role, store its id.
List roles
GET /v1/organizations/rbac_roles returns your organization’s custom roles. Requires the read:members scope.
For complete parameter details and response schemas, see List rolesPreview with links to the API reference available — press Tab until focus enters the card, Escape to return. in the API reference.
client = anthropic.Anthropic()
roles = client.beta.organization.rbac_roles.list(limit=20)
for role in roles:
print(f"{role.id}: {role.display_name}"){
"data": [
{
"type": "rbac_role",
"id": "rbac_role_01CdEfGhIjKlMnOpQrStUv",
"display_name": "Engineering base",
"created_at": "2026-03-18T10:01:42Z",
"updated_at": "2026-05-02T08:55:09Z"
}
],
"has_more": false,
"next_page": null
}Get a role
GET /v1/organizations/rbac_roles/{rbac_role_id} returns one role by ID. Requires the read:members scope.
For complete parameter details and response schemas, see Get rolePreview with links to the API reference available — press Tab until focus enters the card, Escape to return. in the API reference.
client = anthropic.Anthropic()
role = client.beta.organization.rbac_roles.retrieve("rbac_role_01CdEfGhIjKlMnOpQrStUv")
print(f"id: {role.id}")
print(f"display_name: {role.display_name}")List a role’s permissions
GET /v1/organizations/rbac_roles/{rbac_role_id}/permissions returns the role’s permissions. Each permission pairs a resource (what it applies to: the organization’s product features, a connector tool, a connector OAuth scope, one connector, or every connector) with an action (what it grants on that resource). Rows for features not enabled for your organization are omitted, so a page might contain fewer than limit rows while has_more is true. Requires the read:members scope.
Two action values need special care. An organization permission whose action is capability_access_all (every product feature) or capability_access_all_ga (every stable product feature, that is, every feature not labeled beta or research preview) is a blanket grant. It is listed as that single row rather than expanded. A blanket grant covers neither model access nor the permission_-prefixed admin-panel permissions, nor inference_hooks_inspection, which a role holds only through a row that names it. When you tally what a role grants, treat a blanket row as covering everything its variant describes, not just the features named in other rows.
For complete parameter details and response schemas, see List role permissionsPreview with links to the API reference available — press Tab until focus enters the card, Escape to return. in the API reference.
client = anthropic.Anthropic()
permissions = client.beta.organization.rbac_roles.permissions.list(
"rbac_role_01CdEfGhIjKlMnOpQrStUv", limit=20
)
for permission in permissions:
print(permission.action){
"data": [
{
"type": "rbac_role_permission",
"resource": {
"type": "organization",
"organization_id": "12345678-1234-5678-1234-567812345678"
},
"action": "capability_access_all_ga"
},
{
"type": "rbac_role_permission",
"resource": {
"type": "connector_tool",
"connector_id": "mcpsrv_01WxYzAbCdEfGhIjKlMnOp",
"tool_name": "search_tickets"
},
"action": "use"
}
],
"has_more": false,
"next_page": null
}Example workflows
Offboard a departing employee
-
Look up the member by email:
Pythonclient = anthropic.Anthropic() users = client.organization.users.list(email="departing@example.com") for user in users: print(f"{user.id}: {user.email} ({user.role})") -
Remove them with
DELETE /v1/organizations/users/{user_id}, using theidfrom the response. Their seat, if any, returns to the pool. -
If the person had not yet joined, the lookup returns no member; list invites and withdraw their
pendinginvite instead.
Respond to a lost or stolen device
Before you need this workflow, create a key with the write:members and read:members scopes for the sign-out endpoint. If you have no key yet, an owner can use the Sign out everywhere action on the Members page of claude.ai organization settings in place of steps 2 to 4. An owner can’t use it on their own account: they sign out their own sessions from their account settings in claude.ai.
-
First, sign the person out of your identity provider, or disable their account there. Otherwise, whoever holds the lost device can sign in to Claude again through that device’s identity provider session or the person’s mailbox.
-
Look up the member by email address, as in step 1 of Offboard a departing employee. The email match tolerates variants of the same address, so check that the response is the right person.
-
Sign them out with
POST /v1/organizations/users/{user_id}/sign_out, using theidfrom the response. Sign a member out everywhere lists the headers that the request needs and what it ends. -
If the request returns 503, send it again until it returns 200. If it returns 400 with
cannot_sign_out_primary_owner, see Who you can’t sign out. -
Check the audit log export or Activity Feed for a sign-in after the first request. If you find one, or the person was signing in to an app such as Claude Code, send the request again after 5 minutes. If you can’t send the request, use the Sign out everywhere action again instead. This also signs the member out of any session that they have started since, so tell them first.
-
Confirm the sign-out where it is recorded, and review what the request doesn’t end.
Audit group membership
-
List groups and record each group’s
id,name, androle_ids. -
For each group that carries sensitive roles, page through
GET /v1/organizations/rbac_groups/{rbac_group_id}/membersand compare the member emails against your identity provider’s roster. -
Remove members who should no longer be in the group with
DELETE /v1/organizations/rbac_groups/{rbac_group_id}/members/{user_id}. Forscimgroups, make the change in your identity provider instead.
For a workflow that combines group membership with a temporary spend limit raise, see Temporarily raise a member’s spend limit during an incident on the Spend Limits API page.
Frequently asked questions
Is this a different API from the Admin API?
No. The member and invite endpoints are the same /v1/organizations/ endpoints that Claude Console organizations use; this page documents their Claude Enterprise behavior. The group and custom-role endpoints are part of the same API and exist only for Claude Enterprise organizations. The availability table shows which endpoints each organization type can call.
Can the API assign the owner or membership admin role?
No. The API assigns only user and managed, on invite creation and role updates. Administrative roles are assigned in claude.ai organization settings, and members holding them cannot be modified or removed through the API.
Can the API create or modify groups?
Yes, with the write:rbac_groups scope: create, rename, and delete groups, and add or remove their members. Two things the API cannot change: groups provisioned by your identity provider (source_type: "scim"), whose name and membership are owned by the identity provider, and custom roles, which are managed in claude.ai organization settings (the API reads them).
Does an unaccepted invite consume a seat?
On plans with a finite seat pool, yes: a pending invite holds a seat. Withdrawing the invite or letting it expire frees the seat. On plans without a seat pool, invites consume nothing.
Which operations work when your organization uses single sign-on?
If your identity provider provisions users automatically (JIT or SCIM), invite creation returns 400. If it manages roles (advanced SSO or advanced SCIM provisioning), role updates return 400. If it manages membership (SCIM provisioning), member removals return 400. Reads work regardless. So does signing a member out everywhere, whichever single sign-on mode your organization uses.
Does signing a member out keep them out?
No. Signing a member out ends their sign-in sessions, trusted devices, and OAuth tokens for your organization, but they can sign in again right away. To keep someone out, remove them or, if your organization requires single sign-on, disable their account in your identity provider. Disabling the account alone might not end sessions that are already open, so first sign the person out of your identity provider, then sign them out of Claude, and then remove them or disable their account.
What happens to an Admin API key when the person who created it leaves?
The key keeps working. Admin API keys are scoped to the organization, not to individual users, and a key created in claude.ai does not expire. Removing the creator from the organization or deprovisioning them through your identity provider ends their own access, but not the keys they created. Downgrading their role does not change the keys either: each key stays active with its original scopes. When you offboard someone who created Admin API keys, delete those keys in the Keys section of claude.ai > Organization settings > API and create replacements.
See also
Where to create a scoped key and which scopes to select.
Audit activity and retrieve or delete user content across your organization.
Track token usage and costs for your organization.
Set per-member spend limits and review increase requests.
Was this page helpful?