Manage your organization with the Admin API
Onboarding a team onto the Claude API means the same Console clicks every time: invite each person, create a workspace, add members, check which API keys exist, and set up an identity for CI. Doing that by hand leaves no record and doesn't scale past a few teams.
The Admin API exposes those controls as REST endpoints under /v1/organizations, and the Python SDK wraps them as client.beta.organization. This notebook onboards a team end to end, audits the organization's API keys along the way, and then removes everything it created.
By the end of this notebook, you'll be able to:
- Authenticate as an organization admin with an OAuth login or a Console Admin API key
- Invite users, set organization roles, and create a workspace with members
- Audit the organization's API keys and read its rate limits
- Create a service account for automation and grant it workspace access
The same calls work unchanged in a provisioning script or a scheduled audit job.
Prerequisites
- Python fundamentals, and familiarity with Claude Console organizations, workspaces, and API keys
- Python 3.11+ and
anthropic>=1.1.0, the first release withclient.beta.organization - A Claude Console organization where you hold the
admin,owner, orprimary_ownerrole. The Admin API isn't available for individual accounts. - Optional: the
antCLI(opens in new tab) for the OAuth login path
Authenticate as an admin
API keys scoped to a single workspace can't call the Admin API. It accepts three credentials: an org:admin OAuth token, an Admin API key, and a personal or service account key that isn't scoped to one workspace. This notebook uses the first two, and only organization admins can create either:
| Credential | How to get it | Coverage |
|---|---|---|
OAuth token with the org:admin scope | ant auth login --profile admin --scope org:admin | Every endpoint in this notebook |
Admin API key (sk-ant-admin01-...) | Claude Console → Settings → Admin keys(opens in new tab) | Everything except service accounts and workload identity federation |
The OAuth login opens a browser, asks you to pick the organization, and stores a refreshable token under ~/.config/anthropic/. The SDK loads it when you construct the client with profile="admin".
To use an Admin API key instead, add ANTHROPIC_ADMIN_API_KEY=sk-ant-admin01-... to a .env file next to this notebook. The setup cell uses the key if it's set and falls back to the OAuth profile otherwise.
Connected to Example Org (1f6e8a52-93c4-4d7b-a1e0-5b2c9d8e4f37) with OAuth profile 'admin'
organization.retrieve() calls GET /v1/organizations/me. Check the name before going further: an admin credential is bound to one organization, and every call that follows reads or writes it.
The rest of the notebook names what it creates after one team, so you can spot it in the Console.
research-20260826-180659
Invite teammates and set roles
An invite emails the recipient a sign-up link and records the role they get when they accept. For Console organizations the API accepts user, developer, billing, and claude_code_user. The admin role can only be granted in the Console.
Start new members as user, which grants Console and playground access without API keys, and promote them when they need more.
An invite sends a real email. Some organizations accept invites only to their own email domain, and an invite to any other domain returns a 400. The next cell defaults to a placeholder address on an existing admin's domain so it runs in any organization. Set INVITE_EMAIL to a teammate's address to try the full flow.
invite_015gWxHNr6h6TdRPZTmuCGnn new.teammate+20260826-180659@example.com role=user status=pending expires 2026-09-16
Invites expire after 21 days. invites.list() returns every invite in the organization with its status, and invites.delete() revokes a pending one.
new.teammate+20260826-180659@example.com user pending sent 2026-08-26
Once someone accepts, they show up in users.list(). The next cell prints the first 10. Filter by email to find one person, then change their role with users.update() or offboard them with users.remove(). Admins can't be removed through the API.
While the invite is pending, the next cell finds no user and skips the promotion, and the membership cell later skips the add. Both run once the invite is accepted.
ada@example.com admin joined 2026-06-01 new.teammate+20260826-180659@example.com hasn't accepted yet, nothing to promote
Create a workspace for the team
Workspaces partition API keys, spend limits, rate limits, and usage reporting inside one organization. One workspace per team or per environment is the usual layout. tags carry your own metadata, such as a cost center, and come back on every read.
wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ research-20260826-180659 {'team': 'research', 'cost-center': '4711'}workspaces.update() changes the name, display color, or tags. Tags merge with what's already there, and setting a tag to None removes it.
{'env': 'sandbox', 'team': 'research'}Organization admins and billing users are implicit members of every workspace and don't appear in members.list(). Everyone else needs an explicit workspace role, such as workspace_user, workspace_developer, or workspace_admin.
members.update() changes a role and members.remove() drops someone from the workspace without touching their organization membership.
research-20260826-180659: 0 explicit member(s)
Audit API keys
The Admin API lists, renames, deactivates, and archives API keys, but it can't create them: new keys come from the Console only. Use it for a scheduled audit, not for provisioning.
The next cell walks every active key in the organization and flags keys older than MAX_KEY_AGE_DAYS and keys with no expiry.
backend-prod production sk-ant-api03-R2D...igAA 14d expires 2027-08-12 ci-deploy production sk-ant-api03-9xQ...0mAA 14d expires 2026-12-09 0 key(s) flagged
Deactivating a key is reversible (status="active" turns it back on). Archiving is not. Leave APPLY = False for a dry run, or set it to True to deactivate the flagged keys.
Read the flagged list first. A key with no expiry is flagged even if it serves production traffic, and a deactivated key starts failing requests immediately.
no flagged keys, nothing to do
Create a service account for automation
A service account is a non-human member of the organization for CI jobs and backend services. It holds an organization role and workspace roles like a person does, so credentials issued to it don't depend on an employee's account. The service account endpoints accept only the org:admin OAuth credential. An Admin API key is rejected here.
name is a slug of lowercase letters, digits, and hyphens, and it must be unique in the organization. The service account endpoints can lag behind creation. An object created a few seconds ago can briefly return 404 from these endpoints, or be missing from a list. Retry on 404 when a call references something you just created, which is what the helper in the next cell does.
svac_01ABCDEFabcdef0123456789XY ci-research-20260826-180659 developer
Grant it a role in the team workspace, then list its memberships. Every service account is also an implicit workspace_user in the default workspace, and a grant made seconds ago can take a moment to appear in the list.
granted workspace_developer in research-20260826-180659 Default workspace_user implicit research-20260826-180659 workspace_developer explicit
To let a pipeline authenticate as this service account without storing a secret, register your CI provider as a federation issuer and add a rule that maps its OIDC tokens to the account. Workload identity federation(opens in new tab) covers that setup.
Check rate limits
Rate limits are set per organization. Each group covers a model family or another part of the API, such as batch, files, or web_search. rate_limits.list() returns every group. The next cell prints the group that covers MODEL, which the setup cell defines, plus the groups that aren't tied to a model.
batch enqueued_batch_requests=500,000, requests_per_minute=4,000 claude-sonnet-5 input_tokens_per_minute=10,000,000, output_tokens_per_minute=2,000,000, requests_per_minute=10,000
Workspaces inherit those values. An admin can cap a workspace lower in the Console, and workspaces.rate_limits.list() returns only the values that were overridden.
research-20260826-180659 has no overrides and inherits the organization limits
Clean up
Remove what this notebook created. Archiving a workspace is permanent and revokes every API key in it, so double-check workspace.name before running this against a real organization. Archived workspaces don't count toward the 100-workspace limit.
If an earlier cell raised, run this cell by hand. It needs workspace, service_account, and invite from the kernel.
archived workspace research-20260826-180659 at 2026-08-26 18:07 archived service account ci-research-20260826-180659 deleted invite for new.teammate+20260826-180659@example.com
Next steps
You authenticated as an admin, invited a user, created a workspace, gave a service account access to it, audited the organization's API keys, and read its rate limits, all through client.beta.organization.
Related admin surfaces that aren't covered here:
- Usage and cost cookbook(opens in new tab) and the Usage and Cost API(opens in new tab): token and dollar reporting by workspace, key, and model
- Claude Code Analytics API(opens in new tab): per-user Claude Code activity for the organization
- Workload identity federation(opens in new tab): keyless authentication for the service account you created, via
client.beta.organization.federation - Admin API reference(opens in new tab): every endpoint, including the ones the SDK exposes under
external_keysandfederation