मुख्य कंटेंट तक स्किप करें

The Admin API: automate your Claude org

उन्नत
What you'll learn
  • The two credentials the Admin API accepts (Admin API key vs org:admin OAuth token) and which endpoints REQUIRE the OAuth path
  • Which endpoints your org type can actually call — Claude Console (Platform) vs Claude Enterprise (claude.ai)
  • The role model, in plain English: user, claude_code_user, developer, billing, admin (Console) — and user, managed, membership_admin, owner, primary_owner (Enterprise)
  • The three gotchas that break real integrations: the seat-pool 400, the SCIM 400, and the ce-user-management-2026-07-13 beta header
  • Two copy-paste playbooks: clean employee offboarding, and quarterly group audit

If a human clicks it in the Console, you can usually script it with the Admin API — and if you're running a real team on Claude, you eventually have to. This is the guide to doing it without stepping on the three gotchas that break most first integrations.

What the Admin API is (and isn't)

Base: every endpoint lives under https://api.anthropic.com/v1/organizations/. There is no separate host and no separate SDK — you make plain HTTPS calls with curl, requests, or the same HTTP client you already use.

What it can do: list and manage organization members, roles, invites, workspaces and their members, existing API keys, service accounts, federation issuers/rules, and — for Claude Enterprise — RBAC groups and (read-only) custom roles.

What it can NOT do:

  • Create new API keys. For security reasons, new keys are only created in the Console. The API can list, rename, and deactivate the ones already there.
  • Modify admin members. Members with admin, owner, or primary_owner can't have their role changed or be removed via API — you do that in the Console.
  • Bypass your identity provider. If SSO/SCIM is in charge of a facet, the API returns 400 rather than fighting your IdP. See SSO + Admin API.

The two credentials

Every request needs one of these — pick per environment, not per call.

Pro tip
  • A dedicated OAuth profile is the safer default for humans (short-lived tokens, real user in the audit log).
  • Long-lived Admin API keys are simpler for CI, but treat them like production secrets and rotate on a schedule.
  • Service-account, federation-issuer, and federation-rule endpoints ONLY accept an org:admin OAuth token — Admin API keys are rejected on those routes.
CredentialHow you send itWho can create itNotes
Admin API key (sk-ant-admin…)x-api-key: $ANTHROPIC_ADMIN_KEYMembers with the admin roleLong-lived. Covers most endpoints.
OAuth bearer token (org:admin scope)authorization: Bearer $ANTHROPIC_OAUTH_TOKENMembers with admin, owner, or primary_ownerShort-lived; refresh with the ant CLI. REQUIRED for service-account / federation endpoints.

Both must also send anthropic-version: 2023-06-01 on every request (Claude Enterprise group and custom-role requests are the one exception — see the beta header rule below).

First call: who am I?

# With an Admin API key
curl -sS "https://api.anthropic.com/v1/organizations/me" \
-H "anthropic-version: 2023-06-01" \
-H "x-api-key: $ANTHROPIC_ADMIN_KEY"

# With an OAuth bearer token (org:admin scope)
curl -sS "https://api.anthropic.com/v1/organizations/me" \
-H "anthropic-version: 2023-06-01" \
-H "authorization: Bearer $ANTHROPIC_OAUTH_TOKEN"

Response is your org's id, type, and name. If this fails with 401, your credential is bad; if it fails with 403, your role is too low.

Console vs Claude Enterprise: what you can call

Two organization types share one URL space but expose different subsets. This is the single most confusing thing about the Admin API.

EndpointsClaude Console (Platform)Claude Enterprise (claude.ai)
Members & invites✅ GABeta (no extra header)
Workspaces + workspace members✅ GA❌ Not available
API keys (list / rename / deactivate)✅ GA❌ Not available
Usage & cost reports, rate limits✅ GA❌ Not available
Service accounts, federation issuers, federation rules✅ GA (OAuth only)❌ Not available
RBAC groups + group members❌ Not availableBeta (header required)
Custom roles (read-only catalog)❌ Not availableBeta (header required)
Spend Limits API❌ Not available✅ GA

Claude Platform on AWS is a third case: only the workspace endpoints (/v1/organizations/workspaces) work. Everything else returns 404.

The role model

Roles are named differently in each org type. Don't cross-map them by ear.

Claude Console roles

RoleCan
userUse Workbench
claude_code_userWorkbench + Claude Code
developerWorkbench + manage API keys
billingWorkbench + manage billing
adminEverything above + manage users

Above admin sit owner and primary_owner — Console has these but treats them as super-admins for API purposes.

Claude Enterprise roles

Five values, but the API can only assign two of them (user and managed). The rest are set in claude.ai org settings and can't be modified or removed via API.

RoleMeaning
userStandard member — permissions come from plan defaults.
managedPermissions come from the custom roles attached to their groups (this is the RBAC path).
ownerOrganization owner.
membership_adminCan manage members but not billing/settings.
primary_ownerExactly one exists. Cannot be removed.

If you want fine-grained permissions in Enterprise, the recipe is: put the person on the managed role, then add them to the groups that carry the roles you want.

The beta header rule

The single most common integration bug on Enterprise.

Watch out
  • Members and invites: NO extra beta header — just anthropic-version: 2023-06-01.
  • Groups and custom roles: SEND anthropic-beta: ce-user-management-2026-07-13. Requests without it return 404.
  • Group and custom-role requests do NOT require anthropic-version — the official examples omit it. Match the official pattern to avoid unexpected drift when the beta graduates.

If you use one HTTP client for everything, gate it on the URL:

BETA_ROUTES = ("/v1/organizations/rbac_groups", "/v1/organizations/rbac_roles")

def headers(path: str, key: str) -> dict:
h = {"x-api-key": key}
if path.startswith(BETA_ROUTES):
h["anthropic-beta"] = "ce-user-management-2026-07-13"
else:
h["anthropic-version"] = "2023-06-01"
return h

Scopes for Enterprise Admin keys

Claude Enterprise Admin API keys are scoped — the primary owner picks what each key can do at creation time. Pick the smallest set that works.

ScopeGrants
read:membersGET on members, invites, and all custom-role endpoints (there is no separate role scope)
write:membersPOST/DELETE on members and invites
read:rbac_groupsGET on groups + group members
write:rbac_groupsPOST/DELETE on groups + group members. Also required to pass rbac_group_ids when creating an invite, because it can grant permissions.
read:org_auditRead-only "audit integrations" scope — covers every GET on this API plus Compliance API reads. Perfect for your security team's monitoring bot.

Pagination — two different styles

Small annoyance, big cause of "why is my list empty":

  • Members and invites use ID-based pagination: pass limit (default 20, max 1000) plus at most one of before_id or after_id. Page with first_id / last_id and stop when has_more is false.
  • Groups, group members, and custom roles use an opaque cursor: read next_page from each response and pass it back unchanged as page. Stop when next_page is null.

Rate limits on all Admin API endpoints share 100 requests per minute per organization, except invite creation which has its own 1,200 requests per hour budget. Over either limit returns 429.

Common recipes

List all members (paged)

import os, requests

API = "https://api.anthropic.com/v1/organizations/users"
H = {"anthropic-version": "2023-06-01", "x-api-key": os.environ["ANTHROPIC_ADMIN_KEY"]}

after = None
while True:
params = {"limit": 1000}
if after:
params["after_id"] = after
page = requests.get(API, headers=H, params=params).json()
for m in page["data"]:
print(m["email"], m["role"])
if not page["has_more"]:
break
after = page["last_id"]

Find a member by email (case-insensitive, handles +tags)

curl "https://api.anthropic.com/v1/organizations/users?email=jane%2Bhiring@example.com" \
-H "x-api-key: $ANTHROPIC_ADMIN_KEY" \
-H "anthropic-version: 2023-06-01"

Same match on jane@example.com — the server normalizes both sides.

Change a member's role

Only assignable to user or managed on Enterprise; user, claude_code_user, developer, or billing on Console. Trying to assign an admin role, or to modify a member who already holds one, returns 400.

Promote a member to developer (Console)

curl -sS "https://api.anthropic.com/v1/organizations/users/$USER_ID" \
-H "anthropic-version: 2023-06-01" \
-H "content-type: application/json" \
-H "x-api-key: $ANTHROPIC_ADMIN_KEY" \
-d '{"role": "developer"}'

Invite a new hire, pre-assigned to a group (Enterprise)

Passing rbac_group_ids requires the write:rbac_groups scope on the key, because the group grants permissions.

Invite + auto-add to Engineering

curl -sS -X POST "https://api.anthropic.com/v1/organizations/invites" \
-H "anthropic-version: 2023-06-01" \
-H "content-type: application/json" \
-H "x-api-key: $ANTHROPIC_ADMIN_KEY" \
-d '{
  "email": "newhire@example.com",
  "role": "managed",
  "rbac_group_ids": ["rbac_group_01UvWxYzAbCdEfGhIjKlMn"]
}'

Clean employee offboarding (works for both org types)

Guided walkthrough1 of 5
  1. GET /v1/organizations/users?email=<address>. If the array is empty, they never joined — jump to step 3.

Quarterly group audit (Enterprise)

Find members in sensitive groups who shouldn't be, without staring at the Console.

import os, requests

H_BETA = {"x-api-key": os.environ["ANTHROPIC_ADMIN_KEY"],
"anthropic-beta": "ce-user-management-2026-07-13"}

groups = requests.get("https://api.anthropic.com/v1/organizations/rbac_groups?limit=1000",
headers=H_BETA).json()["data"]

for g in groups:
if "prod" not in g["name"].lower():
continue
members = requests.get(
f"https://api.anthropic.com/v1/organizations/rbac_groups/{g['id']}/members?limit=1000",
headers=H_BETA).json()["data"]
print(f"{g['name']} ({len(members)} members)")
for m in members:
print(f" {m['email']}")

Diff that output against your IdP roster and remove anyone stale with DELETE /rbac_groups/{group_id}/members/{user_id}. SCIM-provisioned groups (source_type: "scim") will return 400 on modification — do those in your IdP.

SSO + Admin API

If your identity provider is in charge of a facet, the API defers to it:

Your IdP doesBlocked API operationHTTP
JIT or SCIM user provisioningCreate invite400
Advanced SSO / SCIM role provisioningUpdate member role400
SCIM membership provisioningRemove member from org400
SCIM group provisioning (source_type: "scim")Rename group, delete group, add/remove group member400

Reads always work. This is by design: your IdP is the source of truth for whatever it owns, and the Admin API refuses to let a script silently drift from it.

Seats, invites, and the 400 you'll hit once

On plans with a finite seat pool:

  • A pending invite consumes a seat. Withdraw or let it expire to return the seat.
  • Invite creation does not take a tier parameter. The server picks the lowest tier with availability.
  • If no seat is free, invite creation returns 400 — not a purchase. Buy seats in your plan settings, then retry.
  • Invites expire after 21 days and there's no way to extend them. To change a pending invite's email or role, withdraw and re-create.

Watch out for

Watch out
  • Admin API keys don't expire when their creator leaves. You must rotate them manually — see step 4 of the offboarding playbook.
  • The 'managed' role on Enterprise is inert on its own. A managed member with no group membership has essentially no product access. Always pair the role change with the group assignments.
  • A group's roles field can come back as null (not []) if role data was temporarily unavailable. Retry before concluding a group has zero roles.
  • capability_access_all and capability_access_all_ga on a role permission are blanket grants — do not tally them alongside other rows or you'll double-count. They cover their whole variant except model access and permission_-prefixed admin permissions.

The Admin API vs the Compliance API vs Inference Hooks

Three governance surfaces, often confused:

  • Admin API (this page) manages who is in the org and what they can do.
  • Compliance API exposes what they did: audit events, activity feed, and (on Enterprise) content retrieval and deletion for legal holds.
  • Inference Hooks — the newest of the three (beta August 5, 2026) — let your DLP server allow or deny each prompt in real time before Claude ever sees it, across chat, Claude Code, and Cowork.

For security tooling, a single key with read:org_audit covers both API-side reads. Inference Hooks are a separate configuration in the admin console.

Quiz

Check yourself

0/3
  1. You POST to /v1/organizations/rbac_groups without the anthropic-beta: ce-user-management-2026-07-13 header. What happens?
  2. A departing employee created three Admin API keys used by CI. You DELETE the user. What happens to the keys?
  3. On Claude Enterprise, which two roles CAN the Admin API assign?

Next