Follow Discord
Sweep 06 Nov 2026 · 01:32Z Build v2.1.319 537 read Stable v2.1.311 Latest v2.1.318 Next v2.1.319 Feeds RSS JSON llms.txt llms-full.txt Unofficial
One capture · api

One read of Claude Developer Platformapi-20261105T230715Z

124 pages moved out of 886 read.

Pages moved 124 significant first
Pages read 886 in this capture
Captured 23:07 UTC
Corpus hash 3c8e2c2885cd corpus-hash

What this read moved

51-75 of 124, page 3 of 5

This capture is too large to show at once. Changes 51-75 of 124 are below, significant first; the rest are on the following screens.

manage-claude/rate-limits-api Changed · +94 / -29 lines

### Can you update rate limits with this API? ### Can I update rate limits with this API?

from line 8
88 **The Admin API is unavailable for individual accounts.** To collaborate with teammates and add members, set up your organization on the [Organization](https://platform.claude.com/settings/organization) page (`platform.claude.com/settings/organization`) in the Claude Console.
99</Tip>
1010 
11The Rate Limits API provides programmatic access to the rate limits configured for your organization and its workspaces. This is the same information shown on the [Rate limits](https://platform.claude.com/usage/limits) page in the Claude Console. You can also use it to set and clear a workspace’s rate limits.
11The Rate Limits API provides programmatic access to the rate limits configured for your organization and its workspaces. This is the same information shown on the [Rate limits page in the Claude Console](https://platform.claude.com/usage/limits). You can also use it to set and clear a workspace’s rate limits.
1212 
1313Use this API to:
1414 
from line 21
2121 **Admin API credentials required.** These endpoints are part of the Admin API. You can access them using an [Admin API key](https://platform.claude.com/docs/en/manage-claude/admin-api-keys), an OAuth token with the `org:admin` scope, or a personal or service account key that isn’t scoped to a workspace; workspace API keys don’t work. See [Authentication](https://platform.claude.com/docs/en/manage-claude/admin-api#authentication) for details.
2222</Check>
2323 
24The SDK and CLI examples on this page construct the default client, which reads the Admin API key from the `ANTHROPIC_API_KEY` environment variable. The SDKs expose these endpoints as `client.organization.rate_limits` (typescript: `client.organization.rateLimits`; csharp, go: `client.Organization.RateLimits`; java: `client.organization().rateLimits()`; php: `$client->organization->rateLimits`) and `client.organization.workspaces.rate_limits` (typescript: `client.organization.workspaces.rateLimits`; csharp, go: `client.Organization.Workspaces.RateLimits`; java: `client.organization().workspaces().rateLimits()`; php: `$client->organization->workspaces->rateLimits`); the Python, TypeScript, C#, Go, and Java list methods return an iterator that follows `next_page` for you, while the PHP, Ruby, and curl examples read one page.
24The SDK’s default client and the CLI read the Admin API key from the `ANTHROPIC_API_KEY` environment variable. The SDK exposes these endpoints as `client.organization.rate_limits` (typescript: `client.organization.rateLimits`; csharp, go: `client.Organization.RateLimits`; java: `client.organization().rateLimits()`; php: `$client->organization->rateLimits`) and `client.organization.workspaces.rate_limits` (typescript: `client.organization.workspaces.rateLimits`; csharp, go: `client.Organization.Workspaces.RateLimits`; java: `client.organization().workspaces().rateLimits()`; php: `$client->organization->workspaces->rateLimits`). The comments in each list example say whether it fetches more pages or reads only the first.
2525 
2626## Quick start
2727 
from line 29
2929 
3030<CodeGroup>
3131 ```bash cURL
32 # Returns one page, which holds every entry when `limit` is omitted.
3233 curl "https://api.anthropic.com/v1/organizations/rate_limits" \
3334 -H "x-api-key: $ANTHROPIC_API_KEY" \
3435 -H "anthropic-version: 2026-10-21"
from line 36
3536 ```
3637 
3738 ```bash CLI
39 # Automatically fetches more pages as needed.
3840 ant organization:rate-limits list
3941 ```
4042 
from line 45
4345 
4446 rate_limits = client.organization.rate_limits.list()
4547 
48 # Automatically fetches more pages as needed.
4649 for entry in rate_limits:
4750 models = f" ({', '.join(entry.models)})" if entry.models else ""
4851 print(f"{entry.group.type}{models}")
from line 58
5558 
5659 const rateLimits = await client.organization.rateLimits.list();
5760 
61 // Automatically fetches more pages as needed.
5862 for await (const entry of rateLimits) {
5963 const models = entry.models ? ` (${entry.models.join(", ")})` : "";
6064 console.log(`${entry.group.type}${models}`);
from line 73
6973 
7074 var rateLimits = await client.Organization.RateLimits.List();
7175 
76 // Automatically fetches more pages as needed.
7277 await foreach (var entry in rateLimits.Paginate())
7378 {
7479 var models = entry.Models is null ? "" : $" ({string.Join(", ", entry.Models)})";
from line 90
8590 
8691 rateLimits := client.Organization.RateLimits.ListAutoPaging(context.Background(), anthropic.OrganizationRateLimitListParams{})
8792 
93 // Automatically fetches more pages as needed.
8894 for rateLimits.Next() {
8995 entry := rateLimits.Current()
9096 models := ""
from line 112
106112 
107113 var rateLimits = client.organization().rateLimits().list();
108114 
115 // Automatically fetches more pages as needed.
109116 for (var entry : rateLimits.autoPager()) {
110117 var models = entry.models()
111118 .map(modelIds -> " (" + String.join(", ", modelIds) + ")")
from line 129
122129 
123130 $rateLimits = $client->organization->rateLimits->list();
124131 
132 // Reads only the first page, which holds every entry when `limit` is omitted.
125133 foreach ($rateLimits->data as $entry) {
126134 $models = $entry->models ? ' (' . implode(', ', $entry->models) . ')' : '';
127135 echo "{$entry->group->type}{$models}\n";
from line 144
136144 
137145 rate_limits = client.organization.rate_limits.list
138146 
147 # Reads only the first page, which holds every entry when `limit` is omitted.
139148 rate_limits.data.each do |entry|
140149 models = entry.models ? " (#{entry.models.join(", ")})" : ""
141150 puts "#{entry.group.type}#{models}"
from line 161
152161 
153162### Key concepts
154163 
155* **Rate limit groups:** Each entry in the response represents one rate limit group. Model rate limits are grouped so that several model versions share a single set of limits, and other groups cover resources such as the Message Batches API, the Files API, the Token Counting API, agent skills, and the web search tool.
156* **`group` object:** Present on every entry, it identifies the rate limit group the entry applies to. It always has `type`, which is one of the `group_type` values, and `id`, an opaque identifier with the `rlg_` prefix. On `model_group` entries it also has `display_name`, Anthropic’s current label for the group, such as `Claude Sonnet 4.x`. The label is for display only and may change. Other group types have no `display_name`.
164* **Rate limit groups:** Each entry in the response represents one rate limit group. Model rate limits are grouped so that several model versions share a single set of limits. The other groups cover the Message Batches API and the web search tool.
165* **`group` object:** Present on every entry, it identifies the rate limit group the entry applies to. It always has `type`, which is one of the `group_type` values, and `id`, an opaque identifier with the `rlg_` prefix. On `model_group` entries it also has `display_name`, Anthropic’s current label for the group, such as `Claude Sonnet 4.x`. The label is for display only and might change. Other group types have no `display_name`.
157166* **The `id` inside `group`:** A group has the same `id` in every organization and on every workspace override, and it never changes. Use it to match entries across organizations or against your own catalog. The entry’s own `id` differs for each organization, and `models` changes when Anthropic moves a model between groups. Neither is a stable key for the group.
158167* **`group_type`:** The query parameter that restricts the list to one group type. See [Filtering by group type](https://platform.claude.com/docs/en/manage-claude/rate-limits-api#filtering-by-group-type) for the values.
159168* **`models` list:** For `model_group` entries, the `models` field lists every model ID and alias that counts against that group’s limits. Use this list to look up which group any model string falls under. For other group types, `models` is `null`.
from line 175
166175 
167176<CodeGroup>
168177 ```bash cURL
178 # Returns one page, which holds every entry when `limit` is omitted.
169179 curl "https://api.anthropic.com/v1/organizations/rate_limits" \
170180 -H "x-api-key: $ANTHROPIC_API_KEY" \
171181 -H "anthropic-version: 2026-10-21"
from line 182
172182 ```
173183 
174184 ```bash CLI
185 # Automatically fetches more pages as needed.
175186 ant organization:rate-limits list
176187 ```
177188 
from line 191
180191 
181192 rate_limits = client.organization.rate_limits.list()
182193 
194 # Automatically fetches more pages as needed.
183195 for entry in rate_limits:
184196 models = f" ({', '.join(entry.models)})" if entry.models else ""
185197 print(f"{entry.group.type}{models}")
from line 204
192204 
193205 const rateLimits = await client.organization.rateLimits.list();
194206 
207 // Automatically fetches more pages as needed.
195208 for await (const entry of rateLimits) {
196209 const models = entry.models ? ` (${entry.models.join(", ")})` : "";
197210 console.log(`${entry.group.type}${models}`);
from line 219
206219 
207220 var rateLimits = await client.Organization.RateLimits.List();
208221 
222 // Automatically fetches more pages as needed.
209223 await foreach (var entry in rateLimits.Paginate())
210224 {
211225 var models = entry.Models is null ? "" : $" ({string.Join(", ", entry.Models)})";
from line 236
222236 
223237 rateLimits := client.Organization.RateLimits.ListAutoPaging(context.Background(), anthropic.OrganizationRateLimitListParams{})
224238 
239 // Automatically fetches more pages as needed.
225240 for rateLimits.Next() {
226241 entry := rateLimits.Current()
227242 models := ""
from line 258
243258 
244259 var rateLimits = client.organization().rateLimits().list();
245260 
261 // Automatically fetches more pages as needed.
246262 for (var entry : rateLimits.autoPager()) {
247263 var models = entry.models()
248264 .map(modelIds -> " (" + String.join(", ", modelIds) + ")")
from line 275
259275 
260276 $rateLimits = $client->organization->rateLimits->list();
261277 
278 // Reads only the first page, which holds every entry when `limit` is omitted.
262279 foreach ($rateLimits->data as $entry) {
263280 $models = $entry->models ? ' (' . implode(', ', $entry->models) . ')' : '';
264281 echo "{$entry->group->type}{$models}\n";
from line 290
273290 
274291 rate_limits = client.organization.rate_limits.list
275292 
293 # Reads only the first page, which holds every entry when `limit` is omitted.
276294 rate_limits.data.each do |entry|
277295 models = entry.models ? " (#{entry.models.join(", ")})" : ""
278296 puts "#{entry.group.type}#{models}"
from line 358
340358 
341359<CodeGroup>
342360 ```bash cURL
361 # Returns one page, which holds every entry when `limit` is omitted.
343362 curl "https://api.anthropic.com/v1/organizations/rate_limits?model=claude-opus-5-5" \
344363 -H "x-api-key: $ANTHROPIC_API_KEY" \
345364 -H "anthropic-version: 2026-10-21"
from line 365
346365 ```
347366 
348367 ```bash CLI
368 # Automatically fetches more pages as needed.
349369 ant organization:rate-limits list --model claude-opus-5-5
350370 ```
351371 
from line 374
354374 
355375 rate_limits = client.organization.rate_limits.list(model="claude-opus-5-5")
356376 
377 # Automatically fetches more pages as needed.
357378 for entry in rate_limits:
358379 models = f" ({', '.join(entry.models)})" if entry.models else ""
359380 print(f"{entry.group.type}{models}")
from line 389
368389 model: "claude-opus-5-5"
369390 });
370391 
392 // Automatically fetches more pages as needed.
371393 for await (const entry of rateLimits) {
372394 const models = entry.models ? ` (${entry.models.join(", ")})` : "";
373395 console.log(`${entry.group.type}${models}`);
from line 407
385407 Model = "claude-opus-5-5"
386408 });
387409 
410 // Automatically fetches more pages as needed.
388411 await foreach (var entry in rateLimits.Paginate())
389412 {
390413 var models = entry.Models is null ? "" : $" ({string.Join(", ", entry.Models)})";
from line 426
403426 Model: anthropic.String(anthropic.ModelClaudeOpus5_5),
404427 })
405428 
429 // Automatically fetches more pages as needed.
406430 for rateLimits.Next() {
407431 entry := rateLimits.Current()
408432 models := ""
from line 455
431455 .build();
432456 var rateLimits = client.organization().rateLimits().list(params);
433457 
458 // Automatically fetches more pages as needed.
434459 for (var entry : rateLimits.autoPager()) {
435460 var models = entry.models()
436461 .map(modelIds -> " (" + String.join(", ", modelIds) + ")")
from line 477
452477 model: Model::CLAUDE_OPUS_5_5->value,
453478 );
454479 
480 // Reads only the first page, which holds every entry when `limit` is omitted.
455481 foreach ($rateLimits->data as $entry) {
456482 $models = $entry->models ? ' (' . implode(', ', $entry->models) . ')' : '';
457483 echo "{$entry->group->type}{$models}\n";
from line 492
466492 
467493 rate_limits = client.organization.rate_limits.list(model: Anthropic::Model::CLAUDE_OPUS_5_5)
468494 
495 # Reads only the first page, which holds every entry when `limit` is omitted.
469496 rate_limits.data.each do |entry|
470497 models = entry.models ? " (#{entry.models.join(", ")})" : ""
471498 puts "#{entry.group.type}#{models}"
from line 523
496523 
497524<CodeGroup>
498525 ```bash cURL
526 # Returns one page, which holds every entry when `limit` is omitted.
499527 curl "https://api.anthropic.com/v1/organizations/workspaces/wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ/rate_limits" \
500528 -H "x-api-key: $ANTHROPIC_API_KEY" \
501529 -H "anthropic-version: 2026-10-21"
from line 530
502530 ```
503531 
504532 ```bash CLI
533 # Automatically fetches more pages as needed.
505534 ant organization:workspaces:rate-limits list \
506535 --workspace-id wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ
507536 ```
from line 542
513542 "wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ"
514543 )
515544 
545 # Automatically fetches more pages as needed.
516546 for entry in rate_limits:
517547 models = f" ({', '.join(entry.models)})" if entry.models else ""
518548 print(f"{entry.group.type}{models}")
from line 557
527557 "wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ"
528558 );
529559 
560 // Automatically fetches more pages as needed.
530561 for await (const entry of rateLimits) {
531562 const models = entry.models ? ` (${entry.models.join(", ")})` : "";
532563 console.log(`${entry.group.type}${models}`);
from line 574
543574 "wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ"
544575 );
545576 
577 // Automatically fetches more pages as needed.
546578 await foreach (var entry in rateLimits.Paginate())
547579 {
548580 var models = entry.Models is null ? "" : $" ({string.Join(", ", entry.Models)})";
from line 595
563595 anthropic.OrganizationWorkspaceRateLimitListParams{},
564596 )
565597 
598 // Automatically fetches more pages as needed.
566599 for rateLimits.Next() {
567600 entry := rateLimits.Current()
568601 models := ""
from line 618
585618 var rateLimits = client.organization().workspaces().rateLimits()
586619 .list("wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ");
587620 
621 // Automatically fetches more pages as needed.
588622 for (var entry : rateLimits.autoPager()) {
589623 var models = entry.models()
590624 .map(modelIds -> " (" + String.join(", ", modelIds) + ")")
from line 637
603637 workspaceID: 'wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ',
604638 );
605639 
640 // Reads only the first page, which holds every entry when `limit` is omitted.
606641 foreach ($rateLimits->data as $entry) {
607642 $models = $entry->models ? ' (' . implode(', ', $entry->models) . ')' : '';
608643 echo "{$entry->group->type}{$models}\n";
from line 653
618653 workspace_id = "wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ"
619654 rate_limits = client.organization.workspaces.rate_limits.list(workspace_id)
620655 
656 # Reads only the first page, which holds every entry when `limit` is omitted.
621657 rate_limits.data.each do |entry|
622658 models = entry.models ? " (#{entry.models.join(", ")})" : ""
623659 puts "#{entry.group.type}#{models}"
from line 738
702738 
703739<CodeGroup>
704740 ```bash cURL
741 # Returns one page, which holds every entry when `limit` is omitted.
705742 curl "https://api.anthropic.com/v1/organizations/workspaces/wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ/rate_limits?include_inherited=true" \
706743 -H "x-api-key: $ANTHROPIC_API_KEY" \
707744 -H "anthropic-version: 2026-10-21"
from line 745
708745 ```
709746 
710747 ```bash CLI
748 # Automatically fetches more pages as needed.
711749 ant organization:workspaces:rate-limits list \
712750 --workspace-id wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ \
713751 --include-inherited
from line 759
721759 include_inherited=True,
722760 )
723761 
762 # Automatically fetches more pages as needed.
724763 for entry in rate_limits:
725764 models = f" ({', '.join(entry.models)})" if entry.models else ""
726765 print(f"{entry.group.type}{models}")
from line 775
736775 { include_inherited: true }
737776 );
738777 
778 // Automatically fetches more pages as needed.
739779 for await (const entry of rateLimits) {
740780 const models = entry.models ? ` (${entry.models.join(", ")})` : "";
741781 console.log(`${entry.group.type}${models}`);
from line 793
753793 new() { IncludeInherited = true }
754794 );
755795 
796 // Automatically fetches more pages as needed.
756797 await foreach (var entry in rateLimits.Paginate())
757798 {
758799 var models = entry.Models is null ? "" : $" ({string.Join(", ", entry.Models)})";
from line 816
775816 },
776817 )
777818 
819 // Automatically fetches more pages as needed.
778820 for rateLimits.Next() {
779821 entry := rateLimits.Current()
780822 models := ""
from line 845
803845 var rateLimits = client.organization().workspaces().rateLimits()
804846 .list("wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ", params);
805847 
848 // Automatically fetches more pages as needed.
806849 for (var entry : rateLimits.autoPager()) {
807850 var models = entry.models()
808851 .map(modelIds -> " (" + String.join(", ", modelIds) + ")")
from line 867
824867 includeInherited: true,
825868 );
826869 
870 // Reads only the first page, which holds every entry when `limit` is omitted.
827871 foreach ($rateLimits->data as $entry) {
828872 $models = $entry->models ? ' (' . implode(', ', $entry->models) . ')' : '';
829873 echo "{$entry->group->type}{$models}\n";
from line 883
839883 workspace_id = "wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ"
840884 rate_limits = client.organization.workspaces.rate_limits.list(workspace_id, include_inherited: true)
841885 
886 # Reads only the first page, which holds every entry when `limit` is omitted.
842887 rate_limits.data.each do |entry|
843888 models = entry.models ? " (#{entry.models.join(", ")})" : ""
844889 puts "#{entry.group.type}#{models}"
from line 1001
9561001* `web_search`: `tool_uses_per_second` only
9571002* `batch`: `requests_per_minute` only
9581003 
959Other group types don’t accept any limiter type. You can clear any of the limiter types listed earlier on any group. The list endpoints can return limiter types that you can’t set, such as `enqueued_batch_requests`; sending one returns a 400 error.
1004You can clear any of the limiter types listed earlier on any of these groups. The list endpoints can return limiter types that you can’t set, such as `enqueued_batch_requests`; sending one returns a 400 error.
9601005 
9611006The API stores a value above the organization’s limit for the same limiter type, but it enforces the lower of the two. The response’s `org_limit` shows the organization’s value.
9621007 
from line 1010
9651010The API checks the whole request before it changes anything, so an invalid entry fails the request with a 400 error and changes nothing. If a request passes validation, the API then applies the entries one at a time. If applying one fails, the request returns an error and the entries before it stay applied. Each entry sets or clears an absolute value, so you can safely send the same request again. A resend replaces any change that someone else made in between to the limiter types it names.
9661011 
9671012<Note>
968 Setting workspace rate limits isn’t available on [Claude Platform on AWS](https://platform.claude.com/docs/en/build-with-claude/claude-platform-on-aws) yet.
1013 Setting workspace rate limits is not available on [Claude Platform on AWS](https://platform.claude.com/docs/en/build-with-claude/claude-platform-on-aws).
9691014</Note>
9701015 
9711016Raise the workspace’s requests per minute for the Claude Opus 5.5 group to 2,000 and clear its input tokens per minute override:
from line 1099
10541099 ```
10551100 
10561101 ```go Go
1057 client := anthropic.NewClient()
1102 import (
1103 "context"
1104 "fmt"
1105 "log"
10581106 
1059 entry, err := client.Organization.Workspaces.RateLimits.Update(
1060 context.Background(),
1061 "rlt_01NwFawrTvAijwqn8AjKVBPS",
1062 anthropic.OrganizationWorkspaceRateLimitUpdateParams{
1063 WorkspaceID: "wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ",
1064 Limits: []anthropic.WorkspaceRateLimitUpdateValueParam{
1065 {Type: "requests_per_minute", Value: anthropic.Int(2000)},
1066 {Type: "input_tokens_per_minute", Value: param.Null[int64]()},
1067 },
1068 },
1107 "github.com/anthropics/anthropic-sdk-go/v2"
1108 "github.com/anthropics/anthropic-sdk-go/v2/packages/param"
10691109 )
1070 if err != nil {
1071 log.Fatal(err)
1072 }
10731110 
1074 for _, limit := range entry.Limits {
1075 fmt.Printf("%s: %d\n", limit.Type, limit.Value)
1111 func main() {
1112 client := anthropic.NewClient()
1113 
1114 entry, err := client.Organization.Workspaces.RateLimits.Update(
1115 context.Background(),
1116 "rlt_01NwFawrTvAijwqn8AjKVBPS",
1117 anthropic.OrganizationWorkspaceRateLimitUpdateParams{
1118 WorkspaceID: "wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ",
1119 Limits: []anthropic.WorkspaceRateLimitUpdateValueParam{
1120 {Type: "requests_per_minute", Value: anthropic.Int(2000)},
1121 {Type: "input_tokens_per_minute", Value: param.Null[int64]()},
1122 },
1123 },
1124 )
1125 if err != nil {
1126 log.Fatal(err)
1127 }
1128 
1129 for _, limit := range entry.Limits {
1130 fmt.Printf("%s: %d\n", limit.Type, limit.Value)
1131 }
10761132 }
10771133 ```
10781134 
from line 1231
11751231 
11761232<CodeGroup>
11771233 ```bash cURL
1234 # Returns one page, which holds every entry when `limit` is omitted.
11781235 curl "https://api.anthropic.com/v1/organizations/rate_limits?group_type=batch" \
11791236 -H "x-api-key: $ANTHROPIC_API_KEY" \
11801237 -H "anthropic-version: 2026-10-21"
from line 1238
11811238 ```
11821239 
11831240 ```bash CLI
1241 # Automatically fetches more pages as needed.
11841242 ant organization:rate-limits list --group-type batch
11851243 ```
11861244 
from line 1247
11891247 
11901248 rate_limits = client.organization.rate_limits.list(group_type="batch")
11911249 
1250 # Automatically fetches more pages as needed.
11921251 for entry in rate_limits:
11931252 models = f" ({', '.join(entry.models)})" if entry.models else ""
11941253 print(f"{entry.group.type}{models}")
from line 1260
12011260 
12021261 const rateLimits = await client.organization.rateLimits.list({ group_type: "batch" });
12031262 
1263 // Automatically fetches more pages as needed.
12041264 for await (const entry of rateLimits) {
12051265 const models = entry.models ? ` (${entry.models.join(", ")})` : "";
12061266 console.log(`${entry.group.type}${models}`);
from line 1280
12201280 GroupType = GroupType.Batch
12211281 });
12221282 
1283 // Automatically fetches more pages as needed.
12231284 await foreach (var entry in rateLimits.Paginate())
12241285 {
12251286 var models = entry.Models is null ? "" : $" ({string.Join(", ", entry.Models)})";
from line 1299
12381299 GroupType: anthropic.OrganizationRateLimitListParamsGroupTypeBatch,
12391300 })
12401301 
1302 // Automatically fetches more pages as needed.
12411303 for rateLimits.Next() {
12421304 entry := rateLimits.Current()
12431305 models := ""
from line 1327
12651327 .build();
12661328 var rateLimits = client.organization().rateLimits().list(params);
12671329 
1330 // Automatically fetches more pages as needed.
12681331 for (var entry : rateLimits.autoPager()) {
12691332 var models = entry.models()
12701333 .map(modelIds -> " (" + String.join(", ", modelIds) + ")")
from line 1350
12871350 groupType: GroupType::BATCH,
12881351 );
12891352 
1353 // Reads only the first page, which holds every entry when `limit` is omitted.
12901354 foreach ($rateLimits->data as $entry) {
12911355 $models = $entry->models ? ' (' . implode(', ', $entry->models) . ')' : '';
12921356 echo "{$entry->group->type}{$models}\n";
from line 1365
13011365 
13021366 rate_limits = client.organization.rate_limits.list(group_type: :batch)
13031367 
1368 # Reads only the first page, which holds every entry when `limit` is omitted.
13041369 rate_limits.data.each do |entry|
13051370 models = entry.models ? " (#{entry.models.join(", ")})" : ""
13061371 puts "#{entry.group.type}#{models}"
from line 1376
13111376 ```
13121377</CodeGroup>
13131378 
1314Valid values are `model_group`, `batch`, `token_count`, `files`, `skills`, and `web_search`.
1379Valid values are `model_group`, `batch`, `token_count`, `files`, `skills`, and `web_search`. The `token_count`, `files`, and `skills` values return an empty `data` list, because neither list endpoint returns the limits for the Token Counting API, the Files API, or the Skills API.
13151380 
13161381## Pagination
13171382 
1318Both endpoints accept a `page` query parameter and return a `next_page` field. Responses are currently always a single page, so `next_page` is `null`. Loop on `next_page` so your client paginates correctly without changes when the response grows.
1383Both list endpoints accept optional `limit` and `page` query parameters and return a `next_page` field. `limit` ranges from 1 to 1,000. If you omit it, the response contains every remaining entry and `next_page` is `null`. If `limit` cuts the list short, `next_page` holds a cursor: pass it as `page`, with the same filters, to get the next entries. Loop on `next_page` so your client gets every entry.
13191384 
13201385## Frequently asked questions
13211386 
from line 1394
13291394 
13301395By default, the workspace response lists only overrides, so a missing group has no workspace override and inherits the organization-level limit. Pass `include_inherited=true` to see inherited values on the workspace endpoint, or query the organization endpoint. With `include_inherited=true`, a group is missing only when it doesn’t apply to the workspace or the organization has no limit set for it.
13311396 
1332### Can I update rate limits with this API?
1397### Can you update rate limits with this API?
13331398 
1334**For a workspace:** Yes. The [Set Workspace Rate Limits](https://platform.claude.com/docs/en/api/organization/workspaces/rate_limits/update) endpoint sets or clears a workspace’s overrides for one rate limit group. Pass the top-level `id` of the matching entry in the [organization endpoint’s response](https://platform.claude.com/docs/en/manage-claude/rate-limits-api#list-all-organization-rate-limits) as `rate_limit_id`, not the `rlg_` `id` inside its `group`. The lower of the workspace override and the organization-level limit applies, and a change takes effect within about an hour. For the request body and an example, see [this page’s section on setting workspace rate limits](https://platform.claude.com/docs/en/manage-claude/rate-limits-api#set-workspace-rate-limits). You can also set workspace rate limits on the [Rate limits](https://platform.claude.com/usage/limits) page in the Claude Console: select the workspace from the **Workspace** dropdown menu, and click **Edit** next to a model.
1399**For a workspace:** Yes. The [Set Workspace Rate Limits](https://platform.claude.com/docs/en/api/organization/workspaces/rate_limits/update) endpoint sets or clears a workspace’s overrides for one rate limit group. Pass the top-level `id` of the matching entry in the [organization endpoint’s response](https://platform.claude.com/docs/en/manage-claude/rate-limits-api#list-all-organization-rate-limits) as `rate_limit_id`, not the `rlg_` `id` inside its `group`. The lower of the workspace override and the organization-level limit applies, and a change takes effect within about an hour. For the request body and an example, see [Set workspace rate limits](https://platform.claude.com/docs/en/manage-claude/rate-limits-api#set-workspace-rate-limits). You can also set workspace rate limits on the [Rate limits page in the Claude Console](https://platform.claude.com/usage/limits): select the workspace from the **Workspace** dropdown menu, and click **Edit** next to a model.
13351400 
13361401**For an organization:** No. To request higher limits, see [Requesting higher limits](https://platform.claude.com/docs/en/api/rate-limits#requesting-higher-limits).
13371402 

manage-claude/user-management Changed · +9 / -13 lines

### Can the API assign the owner or membership admin role? ### Can the API create or modify groups? ### Which operations work when your organization uses single sign-on? ### Can I assign the owner or membership admin role through the API? ### Can I create or modify groups through the API? ### My organization uses single sign-on. Which operations work?

from line 15
1515 
1616For Claude Console (Claude Platform) organizations, see the [Admin API guide for Claude Console](https://platform.claude.com/docs/en/manage-claude/admin-api).
1717 
18<Note>
19 Group and custom-role requests don’t require the `anthropic-beta: ce-user-management-2026-07-13` [beta header](https://platform.claude.com/docs/en/api/beta-headers). Requests that send it are accepted and behave identically.
20</Note>
21 
2218## Which endpoints can your organization use?
2319 
2420The 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](https://platform.claude.com/docs/en/manage-claude/admin-api-keys) and each have access to a different subset of the endpoints:
from line 194
198194 
199195### Groups and roles
200196 
201Groups connect members to custom roles (role-based access control, the `rbac` in the endpoint paths and scope names). Groups are owned by your enterprise as a whole (the parent organization together with every organization under it) rather than by 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](https://platform.claude.com/docs/en/manage-claude/user-management#custom-roles), noting that the role catalog is per-organization whereas groups are enterprise-wide, so fetching a role that belongs to a different organization of your enterprise returns 404 for your key. The field is `null` (rather than `[]`) when role data was temporarily unavailable, so retry to distinguish a degraded read from a group with no roles.
197Groups connect members to custom roles (role-based access control, the `rbac` in the endpoint paths and scope names). Groups are owned by your enterprise as a whole (the parent organization together with every organization under it), not by 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](https://platform.claude.com/docs/en/manage-claude/user-management#custom-roles). The role catalog is per-organization, but groups are enterprise-wide. So fetching a role that belongs to a different organization of your enterprise 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.
202198 
203199## Versioning
204200 
205Send the `anthropic-version` header on every request; see [API versions](https://platform.claude.com/docs/en/api/versioning) for the available versions.
201Send the `anthropic-version` header on every request; see [Versions](https://platform.claude.com/docs/en/api/versioning) for the available versions.
206202 
207203## Rate limits
208204 
from line 206
210206 
211207## Pagination
212208 
213Member and invite lists use ID-based pagination: pass `limit` (default 20, max 1000) 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`.
209Member 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`.
214210 
215211When 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.
216212 
from line 638
642638 ```bash cURL
643639 curl -X POST "https://api.anthropic.com/v1/organizations/users/user_01AbCdEfGhIjKlMnOpQrSt/sign_out" \
644640 -H "x-api-key: $ANTHROPIC_API_KEY" \
645 -H "anthropic-version: 2023-06-01" \
641 -H "anthropic-version: 2026-10-21" \
646642 -H "anthropic-beta: admin-user-sign-out-2026-10-08"
647643 ```
648644 
from line 959
963959 
964960### List invites
965961 
966`GET /v1/organizations/invites` returns the organization’s invites, most recent first, across the `pending`, `accepted`, and `expired` states; there is no status filter. Requires the `read:members` scope.
962`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.
967963 
968964For complete parameter details and response schemas, see [List invites](https://platform.claude.com/docs/en/api/organization/invites/list) in the API reference.
969965 
from line 2376
23802376 
23812377`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.
23822378 
2383Two `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 (one that 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) and is listed as that single row rather than expanded. 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.
2379Two `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.
23842380 
23852381For complete parameter details and response schemas, see [List role permissions](https://platform.claude.com/docs/en/api/beta/organization/rbac_roles/permissions/list) in the API reference.
23862382 
from line 2657
26612657 
26622658No. 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](https://platform.claude.com/docs/en/manage-claude/user-management#which-endpoints-can-your-organization-use) shows which endpoints each organization type can call.
26632659 
2664### Can I assign the owner or membership admin role through the API?
2660### Can the API assign the owner or membership admin role?
26652661 
26662662No. 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.
26672663 
2668### Can I create or modify groups through the API?
2664### Can the API create or modify groups?
26692665 
26702666Yes, 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](https://platform.claude.com/docs/en/manage-claude/user-management#custom-roles), which are managed in claude.ai organization settings (the API reads them).
26712667 
from line 2669
26732669 
26742670On 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.
26752671 
2676### My organization uses single sign-on. Which operations work?
2672### Which operations work when your organization uses single sign-on?
26772673 
26782674If 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](https://platform.claude.com/docs/en/manage-claude/user-management#sign-a-member-out-everywhere), whichever single sign-on mode your organization uses.
26792675 

manage-claude/user-profiles Changed · +11 / -10 lines

from line 35
3535 
3636* An organization on the Claude API.
3737* An organization on [Claude Platform on AWS](https://platform.claude.com/docs/en/build-with-claude/claude-platform-on-aws). The calling principal needs the [user profile IAM actions](https://platform.claude.com/docs/en/api/claude-platform-on-aws-iam-actions#user-profiles).
38* A [Microsoft Foundry](https://platform.claude.com/docs/en/build-with-claude/claude-in-microsoft-foundry) deployment [hosted on Anthropic](https://platform.claude.com/docs/en/build-with-claude/claude-in-microsoft-foundry#hosting-options), not one hosted on Azure. You don’t need an organization on the Claude API or Claude Platform on AWS. Use your Foundry endpoint, with the same base URL and authentication that you use for inference.
3938* An organization on [Claude Models on Google Cloud (Anthropic managed)](https://platform.claude.com/docs/en/build-with-claude/claude-models-on-google-cloud/anthropic-managed), where you can create, retrieve, list, and update profiles. Use the latest version of the [SDK client for Claude Models on Google Cloud (Anthropic managed)](https://platform.claude.com/docs/en/build-with-claude/claude-models-on-google-cloud/anthropic-managed#install-an-sdk), or call the [organization-level base URL](https://platform.claude.com/docs/en/build-with-claude/claude-models-on-google-cloud/anthropic-managed#making-requests) directly, with Google Cloud credentials instead of an API key.
4039 
4140Claude Models on Google Cloud (Google managed) and Amazon Bedrock don’t have the `/v1/user_profiles` endpoints. If your inference runs there, create your profiles in an organization on the Claude API or Claude Platform on AWS. On Amazon Bedrock, profiles work only with [Claude in Amazon Bedrock](https://platform.claude.com/docs/en/build-with-claude/claude-in-amazon-bedrock). See [Attribute requests on Claude Models on Google Cloud (Google managed) and Amazon Bedrock](https://platform.claude.com/docs/en/manage-claude/user-profiles#attribute-requests-on-amazon-bedrock-and-google-cloud).
4241 
42If your inference runs on a [Microsoft Foundry](https://platform.claude.com/docs/en/build-with-claude/claude-in-microsoft-foundry) deployment [hosted on Anthropic](https://platform.claude.com/docs/en/build-with-claude/claude-in-microsoft-foundry#hosting-options), create your profiles in an organization on the Claude API. Before your Foundry requests can use those profile IDs, Anthropic has to link your Foundry resource to that organization. To request the link, contact your Anthropic account team. The `/v1/user_profiles` endpoints are not available on Microsoft Foundry.
43 
4344Keep the traffic you send for your end customers in one organization and your own internal usage in another. Profiles belong to an organization, not a workspace, so separate workspaces in one organization aren’t enough. Only the organization for end-customer traffic needs user profiles. To create another organization on the Claude API, see the “How to create a new organization” section of [Creating and managing Workspaces in the Claude Console](https://support.claude.com/en/articles/9796807) in the Claude Help Center.
4445 
4546The examples call the Claude API with an API key. You don’t need an [Admin API key](https://platform.claude.com/docs/en/manage-claude/admin-api-keys). On Claude Platform on AWS, use its base URL and authentication.
from line 360
359360 
360361The header works the same way on [token counting](https://platform.claude.com/docs/en/build-with-claude/token-counting), [Message Batches](https://platform.claude.com/docs/en/build-with-claude/batch-processing), and [OpenAI SDK compatibility](https://platform.claude.com/docs/en/cli-sdks-libraries/libraries/openai-sdk) requests. On a batch, it applies to every request in the batch.
361362 
362The Claude API, Claude Platform on AWS, Microsoft Foundry deployments hosted on Anthropic, and Claude Models on Google Cloud (Anthropic managed) check the ID on every request. If the ID is malformed or doesn’t belong to the organization that sends the request, the API returns a `400` `invalid_request_error`. By default, these platforms accept a profile ID only on requests from the organization that created the profile. This means that if you send traffic under more than one organization, for example one on the Claude API and one on Claude Platform on AWS, a request from an organization that didn’t create the profile gets the same `400`.
363The Claude API, Claude Platform on AWS, Claude Models on Google Cloud (Anthropic managed), and Microsoft Foundry deployments hosted on Anthropic check the ID on every request. If the ID is malformed or doesn’t belong to the organization that sends the request, the API returns a `400` `invalid_request_error`. By default, these platforms accept a profile ID only on requests from the organization that created the profile. This means that if you send traffic under more than one organization, for example one on the Claude API and one on Claude Platform on AWS, a request from an organization that didn’t create the profile gets the same `400`. On Microsoft Foundry deployments hosted on Anthropic, every profile ID gets this `400` until Anthropic [links your Foundry resource](https://platform.claude.com/docs/en/manage-claude/user-profiles#before-you-begin) to the organization that created the profile.
363364 
364365Message Batches is the exception: creating a batch checks only the ID’s format. If a well-formed ID doesn’t belong to the organization that sends the batch, the batch is still created, and each request in it then fails with an `errored` result that contains the same `invalid_request_error`.
365366 
from line 368
367368 
368369A profile ID of either access type also works on Claude Models on Google Cloud (Google managed) and on [Claude in Amazon Bedrock](https://platform.claude.com/docs/en/build-with-claude/claude-in-amazon-bedrock). It doesn’t work with the [earlier Amazon Bedrock integration](https://platform.claude.com/docs/en/build-with-claude/claude-on-amazon-bedrock-legacy) that you call with `InvokeModel` or `Converse`. You use your Anthropic organization’s credentials only to create and manage profiles. Inference stays on your existing AWS or Google Cloud credentials.
369370 
370| Platform | Create profiles | Send the profile ID in |
371| ---------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------ | ------------------------------------------- |
372| Claude API | Yes | `anthropic-user-profile-id` header |
373| [Claude Platform on AWS](https://platform.claude.com/docs/en/build-with-claude/claude-platform-on-aws) | Yes | `anthropic-user-profile-id` header |
374| [Microsoft Foundry](https://platform.claude.com/docs/en/build-with-claude/claude-in-microsoft-foundry), deployments hosted on Anthropic | Yes | `anthropic-user-profile-id` header |
375| [Claude Models on Google Cloud (Anthropic managed)](https://platform.claude.com/docs/en/build-with-claude/claude-models-on-google-cloud/anthropic-managed) | Yes | `anthropic-user-profile-id` header |
376| [Claude Models on Google Cloud (Google managed)](https://platform.claude.com/docs/en/build-with-claude/claude-models-on-google-cloud/google-managed) | No. Create them on the Claude API or Claude Platform on AWS. | `anthropic-user-profile-id` header |
377| [Claude in Amazon Bedrock](https://platform.claude.com/docs/en/build-with-claude/claude-in-amazon-bedrock) | No. Create them on the Claude API or Claude Platform on AWS. | `user_profile_id` field in the request body |
371| Platform | Create profiles | Send the profile ID in |
372| ---------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------- |
373| Claude API | Yes | `anthropic-user-profile-id` header |
374| [Claude Platform on AWS](https://platform.claude.com/docs/en/build-with-claude/claude-platform-on-aws) | Yes | `anthropic-user-profile-id` header |
375| [Microsoft Foundry](https://platform.claude.com/docs/en/build-with-claude/claude-in-microsoft-foundry), deployments hosted on Anthropic | No. Create them on the Claude API, and [ask Anthropic to link your Foundry resource](https://platform.claude.com/docs/en/manage-claude/user-profiles#before-you-begin). | `anthropic-user-profile-id` header |
376| [Claude Models on Google Cloud (Anthropic managed)](https://platform.claude.com/docs/en/build-with-claude/claude-models-on-google-cloud/anthropic-managed) | Yes | `anthropic-user-profile-id` header |
377| [Claude Models on Google Cloud (Google managed)](https://platform.claude.com/docs/en/build-with-claude/claude-models-on-google-cloud/google-managed) | No. Create them on the Claude API or Claude Platform on AWS. | `anthropic-user-profile-id` header |
378| [Claude in Amazon Bedrock](https://platform.claude.com/docs/en/build-with-claude/claude-in-amazon-bedrock) | No. Create them on the Claude API or Claude Platform on AWS. | `user_profile_id` field in the request body |
378379 
379380On Claude in Amazon Bedrock, put the ID at the top level of the request body:
380381 

manage-claude/wif-admin-api Changed · +12 / -7 lines

from line 8
88 
99## Prerequisites
1010 
11Every request on this page authenticates with an OAuth bearer token that carries the `org:admin` scope. The scope is granted only to organization members with the admin, owner, or primary owner role, and it grants access to the whole organization: any workspace binding is ignored. There are two ways to obtain a token, and they carry different permissions: a token from your own login acts as a user, whereas a federated token acts as a service account and cannot perform every operation on this page.
11Every request on this page authenticates with an OAuth bearer token that carries the `org:admin` scope. The scope is granted only to organization members with the admin, owner, or primary owner role, and it grants access to the whole organization: any workspace binding is ignored. There are two ways to obtain a token, and they carry different permissions. A token from your own login acts as a user. A federated token acts as a service account and cannot perform every operation on this page.
1212 
1313### Interactive (your terminal)
1414 
from line 19
1919export ANTHROPIC_AUTH_TOKEN=$(ant auth print-credentials --profile admin --access-token)
2020```
2121 
22Interactive tokens are short-lived; if requests start returning 401, re-run the export command (it refreshes the token automatically).
22Interactive tokens are short-lived. If requests start returning 401, rerun the `export` command to refresh the token.
2323 
2424The SDK and the `ant` CLI read `ANTHROPIC_AUTH_TOKEN` automatically; leave `ANTHROPIC_API_KEY` unset in the same shell, because these endpoints reject API keys and every client uses the key when both are set.
2525 
from line 41
4141 </Step>
4242 
4343 <Step title="Exchange the workload’s identity token">
44 A workload that uses the SDK or the `ant` CLI does not perform the exchange itself. Point the client at the rule with the federation environment variables and construct it with no arguments, exactly as for inference in [Construct the SDK client](https://platform.claude.com/docs/en/manage-claude/workload-identity-federation#construct-the-sdk-client); the client exchanges the identity token on the first request and, before the resulting access token expires, re-reads the identity token and exchanges it again:
44 A workload that uses the SDK or the `ant` CLI does not perform the exchange itself. The client exchanges the identity token on the first request. Before the resulting access token expires, it reads the identity token again and repeats the exchange. Construct the client with no arguments, exactly as for inference in [Construct the SDK client](https://platform.claude.com/docs/en/manage-claude/workload-identity-federation#construct-the-sdk-client), and point it at the rule with the federation environment variables:
4545 
4646 ```bash
4747 export ANTHROPIC_FEDERATION_RULE_ID=fdrl_... # the org:admin rule from step 1
from line 53
5353 unset ANTHROPIC_API_KEY ANTHROPIC_AUTH_TOKEN # both take precedence over federation
5454 ```
5555 
56 The `ant` CLI reads the same variables, or takes `--federation-rule`, `--organization-id`, `--service-account-id`, and `--identity-token-file` flags. For a workload that runs more than one `ant` command, use a [federation profile](https://platform.claude.com/docs/en/manage-claude/wif-reference#profile-configuration-file) rather than flags or environment variables: with flags or variables the CLI exchanges the identity token again in every process, and identity tokens that carry a `jti` claim (GitHub Actions tokens do) are accepted only once, so a second command would be rejected; a profile is also the only way to give the CLI a `workspace_id` for the exchange when the rule is enabled for all workspaces or more than one, because unlike the SDK the CLI does not pass `ANTHROPIC_WORKSPACE_ID` or `--workspace-id` into the exchange. Every SDK also accepts the same settings as explicit constructor arguments, shown for each language in [Construct the SDK client](https://platform.claude.com/docs/en/manage-claude/workload-identity-federation#construct-the-sdk-client). See [Environment variables](https://platform.claude.com/docs/en/manage-claude/wif-reference#environment-variables) and [Credential precedence](https://platform.claude.com/docs/en/manage-claude/wif-reference#credential-precedence) for the full list and ordering.
56 The SDK also accepts these settings as explicit constructor arguments, shown in [Construct the SDK client](https://platform.claude.com/docs/en/manage-claude/workload-identity-federation#construct-the-sdk-client). The `ant` CLI reads these variables too, or takes `--federation-rule`, `--organization-id`, `--service-account-id`, and `--identity-token-file` flags. See [Environment variables](https://platform.claude.com/docs/en/manage-claude/wif-reference#environment-variables) and [Credential precedence](https://platform.claude.com/docs/en/manage-claude/wif-reference#credential-precedence) for the full list of variables and their order.
5757 
58 For a workload that runs more than one `ant` command, use a [federation profile](https://platform.claude.com/docs/en/manage-claude/wif-reference#profile-configuration-file) rather than flags or environment variables. A profile caches the access token between commands. With flags or variables, every command exchanges the identity token again. By default, identity tokens that carry a `jti` claim, as GitHub Actions tokens do, are accepted only once, so a second command would be rejected.
59 
60 When the rule is enabled for all workspaces or more than one, give the `ant` CLI a federation profile that sets `workspace_id`, and set `ANTHROPIC_PROFILE` to its name. Unlike the SDK, the CLI passes `ANTHROPIC_WORKSPACE_ID` into the exchange only through a federation profile, and `--workspace-id` never reaches the exchange.
61 
5862 A workload that calls the API with curl exchanges the JWT for a short-lived `org:admin` bearer token itself, using the same [token exchange](https://platform.claude.com/docs/en/manage-claude/workload-identity-federation#authenticate-from-your-workload) as any other federated workload, and sends it in the `authorization: Bearer` header.
5963 </Step>
6064 
from line 67
6367 </Step>
6468</Steps>
6569 
66For the operations a workload-minted token can and cannot perform, see [Permissions and constraints](https://platform.claude.com/docs/en/manage-claude/wif-admin-api#permissions-and-constraints). If you already created issuers, service accounts, or rules with the **Connect workload** wizard, list them with the following endpoints and import them into your infrastructure-as-code state instead of recreating them.
70For the operations a federated token can and cannot perform, see [Permissions and constraints](https://platform.claude.com/docs/en/manage-claude/wif-admin-api#permissions-and-constraints). If you already created issuers, service accounts, or rules with the **Connect workload** wizard, list them with the following endpoints and import them into your infrastructure-as-code state instead of recreating them.
6771 
6872## Authentication
6973 
7074All endpoints live under `https://api.anthropic.com/v1/organizations/`. Every request to the federation and service-account endpoints needs the API version header and the bearer token:
7175 
72In the SDK, these endpoints are `client.organization.service_accounts` (typescript: `client.organization.serviceAccounts`; csharp, go: `client.Organization.ServiceAccounts`; java: `client.organization().serviceAccounts()`; php: `$client->organization->serviceAccounts`), `client.organization.federation.issuers` (csharp, go: `client.Organization.Federation.Issuers`; java: `client.organization().federation().issuers()`; php: `$client->organization->federation->issuers`), and `client.organization.federation.rules` (csharp, go: `client.Organization.Federation.Rules`; java: `client.organization().federation().rules()`; php: `$client->organization->federation->rules`) (`ant organization:service-accounts`, `federation:issuers`, and `federation:rules` in the CLI). The SDK and CLI examples construct the default client, which sends the bearer token from `ANTHROPIC_AUTH_TOKEN`, or, in an automated workload, performs the federation exchange itself as described in [Bootstrap a workload to manage WIF](https://platform.claude.com/docs/en/manage-claude/wif-admin-api#bootstrap-a-workload-to-manage-wif). SDK list methods fetch further pages on demand, so `limit` sets the page size; the PHP and Ruby examples read one page.
76In the SDK, these endpoints are `client.organization.service_accounts` (typescript: `client.organization.serviceAccounts`; csharp, go: `client.Organization.ServiceAccounts`; java: `client.organization().serviceAccounts()`; php: `$client->organization->serviceAccounts`), `client.organization.federation.issuers` (csharp, go: `client.Organization.Federation.Issuers`; java: `client.organization().federation().issuers()`; php: `$client->organization->federation->issuers`), and `client.organization.federation.rules` (csharp, go: `client.Organization.Federation.Rules`; java: `client.organization().federation().rules()`; php: `$client->organization->federation->rules`) (`ant organization:service-accounts`, `ant organization:federation:issuers`, and `ant organization:federation:rules` in the CLI). The SDK and the `ant` CLI send the bearer token from `ANTHROPIC_AUTH_TOKEN`. In an automated workload, they perform the federation exchange themselves, as described in [Bootstrap a workload to manage WIF](https://platform.claude.com/docs/en/manage-claude/wif-admin-api#bootstrap-a-workload-to-manage-wif).
7377 
7478<CodeGroup>
7579 ```bash cURL
from line 1263
12591263 * OAuth-authenticated callers can only create or modify rules whose `oauth_scope` is `workspace:developer` or `workspace:inference`. To create or modify a rule with any other scope (such as `org:admin` or `workspace:manage_tunnels`), use the Console.
12601264 * An OAuth caller cannot update a federation issuer that backs a rule whose `oauth_scope` is anything other than `workspace:developer` or `workspace:inference` (such as `org:admin` or `workspace:manage_tunnels`). Consider registering a dedicated issuer for the bootstrap rule so the issuers behind workspace-scoped rules stay updatable through the API.
12611265 * Admin API keys are not accepted on these endpoints, for reads or writes; use an `org:admin` OAuth token.
1266 * A federated token cannot set `organization_role` to `admin` on a new or existing service account, even one that is already `admin`. To set that role, use an [interactive token](https://platform.claude.com/docs/en/manage-claude/wif-admin-api#interactive-your-terminal) or the Console.
12621267</Note>
12631268 
12641269A rule with `oauth_scope: org:admin` must target a service account whose `organization_role` is `admin`. Resource names must match `^[a-z0-9-]+$`, be 1 to 255 characters, and be unique within an organization for each resource type; for the full field-level constraints, see [Validation rules](https://platform.claude.com/docs/en/manage-claude/wif-reference#validation-rules).
from line 1270
12651270 
12661271## Pagination and archiving
12671272 
1268The service-account, federation-issuer, and federation-rule list endpoints accept `limit` (1 to 100, default 20) and a `page` cursor taken from the previous response. Pass the response’s `next_page` value as the `page` query parameter on the next request. The rule-workspaces sub-resource list returns the full set without pagination. Archived resources are hidden from lists by default; pass `include_archived=true` to include them.
1273The service-account, federation-issuer, and federation-rule list endpoints accept `limit` (the page size, 1 to 100, default 20) and a `page` cursor taken from the previous response. Pass the response’s `next_page` value as the `page` query parameter on the next request. The SDK fetches further pages on demand when you iterate with `for` (typescript: `for await`; csharp: `Paginate()`; go: `ListAutoPaging()`; java: `autoPager()`; php: `pagingEachItem()`; ruby: `auto_paging_each`), and the `ant` CLI does so by default. The rule-workspaces sub-resource list returns the full set without pagination. Archived resources are hidden from lists by default; pass `include_archived=true` to include them.
12691274 
12701275Archiving is a soft delete and is idempotent: archiving an already-archived resource succeeds. Archiving an issuer or a service account returns `400` while a live federation rule still references it; archive the rule first.
12711276 

manage-claude/wif-providers/aws Changed · +9 / -5 lines

from line 74
7474}
7575```
7676 
77**Federation rule:** Match the audience you pass to `GetWebIdentityToken` and the calling role’s IAM role ARN in the `sub` claim. The `sub` value is the IAM role ARN of the workload that called the API, in the form `arn:aws:iam::<account>:role/<role-name>`. The token also carries an `https://sts.amazonaws.com/` claim with `aws_account`, `org_id`, `principal_id`, and any `request_tags` you passed; you can match on those with the rule’s `claims` map or a CEL `condition` for finer control.
77**Federation rule:** Match the audience you pass to `GetWebIdentityToken` and the calling role’s ARN in the `sub` claim, in the form `arn:aws:iam::<account>:role/<role-name>`. The token also carries an `https://sts.amazonaws.com/` claim with `aws_account`, `org_id`, `principal_id`, and any `request_tags` you passed. For finer control, match on those with the rule’s `claims` map or a CEL `condition`.
7878 
7979```json
8080{
from line 95
9595 
9696### Acquire and use the token
9797 
98Call `GetWebIdentityToken` with `https://api.anthropic.com` as the audience, then pass the result to the SDK’s federation credentials through `identity_token_provider` (typescript: `identityTokenProvider`; php: `identityProvider`; csharp: `IdentityTokenProvider`; go: `option.WithFederationTokenProvider()`; java: `IdentityTokenConfig`). Except in Java (see the comment in that example), that option takes a token provider, so the SDK calls STS again on each refresh.
98Call `GetWebIdentityToken` with `https://api.anthropic.com` as the audience, then pass the result to the SDK’s federation credentials through `identity_token_provider` (typescript: `identityTokenProvider`; php: `identityProvider`; csharp: `IdentityTokenProvider`; go: `option.WithFederationTokenProvider()`; java: `IdentityTokenConfig`). Except in Java, where `IdentityTokenConfig` takes a token or a file path, that option takes a token provider, so the SDK calls STS again on each refresh.
9999 
100100<Note>
101101 `GetWebIdentityToken` is available only on regional STS endpoints. If you receive `'STS' object has no attribute 'get_web_identity_token'` or a similar error, pin your STS client to a region (for example, `boto3.client("sts", region_name="us-east-1")`) and ensure your AWS SDK is recent enough to include the API.
from line 144
144144 --duration-seconds 900 \
145145 --query WebIdentityToken --output text > "$ANTHROPIC_IDENTITY_TOKEN_FILE"
146146 
147 # ANTHROPIC_FEDERATION_RULE_ID, ANTHROPIC_ORGANIZATION_ID,
148 # ANTHROPIC_SERVICE_ACCOUNT_ID, and ANTHROPIC_WORKSPACE_ID are read from the environment
147 # ANTHROPIC_FEDERATION_RULE_ID, ANTHROPIC_ORGANIZATION_ID, and
148 # ANTHROPIC_SERVICE_ACCOUNT_ID are read from the environment.
149 # For a rule enabled for all workspaces or more than one, set ANTHROPIC_PROFILE
150 # to a federation profile that sets workspace_id.
149151 ant messages create \
150152 --model claude-opus-5-5 \
151153 --max-tokens 1024 \
from line 647
645647 
646648 ```bash CLI
647649 # Reads ANTHROPIC_FEDERATION_RULE_ID, ANTHROPIC_ORGANIZATION_ID,
648 # ANTHROPIC_SERVICE_ACCOUNT_ID, ANTHROPIC_WORKSPACE_ID, and ANTHROPIC_IDENTITY_TOKEN_FILE
650 # ANTHROPIC_SERVICE_ACCOUNT_ID, and ANTHROPIC_IDENTITY_TOKEN_FILE.
651 # For a rule enabled for all workspaces or more than one, set ANTHROPIC_PROFILE
652 # to a federation profile that sets workspace_id.
649653 ant messages create \
650654 --model claude-opus-5-5 \
651655 --max-tokens 1024 \

manage-claude/wif-providers/azure Changed · +13 / -9 lines

from line 52
5252 <Step title="Attach a managed identity">
5353 Enable a system-assigned or user-assigned managed identity on your Azure resource. In the Azure portal, open the resource, go to **Identity**, and turn on **System assigned** (or attach a user-assigned identity).
5454 
55 After the identity is created, note its **Object (principal) ID**. This GUID appears as both the `sub` and `oid` claims in the issued token, and your Anthropic federation rule will match on it. You can find it on the resource’s **Identity** page; for a user-assigned identity, it is the **Object (principal) ID** on the managed identity resource’s **Overview** page. (A managed identity has only a service principal in Microsoft Entra ID, not an app registration.)
55 After the identity is created, note its **Object (principal) ID**. This GUID appears as both the `sub` and `oid` claims in the issued token, and your Anthropic federation rule matches on it. You can find it on the resource’s **Identity** page; for a user-assigned identity, it is the **Object (principal) ID** on the managed identity resource’s **Overview** page. (A managed identity has only a service principal in Microsoft Entra ID, not an app registration.)
5656 </Step>
5757 
5858 <Step title="Find the platform’s token endpoint">
from line 141
141141 
142142### Acquire and use the token
143143 
144At runtime your workload fetches its Entra token, exchanges it at `POST /v1/oauth/token`, and uses the returned bearer token to call Claude. The Claude SDK handles the exchange and refresh loop when you supply `identity_token_provider` (typescript: `identityTokenProvider`; php: `identityProvider`; csharp: `IdentityTokenProvider`; go: `option.WithFederationTokenProvider()`; java: `IdentityTokenConfig`), as shown in the following examples. Except in Java (see the comment in that example), that option takes a token provider, and the SDK calls it again for each refresh. The cURL tab shows the raw flow.
144At runtime your workload fetches its Entra token, exchanges it at `POST /v1/oauth/token`, and uses the returned bearer token to call Claude. The Claude SDK handles the exchange and refresh loop when you supply `identity_token_provider` (typescript: `identityTokenProvider`; php: `identityProvider`; csharp: `IdentityTokenProvider`; go: `option.WithFederationTokenProvider()`; java: `IdentityTokenConfig`), as shown in the following examples. Except in Java, where `IdentityTokenConfig` takes a token or a file path, that option takes a token provider, and the SDK calls it again for each refresh.
145145 
146146The samples fetch the managed identity token from the platform’s token endpoint: IMDS on VMs and VM Scale Sets, or the `IDENTITY_ENDPOINT` service on App Service, Functions, and Container Apps. Replace `<APP_ID>` in the `api://<APP_ID>` resource value with the audience app registration’s client ID from [Register the token audience](https://platform.claude.com/docs/en/manage-claude/wif-providers/azure#register-the-token-audience).
147147 
from line 208
208208 "http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=api://<APP_ID>" \
209209 | jq -r .access_token > "$ANTHROPIC_IDENTITY_TOKEN_FILE"
210210 
211 # ANTHROPIC_FEDERATION_RULE_ID, ANTHROPIC_ORGANIZATION_ID,
212 # ANTHROPIC_SERVICE_ACCOUNT_ID, and ANTHROPIC_WORKSPACE_ID are read from the environment.
211 # ANTHROPIC_FEDERATION_RULE_ID, ANTHROPIC_ORGANIZATION_ID, and
212 # ANTHROPIC_SERVICE_ACCOUNT_ID are read from the environment.
213 # For a rule enabled for all workspaces or more than one, set ANTHROPIC_PROFILE
214 # to a federation profile that sets workspace_id.
213215 ant messages create \
214216 --model claude-opus-5-5 \
215217 --max-tokens 1024 \
from line 616
614616 
615617### Verify the setup
616618 
617From your Azure resource, run the cURL exchange shown in [Acquire and use the token](https://platform.claude.com/docs/en/manage-claude/wif-providers/azure#acquire-and-use-the-token) and confirm that `POST /v1/oauth/token` returns a `200` with an `access_token` starting with `sk-ant-oat01-` and an `expires_in` value in seconds. If the exchange fails with the opaque `401` `authentication_error` response (message `Authentication failed`), check the [authentication history page](https://platform.claude.com/settings/workload-identity-federation?tab=history) in the Claude Console for the deny reason, then decode the Entra token (see [Troubleshoot a failed exchange](https://platform.claude.com/docs/en/manage-claude/wif-reference#troubleshoot-a-failed-exchange) for the command) and check the most common Azure-side causes:
619From your Azure resource, run the sample in [Acquire and use the token](https://platform.claude.com/docs/en/manage-claude/wif-providers/azure#acquire-and-use-the-token). A successful exchange returns a `200` with an `access_token` starting with `sk-ant-oat01-` and an `expires_in` value in seconds. If the exchange fails with the opaque `401` `authentication_error` response (message `Authentication failed`), check the [authentication history page](https://platform.claude.com/settings/workload-identity-federation?tab=history) in the Claude Console for the deny reason, then decode the Entra token (see [Troubleshoot a failed exchange](https://platform.claude.com/docs/en/manage-claude/wif-reference#troubleshoot-a-failed-exchange) for the command) and check the most common Azure-side causes:
618620 
619621* **Issuer mismatch:** The registered `issuer_url` must match the token’s `iss` claim exactly. A v2.0 token carries `https://login.microsoftonline.com/<TENANT_ID>/v2.0`; if the decoded `ver` claim is `1.0`, see [If your tokens are v1.0](https://platform.claude.com/docs/en/manage-claude/wif-providers/azure#if-your-tokens-are-v1-0).
620622* **Token lifetime:** Managed identity tokens carry up to 24 hours between `iat` and `exp`. If the issuer still has the wizard’s `7500` (or the 1-hour default), raise `max_jwt_lifetime_seconds` to `86400` as described in [Configure Anthropic](https://platform.claude.com/docs/en/manage-claude/wif-providers/azure#configure-anthropic).
from line 722
720722 </Step>
721723 
722724 <Step title="Decode a sample token">
723 The token your Anthropic federation rule sees is not the projected file; it is the Entra-issued token returned by the `client_credentials` exchange. From inside a labeled pod, run step 1 of the cURL sample in [Acquire and use the token on AKS](https://platform.claude.com/docs/en/manage-claude/wif-providers/azure#acquire-and-use-the-token-2) and decode the result. It carries the same claim shape as the managed identity path:
725 The token your Anthropic federation rule sees is not the projected file; it is the Entra-issued token returned by the `client_credentials` exchange. From inside a labeled pod, fetch the Entra token as shown in [Acquire and use the token on AKS](https://platform.claude.com/docs/en/manage-claude/wif-providers/azure#acquire-and-use-the-token-2) and decode the result. It carries the same claim shape as the managed identity path:
724726 
725727 ```json
726728 {
from line 791
789791 
790792### Acquire and use the token
791793 
792At runtime the pod performs the two-hop exchange: it sends the Kubernetes-projected token (the file at `AZURE_FEDERATED_TOKEN_FILE`) to Entra’s token endpoint as a federated `client_credentials` assertion, then exchanges the resulting Entra access token at `POST /v1/oauth/token`. The Claude SDK handles the second exchange and the refresh loop when you supply `identity_token_provider` (typescript: `identityTokenProvider`; php: `identityProvider`; csharp: `IdentityTokenProvider`; go: `option.WithFederationTokenProvider()`; java: `IdentityTokenConfig`), as shown in the following examples. Except in Java (see the comment in that example), that option takes your Entra fetch as a token provider, and the SDK calls it again for each refresh. The cURL tab shows the raw flow.
794At runtime the pod performs the two-hop exchange: it sends the Kubernetes-projected token (the file at `AZURE_FEDERATED_TOKEN_FILE`) to Entra’s token endpoint as a federated `client_credentials` assertion, then exchanges the resulting Entra access token at `POST /v1/oauth/token`. The Claude SDK handles the second exchange and the refresh loop when you supply `identity_token_provider` (typescript: `identityTokenProvider`; php: `identityProvider`; csharp: `IdentityTokenProvider`; go: `option.WithFederationTokenProvider()`; java: `IdentityTokenConfig`), as shown in the following examples. Except in Java, where `IdentityTokenConfig` takes a token or a file path, that option takes your Entra fetch as a token provider, and the SDK calls it again for each refresh.
793795 
794796Two different client IDs appear in the samples. `<APP_ID>` is the audience app registration’s client ID from [Register the token audience](https://platform.claude.com/docs/en/manage-claude/wif-providers/azure#register-the-token-audience); the scope `api://<APP_ID>/.default` asks Entra for a token addressed to that audience. `$AZURE_CLIENT_ID` is the managed identity’s client ID, injected by the webhook, and identifies the caller. Do not substitute one for the other.
795797 
from line 852
850852 | jq -r .access_token > "$ANTHROPIC_IDENTITY_TOKEN_FILE"
851853 
852854 # 2. Call the Claude API. ANTHROPIC_FEDERATION_RULE_ID,
853 # ANTHROPIC_ORGANIZATION_ID, ANTHROPIC_SERVICE_ACCOUNT_ID, and ANTHROPIC_WORKSPACE_ID are read
855 # ANTHROPIC_ORGANIZATION_ID, and ANTHROPIC_SERVICE_ACCOUNT_ID are read
854856 # from the environment.
857 # For a rule enabled for all workspaces or more than one, set ANTHROPIC_PROFILE
858 # to a federation profile that sets workspace_id.
855859 ant messages create \
856860 --model claude-opus-5-5 \
857861 --max-tokens 1024 \
from line 1245
12411245 
12421246### Verify the setup
12431247 
1244From inside a labeled pod, run the cURL exchange shown in [Acquire and use the token on AKS](https://platform.claude.com/docs/en/manage-claude/wif-providers/azure#acquire-and-use-the-token-2) and confirm that `POST /v1/oauth/token` returns a `200` with an `access_token` starting with `sk-ant-oat01-` and an `expires_in` value in seconds. If the exchange fails with the opaque `401` `authentication_error` response (message `Authentication failed`), check the [authentication history page](https://platform.claude.com/settings/workload-identity-federation?tab=history) in the Claude Console for the deny reason. Then decode the Entra-issued token from step 1 (see [Troubleshoot a failed exchange](https://platform.claude.com/docs/en/manage-claude/wif-reference#troubleshoot-a-failed-exchange) for the command) and check the most common Azure-side causes:
1248From inside a labeled pod, run the sample in [Acquire and use the token on AKS](https://platform.claude.com/docs/en/manage-claude/wif-providers/azure#acquire-and-use-the-token-2). A successful exchange returns a `200` with an `access_token` starting with `sk-ant-oat01-` and an `expires_in` value in seconds. If the exchange fails with the opaque `401` `authentication_error` response (message `Authentication failed`), check the [authentication history page](https://platform.claude.com/settings/workload-identity-federation?tab=history) in the Claude Console for the deny reason. Then decode the Entra-issued token (see [Troubleshoot a failed exchange](https://platform.claude.com/docs/en/manage-claude/wif-reference#troubleshoot-a-failed-exchange) for the command) and check the most common Azure-side causes:
12451249 
12461250* **Issuer mismatch:** The registered `issuer_url` must match the token’s `iss` claim exactly. A v2.0 token carries `https://login.microsoftonline.com/<TENANT_ID>/v2.0`; if the decoded `ver` claim is `1.0`, see [If your tokens are v1.0](https://platform.claude.com/docs/en/manage-claude/wif-providers/azure#if-your-tokens-are-v1-0).
12471251* **Token lifetime:** If a tenant token-lifetime policy or CAE extends the `client_credentials` token past 7,500 seconds, raise the issuer’s `max_jwt_lifetime_seconds` as described in [Configure Anthropic for Entra Workload Identity on AKS](https://platform.claude.com/docs/en/manage-claude/wif-providers/azure#configure-anthropic-2).

manage-claude/wif-providers/gcp Changed · +6 / -4 lines

from line 126
126126 
127127## Acquire and use the token
128128 
129Inside your Google Cloud workload, fetch the identity token from the metadata server, exchange it at `POST /v1/oauth/token`, and use the returned bearer token to call the Claude API. The Claude SDK handles the exchange and refresh loop for you when you supply `identity_token_provider` (typescript: `identityTokenProvider`; php: `identityProvider`; csharp: `IdentityTokenProvider`; go: `option.WithFederationTokenProvider()`; java: `IdentityTokenConfig`), as shown in the following examples. Except in Java (see the comment in that example), that option takes a token provider that returns a fresh identity token from the metadata server.
129Inside your Google Cloud workload, fetch the identity token from the metadata server, exchange it at `POST /v1/oauth/token`, and use the returned bearer token to call the Claude API. The Claude SDK handles the exchange and refresh loop for you when you supply `identity_token_provider` (typescript: `identityTokenProvider`; php: `identityProvider`; csharp: `IdentityTokenProvider`; go: `option.WithFederationTokenProvider()`; java: `IdentityTokenConfig`), as shown in the following examples. Except in Java, where `IdentityTokenConfig` takes a token or a file path, that option takes a token provider that returns a fresh identity token from the metadata server.
130130 
131131<CodeGroup>
132132 ```bash cURL
from line 169
169169 "http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/identity?audience=https://api.anthropic.com&format=full" \
170170 > "$ANTHROPIC_IDENTITY_TOKEN_FILE"
171171 
172 # ANTHROPIC_FEDERATION_RULE_ID, ANTHROPIC_ORGANIZATION_ID,
173 # ANTHROPIC_SERVICE_ACCOUNT_ID, and ANTHROPIC_WORKSPACE_ID are read from the environment.
172 # ANTHROPIC_FEDERATION_RULE_ID, ANTHROPIC_ORGANIZATION_ID, and
173 # ANTHROPIC_SERVICE_ACCOUNT_ID are read from the environment.
174 # For a rule enabled for all workspaces or more than one, set ANTHROPIC_PROFILE
175 # to a federation profile that sets workspace_id.
174176 ant messages create \
175177 --model claude-opus-5-5 \
176178 --max-tokens 1024 \
from line 455
453455 ```
454456</CodeGroup>
455457 
456Google identity tokens expire after roughly 1 hour. Except in Java (see the comment in that example), the SDK calls the token provider again and re-exchanges automatically before expiry. For shell scripts that run longer than the access token’s `expires_in`, refresh on a timer and repeat the exchange.
458Google identity tokens expire after roughly 1 hour. Except in Java, where `IdentityTokenConfig` takes a token or a file path, the SDK calls the token provider again and repeats the exchange automatically before expiry. For shell scripts that run longer than the access token’s `expires_in`, refresh on a timer and repeat the exchange.
457459 
458460## Verify the setup
459461 

manage-claude/wif-providers/github-actions Changed · +6 / -4 lines

from line 109
109109 
110110## Acquire and use a token
111111 
112Set the federation environment variables on the job and call the SDK normally. `Anthropic()` (typescript: `new Anthropic()`; csharp: `new AnthropicClient()`; go: `anthropic.NewClient()`; java: `AnthropicOkHttpClient.fromEnv()`; php: `new Client()`; ruby: `Anthropic::Client.new`) reads `ANTHROPIC_IDENTITY_TOKEN_FILE`, exchanges the JWT on the first request, and refreshes the access token automatically before it expires.
112Set the federation environment variables on the job. In the SDK, `anthropic.Anthropic()` (typescript: `new Anthropic()`; csharp: `new AnthropicClient()`; go: `anthropic.NewClient()`; java: `AnthropicOkHttpClient.fromEnv()`; php: `new Client()`; ruby: `Anthropic::Client.new`) reads `ANTHROPIC_IDENTITY_TOKEN_FILE`, exchanges the JWT on the first request, and refreshes the access token automatically before it expires.
113113 
114114<CodeGroup>
115115 ```yaml Workflow
from line 172
172172 
173173 ```bash CLI
174174 # Reads ANTHROPIC_FEDERATION_RULE_ID, ANTHROPIC_ORGANIZATION_ID,
175 # ANTHROPIC_SERVICE_ACCOUNT_ID, ANTHROPIC_WORKSPACE_ID, and ANTHROPIC_IDENTITY_TOKEN_FILE
175 # ANTHROPIC_SERVICE_ACCOUNT_ID, and ANTHROPIC_IDENTITY_TOKEN_FILE
176176 # from the job environment.
177 # For a rule enabled for all workspaces or more than one, set ANTHROPIC_PROFILE
178 # to a federation profile that sets workspace_id.
177179 ant messages create \
178180 --model claude-opus-5-5 \
179181 --max-tokens 1024 \
from line 309
307309 ```
308310</CodeGroup>
309311 
310Each GitHub-issued identity token expires roughly 5 minutes after issuance. The token-request endpoint (`ACTIONS_ID_TOKEN_REQUEST_URL`) stays valid for the entire job, so you can fetch a fresh token at any point. The SDK exchanges the token on first use and caches the resulting Anthropic access token. For jobs that run longer than the Anthropic token’s lifetime, the SDK re-reads `ANTHROPIC_IDENTITY_TOKEN_FILE` on each refresh, so re-run the fetch step periodically (or wrap it in a background loop) to keep the file current. Alternatively, except in Java, pass the SDK a token provider that calls `ACTIONS_ID_TOKEN_REQUEST_URL` directly instead of using the file path.
312Each GitHub-issued identity token expires roughly 5 minutes after issuance. The token-request endpoint (`ACTIONS_ID_TOKEN_REQUEST_URL`) stays valid for the entire job, so you can fetch a fresh token at any point. The SDK exchanges the token on first use and caches the resulting Anthropic access token. On each refresh, the SDK rereads `ANTHROPIC_IDENTITY_TOKEN_FILE`. For jobs that run longer than the Anthropic token’s lifetime, rerun the fetch step periodically (or wrap it in a background loop) to keep the file current. Alternatively, except in Java, pass the SDK a token provider that calls `ACTIONS_ID_TOKEN_REQUEST_URL` directly instead of using the file path.
311313 
312314## Verify the setup
313315 
314A successful exchange returns an `access_token` starting with `sk-ant-oat01-` and an `expires_in` value in seconds. A denied exchange returns an opaque `401` `authentication_error` with the fixed message `Authentication failed`, whichever check failed; in most cases the deny reason is recorded on the attempt’s entry in the [authentication history page](https://platform.claude.com/settings/workload-identity-federation?tab=history) in the Claude Console, and [Troubleshoot a failed exchange](https://platform.claude.com/docs/en/manage-claude/wif-reference#troubleshoot-a-failed-exchange) walks the checks in order. The most common GitHub Actions-side cause is the `sub` claim format not matching (its trailing segment varies among `ref:...`, `environment:...`, and `pull_request` events); the history entry shows reason `match_subject_prefix`.
316A successful exchange returns an `access_token` starting with `sk-ant-oat01-` and an `expires_in` value in seconds. A denied exchange returns an opaque `401` `authentication_error` with the fixed message `Authentication failed`, whichever check failed. In most cases the deny reason is recorded on the attempt’s entry in the [authentication history page](https://platform.claude.com/settings/workload-identity-federation?tab=history) in the Claude Console. [Troubleshoot a failed exchange](https://platform.claude.com/docs/en/manage-claude/wif-reference#troubleshoot-a-failed-exchange) walks the checks in order. The most common GitHub Actions-side cause is the `sub` claim format not matching (its trailing segment varies among `ref:...`, `environment:...`, and `pull_request` events); the history entry shows reason `match_subject_prefix`.
315317 
316318## Restrict which workflows can authenticate
317319 

manage-claude/wif-providers/kubernetes Changed · +4 / -2 lines

from line 11
1111```
1212 
1313<Note>
14 The mechanism on this page (projected service-account token, cluster API server as the OIDC issuer) is native to Kubernetes itself, so it underlies every Kubernetes distribution. If you run on a managed Kubernetes service, the cloud provider guides walk through where to find the provider-managed issuer URL: [AWS (EKS)](https://platform.claude.com/docs/en/manage-claude/wif-providers/aws#use-eks-projected-service-account-tokens), [Google Cloud (GKE)](https://platform.claude.com/docs/en/manage-claude/wif-providers/gcp), or [Azure (AKS)](https://platform.claude.com/docs/en/manage-claude/wif-providers/azure). If your cluster runs SPIRE, the SPIRE OIDC Discovery Provider is the issuer rather than the cluster API server; see [SPIFFE](https://platform.claude.com/docs/en/manage-claude/wif-providers/spiffe). For any other distribution or a managed provider not listed there, follow this guide and use the issuer URL your cluster reports.
14 The mechanism on this page (projected service account token, cluster API server as the OIDC issuer) is native to Kubernetes itself, so it underlies every Kubernetes distribution. If you run on a managed Kubernetes service, the cloud provider guides walk through where to find the provider-managed issuer URL: [AWS (EKS)](https://platform.claude.com/docs/en/manage-claude/wif-providers/aws#use-eks-projected-service-account-tokens), [Google Cloud (GKE)](https://platform.claude.com/docs/en/manage-claude/wif-providers/gcp), or [Azure (AKS)](https://platform.claude.com/docs/en/manage-claude/wif-providers/azure). If your cluster runs SPIRE, the SPIRE OIDC Discovery Provider is the issuer rather than the cluster API server; see [Use WIF with SPIFFE](https://platform.claude.com/docs/en/manage-claude/wif-providers/spiffe). For any other distribution or a managed provider not listed there, follow this guide and use the issuer URL your cluster reports.
1515</Note>
1616 
1717## Prerequisites
from line 157
157157 
158158 ```bash CLI
159159 # Reads ANTHROPIC_FEDERATION_RULE_ID, ANTHROPIC_ORGANIZATION_ID,
160 # ANTHROPIC_SERVICE_ACCOUNT_ID, ANTHROPIC_WORKSPACE_ID, and ANTHROPIC_IDENTITY_TOKEN_FILE
160 # ANTHROPIC_SERVICE_ACCOUNT_ID, and ANTHROPIC_IDENTITY_TOKEN_FILE.
161 # For a rule enabled for all workspaces or more than one, set ANTHROPIC_PROFILE
162 # to a federation profile that sets workspace_id.
161163 ant messages create \
162164 --model claude-opus-5-5 \
163165 --max-tokens 1024 \

manage-claude/wif-providers/okta Changed · +5 / -3 lines

from line 9
99The Okta authorization server’s issuer URL takes the form `https://<your-domain>.okta.com/oauth2/<auth-server-id>`. If you use the built-in default server, the path is `/oauth2/default`.
1010 
1111<Note>
12 You must use an Okta **custom authorization server** (including the `default` one). Tokens issued directly by the Okta org authorization server (the `/oauth2/v1/token` endpoint with no authorization server ID in the path) cannot be validated by external parties because Okta does not publish signing keys for them.
12 You must use an Okta **custom authorization server** (including the `default` one). External parties cannot validate tokens issued directly by the Okta org authorization server (the `/oauth2/v1/token` endpoint with no authorization server ID in the path), because Okta does not publish signing keys for them.
1313</Note>
1414 
1515There are many ways to configure and authenticate to Okta that are outside the scope of this documentation. Ensure that your configuration and authentication mechanisms follow your company’s guidance and security practices.
from line 124
124124 | jq -r .access_token > "$ANTHROPIC_IDENTITY_TOKEN_FILE"
125125 
126126 # 2. Call the Claude API. The CLI reads ANTHROPIC_FEDERATION_RULE_ID,
127 # ANTHROPIC_ORGANIZATION_ID, ANTHROPIC_SERVICE_ACCOUNT_ID, ANTHROPIC_WORKSPACE_ID, and
127 # ANTHROPIC_ORGANIZATION_ID, ANTHROPIC_SERVICE_ACCOUNT_ID, and
128128 # ANTHROPIC_IDENTITY_TOKEN_FILE and performs the exchange.
129 # For a rule enabled for all workspaces or more than one, set ANTHROPIC_PROFILE
130 # to a federation profile that sets workspace_id.
129131 ant messages create \
130132 --model claude-opus-5-5 \
131133 --max-tokens 1024 \
from line 494
492494 ```
493495</CodeGroup>
494496 
495Except in Java (see the comment in that example), the SDK example passes your Okta token fetch to `identity_token_provider` (typescript: `identityTokenProvider`; php: `identityProvider`; csharp: `IdentityTokenProvider`; go: `option.WithFederationTokenProvider()`; java: `IdentityTokenConfig`) as a token provider. The Claude SDK calls it each time the Anthropic access token approaches expiry, so your Okta fetcher should return a fresh token on each call rather than caching one indefinitely. The `ant` CLI re-reads `ANTHROPIC_IDENTITY_TOKEN_FILE` on each exchange, so refresh that file on a timer for long-running shells.
497Pass your Okta token to `identity_token_provider` (typescript: `identityTokenProvider`; php: `identityProvider`; csharp: `IdentityTokenProvider`; go: `option.WithFederationTokenProvider()`; java: `IdentityTokenConfig`). Except in Java, where `IdentityTokenConfig` takes a token or a file path, that option takes your Okta fetch as a token provider. The Claude SDK calls it each time the Anthropic access token approaches expiry, so your Okta fetcher should return a fresh token on each call rather than caching one indefinitely. The `ant` CLI re-reads `ANTHROPIC_IDENTITY_TOKEN_FILE` on each exchange, so refresh that file on a timer for long-running shells.
496498 
497499## Verify the setup
498500 

manage-claude/wif-providers/spiffe Changed · +4 / -2 lines

from line 209
209209 ```bash CLI
210210 # Reads the JWT-SVID that spiffe-helper writes to
211211 # ANTHROPIC_IDENTITY_TOKEN_FILE, plus ANTHROPIC_FEDERATION_RULE_ID,
212 # ANTHROPIC_ORGANIZATION_ID, ANTHROPIC_SERVICE_ACCOUNT_ID, and ANTHROPIC_WORKSPACE_ID.
212 # ANTHROPIC_ORGANIZATION_ID, and ANTHROPIC_SERVICE_ACCOUNT_ID.
213 # For a rule enabled for all workspaces or more than one, set ANTHROPIC_PROFILE
214 # to a federation profile that sets workspace_id.
213215 ant messages create \
214216 --model claude-opus-5-5 \
215217 --max-tokens 1024 \
from line 468
466468 | jq -rR 'split(".")[1] | gsub("-";"+") | gsub("_";"/") | @base64d | fromjson'
467469```
468470 
469The `-output json` flag returns the SVID response and bundle response as a two-element JSON array, so `jq -r '.[0].svids[0].svid'` extracts the bare token. On older SPIRE versions without `-output`, the command prints a labeled block instead. In that case, pipe the default output through `awk '/^[[:space:]]*eyJ/{print $1; exit}'` to extract the token line. Check that `iss` is the OIDC Discovery Provider URL you registered, `sub` is the workload’s SPIFFE ID, and `aud` contains `https://api.anthropic.com`. Then run the cURL example from [Acquire and use the token](https://platform.claude.com/docs/en/manage-claude/wif-providers/spiffe#acquire-and-use-the-token). A successful exchange returns an `access_token` starting with `sk-ant-oat01-`. If the exchange fails with the opaque `401` `authentication_error` response (message `Authentication failed`), check the [authentication history page](https://platform.claude.com/settings/workload-identity-federation?tab=history) in the Claude Console for the deny reason and see [Troubleshoot a failed exchange](https://platform.claude.com/docs/en/manage-claude/wif-reference#troubleshoot-a-failed-exchange). The most common SPIRE-side cause is a mismatch between SPIRE Server’s `jwt_issuer` and the URL registered as the federation issuer.
471The `-output json` flag returns the SVID response and bundle response as a two-element JSON array, so `jq -r '.[0].svids[0].svid'` extracts the bare token. On older SPIRE versions without `-output`, the command prints a labeled block instead. In that case, pipe the default output through `awk '/^[[:space:]]*eyJ/{print $1; exit}'` to extract the token line. Check that `iss` is the OIDC Discovery Provider URL you registered, `sub` is the workload’s SPIFFE ID, and `aud` contains `https://api.anthropic.com`. Then run the sample in [Acquire and use the token](https://platform.claude.com/docs/en/manage-claude/wif-providers/spiffe#acquire-and-use-the-token). A successful exchange returns an `access_token` starting with `sk-ant-oat01-`. If the exchange fails with the opaque `401` `authentication_error` response (message `Authentication failed`), check the [authentication history page](https://platform.claude.com/settings/workload-identity-federation?tab=history) in the Claude Console for the deny reason and see [Troubleshoot a failed exchange](https://platform.claude.com/docs/en/manage-claude/wif-reference#troubleshoot-a-failed-exchange). The most common SPIRE-side cause is a mismatch between SPIRE Server’s `jwt_issuer` and the URL registered as the federation issuer.
470472 
471473## Scope your rule
472474 

manage-claude/wif-reference Changed · +22 / -22 lines

from line 8
88 
99## Token exchange request
1010 
11`POST /v1/oauth/token` accepts a JSON body using the [RFC 7523](https://www.rfc-editor.org/rfc/rfc7523) `jwt-bearer` grant. The SDK builds this request for you from the [environment variables](https://platform.claude.com/docs/en/manage-claude/wif-reference#environment-variables); the cURL examples on each provider guide show the raw body.
11`POST /v1/oauth/token` accepts a JSON body using the [RFC 7523](https://www.rfc-editor.org/rfc/rfc7523) `jwt-bearer` grant. The SDK builds this request for you from the [environment variables](https://platform.claude.com/docs/en/manage-claude/wif-reference#environment-variables).
1212 
1313| Field | Required | Description |
1414| -------------------- | ----------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
from line 34
3434 
3535The SDK reads these variables to perform a federated token exchange with no constructor arguments.
3636 
37| Variable | Required | Description | Example |
38| ------------------------------- | -------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------- |
39| `ANTHROPIC_FEDERATION_RULE_ID` | Yes | Tagged ID of the federation rule to evaluate. | `fdrl_...` |
40| `ANTHROPIC_ORGANIZATION_ID` | Yes | UUID of your Anthropic organization. Find it on the [Organization](https://platform.claude.com/settings/organization) page (`platform.claude.com/settings/organization`) in the Claude Console. | `00000000-0000-0000-0000-000000000000` |
41| `ANTHROPIC_IDENTITY_TOKEN_FILE` | One of `_TOKEN_FILE` or `_TOKEN` | Filesystem path to the JWT issued by your identity provider (IdP). The SDK re-reads this file on every exchange so that projected tokens that rotate on disk are always current. | `/var/run/secrets/anthropic.com/token` |
42| `ANTHROPIC_IDENTITY_TOKEN` | One of `_TOKEN_FILE` or `_TOKEN` | The literal JWT as a string. Use when your platform injects the token as an environment variable rather than a file. | `eyJhbGciOiJSUzI1NiIs...` |
43| `ANTHROPIC_SERVICE_ACCOUNT_ID` | Yes | Tagged ID of the target Anthropic service account that the issued access token acts as. | `svac_...` |
44| `ANTHROPIC_WORKSPACE_ID` | Conditional | Tagged ID of the workspace to scope the minted token to. Required when the federation rule is enabled for more than one workspace; optional when the rule is bound to a single workspace. The minted token is scoped to this workspace at exchange time, so switching workspaces requires a new exchange. The literal `default` also works for the Default Workspace but is deprecated; use its `wrkspc_...` ID. | `wrkspc_...` |
45| `ANTHROPIC_PROFILE` | No | Name of a [configuration profile](https://platform.claude.com/docs/en/manage-claude/wif-reference#profile-configuration-file) to load. Takes precedence over the federation environment variables in this table. | `staging-profile` |
37| Variable | Required | Description | Example |
38| ------------------------------- | -------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------- |
39| `ANTHROPIC_FEDERATION_RULE_ID` | Yes | Tagged ID of the federation rule to evaluate. | `fdrl_...` |
40| `ANTHROPIC_ORGANIZATION_ID` | Yes | UUID of your Anthropic organization. Find it on the [Organization](https://platform.claude.com/settings/organization) page (`platform.claude.com/settings/organization`) in the Claude Console. | `00000000-0000-0000-0000-000000000000` |
41| `ANTHROPIC_IDENTITY_TOKEN_FILE` | One of `_TOKEN_FILE` or `_TOKEN` | Filesystem path to the JWT issued by your identity provider (IdP). The SDK re-reads this file on every exchange so that projected tokens that rotate on disk are always current. | `/var/run/secrets/anthropic.com/token` |
42| `ANTHROPIC_IDENTITY_TOKEN` | One of `_TOKEN_FILE` or `_TOKEN` | The literal JWT as a string. Use when your platform injects the token as an environment variable rather than a file. | `eyJhbGciOiJSUzI1NiIs...` |
43| `ANTHROPIC_SERVICE_ACCOUNT_ID` | Yes | Tagged ID of the target Anthropic service account that the issued access token acts as. | `svac_...` |
44| `ANTHROPIC_WORKSPACE_ID` | Conditional | Tagged ID of the workspace to scope the minted token to. Required when the federation rule is enabled for more than one workspace; optional when the rule is bound to a single workspace. The minted token is scoped to this workspace at exchange time, so switching workspaces requires a new exchange. Without a profile, the `ant` CLI does not pass this variable into the exchange, so set `workspace_id` in a federation profile and set `ANTHROPIC_PROFILE` to its name. The literal `default` also works for the Default Workspace but is deprecated; use its `wrkspc_...` ID. | `wrkspc_...` |
45| `ANTHROPIC_PROFILE` | No | Name of a [configuration profile](https://platform.claude.com/docs/en/manage-claude/wif-reference#profile-configuration-file) to load. Takes precedence over the federation environment variables in this table. | `staging-profile` |
4646 
4747The direct environment-variable federation path activates only when `ANTHROPIC_FEDERATION_RULE_ID`, `ANTHROPIC_ORGANIZATION_ID`, `ANTHROPIC_SERVICE_ACCOUNT_ID`, and one of `ANTHROPIC_IDENTITY_TOKEN_FILE` or `ANTHROPIC_IDENTITY_TOKEN` are all set. `ANTHROPIC_WORKSPACE_ID` is read alongside but does not gate activation.
4848 
from line 95
9595| `<config_dir>/configs/<profile>.json` | `version`, the `authentication` block, `organization_id`, `workspace_id`, and `base_url`. | Non-secret. Safe to commit or bake into an image. |
9696| `<config_dir>/credentials/<profile>.json` | `version`, the cached `access_token`, `expires_at`, and (for interactive login) `refresh_token`. | Secret. Written by the SDK with mode `0600`. |
9797 
98Both the config file and the credentials file carry a top-level string `version` field in `major.minor` format (currently `"1.0"`). The SDK writes this field automatically so future releases can detect and migrate older formats; omit it when authoring a config by hand and the SDK treats the file as the current version.
98Both the config file and the credentials file carry a top-level string `version` field in `major.minor` format, such as `"1.0"`. The SDK writes this field automatically. If you omit it when authoring a config by hand, the SDK treats the file as the current version.
9999 
100100### Federation profile example
101101 
from line 219
219219 
220220`POST /v1/oauth/token` returns errors in the standard [API error shape](https://platform.claude.com/docs/en/api/errors). The SDK reports an exchange failure as `WorkloadIdentityError` (ruby: `Anthropic::Credentials::WorkloadIdentityError`; go: `error`; java: `UnexpectedStatusCodeException`; csharp: `WorkloadIdentityException`; php: `OAuthException`), which gives the HTTP status and the error details from the response body. The request ID is on the error in Python, TypeScript, and Ruby, and in the exception’s response headers in Java. In Go it is only in the error’s message, because the error’s type is in an internal package; the C# and PHP errors do not carry it.
221221 
222| Status | Error | Cause | Resolution |
223| ------ | ----------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
224| 400 | `invalid_request_error` | `federation_rule_id` is malformed or a required request field is missing. | Verify the `fdrl_` ID and that the request body includes all required fields. |
225| 400 | `invalid_request_error` | `workspace_id` is present but is not a well-formed `wrkspc_...` ID or the literal `default`. | Fix the `workspace_id` value; the response message names the expected format. |
226| 401 | `authentication_error` | The JWT `iss` claim does not equal the registered `issuer_url` exactly. | Compare byte-for-byte, including trailing slashes and scheme: `jq -rR 'split(".")[1] \| gsub("-";"+") \| gsub("_";"/") \| @base64d \| fromjson \| .iss' <<< "$JWT"`. |
227| 401 | `authentication_error` | JWKS fetch failed, JWKS is stale, or the JWT was signed with a key not in the JWKS. | For `inline` mode, update the issuer with the rotated keys. For `discovery` and `explicit_url`, confirm the JWKS endpoint is reachable on port 443; if the issuer recently rotated its signing key, see [Key rotation and caching](https://platform.claude.com/docs/en/manage-claude/wif-reference#key-rotation-and-caching). |
228| 401 | `authentication_error` | The JWT `exp` claim is in the past (beyond the 30-second skew window). | Confirm your identity provider is projecting a fresh token and the SDK is re-reading the token file. |
229| 401 | `authentication_error` | The JWT was verified but its claims do not satisfy the rule’s `match` block. | Decode the JWT and compare each claim against the rule. `subject_prefix` is case-sensitive. `audience` requires an exact element match. |
230| 401 | `authentication_error` | The `federation_rule_id` does not exist or is archived, or the JWT is not authorized for it (consolidated to prevent enumeration). | Confirm the rule ID in the Claude Console and that the rule has not been archived. |
231| 401 | `authentication_error` | The federation rule is enabled for more than one workspace and the request omits `workspace_id`. The authentication history entry shows reason `workspace_id_required`. | Set `ANTHROPIC_WORKSPACE_ID` (or the `workspace_id` body field on a raw request) to the `wrkspc_...` ID you want the token scoped to. See [Token exchange request](https://platform.claude.com/docs/en/manage-claude/wif-reference#token-exchange-request). |
222| Status | Error | Cause | Resolution |
223| ------ | ----------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
224| 400 | `invalid_request_error` | `federation_rule_id` is malformed or a required request field is missing. | Verify the `fdrl_` ID and that the request body includes all required fields. |
225| 400 | `invalid_request_error` | `workspace_id` is present but is not a well-formed `wrkspc_...` ID or the literal `default`. | Fix the `workspace_id` value; the response message names the expected format. |
226| 401 | `authentication_error` | The JWT `iss` claim does not equal the registered `issuer_url` exactly. | Compare byte-for-byte, including trailing slashes and scheme: `jq -rR 'split(".")[1] \| gsub("-";"+") \| gsub("_";"/") \| @base64d \| fromjson \| .iss' <<< "$JWT"`. |
227| 401 | `authentication_error` | JWKS fetch failed, JWKS is stale, or the JWT was signed with a key not in the JWKS. | For `inline` mode, update the issuer with the rotated keys. For `discovery` and `explicit_url`, confirm the JWKS endpoint is reachable on port 443; if the issuer recently rotated its signing key, see [Key rotation and caching](https://platform.claude.com/docs/en/manage-claude/wif-reference#key-rotation-and-caching). |
228| 401 | `authentication_error` | The JWT `exp` claim is in the past (beyond the 30-second skew window). | Confirm your identity provider is projecting a fresh token and the SDK is re-reading the token file. |
229| 401 | `authentication_error` | The JWT was verified but its claims do not satisfy the rule’s `match` block. | Decode the JWT and compare each claim against the rule. `subject_prefix` is case-sensitive. `audience` requires an exact element match. |
230| 401 | `authentication_error` | The `federation_rule_id` does not exist or is archived, or the JWT is not authorized for it (consolidated to prevent enumeration). | Confirm the rule ID in the Claude Console and that the rule has not been archived. |
231| 401 | `authentication_error` | The federation rule is enabled for more than one workspace and the request omits `workspace_id`. The authentication history entry shows reason `workspace_id_required`. | Set `ANTHROPIC_WORKSPACE_ID` (or the `workspace_id` body field on a raw request) to the `wrkspc_...` ID you want the token scoped to. With the `ant` CLI, set `workspace_id` in a federation profile and set `ANTHROPIC_PROFILE` to its name. See [Token exchange request](https://platform.claude.com/docs/en/manage-claude/wif-reference#token-exchange-request). |
232232 
233233Every assertion denial returns the same opaque `401` `authentication_error` with the fixed message `Authentication failed`, regardless of which check failed; a distinguishable error would let a caller probe rule configuration. The deny reason is recorded on the attempt’s entry in the [authentication history](https://platform.claude.com/settings/workload-identity-federation?tab=history) in the Claude Console, for example `match_subject_prefix` when the `sub` claim fails the rule’s `subject_prefix`, or `workspace_id_required` when the rule spans multiple workspaces and the request names none. Requests rejected before the rule’s organization is corroborated (the `400 invalid_request_error` family in the previous table) leave no history entry. Their response messages name the problem directly. A `401` with no matching history entry usually means the `federation_rule_id` itself was not recognized.
234234 
from line 238
238238| ------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
239239| SDK reports “no credentials” instead of exchanging | One of `ANTHROPIC_FEDERATION_RULE_ID`, `ANTHROPIC_ORGANIZATION_ID`, `ANTHROPIC_SERVICE_ACCOUNT_ID`, or `ANTHROPIC_IDENTITY_TOKEN[_FILE]` is unset and no profile is active. | Set all four variables, or configure a profile. |
240240| SDK authenticates with an API key instead of federating | `ANTHROPIC_API_KEY` or `ANTHROPIC_AUTH_TOKEN` is set and wins precedence. | Unset the key or token variable. |
241| `FileNotFoundError` on first request | The path in `ANTHROPIC_IDENTITY_TOKEN_FILE` does not exist. The SDK opens the file lazily at exchange time. | Confirm the projected-token volume is mounted and the path matches. |
241| File-not-found error on first request | The path in `ANTHROPIC_IDENTITY_TOKEN_FILE` does not exist. The SDK opens the file lazily at exchange time. | Confirm the projected-token volume is mounted and the path matches. |
242242| Token exchange succeeds but a Claude API request returns 403 | The minted token’s scope does not grant access to that endpoint. | Check the rule’s `oauth_scope` against [OAuth scopes](https://platform.claude.com/docs/en/manage-claude/wif-reference#oauth-scopes). |
243243| Authentication fails with empty credential | A credential environment variable is exported but set to an empty string. Empty values can still win their precedence slot. | Unset the variable with `unset VAR` rather than `VAR=""`. |
244244 

manage-claude/workload-identity-federation Changed · +10 / -9 lines

from line 41
4141 
4242* **Match:** The conditions an incoming JWT must satisfy. You can match on a `subject_prefix` (for example, `system:serviceaccount:prod:worker`, or with a trailing `*` for a prefix match), an exact `audience`, a map of exact claim values, a [CEL](https://cel.dev/) `condition` expression for complex logic, or any combination. At least one of `subject_prefix`, `claims`, or `condition` must be set, and all configured matchers must pass for the JWT to be accepted.
4343* **Target:** The service account the matched JWT maps to.
44* **Authorization:** The OAuth `scope` granted on the minted token. The default is `workspace:developer`, which grants the same access as a workspace API key. Some products lock the scope when you create a rule from their flow; for example, the [MCP tunnels](https://platform.claude.com/docs/en/agents-and-tools/mcp-tunnels/overview) create-tunnel modal creates rules scoped to `workspace:manage_tunnels`. See [OAuth scopes](https://platform.claude.com/docs/en/manage-claude/wif-reference#oauth-scopes). The rule also sets `token_lifetime_seconds` (60 to 86400, default 3600).
44* **Authorization:** The OAuth `scope` granted on the minted token. The default is `workspace:developer`, which grants the same access as a workspace API key. Some products lock the scope when you create a rule from their flow; for example, the [MCP tunnels](https://platform.claude.com/docs/en/agents-and-tools/mcp-tunnels/overview) create-tunnel modal creates rules scoped to `workspace:manage_tunnels`. See [OAuth scopes](https://platform.claude.com/docs/en/manage-claude/wif-reference#oauth-scopes). The rule also sets `token_lifetime_seconds` (60 to 86,400, default 3,600).
4545 
4646A single issuer can have many rules: one for each team, namespace, or permission level. Rules are evaluated by ID: the client specifies which rule to use in the exchange request, and Anthropic verifies the JWT satisfies that rule’s match criteria. There is no implicit rule search.
4747 
from line 49
4949 
50501. **Your IdP issues a JWT to the workload.** On most platforms this is ambient: a Kubernetes projected service-account token, the Google Cloud metadata server, Azure IMDS, or the GitHub Actions OIDC endpoint. The JWT’s `iss` claim identifies the provider, and its `sub` and other claims identify the specific workload.
51512. **The SDK exchanges the JWT for an Anthropic access token.** The SDK posts the JWT to `POST /v1/oauth/token` using the [RFC 7523](https://www.rfc-editor.org/rfc/rfc7523) `jwt-bearer` grant. Anthropic verifies the JWT against the issuer’s JWKS and the federation rule’s match conditions, then returns a short-lived `sk-ant-oat01-...` token that acts on behalf of the rule’s target service account.
523. **The SDK sends the token on every request and refreshes it before it expires.** Your application code constructs the client with no API key and calls the API as usual. The SDK re-runs the exchange before the token expires.
523. **The SDK sends the token on every request and refreshes it before it expires.** Your application code constructs the client with no API key and calls the API as usual. The SDK reruns the exchange before the token expires.
5353 
5454## Set up federation
5555 
from line 67
6767 </Step>
6868 
6969 <Step title="Fill in the guided fields">
70 The wizard walks you through the provider-specific fields: the issuer configuration, the match conditions for incoming JWTs, and names for the service account and federation rule it creates. The wizard prefills `oauth_scope=workspace:developer` and `token_lifetime_seconds=600` (the API default when `token_lifetime_seconds` is omitted is 3600); adjust these if your workload needs a different scope or lifetime.
70 The wizard walks you through the provider-specific fields: the issuer configuration, the match conditions for incoming JWTs, and names for the service account and federation rule it creates. The wizard prefills `oauth_scope=workspace:developer` and `token_lifetime_seconds=600` (the API default when `token_lifetime_seconds` is omitted is 3,600); adjust these if your workload needs a different scope or lifetime.
7171 </Step>
7272 
7373 <Step title="Verify the issuer">
from line 75
7575 </Step>
7676 
7777 <Step title="Test the connection">
78 The wizard creates the issuer, service account, and federation rule, then listens for a successful token exchange for 15 minutes. Trigger an exchange from your workload within that window (see [Authenticate from your workload](https://platform.claude.com/docs/en/manage-claude/workload-identity-federation#authenticate-from-your-workload)) to confirm the setup works. If the window elapses, the resources persist; you can re-run the test from the federation rule’s detail page. Note the rule’s ID (`fdrl_...`) and the service account ID (`svac_...`) the wizard creates: your workload passes both, along with your organization ID (and your workspace ID when the rule covers more than one workspace), in every token-exchange request.
78 The wizard creates the issuer, service account, and federation rule, then listens for a successful token exchange for 15 minutes. Trigger an exchange from your workload within that window (see [Authenticate from your workload](https://platform.claude.com/docs/en/manage-claude/workload-identity-federation#authenticate-from-your-workload)) to confirm the setup works. If the window elapses, the resources persist; you can rerun the test from the federation rule’s detail page. Note the rule’s ID (`fdrl_...`) and the service account ID (`svac_...`) the wizard creates. Your workload passes both in every token-exchange request, along with your organization ID and, when the rule covers more than one workspace, your workspace ID.
7979 </Step>
8080</Steps>
8181 
82To manage these resources programmatically, see [Manage WIF with the Admin API](https://platform.claude.com/docs/en/manage-claude/wif-admin-api) for the curl walkthrough, or see the [Service accounts API reference](https://platform.claude.com/docs/en/api/organization/service_accounts), [Federation issuers API reference](https://platform.claude.com/docs/en/api/organization/federation/issuers), and [Federation rules API reference](https://platform.claude.com/docs/en/api/organization/federation/rules) for complete parameter details and response schemas.
82To manage these resources programmatically, see [Manage WIF with the Admin API](https://platform.claude.com/docs/en/manage-claude/wif-admin-api). For complete parameter details and response schemas, see the [Service accounts API reference](https://platform.claude.com/docs/en/api/organization/service_accounts), [Federation issuers API reference](https://platform.claude.com/docs/en/api/organization/federation/issuers), and [Federation rules API reference](https://platform.claude.com/docs/en/api/organization/federation/rules).
8383 
8484## Authenticate from your workload
8585 
86With federation configured, your workload exchanges its IdP-issued JWT for an Anthropic token at runtime. The SDK handles the exchange and refresh loop for you. The cURL tab shows the underlying HTTP exchange for shell scripts, debugging, or languages without SDK support.
86With federation configured, your workload exchanges its IdP-issued JWT for an Anthropic token at runtime. The SDK handles the exchange and refresh loop for you. For debugging, or for a language without SDK support, [Token exchange request](https://platform.claude.com/docs/en/manage-claude/wif-reference#token-exchange-request) lists the fields of the underlying HTTP request.
8787 
8888### Construct the SDK client
8989 
from line 124
124124 
125125 ```bash CLI
126126 # The CLI exchanges the identity token for an access token itself.
127 # For a rule enabled for all workspaces or more than one, set ANTHROPIC_PROFILE
128 # to a federation profile that sets workspace_id.
127129 export ANTHROPIC_IDENTITY_TOKEN_FILE=/var/run/secrets/anthropic.com/token
128130 export ANTHROPIC_FEDERATION_RULE_ID=fdrl_...
129131 export ANTHROPIC_ORGANIZATION_ID=00000000-0000-0000-0000-000000000000
130132 export ANTHROPIC_SERVICE_ACCOUNT_ID=svac_...
131 export ANTHROPIC_WORKSPACE_ID=wrkspc_...
132133 
133134 ant messages create \
134135 --model claude-opus-5-5 \
from line 344
343344 
344345## Credential precedence
345346 
346Every SDK resolves credentials in the same five-tier order: constructor arguments, then `ANTHROPIC_API_KEY` / `ANTHROPIC_AUTH_TOKEN`, then an explicit `ANTHROPIC_PROFILE`, then the federation environment variables, then the implicit active profile. The first source that yields a credential wins.
347The SDK resolves credentials in a five-tier order: constructor arguments, then `ANTHROPIC_API_KEY` / `ANTHROPIC_AUTH_TOKEN`, then an explicit `ANTHROPIC_PROFILE`, then the federation environment variables, then the implicit active profile. The first source that yields a credential wins.
347348 
348349<Warning>
349350 `ANTHROPIC_API_KEY` sits above the federation tiers, so a leftover key in the environment silently shadows federation. When migrating a workload from API keys to Workload Identity Federation, confirm `ANTHROPIC_API_KEY` is unset everywhere that workload runs (container env, CI secrets, shell profiles). The CLI’s [`ant auth status`](https://platform.claude.com/docs/en/cli-sdks-libraries/cli/authentication#check-authentication-status) command reports which source won.
from line 358
357358 
3583591. **Configure federation in parallel.** Complete the [setup walkthrough](https://platform.claude.com/docs/en/manage-claude/workload-identity-federation#set-up-federation) and confirm the federation rule matches your workload’s token. Leave the existing `ANTHROPIC_API_KEY` in place for now.
3593602. **Smoke-test which credential wins.** Run `ant auth status` from inside the workload (or inspect SDK debug logs). Because `ANTHROPIC_API_KEY` sits above the federation tiers in the precedence chain, the API key still wins at this stage.
3603. **Unset `ANTHROPIC_API_KEY` everywhere it is injected.** Remove it from CI secrets, container environment, and shell profiles (see the preceding warning). Re-run `ant auth status` and confirm the federation source now wins.
3613. **Unset `ANTHROPIC_API_KEY` everywhere it is injected.** Remove it from CI secrets, container environment, and shell profiles (see the preceding warning). Rerun `ant auth status` and confirm the federation source now wins.
3613624. **Delete the API key.** Once the workload is running on the federated token, delete the key on the [API keys](https://platform.claude.com/settings/keys) page (`platform.claude.com/settings/keys`) in the Claude Console.
362363 
363364## Token lifetime and refresh

managed-agents/choosing-an-environment Changed · +3 / -3 lines

from line 82
8282* [`file` and `github_repository` session resources](https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes#session-resources). You [stage input files yourself](https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes-workers#stage-files-for-a-session), and you are responsible for mounting your own GitHub repository too.
8383* [Repository skill discovery](https://platform.claude.com/docs/en/managed-agents/skills#load-skills-from-a-github-repository).
8484* [Environment variable credentials](https://platform.claude.com/docs/en/managed-agents/vaults#add-a-credential) in vaults.
85* The [pre-installed runtimes and packages](https://platform.claude.com/docs/en/managed-agents/cloud-sandboxes-reference) of a cloud sandbox. A self-hosted sandbox has whatever your worker provides.
85* The [preinstalled runtimes and packages](https://platform.claude.com/docs/en/managed-agents/cloud-sandboxes-reference) of a cloud sandbox. A self-hosted sandbox has whatever your worker provides.
8686 
8787## Differences on Claude Platform on AWS
8888 
from line 90
9090 
9191## Differences on Claude Models on Google Cloud (Anthropic managed)
9292 
93If you use Claude Managed Agents through Claude Models on Google Cloud (Anthropic managed), Anthropic still operates the service. There, memory stores aren’t supported in a self-hosted sandbox, and MCP tunnels aren’t available. Workers authenticate with Google Cloud credentials, not an environment key, and you write your own, because the pre-built workers in the `ant` CLI and the Python, TypeScript, and Go SDKs don’t work there. See [Feature support](https://platform.claude.com/docs/en/build-with-claude/claude-models-on-google-cloud/anthropic-managed#feature-support) in the Claude Models on Google Cloud (Anthropic managed) guide.
93If you use Claude Managed Agents through Claude Models on Google Cloud (Anthropic managed), Anthropic still operates the service. There, memory stores aren’t available in a self-hosted sandbox, and MCP tunnels aren’t available. Workers authenticate with Google Cloud credentials, not an environment key. You write your own worker, because the prebuilt workers in the `ant` CLI and the Python, TypeScript, and Go SDKs don’t work there. See [Feature support](https://platform.claude.com/docs/en/build-with-claude/claude-models-on-google-cloud/anthropic-managed#feature-support) in the Claude Models on Google Cloud (Anthropic managed) guide.
9494 
9595## Switch from a cloud environment to a self-hosted sandbox
9696 
from line 102
102102 
103103On Claude Platform on AWS, memory stores don’t carry over to a self-hosted sandbox, and the worker doesn’t use an environment key. See [Differences on Claude Platform on AWS](https://platform.claude.com/docs/en/managed-agents/choosing-an-environment#differences-on-claude-platform-on-aws).
104104 
105On Claude Models on Google Cloud (Anthropic managed), memory stores aren’t supported in a self-hosted sandbox, and you write your own worker, which doesn’t use an environment key. See [Differences on Claude Models on Google Cloud (Anthropic managed)](https://platform.claude.com/docs/en/managed-agents/choosing-an-environment#differences-on-claude-models-on-google-cloud-anthropic-managed).
105On Claude Models on Google Cloud (Anthropic managed), memory stores aren’t available in a self-hosted sandbox, and you write your own worker, which doesn’t use an environment key. See [Differences on Claude Models on Google Cloud (Anthropic managed)](https://platform.claude.com/docs/en/managed-agents/choosing-an-environment#differences-on-claude-models-on-google-cloud-anthropic-managed).
106106 

managed-agents/environments Changed · +18 / -18 lines

from line 682
682682 -H "anthropic-version: 2026-10-21" \
683683 -H "anthropic-beta: managed-agents-2026-04-01"
684684 
685 # Archive an environment (read-only, existing sessions continue)
685 # Archive an environment (read-only, no new sessions)
686686 curl -fsS -X POST "https://api.anthropic.com/v1/environments/$ENVIRONMENT_ID/archive" \
687687 -H "x-api-key: $ANTHROPIC_API_KEY" \
688688 -H "anthropic-version: 2026-10-21" \
689689 -H "anthropic-beta: managed-agents-2026-04-01"
690690 
691 # Delete an environment (only if no sessions reference it)
691 # Delete an environment
692692 curl -fsS -X DELETE "https://api.anthropic.com/v1/environments/$ENVIRONMENT_ID" \
693693 -H "x-api-key: $ANTHROPIC_API_KEY" \
694694 -H "anthropic-version: 2026-10-21" \
from line 702
702702 # Retrieve a specific environment
703703 ant beta:environments retrieve --environment-id "$ENVIRONMENT_ID"
704704 
705 # Archive an environment (read-only, existing sessions continue)
705 # Archive an environment (read-only, no new sessions)
706706 ant beta:environments archive --environment-id "$ENVIRONMENT_ID"
707707 
708 # Delete an environment (only if no sessions reference it)
708 # Delete an environment
709709 ant beta:environments delete --environment-id "$ENVIRONMENT_ID"
710710 ```
711711 
from line 716
716716 # Retrieve a specific environment
717717 env = client.beta.environments.retrieve(environment.id)
718718 
719 # Archive an environment (read-only, existing sessions continue)
719 # Archive an environment (read-only, no new sessions)
720720 client.beta.environments.archive(environment.id)
721721 
722 # Delete an environment (only if no sessions reference it)
722 # Delete an environment
723723 client.beta.environments.delete(environment.id)
724724 ```
725725 
from line 730
730730 // Retrieve a specific environment
731731 const env = await client.beta.environments.retrieve(environment.id);
732732 
733 // Archive an environment (read-only, existing sessions continue)
733 // Archive an environment (read-only, no new sessions)
734734 await client.beta.environments.archive(environment.id);
735735 
736 // Delete an environment (only if no sessions reference it)
736 // Delete an environment
737737 await client.beta.environments.delete(environment.id);
738738 ```
739739 
from line 744
744744 // Retrieve a specific environment
745745 var env = await client.Beta.Environments.Retrieve(environment.ID);
746746 
747 // Archive an environment (read-only, existing sessions continue)
747 // Archive an environment (read-only, no new sessions)
748748 await client.Beta.Environments.Archive(environment.ID);
749749 
750 // Delete an environment (only if no sessions reference it)
750 // Delete an environment
751751 await client.Beta.Environments.Delete(environment.ID);
752752 ```
753753 
from line 760
760760 env, err := client.Beta.Environments.Get(ctx, environment.ID, anthropic.BetaEnvironmentGetParams{})
761761 // ...
762762 
763 // Archive an environment (read-only, existing sessions continue)
763 // Archive an environment (read-only, no new sessions)
764764 _, err = client.Beta.Environments.Archive(ctx, environment.ID, anthropic.BetaEnvironmentArchiveParams{})
765765 // ...
766766 
767 // Delete an environment (only if no sessions reference it)
767 // Delete an environment
768768 _, err = client.Beta.Environments.Delete(ctx, environment.ID, anthropic.BetaEnvironmentDeleteParams{})
769769 ```
770770 
from line 773
773773 var environments = client.beta().environments().list();
774774 // Retrieve a specific environment
775775 var env = client.beta().environments().retrieve(environment.id());
776 // Archive an environment (read-only, existing sessions continue)
776 // Archive an environment (read-only, no new sessions)
777777 client.beta().environments().archive(environment.id());
778 // Delete an environment (only if no sessions reference it)
778 // Delete an environment
779779 client.beta().environments().delete(environment.id());
780780 ```
781781 
from line 784
784784 $environments = $client->beta->environments->list();
785785 // Retrieve a specific environment
786786 $env = $client->beta->environments->retrieve($environment->id);
787 // Archive an environment (read-only, existing sessions continue)
787 // Archive an environment (read-only, no new sessions)
788788 $client->beta->environments->archive($environment->id);
789 // Delete an environment (only if no sessions reference it)
789 // Delete an environment
790790 $client->beta->environments->delete($environment->id);
791791 ```
792792 
from line 797
797797 # Retrieve a specific environment
798798 env = client.beta.environments.retrieve(environment.id)
799799 
800 # Archive an environment (read-only, existing sessions continue)
800 # Archive an environment (read-only, no new sessions)
801801 client.beta.environments.archive(environment.id)
802802 
803 # Delete an environment (only if no sessions reference it)
803 # Delete an environment
804804 client.beta.environments.delete(environment.id)
805805 ```
806806</CodeGroup>

managed-agents/quickstart Changed · +6 / -6 lines

from line 81
8181 For Linux environments, download the release binary directly.
8282 
8383 ```bash
84 VERSION=2.6.0
84 VERSION=2.7.0
8585 OS=$(uname -s | tr '[:upper:]' '[:lower:]')
8686 case $(uname -m) in
8787 x86_64) ARCH=amd64 ;;
from line 95
9595 </Tab>
9696 
9797 <Tab title="go install">
98 You can also install the CLI from source using `go install`. Requires Go 1.25 or later.
98 You can also install the CLI from source with `go install`, which requires Go 1.26.10 or later.
9999 
100100 ```bash
101101 go install github.com/anthropics/anthropic-cli/v2/cmd/ant@latest
102102 ```
103103 
104 The binary is placed in `$(go env GOPATH)/bin`. Add it to your `PATH` if it isn’t already:
104 `go install` places the binary in `$(go env GOPATH)/bin`. Add that directory to your `PATH` if it isn’t already there:
105105 
106106 ```bash
107107 export PATH="$PATH:$(go env GOPATH)/bin"
from line 150
150150 For Linux environments, download the release binary directly.
151151 
152152 ```bash
153 VERSION=2.6.0
153 VERSION=2.7.0
154154 OS=$(uname -s | tr '[:upper:]' '[:lower:]')
155155 case $(uname -m) in
156156 x86_64) ARCH=amd64 ;;
from line 164
164164 </Tab>
165165 
166166 <Tab title="go install">
167 You can also install the CLI from source using `go install`. Requires Go 1.25 or later.
167 You can also install the CLI from source with `go install`, which requires Go 1.26.10 or later.
168168 
169169 ```bash
170170 go install github.com/anthropics/anthropic-cli/v2/cmd/ant@latest
171171 ```
172172 
173 The binary is placed in `$(go env GOPATH)/bin`. Add it to your `PATH` if it isn’t already:
173 `go install` places the binary in `$(go env GOPATH)/bin`. Add that directory to your `PATH` if it isn’t already there:
174174 
175175 ```bash
176176 export PATH="$PATH:$(go env GOPATH)/bin"

managed-agents/self-hosted-sandboxes-operations Changed · +5 / -5 lines

from line 30
3030 - claude-sonnet-4-5-20250929
3131---
3232 
33The monitoring calls on this page run from your monitoring or operations tooling, authenticated with your Claude API key. The worker helpers handle the claim and keep-alive loop, so you don’t call those endpoints directly.
33The queue statistics and stop calls on this page run from your monitoring or operations tooling, authenticated with your organization API key. The worker helpers handle the claim and keep-alive loop, so you don’t call those endpoints directly.
3434 
3535<Warning>
36 These endpoints accept either your organization API key or the environment key. Call them from outside the worker host with your organization API key. Setting `ANTHROPIC_API_KEY` on the worker host exposes an organization-scoped credential to agent tool calls.
36 The queue statistics and stop endpoints accept either your organization API key or the environment key. Call them from outside the worker host with your organization API key. Setting `ANTHROPIC_API_KEY` on the worker host exposes an organization-scoped credential to agent tool calls.
3737</Warning>
3838 
3939## Read queue depth
from line 176
176176 
177177By default the work item moves to `stopping`. The worker detects this on its next lease heartbeat, cancels the session’s in-flight tool call, and confirms the shutdown. The work item then becomes `stopped`. A Python SDK worker instead lets the in-flight tool call complete first, which can take up to 2.5 minutes.
178178 
179Pass `force: true` (python: `force=True`; cli: `--force`) to mark the work item `stopped` immediately instead of waiting for the worker’s confirmation. A forced stop doesn’t end an in-flight tool call any sooner, because the worker still detects the stop on its next heartbeat.
179Pass `force: true` (python: `force=True`; csharp: `Force = true`; go: `BetaSelfHostedWorkStopRequest: anthropic.BetaSelfHostedWorkStopRequestParam{Force: anthropic.Bool(true)}`; java: `.force(true)`; cli: `--force`) to mark the work item `stopped` immediately instead of waiting for the worker’s confirmation. A forced stop doesn’t end an in-flight tool call any sooner, because the worker still detects the stop on its next heartbeat.
180180 
181Because these calls run from your operations tooling rather than the worker host, `ANTHROPIC_WORK_ID` isn’t set automatically. Set it to the target work item’s ID before running the following examples. To find a work item’s ID, list the environment’s work items through the [Environments Work endpoints](https://platform.claude.com/docs/en/api/beta/environments/work).
181Because these calls run from your operations tooling rather than the worker host, `ANTHROPIC_WORK_ID` isn’t set automatically. Set it to the target work item’s ID before running the following examples. To find a work item’s ID, call [List Work Items](https://platform.claude.com/docs/en/api/beta/environments/work/list) with the environment key, sent as `Authorization: Bearer $ANTHROPIC_ENVIRONMENT_KEY`. That endpoint rejects your organization API key.
182182 
183183<CodeGroup>
184184 ```bash cURL

models/haiku-5-5/migration-guide Changed · +6 / -6 lines

from line 14
1414/claude-api migrate this project to claude-haiku-5-5
1515```
1616 
17This guide covers moving code that calls Claude Haiku 4.5 to Claude Haiku 5.5. For code that calls Claude Haiku 3.5 or Claude Haiku 3, also make the changes in [Migrating to Claude Haiku 5.5 from Claude Haiku 3.5 and earlier Haiku models](https://platform.claude.com/docs/en/models/haiku-5-5/migration-guide#migrating-from-haiku-35). To move up to a Sonnet or Opus model instead, see [Upgrade between model versions](https://platform.claude.com/docs/en/about-claude/models/migration-guide). For how long Claude Haiku 4.5 stays available, see [Model deprecations](https://platform.claude.com/docs/en/about-claude/model-deprecations).
17This guide covers moving code that calls Claude Haiku 4.5 to Claude Haiku 5.5. For code that calls Claude Haiku 3.5 or Claude Haiku 3, also make the changes in [Migrating to Claude Haiku 5.5 from Claude Haiku 3.5 and earlier Haiku models](https://platform.claude.com/docs/en/models/haiku-5-5/migration-guide#migrating-from-haiku-35). To move up to a Sonnet or Opus model instead, see [Migration guides](https://platform.claude.com/docs/en/about-claude/models/migration-guide). For how long Claude Haiku 4.5 stays available, see [Model deprecations](https://platform.claude.com/docs/en/about-claude/model-deprecations).
1818 
1919## Migration checklist by starting model
2020 
from line 61
6161 
6262## Recount tokens
6363 
64Claude Haiku 5.5 uses the same newer tokenizer as Claude 4.7 and later models. As with all models that use this tokenizer, the same input text produces approximately 30 percent more tokens on Claude Haiku 5.5 than on Claude Haiku 4.5. The exact increase depends on the content. Requests, responses, and streaming events keep the same shape. What changes is anything you measure or budget in tokens:
64Claude Haiku 5.5 uses the same tokenizer as Claude 4.7 and later models. As with all models that use this tokenizer, the same input text produces approximately 30 percent more tokens on Claude Haiku 5.5 than on Claude Haiku 4.5. The exact increase depends on the content. Requests, responses, and streaming events keep the same shape. What changes is anything you measure or budget in tokens:
6565 
6666* `usage` fields and [token counting](https://platform.claude.com/docs/en/build-with-claude/token-counting) results are higher for the same text.
6767* A given number of tokens holds less text.
6868* A `max_tokens` limit tuned for Claude Haiku 4.5 might cut off equivalent output.
69* Cost estimates made from Claude Haiku 4.5’s token counts need recomputing with Claude Haiku 5.5’s counts and [prices](https://platform.claude.com/docs/en/about-claude/pricing), including its higher prices for long prompts. See [Long context pricing](https://platform.claude.com/docs/en/about-claude/pricing#long-context-pricing).
69* Cost estimates made from Claude Haiku 4.5’s token counts need recomputing with Claude Haiku 5.5’s counts and prices, including its higher prices for long prompts. See [Pricing](https://platform.claude.com/docs/en/about-claude/pricing) and [Long context pricing](https://platform.claude.com/docs/en/about-claude/pricing#long-context-pricing).
7070 
7171Large images can also cost more tokens. Claude Haiku 5.5 uses the high-resolution image tier, which downscales images above 2,576 pixels on the long edge or 4,784 visual tokens. Claude Haiku 4.5 and earlier Haiku models use the standard tier, which downscales images above 1,568 pixels on the long edge or 1,568 visual tokens. An image of 2,000 by 1,500 pixels costs about 2.5 times as many visual tokens on Claude Haiku 5.5 as on Claude Haiku 4.5. See [Resolution and token cost](https://platform.claude.com/docs/en/build-with-claude/vision#evaluate-image-size).
7272 
from line 144
144144 
145145## Migrating to Claude Haiku 5.5 from Claude Haiku 3.5 and earlier Haiku models
146146 
147Claude Haiku 3.5 is retired on the Claude API and Amazon Bedrock, and Claude Haiku 3 is retired on the Claude API and Claude Models on Google Cloud (Google managed). Requests to a retired model fail. Claude Models on Google Cloud (Google managed) lists Claude Haiku 3.5 as deprecated and available only to existing customers. See [Model deprecations](https://platform.claude.com/docs/en/about-claude/model-deprecations).
147Claude Haiku 3.5 is retired on the Claude API, Amazon Bedrock, and Claude Models on Google Cloud (Google managed). Claude Haiku 3 is retired on the Claude API and Claude Models on Google Cloud (Google managed). See [Model deprecations](https://platform.claude.com/docs/en/about-claude/model-deprecations).
148148 
149149From either model, first apply every preceding section, then these changes:
150150 
from line 151
151151* **Model ID:** Replace `claude-3-5-haiku-20241022`, its alias `claude-3-5-haiku-latest`, or `claude-3-haiku-20240307` with `claude-haiku-5-5`. On Claude Models on Google Cloud (Google managed), replace `claude-3-5-haiku@20241022` with `claude-haiku-5-5`. On Amazon Bedrock, use the Claude Haiku 5.5 ID from [Use the Claude Haiku 5.5 model ID](https://platform.claude.com/docs/en/models/haiku-5-5/migration-guide#use-the-claude-haiku-5-5-model-id).
152152* **Code execution:** Claude Haiku 5.5 accepts `code_execution_20250825` and later versions. If you use the Python-only `code_execution_20250522`, move to one of them. See [Upgrade to latest tool version](https://platform.claude.com/docs/en/agents-and-tools/tool-use/code-execution-tool#upgrade-to-latest-tool-version).
153153* **Text editor:** If you use the text editor tool, move to `text_editor_20250728` (tool name `str_replace_based_edit_tool`), which has no `undo_edit` command. See [Text editor tool](https://platform.claude.com/docs/en/agents-and-tools/tool-use/text-editor-tool).
154* **Stop reasons:** Handle `refusal` and `model_context_window_exceeded`. See [Handling stop reasons](https://platform.claude.com/docs/en/build-with-claude/handling-stop-reasons).
154* **Stop reasons:** Handle `refusal` and `model_context_window_exceeded`. See [Stop reasons and fallback](https://platform.claude.com/docs/en/build-with-claude/handling-stop-reasons).
155155* **Trailing newlines:** Claude 4.5 and later models keep trailing newlines in tool call string parameters. If your code matches those strings exactly, allow for them.
156* **Prompts:** Claude 4 and later models have a more concise, direct communication style and need explicit direction. Review your prompts against [Prompting Claude Haiku 5.5](https://platform.claude.com/docs/en/build-with-claude/prompt-engineering/prompting-claude-haiku-5-5) and [prompting best practices](https://platform.claude.com/docs/en/build-with-claude/prompt-engineering/claude-prompting-best-practices).
156* **Prompts:** Claude 4 and later models have a more concise, direct communication style and need explicit direction. Review your prompts against [Prompting Claude Haiku 5.5](https://platform.claude.com/docs/en/build-with-claude/prompt-engineering/prompting-claude-haiku-5-5) and [Prompting best practices](https://platform.claude.com/docs/en/build-with-claude/prompt-engineering/claude-prompting-best-practices).
157157 

about-claude/additional-resources Changed · +1 / -1 lines

from line 7
77## Learning resources
88 
99<CardGroup cols={3}>
10 <Card title="Quickstarts" icon="lightning" href="https://github.com/anthropics/anthropic-quickstarts">
10 <Card title="Quickstarts" icon="lightning" href="https://github.com/anthropics/claude-quickstarts">
1111 Deployable applications built with the API.
1212 </Card>
1313 

agents-and-tools/tool-use/code-execution-tool Changed · +1 / -3 lines

from line 868
868868 file_ids = []
869869 response.content.each do |item|
870870 if item.type == :bash_code_execution_tool_result
871 # WORKAROUND for anthropic-sdk-ruby union coercion bug (SDK-636): item.content is a
872 # nested content union, so the typed accessors on `item.content` are unreliable.
873 # Read the raw response data through the public `BaseModel#[]` API instead.
871 # Collect the file IDs from the tool result
874872 content_item = item.content
875873 if content_item[:type].to_s == "bash_code_execution_result"
876874 Array(content_item[:content]).each do |output_block|

agents-and-tools/tool-use/troubleshooting-tool-use Changed · +1 / -1 lines

from line 33
3333| Symptom | Likely cause | Fix |
3434| ------------------------------------------- | --------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
3535| Every request is a cache miss | `tool_choice`, the thinking configuration, or `output_config.effort` varying between requests | Keep `tool_choice` stable or place the `cache_control` breakpoint before the variation point; hold the thinking configuration and effort level constant for the life of a cached conversation. See [Tool use with prompt caching](https://platform.claude.com/docs/en/agents-and-tools/tool-use/tool-use-with-prompt-caching) and [Thinking and prompt caching](https://platform.claude.com/docs/en/build-with-claude/thinking#thinking-and-prompt-caching). |
36| Adding a tool mid-conversation breaks cache | Tool prepended to the tools array | Use `defer_loading: true` with tool search to append the tool inline instead of modifying the array head. |
36| Adding a tool mid-conversation breaks cache | Tool prepended to the tools array | Declare the tool with `defer_loading: true` from the first request and let tool search load it inline, instead of adding it to the array later. |
3737 
3838## Errors at request time
3939 

api/beta/messages/batches/create Changed · +1 / -1 lines

from line 3260
32603260 
32613261 - `max_tokens: optional number or null`
32623262 
3263 Bounds the advisor's total output (thinking + text) per call. When the advisor hits this cap, the returned advisor_result or advisor_redacted_result block carries stop_reason='max_tokens', and a truncation note is appended to the advice text the worker model sees (inside the encrypted blob in redacted mode). When set, the server also emits a remaining-tokens budget block in the advisor's prompt so the advisor self-shapes toward the cap. When omitted, the advisor model's default output cap applies and no budget block is emitted.
3263 Bounds the advisor's total output (thinking + text) per call. When the advisor hits this cap, the returned advisor_result or advisor_redacted_result block carries stop_reason='max_tokens', and a truncation note is appended to the advice text the worker model sees (inside the encrypted blob in redacted mode). When set, the API also passes the advisor its remaining-token budget, so the advisor shapes its output toward the cap. When omitted, the advisor model's default output cap applies and the API doesn't pass a budget.
32643264 
32653265 minimum: 1024
32663266 

api/beta/messages/count_tokens Changed · +1 / -1 lines

from line 3228
32283228 
32293229 - `max_tokens: optional number or null`
32303230 
3231 Bounds the advisor's total output (thinking + text) per call. When the advisor hits this cap, the returned advisor_result or advisor_redacted_result block carries stop_reason='max_tokens', and a truncation note is appended to the advice text the worker model sees (inside the encrypted blob in redacted mode). When set, the server also emits a remaining-tokens budget block in the advisor's prompt so the advisor self-shapes toward the cap. When omitted, the advisor model's default output cap applies and no budget block is emitted.
3231 Bounds the advisor's total output (thinking + text) per call. When the advisor hits this cap, the returned advisor_result or advisor_redacted_result block carries stop_reason='max_tokens', and a truncation note is appended to the advice text the worker model sees (inside the encrypted blob in redacted mode). When set, the API also passes the advisor its remaining-token budget, so the advisor shapes its output toward the cap. When omitted, the advisor model's default output cap applies and the API doesn't pass a budget.
32323232 
32333233 minimum: 1024
32343234 

api/beta/organization/analytics/artifacts Changed · +1 / -1 lines

from line 27
2727 
2828- `filter: optional array of string`
2929 
30 Filters as `dimension:value`, e.g. `filter[]=rbac_group_id:{id}`. Repeat the param for OR within a dimension and across dimensions for AND. Supported dimensions on this endpoint: `artifact_type`, `is_shared`, `product`, `rbac_group_id`, `user_id`. Value forms: `artifact_type` is a canonical artifact MIME type (e.g. `text/markdown`) or `other`; `is_shared` is `true` or `false`; `product` is `chat_cowork_unified`, `chat`, `claude_code`, or `cowork` (the surfaces that create artifacts); `rbac_group_id` takes the tagged id (`rbac_group_...`, as emitted in responses and by the spend-limits API) or a bare group UUID, and matches users who held the group at any point during each covered UTC day (time-of-usage attribution); `user_id` takes a tagged user id (`user_...`), as emitted in responses. An unsupported dimension returns 400. At most 100 entries. `chat_cowork_unified` is accepted as a `product` value only on deployments that offer Chat and Cowork unified.
30 Filters as `dimension:value`, e.g. `filter[]=rbac_group_id:{id}`. Repeat the param for OR within a dimension and across dimensions for AND. Supported dimensions on this endpoint: `artifact_type`, `is_shared`, `product`, `rbac_group_id`, `user_id`. Value forms: `artifact_type` is a canonical artifact MIME type (e.g. `text/markdown`) or `other`; `is_shared` is `true` or `false`; `product` is `chat_cowork_unified`, `chat`, `claude_code`, or `cowork` (the surfaces that create artifacts); `rbac_group_id` takes the tagged id (`rbac_group_...`, as emitted in responses and by the spend-limits API) or a bare group UUID, and matches users who held the group at any point during each covered UTC day (time-of-usage attribution); `user_id` takes a tagged user id (`user_...`), as emitted in responses. An unsupported dimension returns 400. At most 100 entries. `chat_cowork_unified` is accepted as a `product` value only where Chat and Cowork unified is available.
3131 
3232 maxItems: 100
3333 

api/beta/organization/analytics/artifacts/list Changed · +1 / -1 lines

from line 25
2525 
2626- `filter: optional array of string`
2727 
28 Filters as `dimension:value`, e.g. `filter[]=rbac_group_id:{id}`. Repeat the param for OR within a dimension and across dimensions for AND. Supported dimensions on this endpoint: `artifact_type`, `is_shared`, `product`, `rbac_group_id`, `user_id`. Value forms: `artifact_type` is a canonical artifact MIME type (e.g. `text/markdown`) or `other`; `is_shared` is `true` or `false`; `product` is `chat_cowork_unified`, `chat`, `claude_code`, or `cowork` (the surfaces that create artifacts); `rbac_group_id` takes the tagged id (`rbac_group_...`, as emitted in responses and by the spend-limits API) or a bare group UUID, and matches users who held the group at any point during each covered UTC day (time-of-usage attribution); `user_id` takes a tagged user id (`user_...`), as emitted in responses. An unsupported dimension returns 400. At most 100 entries. `chat_cowork_unified` is accepted as a `product` value only on deployments that offer Chat and Cowork unified.
28 Filters as `dimension:value`, e.g. `filter[]=rbac_group_id:{id}`. Repeat the param for OR within a dimension and across dimensions for AND. Supported dimensions on this endpoint: `artifact_type`, `is_shared`, `product`, `rbac_group_id`, `user_id`. Value forms: `artifact_type` is a canonical artifact MIME type (e.g. `text/markdown`) or `other`; `is_shared` is `true` or `false`; `product` is `chat_cowork_unified`, `chat`, `claude_code`, or `cowork` (the surfaces that create artifacts); `rbac_group_id` takes the tagged id (`rbac_group_...`, as emitted in responses and by the spend-limits API) or a bare group UUID, and matches users who held the group at any point during each covered UTC day (time-of-usage attribution); `user_id` takes a tagged user id (`user_...`), as emitted in responses. An unsupported dimension returns 400. At most 100 entries. `chat_cowork_unified` is accepted as a `product` value only where Chat and Cowork unified is available.
2929 
3030 maxItems: 100
3131 
Feedback