admin-api changedmanage-claude/admin-api
Nearest release: v2.1.319, published an hour after this site recorded the change. Shown because the two are within 24 hours of each other. Nothing here says the release caused the edit.
Recorded here
Lines+44added
Lines−12removed
From line
31
where the diff opens
First seen
14 Aug 2026
this site's first read of the page
Recorded edits26to this page, all time
The whole hunk
from line 31, old and new numbered
/
from line 31
3131
3232An Admin API key covers most endpoints. The service-account, federation-issuer, and federation-rule endpoints accept only an `org:admin` OAuth token. Send a personal key or service account key in the `x-api-key` header, as you would an Admin API key. The following examples call the [organization info endpoint](https://platform.claude.com/docs/en/manage-claude/admin-api#accessing-organization-info) with an OAuth token and with an Admin API key.
3333
34In Python, TypeScript, C#, Go, Java, PHP, and Ruby, the SDK exposes the endpoints on this page under `client.organization` (csharp, go: `client.Organization`; java: `client.organization()`; php: `$client->organization`), and the `ant` CLI under `ant organization`. The examples on this page use the default client, which reads an Admin API key from `ANTHROPIC_API_KEY` or an OAuth bearer token from `ANTHROPIC_AUTH_TOKEN`. SDK list methods in Python, TypeScript, C#, Go, and Java return an iterator that fetches more pages on demand, so `limit` sets the page size, not the total. The PHP, Ruby, and curl examples return one page. In the CLI, `--limit` caps the results on the member, invite, workspace, workspace-member, and API-key lists. For each endpoint’s parameters and responses, see the [Admin API reference](https://platform.claude.com/docs/en/api/organization).
34The SDK exposes the endpoints on this page under `client.organization` (csharp, go: `client.Organization`; java: `client.organization()`; php: `$client->organization`), and the `ant` CLI under `ant organization`. The examples on this page use the default client, which reads an Admin API key from `ANTHROPIC_API_KEY` or an OAuth bearer token from `ANTHROPIC_AUTH_TOKEN`. The comments in each list example say whether it fetches more pages or reads only the first. For each endpoint’s parameters and responses, see the [Admin API reference](https://platform.claude.com/docs/en/api/organization).
3535
3636### OAuth bearer token
3737
from line 42
4242export ANTHROPIC_AUTH_TOKEN=$(ant auth print-credentials --profile admin --access-token)
4343```
4444
45Interactive tokens are short-lived. If requests start returning 401, re-run the `export` command to refresh the token.
45Interactive tokens are short-lived. If requests start returning 401, rerun the `export` command to refresh the token.
4646
47The SDK and the `ant` CLI read `ANTHROPIC_AUTH_TOKEN` automatically. Leave `ANTHROPIC_API_KEY` unset in the same shell so they send the bearer token. Automated workloads skip the login: they authenticate through workload identity federation, and the SDK and CLI perform the token exchange from the federation environment variables. See [Bootstrap a workload to manage WIF](https://platform.claude.com/docs/en/manage-claude/wif-admin-api#bootstrap-a-workload-to-manage-wif).
47The SDK and the `ant` CLI read `ANTHROPIC_AUTH_TOKEN` automatically. Leave `ANTHROPIC_API_KEY` unset in the same shell so they send the bearer token. Automated workloads skip the login: they authenticate through Workload Identity Federation, and the SDK and CLI perform the token exchange from the federation environment variables. See [Bootstrap a workload to manage WIF](https://platform.claude.com/docs/en/manage-claude/wif-admin-api#bootstrap-a-workload-to-manage-wif).
4848
4949Call the Admin API with the exported token:
5050
from line 248
248248
249249<CodeGroup>
250250 ```bash cURL
251 # Returns one page.
251252 curl "https://api.anthropic.com/v1/organizations/users?limit=10" \
252253 -H "x-api-key: $ANTHROPIC_API_KEY" \
253254 -H "anthropic-version: 2026-10-21"
from line 255
254255 ```
255256
256257 ```bash CLI
258 # At a terminal, the view fetches more pages as you scroll. When piped or with `--format json`, `--limit` caps the results.
257259 ant organization:users list --limit 10
258260 ```
259261
from line 264
262264
263265 users = client.organization.users.list(limit=10)
264266
265 # Automatically fetches more pages as needed.
267 # Automatically fetches more pages as needed, so `limit` sets the page size, not the total.
266268 for user in users:
267269 print(f"{user.id}: {user.email} ({user.role})")
268270 ```
from line 274
272274
273275 const users = await client.organization.users.list({ limit: 10 });
274276
277 // Automatically fetches more pages as needed, so `limit` sets the page size, not the total.
275278 for await (const user of users) {
276279 console.log(`${user.id}: ${user.email} (${user.role})`);
277280 }
from line 285
282285
283286 var page = await client.Organization.Users.List(new() { Limit = 10 });
284287
288 // Automatically fetches more pages as needed, so `limit` sets the page size, not the total.
285289 await foreach (var user in page.Paginate())
286290 {
287291 Console.WriteLine($"{user.ID}: {user.Email} ({user.Role.Raw()})");
from line 299
295299 Limit: anthropic.Int(10),
296300 })
297301
302 // Automatically fetches more pages as needed, so `limit` sets the page size, not the total.
298303 for users.Next() {
299304 user := users.Current()
300305 fmt.Printf("%s: %s (%s)\n", user.ID, user.Email, user.Role)
from line 320
315320 .build();
316321 var users = client.organization().users().list(params);
317322
323 // Automatically fetches more pages as needed, so `limit` sets the page size, not the total.
318324 for (var user : users.autoPager()) {
319325 IO.println(user.id() + ": " + user.email() + " (" + user.role().asString() + ")");
320326 }
from line 332
326332
327333 $users = $client->organization->users->list(limit: 10);
328334
335 // Reads only the first page.
329336 foreach ($users->getItems() as $user) {
330337 echo "{$user->id}: {$user->email} ({$user->role})\n";
331338 }
from line 343
336343
337344 users = client.organization.users.list(limit: 10)
338345
346 # Reads only the first page.
339347 users.data.each do |user|
340348 puts "#{user.id}: #{user.email} (#{user.role})"
341349 end
from line 672
664672 ```
665673</CodeGroup>
666674
667List pending invites:
675List pending, accepted, and expired invites:
668676
669677<CodeGroup>
670678 ```bash cURL
679 # Returns one page.
671680 curl "https://api.anthropic.com/v1/organizations/invites?limit=10" \
672681 -H "x-api-key: $ANTHROPIC_API_KEY" \
673682 -H "anthropic-version: 2026-10-21"
from line 683
674683 ```
675684
676685 ```bash CLI
686 # At a terminal, the view fetches more pages as you scroll. When piped or with `--format json`, `--limit` caps the results.
677687 ant organization:invites list --limit 10
678688 ```
679689
from line 692
682692
683693 invites = client.organization.invites.list(limit=10)
684694
685 # Automatically fetches more pages as needed.
695 # Automatically fetches more pages as needed, so `limit` sets the page size, not the total.
686696 for invite in invites:
687697 print(f"{invite.id}: {invite.email} ({invite.status})")
688698 ```
from line 702
692702
693703 const invites = await client.organization.invites.list({ limit: 10 });
694704
705 // Automatically fetches more pages as needed, so `limit` sets the page size, not the total.
695706 for await (const invite of invites) {
696707 console.log(`${invite.id}: ${invite.email} (${invite.status})`);
697708 }
from line 713
702713
703714 var page = await client.Organization.Invites.List(new() { Limit = 10 });
704715
716 // Automatically fetches more pages as needed, so `limit` sets the page size, not the total.
705717 await foreach (var invite in page.Paginate())
706718 {
707719 Console.WriteLine($"{invite.ID}: {invite.Email} ({invite.Status.Raw()})");
from line 727
715727 Limit: anthropic.Int(10),
716728 })
717729
730 // Automatically fetches more pages as needed, so `limit` sets the page size, not the total.
718731 for invites.Next() {
719732 invite := invites.Current()
720733 fmt.Printf("%s: %s (%s)\n", invite.ID, invite.Email, invite.Status)
from line 748
735748 .build();
736749 var invites = client.organization().invites().list(params);
737750
751 // Automatically fetches more pages as needed, so `limit` sets the page size, not the total.
738752 for (var invite : invites.autoPager()) {
739753 IO.println(invite.id() + ": " + invite.email() + " (" + invite.status().asString() + ")");
740754 }
from line 760
746760
747761 $invites = $client->organization->invites->list(limit: 10);
748762
763 // Reads only the first page.
749764 foreach ($invites->getItems() as $invite) {
750765 echo "{$invite->id}: {$invite->email} ({$invite->status})\n";
751766 }
from line 771
756771
757772 invites = client.organization.invites.list(limit: 10)
758773
774 # Reads only the first page.
759775 invites.data.each do |invite|
760776 puts "#{invite.id}: #{invite.email} (#{invite.status})"
761777 end
from line 865
849865
850866### Workspace members
851867
852Manage [user access to specific workspaces](https://platform.claude.com/docs/en/api/organization/workspaces/members/retrieve):
868Manage [user access to specific workspaces](https://platform.claude.com/docs/en/api/organization/workspaces/members/retrieve).
853869
854870Add a member to a workspace:
855871
from line 1007
9911007
9921008<CodeGroup>
9931009 ```bash cURL
1010 # Returns one page.
9941011 curl "https://api.anthropic.com/v1/organizations/workspaces/wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ/members?limit=10" \
9951012 -H "x-api-key: $ANTHROPIC_API_KEY" \
9961013 -H "anthropic-version: 2026-10-21"
from line 1014
9971014 ```
9981015
9991016 ```bash CLI
1017 # At a terminal, the view fetches more pages as you scroll. When piped or with `--format json`, `--limit` caps the results.
10001018 ant organization:workspaces:members list \
10011019 --workspace-id wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ \
10021020 --limit 10
from line 1027
10091027 "wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ", limit=10
10101028 )
10111029
1012 # Automatically fetches more pages as needed.
1030 # Automatically fetches more pages as needed, so `limit` sets the page size, not the total.
10131031 for member in members:
10141032 print(f"{member.user_id}: {member.workspace_role}")
10151033 ```
from line 1040
10221040 { limit: 10 }
10231041 );
10241042
1043 // Automatically fetches more pages as needed, so `limit` sets the page size, not the total.
10251044 for await (const member of members) {
10261045 console.log(`${member.user_id}: ${member.workspace_role}`);
10271046 }
from line 1054
10351054 new() { Limit = 10 }
10361055 );
10371056
1057 // Automatically fetches more pages as needed, so `limit` sets the page size, not the total.
10381058 await foreach (var member in page.Paginate())
10391059 {
10401060 Console.WriteLine($"{member.UserID}: {member.WorkspaceRole.Raw()}");
from line 1072
10521072 },
10531073 )
10541074
1075 // Automatically fetches more pages as needed, so `limit` sets the page size, not the total.
10551076 for members.Next() {
10561077 member := members.Current()
10571078 fmt.Printf("%s: %s\n", member.UserID, member.WorkspaceRole)
from line 1094
10731094 var members = client.organization().workspaces().members()
10741095 .list("wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ", params);
10751096
1097 // Automatically fetches more pages as needed, so `limit` sets the page size, not the total.
10761098 for (var member : members.autoPager()) {
10771099 IO.println(member.userId() + ": " + member.workspaceRole().asString());
10781100 }
from line 1109
10871109 limit: 10,
10881110 );
10891111
1112 // Reads only the first page.
10901113 foreach ($members->getItems() as $member) {
10911114 echo "{$member->userID}: {$member->workspaceRole}\n";
10921115 }
from line 1121
10981121 workspace_id = "wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ"
10991122 members = client.organization.workspaces.members.list(workspace_id, limit: 10)
11001123
1124 # Reads only the first page.
11011125 members.data.each do |member|
11021126 puts "#{member.user_id}: #{member.workspace_role}"
11031127 end
from line 1373
13491373
13501374<CodeGroup>
13511375 ```bash cURL
1376 # Returns one page.
13521377 curl "https://api.anthropic.com/v1/organizations/api_keys?limit=10&status=active&workspace_id=wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ" \
13531378 -H "x-api-key: $ANTHROPIC_API_KEY" \
13541379 -H "anthropic-version: 2026-10-21"
from line 1380
13551380 ```
13561381
13571382 ```bash CLI
1383 # At a terminal, the view fetches more pages as you scroll. When piped or with `--format json`, `--limit` caps the results.
13581384 ant organization:api-keys list \
13591385 --limit 10 \
13601386 --status active \
from line 1394
13681394 limit=10, status="active", workspace_id="wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ"
13691395 )
13701396
1371 # Automatically fetches more pages as needed.
1397 # Automatically fetches more pages as needed, so `limit` sets the page size, not the total.
13721398 for api_key in api_keys:
13731399 print(f"{api_key.id}: {api_key.name} ({api_key.status})")
13741400 ```
from line 1408
13821408 workspace_id: "wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ"
13831409 });
13841410
1411 // Automatically fetches more pages as needed, so `limit` sets the page size, not the total.
13851412 for await (const apiKey of apiKeys) {
13861413 console.log(`${apiKey.id}: ${apiKey.name} (${apiKey.status})`);
13871414 }
from line 1426
13991426 WorkspaceID = "wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ"
14001427 });
14011428
1429 // Automatically fetches more pages as needed, so `limit` sets the page size, not the total.
14021430 await foreach (var apiKey in page.Paginate())
14031431 {
14041432 Console.WriteLine($"{apiKey.ID}: {apiKey.Name} ({apiKey.Status.Raw()})");
from line 1442
14141442 WorkspaceID: anthropic.String("wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ"),
14151443 })
14161444
1445 // Automatically fetches more pages as needed, so `limit` sets the page size, not the total.
14171446 for apiKeys.Next() {
14181447 apiKey := apiKeys.Current()
14191448 fmt.Printf("%s: %s (%s)\n", apiKey.ID, apiKey.Name, apiKey.Status)
from line 1465
14361465 .build();
14371466 var apiKeys = client.organization().apiKeys().list(params);
14381467
1468 // Automatically fetches more pages as needed, so `limit` sets the page size, not the total.
14391469 for (var apiKey : apiKeys.autoPager()) {
14401470 IO.println(apiKey.id() + ": " + apiKey.name() + " (" + apiKey.status().asString() + ")");
14411471 }
from line 1484
14541484 workspaceID: 'wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ',
14551485 );
14561486
1487 // Reads only the first page.
14571488 foreach ($apiKeys->getItems() as $apiKey) {
14581489 echo "{$apiKey->id}: {$apiKey->name} ({$apiKey->status})\n";
14591490 }
from line 1499
14681499 workspace_id: "wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ"
14691500 )
14701501
1502 # Reads only the first page.
14711503 api_keys.data.each do |api_key|
14721504 puts "#{api_key.id}: #{api_key.name} (#{api_key.status})"
14731505 end
from line 1772
17401772* Use meaningful names and descriptions for workspaces and API keys
17411773* Handle errors from failed operations
17421774* Regularly audit member roles and permissions
1743* Clean up unused workspaces and expired invites
1775* Archive unused workspaces and delete pending invites you no longer need
17441776* Monitor API key usage, audit each key’s [`expires_at`](https://platform.claude.com/docs/en/manage-claude/authentication#key-expiration), and rotate keys periodically
17451777
17461778## FAQ
from line 1782
17501782 The Admin API accepts an Admin API key (starting with `sk-ant-admin`), an OAuth bearer token with the `org:admin` scope, or a personal key or service account key that isn’t scoped to a specific workspace. Only organization members with the admin role can provision Admin API keys, and only members with the admin, owner, or primary owner role can obtain `org:admin` tokens. A personal key or service account key has the same permissions as the linked account. See [Authentication](https://platform.claude.com/docs/en/manage-claude/admin-api#authentication).
17511783 </Accordion>
17521784
1753 <Accordion title="Can I create new API keys through the Admin API?">
1785 <Accordion title="Can the Admin API create API keys?">
17541786 No. You create API keys in the Claude Console. The Admin API can only read, rename, and change the status of existing keys.
17551787 </Accordion>
17561788
No line in this hunk matches that.