Follow Discord
Sweep 27 Oct 2026 · 19:04Z Build v2.1.312 531 read Stable v2.1.308 Latest v2.1.312 Next v2.1.312 Feeds RSS JSON llms.txt llms-full.txt Unofficial
One capture · api

One read of Claude Developer Platformapi-20261027T185806Z

260 pages moved out of 821 read.

Pages moved 260 significant first
Pages read 821 in this capture
Captured 18:58 UTC
Corpus hash 23cb04cc4921 corpus-hash

What this read moved

151-175 of 260, page 7 of 11

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

manage-claude/cmek-troubleshooting Changed · +19 / -19 lines

### The workspace doesn’t retain data ### The workspace doesn't retain data

from line 4
44description: Find the cause and fix for a CMEK error message, a failed verification, or an unexpected log entry.
55---
66 
7**Verify** in the Claude Console, **Add** on claude.ai, and the Admin API's validate call all run the same check. When it fails (**Connection failed** in the Claude Console), see the causes for [AWS KMS](https://platform.claude.com/docs/en/manage-claude/cmek-troubleshooting#aws-kms), [Google Cloud KMS](https://platform.claude.com/docs/en/manage-claude/cmek-troubleshooting#google-cloud-kms), or [Azure Key Vault](https://platform.claude.com/docs/en/manage-claude/cmek-troubleshooting#azure-key-vault).
7**Verify** in the Claude Console, **Add** on claude.ai, and the Admin API’s validate call all run the same check. When it fails (**Connection failed** in the Claude Console), see the causes for [AWS KMS](https://platform.claude.com/docs/en/manage-claude/cmek-troubleshooting#aws-kms), [Google Cloud KMS](https://platform.claude.com/docs/en/manage-claude/cmek-troubleshooting#google-cloud-kms), or [Azure Key Vault](https://platform.claude.com/docs/en/manage-claude/cmek-troubleshooting#azure-key-vault).
88 
99If a feature stopped working, it might be one that customer-managed encryption keys (CMEK) turn off. Check the [Claude Platform list](https://platform.claude.com/docs/en/manage-claude/cmek-coverage-claude-platform#turned-off-or-changed) or [Claude Enterprise list](https://platform.claude.com/docs/en/manage-claude/cmek-coverage-claude-enterprise#turned-off-or-changed).
1010 
from line 18
1818Customer-managed encryption key is disabled or revoked. Re-enable the key to restore access.
1919```
2020 
21This 400 error means your key management service refused Anthropic's call. Check these causes in order:
21This 400 error means your key management service refused Anthropic’s call. Check these causes in order:
2222 
23231. The key is disabled.
242. Anthropic's access to the key was removed. [Your setup page](https://platform.claude.com/docs/en/manage-claude/cmek#set-it-up) shows the access Anthropic needs.
242. Anthropic’s access to the key was removed. [Your setup page](https://platform.claude.com/docs/en/manage-claude/cmek#set-it-up) shows the access Anthropic needs.
25253. On AWS KMS, the key policy [lists workspaces](https://platform.claude.com/docs/en/manage-claude/cmek-aws-kms-workspaces) but not this one.
264. On AWS KMS, an IP condition blocks [Anthropic's outbound IP addresses](https://platform.claude.com/docs/en/api/ip-addresses#outbound-ip-addresses).
264. On AWS KMS, an IP condition blocks [Anthropic’s outbound IP addresses](https://platform.claude.com/docs/en/api/ip-addresses#outbound-ip-addresses).
2727 
2828Fix the cause. [Two limits apply](https://platform.claude.com/docs/en/manage-claude/cmek-key-lifecycle#restore-access) when access returns.
2929 
from line 33
3333The request to your key management service was blocked by its network access controls (for example, a KMS firewall or IP allowlist). Verify that your KMS network rules allow requests from Anthropic's published IP addresses, or contact Anthropic support if your configuration looks correct.
3434```
3535 
36This is a 400 error. The key itself might be healthy. Allow [Anthropic's published IP addresses](https://platform.claude.com/docs/en/api/ip-addresses) in your key management service's network rules.
36This is a 400 error. The key itself might be healthy. Allow [Anthropic’s published IP addresses](https://platform.claude.com/docs/en/api/ip-addresses) in your key management service’s network rules.
3737 
3838### `cmek_key_unreachable`
3939 
from line 41
4141The workspace's customer-managed encryption key could not be reached. Try again shortly. If this continues, check that the key is available in your key management service, or contact Anthropic support.
4242```
4343 
44This 503 error means [Anthropic couldn't reach your key](https://platform.claude.com/docs/en/manage-claude/cmek-key-lifecycle#unreachable-key). Retry the request.
44This 503 error means [Anthropic couldn’t reach your key](https://platform.claude.com/docs/en/manage-claude/cmek-key-lifecycle#unreachable-key). Retry the request.
4545 
4646## Verification fails: AWS KMS
4747 
from line 49
4949| ---------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
5050| Wrong organization ID | The `org_uuid` condition must list [your Anthropic organization ID](https://platform.claude.com/docs/en/manage-claude/cmek-aws-kms#prerequisites), the UUID without the `org_` prefix. |
5151| A workspace is missing from the policy | A `compartment_uuid` condition must [list the compartment ID](https://platform.claude.com/docs/en/manage-claude/cmek-aws-kms-workspaces) of each workspace the key is attached to. |
52| Access granted through IAM instead of the key policy | Anthropic's role needs access in [the key policy itself](https://platform.claude.com/docs/en/manage-claude/cmek-aws-kms#key-policy). |
52| Access granted through IAM instead of the key policy | Anthropic’s role needs access in [the key policy itself](https://platform.claude.com/docs/en/manage-claude/cmek-aws-kms#key-policy). |
5353 
5454To print the key policy, run:
5555 
from line 62
6262 
6363### A key that already protects data
6464 
65If you're [replacing the policy on a key](https://platform.claude.com/docs/en/manage-claude/cmek-aws-kms-workspaces#replace-the-key-policy) that already protects data, add this statement so Anthropic can still decrypt that data. In its condition, list the compartment ID of every workspace the key is or was attached to.
65If you’re [replacing the policy on a key](https://platform.claude.com/docs/en/manage-claude/cmek-aws-kms-workspaces#replace-the-key-policy) that already protects data, add this statement so Anthropic can still decrypt that data. In its condition, list the compartment ID of every workspace the key is or was attached to.
6666 
6767```json
6868{
from line 86
8686| Cause | Fix |
8787| --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
8888| Wrong organization label | The key needs the [organization label](https://platform.claude.com/docs/en/manage-claude/cmek-google-cloud-kms#organization-label), with your Anthropic organization ID in lowercase. |
89| Domain restricted sharing | This organization policy blocks the grant to Anthropic's service account. [Add an exception](https://platform.claude.com/docs/en/manage-claude/cmek-google-cloud-kms#prerequisites). |
90| Disabled or destroyed key version | The key's primary version must be enabled. |
89| Domain restricted sharing | This organization policy blocks the grant to Anthropic’s service account. [Add an exception](https://platform.claude.com/docs/en/manage-claude/cmek-google-cloud-kms#prerequisites). |
90| Disabled or destroyed key version | The key’s primary version must be enabled. |
9191 
9292To check the grant, run:
9393 
from line 102
102102 
103103| Cause | Fix |
104104| ----------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
105| Wrong organization tag | The key's current version needs the [organization tag](https://platform.claude.com/docs/en/manage-claude/cmek-azure-key-vault#organization-tag). |
105| Wrong organization tag | The key’s current version needs the [organization tag](https://platform.claude.com/docs/en/manage-claude/cmek-azure-key-vault#organization-tag). |
106106| Role assignment not yet in effect | A new role assignment can take a few minutes. Wait, then try again. |
107| The vault's network rules block Anthropic | Check the rules against the [vault settings Anthropic needs](https://platform.claude.com/docs/en/manage-claude/cmek-azure-key-vault#check-your-vault-configuration). |
107| The vault’s network rules block Anthropic | Check the rules against the [vault settings Anthropic needs](https://platform.claude.com/docs/en/manage-claude/cmek-azure-key-vault#check-your-vault-configuration). |
108108 
109109## Attaching fails on Claude Platform on AWS
110110 
from line 115
115115| Key policy mismatch | Print the key policy with the [`get-key-policy` command](https://platform.claude.com/docs/en/manage-claude/cmek-troubleshooting#aws-kms) and compare it with the [policy on the setup page](https://platform.claude.com/docs/en/manage-claude/cmek-claude-platform-on-aws#prepare-the-key-policy). |
116116| Condition mismatch | Any `EncryptionContext` or `aws:SourceArn` condition must include this workspace. |
117117| Key state or location | The key must be enabled, single-Region, and in the same AWS account and region as the workspace. |
118| Missing permissions | The principal you're signed in as needs `kms:DescribeKey`, `kms:Encrypt`, and `kms:Decrypt` on the key. |
118| Missing permissions | The principal you’re signed in as needs `kms:DescribeKey`, `kms:Encrypt`, and `kms:Decrypt` on the key. |
119119 
120If attaching still fails, find the denied `kms:` event in CloudTrail in the key's account. It shows the calling principal and, for cryptographic calls, the encryption context. Fix the cause, then click **Save** again.
120If attaching still fails, find the denied `kms:` event in CloudTrail in the key’s account. It shows the calling principal and, for cryptographic calls, the encryption context. Fix the cause, then click **Save** again.
121121 
122122## Attaching or adding a key is refused
123123 
124### The workspace doesn't retain data
124### The workspace doesn’t retain data
125125 
126126```text wrap
127127CMEK keys can only be attached to workspaces in this organization that have inference data retention enabled.
from line 131
131131 
132132### The workspace has no Encryption key setting
133133 
134Only [a workspace that retains data](https://platform.claude.com/docs/en/manage-claude/cmek-data-retention#data-retention) has this setting, so select **Standard data retention** for the workspace first. A ZDR organization's default workspace can't be switched, so use another.
134Only [a workspace that retains data](https://platform.claude.com/docs/en/manage-claude/cmek-data-retention#data-retention) has this setting, so select **Standard data retention** for the workspace first. A ZDR organization’s default workspace can’t be switched, so use another.
135135 
136136### There is no Encryption keys section
137137 
138In the Claude Console, select **Organization** from the dropdown menu at the top of the Data retention page. If the section is still missing, your role doesn't include it or CMEK isn't turned on for your organization. Your Anthropic account team turns CMEK on.
138In the Claude Console, select **Organization** from the dropdown menu at the top of the Data retention page. If the section is still missing, your role doesn’t include it or CMEK isn’t turned on for your organization. Your Anthropic account team turns CMEK on.
139139 
140140### The workspace already has a key
141141 
from line 143
143143This workspace already has a different external key attached.
144144```
145145 
146A workspace's key can't be replaced, so [create a new workspace](https://platform.claude.com/docs/en/manage-claude/cmek-key-lifecycle#change-keys) for a different key.
146A workspace’s key can’t be replaced, so [create a new workspace](https://platform.claude.com/docs/en/manage-claude/cmek-key-lifecycle#change-keys) for a different key.
147147 
148148### Adding a key on claude.ai fails
149149 
from line 163
163163* `userIdentity.accountId`: `915198916910`
164164* `resources.ARN`: `arn:aws:kms:<REGION>:<AWS_ACCOUNT_ID>:key/<KEY_ID>`
165165 
166The first value alone isn't enough, because any caller can set it.
166The first value alone isn’t enough, because any caller can set it.
167167 

manage-claude/compliance-activity-feed Changed · +10 / -10 lines

from line 51
5151 
5252## Filter activities
5353 
54Filter by organization, actor, activity type, or a `created_at` time window using the dotted sub-parameters `created_at.gte`, `.gt`, `.lte`, and `.lt`. See the [API reference](https://platform.claude.com/docs/en/api/compliance/activities/list) for each parameter's type and accepted values.
54Filter by organization, actor, activity type, or a `created_at` time window using the dotted sub-parameters `created_at.gte`, `.gt`, `.lte`, and `.lt`. See the [API reference](https://platform.claude.com/docs/en/api/compliance/activities/list) for each parameter’s type and accepted values.
5555 
5656Repeatable parameters use array-bracket query syntax: pass `activity_types[]=...`, `actor_ids[]=...`, or `organization_ids[]=...` once for each value.
5757 
from line 86
8686 
8787To page through activities:
8888 
89* Pass the response's `last_id` as `after_id` to advance to the next page in result order. With activities sorted newest first, the next page contains older entries.
89* Pass the response’s `last_id` as `after_id` to advance to the next page in result order. With activities sorted newest first, the next page contains older entries.
9090* Pass `first_id` as `before_id` to return to the previous page.
9191* Stop when `has_more` is `false`.
9292 
93The cursor parameter sets the page direction; the endpoint's sort order sets the time direction. The same `after_id` parameter reaches older activities here. Chats sort oldest first; see [Retrieve and delete chats, files, and projects](https://platform.claude.com/docs/en/manage-claude/compliance-content-data) for the cursor semantics there.
93The cursor parameter sets the page direction; the endpoint’s sort order sets the time direction. The same `after_id` parameter reaches older activities here. Chats sort oldest first; see [Retrieve and delete chats, files, and projects](https://platform.claude.com/docs/en/manage-claude/compliance-content-data) for the cursor semantics there.
9494 
9595<Note>
9696 **Cursors are safe to reuse on retry.** A cursor or page token from a successfully returned page remains valid; a request that fails (5xx, timeout, network error) does not advance your position. Retry the same request with the same cursor. Only move to the next cursor after you have stored the page it points past.
9797 
98 Page tokens on the local session endpoints are the exception over longer pauses. On the [local session messages endpoint](https://platform.claude.com/docs/en/manage-claude/compliance-sessions#retrieve-a-local-session-transcript), a walk's `page` tokens expire 24 hours after its first page (a walk is one pass through the pages), so finish or resume within that window, or restart without the `page` parameter. On the [local session list](https://platform.claude.com/docs/en/manage-claude/compliance-sessions#retrieve-local-sessions), an older `page` token is still accepted but is re-evaluated against the current retention boundary and can skip sessions, so complete list walks within 24 hours as well.
98 Page tokens on the local session endpoints are the exception over longer pauses. On the [local session messages endpoint](https://platform.claude.com/docs/en/manage-claude/compliance-sessions#retrieve-a-local-session-transcript), a walk’s `page` tokens expire 24 hours after its first page (a walk is one pass through the pages), so finish or resume within that window, or restart without the `page` parameter. On the [local session list](https://platform.claude.com/docs/en/manage-claude/compliance-sessions#retrieve-local-sessions), an older `page` token is still accepted but is re-evaluated against the current retention boundary and can skip sessions, so complete list walks within 24 hours as well.
9999</Note>
100100 
101101```bash cURL
from line 118
118118 
1191191. Start from your stored cursor (or omit `after_id` to start from the beginning).
1201202. Page through with `after_id=<last_id>` until `has_more` is `false`.
1213. Persist the final `last_id` only after you've stored every page it covers.
1213. Persist the final `last_id` only after you’ve stored every page it covers.
122122 
123123```text
124124cursor = stored_cursor
from line 142
142142| ------------------- | --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
143143| `id` | string | Unique identifier for the activity. |
144144| `created_at` | RFC 3339 string | When the activity occurred. |
145| `organization_id` | string or null | Organization where the activity occurred, or `null` for events not tied to an organization (sign-in, sign-out, Compliance API calls). |
145| `organization_id` | string or null | Organization where the activity occurred, or `null` for events not tied to an organization. |
146146| `organization_uuid` | string or null | Same scoping as `organization_id`, expressed as a UUID. |
147147| `actor` | Actor union | Who or what performed the activity. See the following actor table. |
148148| `type` | string | The activity type, for example `claude_chat_created`. |
from line 152
152152 
153153| `actor.type` | When it appears | Key fields |
154154| ---------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
155| `user_actor` | A signed-in claude.ai or Claude Console user took the action. Processes Anthropic runs on the user's behalf can also appear as this type; see the paragraph after this table. | `email_address`, `user_id`, `ip_address`, `user_agent` |
155| `user_actor` | A signed-in claude.ai or Claude Console user took the action. Processes Anthropic runs on the user’s behalf can also appear as this type; see the paragraph after this table. | `email_address`, `user_id`, `ip_address`, `user_agent` |
156156| `api_actor` | A request called the Claude API or the Compliance API with a customer-issued API key. Compliance API calls produce this actor type for both Compliance Access Keys and Admin API keys. | `api_key_id`, `ip_address`, `user_agent` |
157157| `admin_api_key_actor` | An organization admin used an Admin API key to manage users, invites, workspaces, or API keys. | `admin_api_key_id`, `ip_address`, `user_agent` |
158158| `unauthenticated_user_actor` | An action occurred before sign-in completed, for example `sso_login_initiated`. | `unauthenticated_email_address`, `ip_address`, `user_agent` |
from line 160
160160| `system_actor` | Automated background processing performed by Anthropic systems, acting without a user or customer credential. | `service` (nullable; the name of the automated process that performed the action, when known) |
161161| `scim_directory_sync_actor` | An identity provider (such as Okta, Microsoft Entra ID, or JumpCloud) pushed a change through SCIM directory sync. | `workos_event_id`, `directory_id`, `idp_connection_type` (nullable; for example `OktaSCIMV2`, `AzureSCIMV2`) |
162162 
163A `user_actor` activity does not always mean the user took the action. Processes that Anthropic runs on a user's behalf can currently appear as `user_actor` for the affected user rather than as `system_actor`, and this attribution may change. For example, memory activities from a migration, such as `platform_memory_store_created`, `platform_memory_created`, and `platform_memory_deleted`, are attributed this way. The memory activities `platform_memory_store_created`, `platform_memory_created`, `platform_memory_updated`, and `platform_memory_deleted` currently show an `ip_address` of `0.0.0.0` whoever performed them. As a result, this value does not on its own identify a process that Anthropic runs on the user's behalf.
163A `user_actor` activity does not always mean the user took the action. Processes that Anthropic runs on a user’s behalf can currently appear as `user_actor` for the affected user rather than as `system_actor`, and this attribution may change. For example, memory activities from a migration, such as `platform_memory_store_created`, `platform_memory_created`, and `platform_memory_deleted`, are attributed this way. The memory activities `platform_memory_store_created`, `platform_memory_created`, `platform_memory_updated`, and `platform_memory_deleted` currently show an `ip_address` of `0.0.0.0` whoever performed them. As a result, this value does not on its own identify a process that Anthropic runs on the user’s behalf.
164164 
165A `claude_*_viewed` activity means a Claude app loaded content, not that a person viewed it. Types such as `claude_chat_viewed`, `claude_file_viewed`, and `claude_project_viewed` are recorded each time a Claude app loads the chat, file, or project from Anthropic's servers. Repeated loads are not deduplicated. The web, desktop, and mobile apps load content at different moments, sometimes in the background, and can display a cached copy without loading it. Counts of these activities vary by platform as a result, and they do not correspond to messages sent or screens viewed.
165A `claude_*_viewed` activity means a Claude app loaded content, not that a person viewed it. Types such as `claude_chat_viewed`, `claude_file_viewed`, and `claude_project_viewed` are recorded each time a Claude app loads the chat, file, or project from Anthropic’s servers. Repeated loads are not deduplicated. The web, desktop, and mobile apps load content at different moments, sometimes in the background, and can display a cached copy without loading it. Counts of these activities vary by platform as a result, and they do not correspond to messages sent or screens viewed.
166166 
167Activities about a file, project document, or artifact do not include its name or title. As of September 24, 2026, the `filename` and `title` fields on these activities are always `null`, an empty string, or omitted, including on activities recorded before that date. To look up a name or title, pass the activity's `claude_file_*`, `claude_proj_doc_*`, or `claude_artifact_version_*` ID to the matching metadata endpoint in [Retrieve files and artifacts](https://platform.claude.com/docs/en/manage-claude/compliance-content-data#retrieve-files-and-artifacts), using a Compliance Access Key with the `read:compliance_user_data` scope. You cannot look up a name or title after the file, document, or artifact is deleted, or when the activity has no such ID.
167Activities about a file, project document, or artifact do not include its name or title. As of September 24, 2026, the `filename` and `title` fields on these activities are always `null`, an empty string, or omitted, including on activities recorded before that date. To look up a name or title, pass the activity’s `claude_file_*`, `claude_proj_doc_*`, or `claude_artifact_version_*` ID to the matching metadata endpoint in [Retrieve files and artifacts](https://platform.claude.com/docs/en/manage-claude/compliance-content-data#retrieve-files-and-artifacts), using a Compliance Access Key with the `read:compliance_user_data` scope. You cannot look up a name or title after the file, document, or artifact is deleted, or when the activity has no such ID.
168168 
169169<Note>
170170 **Build forward-compatible handlers.** Pass through unrecognized `type` and `actor.type` values, and ignore fields your handler does not expect, so your integration keeps working when new activity types ship.

manage-claude/compliance-api Changed · +6 / -6 lines

from line 4
44description: Programmatic access to your organization's Claude activity, chats, files, projects, sessions in Claude apps, and users for compliance, audit, and governance.
55---
66 
7The Compliance API gives Claude Enterprise and Claude Console customers programmatic access to their organization's Activity Feed. For Claude Enterprise organizations, it also covers the directory of users, roles, and groups across every linked organization; the effective settings in force for each organization; the underlying chats, files, and projects in claude.ai organizations; and sessions in Cowork, Claude Code, Claude Science, Claude for Microsoft 365, the Claude add-ins for Google Docs, Google Sheets, and Google Slides, and Claude in Chrome. Security, legal, and compliance teams use it to audit activity, retrieve or delete content, and feed events into downstream tooling.
7The Compliance API gives Claude Enterprise and Claude Console customers programmatic access to their organization’s Activity Feed. For Claude Enterprise organizations, it also covers the directory of users, roles, and groups across every linked organization; the effective settings in force for each organization; the underlying chats, files, and projects in claude.ai organizations; and sessions in Cowork, Claude Code, Claude Science, Claude for Microsoft 365, the Claude add-ins for Google Docs, Google Sheets, and Google Slides, and Claude in Chrome. Security, legal, and compliance teams use it to audit activity, retrieve or delete content, and feed events into downstream tooling.
88 
99<Note>
1010 Two key types unlock the Compliance API. A **Compliance Access Key** (created in claude.ai) reaches every endpoint, and an **Admin API key** (created in Claude Console) reaches the Activity Feed only. See [Which key do you need?](https://platform.claude.com/docs/en/manage-claude/compliance-api-access#which-key-do-you-need) for the full key-type comparison.
from line 55
5555 
5656The Activity Feed (`GET /v1/compliance/activities`) is available to any key that carries the `read:compliance_activities` scope; see [Query the Activity Feed](https://platform.claude.com/docs/en/manage-claude/compliance-activity-feed) for filters, pagination, and the full `Activity` object. The remaining endpoints require a Compliance Access Key carrying the relevant scope.
5757 
58A Claude Enterprise tenant has one parent organization (the top-level container that centralizes identity) with linked organizations of two kinds: claude.ai organizations, where users chat and store content, and Claude Console organizations, where users manage Claude API workloads. For a key that covers the parent organization, the directory endpoints (organizations, users, roles, and groups) return data from every linked organization of either kind. The content endpoints (chats, files, projects, project attachments, and sessions) serve Claude Enterprise data only. The chat, file, and project endpoints return claude.ai chats, files, and projects. The session endpoints return transcripts of sessions on users' machines (local sessions), captured while users are signed in with their Claude Enterprise account: sessions in Cowork, Claude Code, Claude Science, Claude for Microsoft 365, the Claude add-ins for Google Docs, Google Sheets, and Google Slides, and Claude in Chrome. They also return transcripts of Cowork sessions started on claude.ai web or mobile, which run in the cloud in Anthropic-managed environments (remote sessions). A standalone Claude Console organization (one with no parent organization) is not part of a Claude Enterprise tenant; it uses Admin API keys and can query the Activity Feed only.
58A Claude Enterprise tenant has one parent organization (the top-level container that centralizes identity) with linked organizations of two kinds: claude.ai organizations, where users chat and store content, and Claude Console organizations, where users manage Claude API workloads. For a key that covers the parent organization, the directory endpoints (organizations, users, roles, and groups) return data from every linked organization of either kind. The content endpoints (chats, files, projects, project attachments, and sessions) serve Claude Enterprise data only. The chat, file, and project endpoints return claude.ai chats, files, and projects. The session endpoints return transcripts of sessions on users’ machines (local sessions), captured while users are signed in with their Claude Enterprise account: sessions in Cowork, Claude Code, Claude Science, Claude for Microsoft 365, the Claude add-ins for Google Docs, Google Sheets, and Google Slides, and Claude in Chrome. They also return transcripts of Cowork sessions started on claude.ai web or mobile, which run in the cloud in Anthropic-managed environments (remote sessions). A standalone Claude Console organization (one with no parent organization) is not part of a Claude Enterprise tenant; it uses Admin API keys and can query the Activity Feed only.
5959 
6060All `/v1/compliance/*` endpoints share a rate limit of 600 requests per minute for each parent organization (for a standalone Claude Console organization, for each organization). The local session endpoints count only against that shared limit, and the remote session endpoints carry a second request budget on top. See [429 Too Many Requests](https://platform.claude.com/docs/en/manage-claude/compliance-errors#429-too-many-requests) for the response headers and retry contract.
6161 
from line 73
7373 
7474### Export audit logs
7575 
76The audit log export is a separate feature in [claude.ai > Organization settings > Data and privacy](https://claude.ai/admin-settings/data-privacy-controls) that lets owners and primary owners download a CSV of organization events. It's significantly narrower than the Compliance API: a capped lookback window, CSV download only, and no access to chat, file, or project content. Standardize on the Compliance API for ongoing programmatic use.
76The audit log export is a separate feature in [claude.ai > Organization settings > Data and privacy](https://claude.ai/admin-settings/data-privacy-controls) that lets owners and primary owners download a CSV of organization events. It’s significantly narrower than the Compliance API: a capped lookback window, CSV download only, and no access to chat, file, or project content. Standardize on the Compliance API for ongoing programmatic use.
7777 
7878### Analytics API
7979 
from line 81
8181 
8282### OpenTelemetry logging
8383 
84[Cowork's OpenTelemetry logging](https://support.claude.com/en/articles/14477985-monitor-claude-cowork-activity-with-opentelemetry) and [Claude Code monitoring](https://code.claude.com/docs/en/monitoring-usage) stream per-event telemetry, including token, cost, and host metadata, to a collector you run as activity occurs, whereas the Compliance API returns retained per-session transcripts from Anthropic on request and works with your existing Compliance Access Key. OpenTelemetry logging can also capture prompts and responses, but Anthropic recommends the Compliance API for retrieving the content of Cowork and Claude Code sessions. For a table comparing local sessions, remote sessions, and OpenTelemetry logging, see the introduction to [Retrieve session transcripts](https://platform.claude.com/docs/en/manage-claude/compliance-sessions).
84[Cowork’s OpenTelemetry logging](https://support.claude.com/en/articles/14477985-monitor-claude-cowork-activity-with-opentelemetry) and [Claude Code monitoring](https://code.claude.com/docs/en/monitoring-usage) stream per-event telemetry, including token, cost, and host metadata, to a collector you run as activity occurs, whereas the Compliance API returns retained per-session transcripts from Anthropic on request and works with your existing Compliance Access Key. OpenTelemetry logging can also capture prompts and responses, but Anthropic recommends the Compliance API for retrieving the content of Cowork and Claude Code sessions. For a table comparing local sessions, remote sessions, and OpenTelemetry logging, see the introduction to [Retrieve session transcripts](https://platform.claude.com/docs/en/manage-claude/compliance-sessions).
8585 
8686### Inference hooks
8787 
88[Inference hooks](https://platform.claude.com/docs/en/manage-claude/inference-hooks) act inline: your organization's AI security server receives each governed prompt before inference and can deny it in real time, whereas the Compliance API retrieves records after the fact and returns richer data, such as organization settings and full non-text files.
88[Inference hooks](https://platform.claude.com/docs/en/manage-claude/inference-hooks) act inline: your organization’s AI security server receives each governed prompt before inference and can deny it in real time, whereas the Compliance API retrieves records after the fact and returns richer data, such as organization settings and full non-text files.
8989 
9090***
9191 
from line 109
109109 </Card>
110110 
111111 <Card href="https://platform.claude.com/docs/en/manage-claude/compliance-org-data" title="List organizations, users, roles, groups, and settings">
112 Enumerate linked organizations, members, roles, and directory groups, and read each organization's effective settings.
112 Enumerate linked organizations, members, roles, and directory groups, and read each organization’s effective settings.
113113 </Card>
114114 
115115 <Card href="https://platform.claude.com/docs/en/manage-claude/compliance-integration-patterns" title="Design your compliance integration">

manage-claude/compliance-api-access Changed · +10 / -10 lines

## Check your key’s scopes ## Check your key's scopes

from line 12
1212 **Required role:** organization admin (Claude Console), or primary owner or organization owner (claude.ai).
1313</Check>
1414 
15The Compliance API uses two key types, and which one you create depends on which Claude product your organization uses. Primary owners and organization owners create Compliance Access Keys in claude.ai; these keys unlock the full Compliance API. A primary owner's key can cover every organization under the parent organization; an organization owner's key covers their own organization only. Organization admins create Admin API keys in Claude Console; these keys unlock the [Activity Feed](https://platform.claude.com/docs/en/manage-claude/compliance-activity-feed) only.
15The Compliance API uses two key types, and which one you create depends on which Claude product your organization uses. Primary owners and organization owners create Compliance Access Keys in claude.ai; these keys unlock the full Compliance API. A primary owner’s key can cover every organization under the parent organization; an organization owner’s key covers their own organization only. Organization admins create Admin API keys in Claude Console; these keys unlock the [Activity Feed](https://platform.claude.com/docs/en/manage-claude/compliance-activity-feed) only.
1616 
1717## Which key do you need?
1818 
from line 23
2323| **Analytics API key** | [claude.ai > Organization settings > API](https://claude.ai/admin-settings/api-access) | The Claude Enterprise Analytics API (see [Analytics APIs](https://platform.claude.com/docs/en/manage-claude/analytics-api)) | No |
2424| **Claude API key** (`sk-ant-api03-...`) | [API keys](https://platform.claude.com/settings/keys) page (`platform.claude.com/settings/keys`) in the Claude Console | Calling Claude models through the [Claude API](https://platform.claude.com/docs/en/api/overview) | No |
2525 
26A Claude Enterprise tenant has one **parent organization** that centralizes identity, SSO, and SCIM for every workload organization beneath it. These workload organizations are the parent's **linked organizations**.
26A Claude Enterprise tenant has one **parent organization** that centralizes identity, SSO, and SCIM for every workload organization beneath it. These workload organizations are the parent’s **linked organizations**.
2727 
2828<Warning>
2929 **Claude Enterprise parent organizations do not appear in Claude Console (`platform.claude.com`).** The parent carries no workloads, no Claude API keys, and no Admin API keys. Create Compliance Access Keys in claude.ai **Organization settings**, not in Claude Console.
from line 42
4242 Where you enable the Compliance API depends on how your organization is set up:
4343 
4444 * **Claude Enterprise organizations:** The primary owner enables the Compliance API at [claude.ai > Organization settings > API](https://claude.ai/admin-settings/api-access). Enablement occurs at the parent organization level and cascades to every linked organization, both claude.ai and Claude Console.
45 * **Standalone Claude Console organizations:** An organization admin turns on the **Compliance API** toggle on the [Compliance](https://platform.claude.com/settings/security) page (`platform.claude.com/settings/security`) in the Claude Console. Enablement is self-service for eligible organizations, and the change takes effect immediately. If the page shows a page-not-found error, or doesn't show the **Compliance API** section, you do not have the admin role, your organization is linked to a parent organization (the Compliance API is enabled from the parent organization instead), or your organization is not eligible for self-service enablement; contact your account team or [Anthropic support](https://support.claude.com) if you are not sure which applies.
45 * **Standalone Claude Console organizations:** An organization admin turns on the **Compliance API** toggle on the [Compliance](https://platform.claude.com/settings/security) page (`platform.claude.com/settings/security`) in the Claude Console. Enablement is self-service for eligible organizations, and the change takes effect immediately. If the page shows a page-not-found error, or doesn’t show the **Compliance API** section, you do not have the admin role, your organization is linked to a parent organization (the Compliance API is enabled from the parent organization instead), or your organization is not eligible for self-service enablement; contact your account team or [Anthropic support](https://support.claude.com) if you are not sure which applies.
4646 * **Claude Console organizations linked to a parent organization:** There is nothing to turn on in Claude Console. Ask the primary owner of your parent organization to enable the Compliance API in claude.ai, or contact your account team.
4747 
4848 <Warning>
49 **Turning the Compliance API off stops activity recording.** An organization admin can turn the Compliance API off at any time with the same **Compliance API** toggle that turns it on. While the Compliance API is off, no activity events are recorded for your organization, so the [Activity Feed](https://platform.claude.com/docs/en/manage-claude/compliance-activity-feed) receives no new events. Activity that is not recorded while the Compliance API is off cannot be recovered later. Turning the Compliance API back on resumes recording from that point forward; activity that was already recorded is not deleted. Access Transparency events are an exception. If your organization is enrolled in [Access Transparency](https://platform.claude.com/docs/en/manage-claude/access-transparency), turning the Compliance API off stops your access to these events, not their recording. They are still recorded while the Compliance API is off, and the Activity Feed returns them after the Compliance API is turned back on. For Claude Enterprise organizations, the Compliance API setting in claude.ai also governs transcript capture for [local sessions](https://platform.claude.com/docs/en/manage-claude/compliance-sessions#retrieve-local-sessions) (sessions on users' machines): capture starts when the Compliance API is enabled and stops while it is off, and transcript content from sessions that run while it is off is not captured and cannot be recovered later.
49 **Turning the Compliance API off stops activity recording.** An organization admin can turn the Compliance API off at any time with the same **Compliance API** toggle that turns it on. While the Compliance API is off, no activity events are recorded for your organization, so the [Activity Feed](https://platform.claude.com/docs/en/manage-claude/compliance-activity-feed) receives no new events. Activity that is not recorded while the Compliance API is off cannot be recovered later. Turning the Compliance API back on resumes recording from that point forward; activity that was already recorded is not deleted. Access Transparency events are an exception. If your organization is enrolled in [Access Transparency](https://platform.claude.com/docs/en/manage-claude/access-transparency), turning the Compliance API off stops your access to these events, not their recording. They are still recorded while the Compliance API is off, and the Activity Feed returns them after the Compliance API is turned back on. For Claude Enterprise organizations, the Compliance API setting in claude.ai also governs transcript capture for [local sessions](https://platform.claude.com/docs/en/manage-claude/compliance-sessions#retrieve-local-sessions) (sessions on users’ machines): capture starts when the Compliance API is enabled and stops while it is off, and transcript content from sessions that run while it is off is not captured and cannot be recovered later.
5050 </Warning>
5151 
5252 A standalone Claude Console organization uses Admin API keys rather than Compliance Access Keys: after enablement, skip the remaining steps and [create a new Admin API key](https://platform.claude.com/docs/en/manage-claude/compliance-api-access#create-an-admin-api-key) instead. The remaining steps provision Compliance Access Keys, which are available only to organizations that are part of a Claude Enterprise tenant.
5353 </Step>
5454 
55 <Step title="Decide the key's scope">
56 A key's access is set when it is created. Decide which organizations the key covers:
55 <Step title="Decide the key’s scope">
56 A key’s access is set when it is created. Decide which organizations the key covers:
5757 
5858 * A key for the **parent organization** can access every organization under the parent organization.
5959 * A key for a **single organization** can access that organization only.
from line 79
7979 | `delete:compliance_user_data` | Delete user chats, files, and projects |
8080 | `read:compliance_org_data` | Read organization metadata (names, types, roles, and groups) and the effective settings in force for organizations under the parent organization. User listings and group membership require `read:compliance_user_data`. |
8181 
82 With the Plugins API, `read:compliance_org_data` also reads your organization's plugin and plugin marketplace inventory through the Admin API, including members' personal plugins and their files. That inventory identifies members: it carries the user ID of each member who owns or created a plugin, or with whom a plugin has been shared individually, and the email address of a plugin's creator while they are still a member; see [Read plugins and plugin marketplaces](https://platform.claude.com/docs/en/manage-claude/compliance-org-data#read-plugins-and-plugin-marketplaces).
82 With the Plugins API, `read:compliance_org_data` also reads your organization’s plugin and plugin marketplace inventory through the Admin API, including members’ personal plugins and their files. That inventory identifies members: it carries the user ID of each member who owns or created a plugin, or with whom a plugin has been shared individually, and the email address of a plugin’s creator while they are still a member; see [Read plugins and plugin marketplaces](https://platform.claude.com/docs/en/manage-claude/compliance-org-data#read-plugins-and-plugin-marketplaces).
8383 
8484 Choose the smallest scope set that your integration needs:
8585 
from line 119
119119 
120120Admin API keys carry the `read:compliance_activities` scope only if the Compliance API was enabled for the organization at the time the key was created; see [Set up the Compliance API](https://platform.claude.com/docs/en/manage-claude/compliance-api-access#set-up-the-compliance-api). They cannot be granted any other Compliance API scope, so calls to any endpoint other than the Activity Feed return [403 Forbidden](https://platform.claude.com/docs/en/manage-claude/compliance-errors#403-forbidden).
121121 
122For the same key's role in managing your Claude Console organization, see [Admin API](https://platform.claude.com/docs/en/manage-claude/admin-api).
122For the same key’s role in managing your Claude Console organization, see [Admin API](https://platform.claude.com/docs/en/manage-claude/admin-api).
123123 
124## Check your key's scopes
124## Check your key’s scopes
125125 
126126To inspect the scopes on a key you already have, use one of the following signals.
127127 
128128* **Key prefix.** `sk-ant-admin01-` is an Admin API key (carries `read:compliance_activities` only, subject to the enablement timing in the preceding section). `sk-ant-api01-` is a Compliance Access Key; its scopes are the subset you selected at creation.
129129* **Settings UI.** For a Compliance Access Key, open the **Keys** section in [claude.ai > Organization settings > API](https://claude.ai/admin-settings/api-access) and read the **Scopes** column for the key. Admin API keys, listed on the [Admin keys](https://platform.claude.com/settings/admin-keys) page (`platform.claude.com/settings/admin-keys`) in the Claude Console, have no selectable scopes.
130* **Error responses.** A call that exceeds the key's scopes returns a 403 with a message in the format `Missing required scopes. Got: [<scopes the key carries>] Needed one of: [<scopes the endpoint accepts>]` (`Needed: [...]` on the delete endpoints). See [Handle Compliance API errors](https://platform.claude.com/docs/en/manage-claude/compliance-errors#403-forbidden) for the full error catalog.
130* **Error responses.** A call that exceeds the key’s scopes returns a 403 with a message in the format `Missing required scopes. Got: [<scopes the key carries>] Needed one of: [<scopes the endpoint accepts>]` (`Needed: [...]` on the delete endpoints). See [Handle Compliance API errors](https://platform.claude.com/docs/en/manage-claude/compliance-errors#403-forbidden) for the full error catalog.
131131 
132132```json
133133{

manage-claude/compliance-content-data Changed · +26 / -26 lines

from line 14
1414 **Prerequisite:** None for listing chats organization-wide. To filter the chat list to specific users, you need user IDs from [List organization users](https://platform.claude.com/docs/en/manage-claude/compliance-org-data#list-organization-users). The other endpoints on this page take resource IDs directly.
1515</Check>
1616 
17The endpoints on this page expose Claude Enterprise chat content, file uploads, projects, and project attachments to compliance reviewers. They support eDiscovery (electronic discovery) exports, data loss prevention (DLP) enforcement, and account-deletion responses. Chat, file, and project content is retained for as long as your organization's retention policy allows. When a user deletes a chat in claude.ai, its message content, attached files, tool-generated files, and artifacts are deleted with it. The Compliance API still lists the chat, with `deleted_at` populated and an empty `name`, and returns its messages without their content. Chats that have been hard-deleted (through the Compliance API itself, or after the organization's retention window expires) are not retrievable.
17The endpoints on this page expose Claude Enterprise chat content, file uploads, projects, and project attachments to compliance reviewers. They support eDiscovery (electronic discovery) exports, data loss prevention (DLP) enforcement, and account-deletion responses. Chat, file, and project content is retained for as long as your organization’s retention policy allows. When a user deletes a chat in claude.ai, its message content, attached files, tool-generated files, and artifacts are deleted with it. The Compliance API still lists the chat, with `deleted_at` populated and an empty `name`, and returns its messages without their content. Chats that have been hard-deleted (through the Compliance API itself, or after the organization’s retention window expires) are not retrievable.
1818 
1919Both scopes are granted only on Compliance Access Keys (`sk-ant-api01-...`) created in claude.ai; see [Set up the Compliance API](https://platform.claude.com/docs/en/manage-claude/compliance-api-access) to provision one. The `read:compliance_user_data` scope covers retrieval; `delete:compliance_user_data` is required only for the delete endpoints. The chat, file, project, and attachment endpoints are not available to Admin API keys (`sk-ant-admin01-...`); calls authenticated with an Admin API key return [403 Forbidden](https://platform.claude.com/docs/en/manage-claude/compliance-errors#403-forbidden).
2020 
from line 24
2424 
2525Use [List chats](https://platform.claude.com/docs/en/api/compliance/apps/chats/list) to page through chat metadata, then [Get chat messages](https://platform.claude.com/docs/en/api/compliance/apps/chats/messages/list) to fetch the full message content of one chat.
2626 
27Chats in the unified Claude experience are returned by these endpoints like any other chat: a chat that continues in a session in the cloud comes back as one chat. The work Claude does there appears in each message's `content` as `tool_use` blocks (the tool's `name` and `input`) and `tool_result` blocks (its output, matched by `tool_use_id`). Coverage of these chats is in beta.
27Chats in the unified Claude experience are returned by these endpoints like any other chat: a chat that continues in a session in the cloud comes back as one chat. The work Claude does there appears in each message’s `content` as `tool_use` blocks (the tool’s `name` and `input`) and `tool_result` blocks (its output, matched by `tool_use_id`). Coverage of these chats is in beta.
2828 
2929The chat list endpoint defaults to organization-wide scope: leave off `user_ids[]` to include every chat under your parent organization. Add `order_by=updated_at` to sort by last update time. This combination is the recommended way to export chats and keep an export current, because one paginated loop picks up new chats, chats with new messages, and chats deleted in claude.ai for every user without enumerating users first. The following request lists chats updated since a given date.
3030 
from line 63
6363}
6464```
6565 
66Results sort ascending by the `order_by` field, oldest first, with ties broken by `id`. Pagination uses the standard `first_id`/`last_id`/`has_more` cursor fields described in [Paginate results](https://platform.claude.com/docs/en/manage-claude/compliance-activity-feed#paginate-results). To walk forward toward newer chats, pass the response's `last_id` back as `after_id` on the next request.
66Results sort ascending by the `order_by` field, oldest first, with ties broken by `id`. Pagination uses the standard `first_id`/`last_id`/`has_more` cursor fields described in [Paginate results](https://platform.claude.com/docs/en/manage-claude/compliance-activity-feed#paginate-results). To walk forward toward newer chats, pass the response’s `last_id` back as `after_id` on the next request.
6767 
68That forward walk is also how you keep an export current across runs: persist the final page's `last_id` and resume from it as `after_id` on the next run. Because the list is ordered by `updated_at`, a chat reappears ahead of your saved cursor when it receives a new message, is moved into or out of a project, or is deleted in claude.ai. Each incremental run therefore returns both brand-new chats and older chats that have since changed in one of those ways. Other edits, such as a rename, are not guaranteed to make a chat reappear. Process results idempotently, keyed by chat `id`, to handle those reappearances. A chat that comes back with `deleted_at` populated has no content left to fetch, so treat it as deleted rather than updated.
68That forward walk is also how you keep an export current across runs: persist the final page’s `last_id` and resume from it as `after_id` on the next run. Because the list is ordered by `updated_at`, a chat reappears ahead of your saved cursor when it receives a new message, is moved into or out of a project, or is deleted in claude.ai. Each incremental run therefore returns both brand-new chats and older chats that have since changed in one of those ways. Other edits, such as a rename, are not guaranteed to make a chat reappear. Process results idempotently, keyed by chat `id`, to handle those reappearances. A chat that comes back with `deleted_at` populated has no content left to fetch, so treat it as deleted rather than updated.
6969 
7070A few constraints apply to these organization-wide queries. Cursors are opaque and bound to the sort key, so an `after_id` issued under one `order_by` value is rejected with a 400 error under the other. Time-filter bounds must match the sort key too: pair `updated_at.*` bounds with `order_by=updated_at`, and `created_at.*` bounds with the default `order_by=created_at`. Backward pagination with `before_id` is not supported, and the `project_ids[]` filter is not available. See [List chats](https://platform.claude.com/docs/en/api/compliance/apps/chats/list) for the full filter reference.
7171 
72To scope the list to specific users instead (for example, a legal hold on named custodians), pass 1–10 `user_ids[]` values. Obtain the IDs from [List organization users](https://platform.claude.com/docs/en/manage-claude/compliance-org-data#list-organization-users). User-filtered queries always sort by `created_at` (passing `order_by=updated_at` returns a 400 error) and support both `after_id` and `before_id`. Filtering by `project_ids[]` is only available in this user-filtered form. Combining `user_ids[]` with any `updated_at.*` bound is deprecated and will be rejected with a 400 error after 2026-09-22. To keep a custodian set current by update time, run the organization-wide `order_by=updated_at` walk without `user_ids[]` and select the custodians' chats from its results. Keep the user-filtered listing for `created_at`-ordered exports.
72To scope the list to specific users instead (for example, a legal hold on named custodians), pass 1–10 `user_ids[]` values. Obtain the IDs from [List organization users](https://platform.claude.com/docs/en/manage-claude/compliance-org-data#list-organization-users). User-filtered queries always sort by `created_at` (passing `order_by=updated_at` returns a 400 error) and support both `after_id` and `before_id`. Filtering by `project_ids[]` is only available in this user-filtered form. Combining `user_ids[]` with any `updated_at.*` bound is deprecated and will be rejected with a 400 error after 2026-09-22. To keep a custodian set current by update time, run the organization-wide `order_by=updated_at` walk without `user_ids[]` and select the custodians’ chats from its results. Keep the user-filtered listing for `created_at`-ordered exports.
7373 
7474```bash cURL
7575curl --fail-with-body -sS -G \
from line 90
9090 -H "anthropic-version: 2023-06-01"
9191```
9292 
93The messages endpoint returns the chat's metadata plus a `chat_messages` array sorted by `created_at`. When `limit` is omitted, the full message set is returned in one response; pass `limit`, `after_id`, or `before_id` to page through very long chats. The endpoint also accepts `created_at.*` and `updated_at.*` range bounds (`gt`, `gte`, `lt`, `lte`) and an `order` parameter (`asc` or `desc`). See [Get chat messages](https://platform.claude.com/docs/en/api/compliance/apps/chats/messages/list) for the full parameter list. For user messages, `created_at` is when the message was sent; for assistant messages, it is when Claude finished generating the message. Each message carries its text content and, when present, any uploaded files (typically on user messages), any tool-generated files, and any artifacts the assistant produced or updated (typically on assistant messages):
93The messages endpoint returns the chat’s metadata plus a `chat_messages` array sorted by `created_at`. When `limit` is omitted, the full message set is returned in one response; pass `limit`, `after_id`, or `before_id` to page through very long chats. The endpoint also accepts `created_at.*` and `updated_at.*` range bounds (`gt`, `gte`, `lt`, `lte`) and an `order` parameter (`asc` or `desc`). See [Get chat messages](https://platform.claude.com/docs/en/api/compliance/apps/chats/messages/list) for the full parameter list. For user messages, `created_at` is when the message was sent; for assistant messages, it is when Claude finished generating the message. Each message carries its text content and, when present, any uploaded files (typically on user messages), any tool-generated files, and any artifacts the assistant produced or updated (typically on assistant messages):
9494 
9595```json Response
9696{
from line 164
164164}
165165```
166166 
167`files`, `generated_files`, and `artifacts` can each be `null` on a given message. `files` are the files and text attachments (for example, PDFs, images, spreadsheets, documents, and pasted text) the user attached to the message, as claude.ai stored them. `generated_files` are binary files the assistant created during the conversation through tool use (for example, PDFs, spreadsheets, or slide decks). `artifacts` are versioned documents (for example, code or markdown) the assistant generated or updated in its response; an artifact can be revised across multiple assistant turns in the same chat, and each revision appears as a new `version_id` under the same artifact `id`. Pass each entry's `id` (or `version_id` for artifacts) to the matching content endpoint in [Retrieve files and artifacts](https://platform.claude.com/docs/en/manage-claude/compliance-content-data#retrieve-files-and-artifacts) to download it.
167`files`, `generated_files`, and `artifacts` can each be `null` on a given message. `files` are the files and text attachments (for example, PDFs, images, spreadsheets, documents, and pasted text) the user attached to the message, as claude.ai stored them. `generated_files` are binary files the assistant created during the conversation through tool use (for example, PDFs, spreadsheets, or slide decks). `artifacts` are versioned documents (for example, code or markdown) the assistant generated or updated in its response; an artifact can be revised across multiple assistant turns in the same chat, and each revision appears as a new `version_id` under the same artifact `id`. Pass each entry’s `id` (or `version_id` for artifacts) to the matching content endpoint in [Retrieve files and artifacts](https://platform.claude.com/docs/en/manage-claude/compliance-content-data#retrieve-files-and-artifacts) to download it.
168168 
169169## Retrieve files and artifacts
170170 
171Files and artifacts are downloaded by ID. Except for Claude Docs documents (see the end of this section), they aren't listed independently. The IDs come from the chat messages endpoint in [Retrieve chats and messages](https://platform.claude.com/docs/en/manage-claude/compliance-content-data#retrieve-chats-and-messages) (the `files`, `generated_files`, and `artifacts` arrays on each message) or, for project-level uploads, from the [project attachments endpoint](https://platform.claude.com/docs/en/manage-claude/compliance-content-data#retrieve-projects-and-attachments).
171Files and artifacts are downloaded by ID. Except for Claude Docs documents (see the end of this section), they aren’t listed independently. The IDs come from the chat messages endpoint in [Retrieve chats and messages](https://platform.claude.com/docs/en/manage-claude/compliance-content-data#retrieve-chats-and-messages) (the `files`, `generated_files`, and `artifacts` arrays on each message) or, for project-level uploads, from the [project attachments endpoint](https://platform.claude.com/docs/en/manage-claude/compliance-content-data#retrieve-projects-and-attachments).
172172 
173173Pick the endpoint that matches your ID type and the data you need. The same file content endpoint serves both chat files and project files.
174174 
175175| You have | You want | Use this endpoint |
176176| ------------------------------ | --------------------------------------- | -------------------------------------------------------------------------------------------------------------------------- |
177| `claude_file_*` ID | The file's content | [Download file content](https://platform.claude.com/docs/en/api/compliance/apps/chats/files/download) |
178| `claude_file_*` ID | The file's metadata only | [Get file metadata](https://platform.claude.com/docs/en/api/compliance/apps/chats/files/retrieve) |
179| `claude_gen_file_*` ID | A tool-generated file's binary content | [Download a Claude-generated file](https://platform.claude.com/docs/en/api/compliance/apps/chats/generated_files/download) |
180| `claude_gen_file_*` ID | A tool-generated file's metadata only | [Get generated-file metadata](https://platform.claude.com/docs/en/api/compliance/apps/chats/generated_files/retrieve) |
181| `claude_artifact_version_*` ID | One artifact version's text | [Download artifact content](https://platform.claude.com/docs/en/api/compliance/apps/artifacts/download) |
182| `claude_artifact_version_*` ID | The artifact version's metadata only | [Get artifact metadata](https://platform.claude.com/docs/en/api/compliance/apps/artifacts/retrieve) |
183| `claude_proj_doc_*` ID | A project document's plain-text content | [Get project document content](https://platform.claude.com/docs/en/api/compliance/apps/projects/documents/retrieve) |
184| `claude_proj_doc_*` ID | A project document's metadata only | [Get project document metadata](https://platform.claude.com/docs/en/api/compliance/apps/projects/documents/metadata) |
177| `claude_file_*` ID | The file’s content | [Download file content](https://platform.claude.com/docs/en/api/compliance/apps/chats/files/download) |
178| `claude_file_*` ID | The file’s metadata only | [Get file metadata](https://platform.claude.com/docs/en/api/compliance/apps/chats/files/retrieve) |
179| `claude_gen_file_*` ID | A tool-generated file’s binary content | [Download a Claude-generated file](https://platform.claude.com/docs/en/api/compliance/apps/chats/generated_files/download) |
180| `claude_gen_file_*` ID | A tool-generated file’s metadata only | [Get generated-file metadata](https://platform.claude.com/docs/en/api/compliance/apps/chats/generated_files/retrieve) |
181| `claude_artifact_version_*` ID | One artifact version’s text | [Download artifact content](https://platform.claude.com/docs/en/api/compliance/apps/artifacts/download) |
182| `claude_artifact_version_*` ID | The artifact version’s metadata only | [Get artifact metadata](https://platform.claude.com/docs/en/api/compliance/apps/artifacts/retrieve) |
183| `claude_proj_doc_*` ID | A project document’s plain-text content | [Get project document content](https://platform.claude.com/docs/en/api/compliance/apps/projects/documents/retrieve) |
184| `claude_proj_doc_*` ID | A project document’s metadata only | [Get project document metadata](https://platform.claude.com/docs/en/api/compliance/apps/projects/documents/metadata) |
185185 
186The file content endpoint streams the content that claude.ai stored for the file as a chunked binary response. That content is not always identical to the file the user uploaded. Images can be served as a processed copy rather than the uploaded bytes. Some documents attached to chats (for example, Word files, PowerPoint files, and some PDFs) are stored as the text claude.ai extracted from them. For these documents, the endpoint returns the extracted text under the original file name, and the original document is not available through the Compliance API. The `size_bytes` and `md5` fields describe the stored content rather than the uploaded file. The file name and `mime_type` can still name the uploaded document's format. Identify a file's format from the returned bytes, not from its name or declared type.
186The file content endpoint streams the content that claude.ai stored for the file as a chunked binary response. That content is not always identical to the file the user uploaded. Images can be served as a processed copy rather than the uploaded bytes. Some documents attached to chats (for example, Word files, PowerPoint files, and some PDFs) are stored as the text claude.ai extracted from them. For these documents, the endpoint returns the extracted text under the original file name, and the original document is not available through the Compliance API. The `size_bytes` and `md5` fields describe the stored content rather than the uploaded file. The file name and `mime_type` can still name the uploaded document’s format. Identify a file’s format from the returned bytes, not from its name or declared type.
187187 
188188The response carries these headers:
189189 
from line 200
200200 --output "dashboard_mockup_v1.pdf"
201201```
202202 
203In curl, the `--remote-header-name` (`-J`) option, which normally saves a download under the `Content-Disposition` file name, does not read the `filename*` form, so name the saved file yourself with `--output`. In a script, take the name from the file's `filename` field in the chat messages or [Get file metadata](https://platform.claude.com/docs/en/api/compliance/apps/chats/files/retrieve) response, or decode `filename*`. Either way, it is the name the user gave the upload, so treat it as untrusted before using it as an output path:
203In curl, the `--remote-header-name` (`-J`) option, which normally saves a download under the `Content-Disposition` file name, does not read the `filename*` form, so name the saved file yourself with `--output`. In a script, take the name from the file’s `filename` field in the chat messages or [Get file metadata](https://platform.claude.com/docs/en/api/compliance/apps/chats/files/retrieve) response, or decode `filename*`. Either way, it is the name the user gave the upload, so treat it as untrusted before using it as an output path:
204204 
205205* Keep only the base name.
206206* Allow only characters that are safe on your filesystem.
207207* Refuse names that begin with `-` or `.`.
208208 
209Unlike the file content endpoint, the artifact content endpoint returns a JSON object. Pass the `version_id` from one of the entries in an assistant message's `artifacts` array, not the artifact's stable `id`; each new version of an artifact has its own `version_id`. The response's `content` field holds exactly that version's text, and its `title` and `artifact_type` fields describe the artifact. [Get artifact metadata](https://platform.claude.com/docs/en/api/compliance/apps/artifacts/retrieve) computes `size_bytes` and `md5` over the UTF-8 encoding of that text, so compare them with the `content` value rather than the whole response body.
209Unlike the file content endpoint, the artifact content endpoint returns a JSON object. Pass the `version_id` from one of the entries in an assistant message’s `artifacts` array, not the artifact’s stable `id`; each new version of an artifact has its own `version_id`. The response’s `content` field holds exactly that version’s text, and its `title` and `artifact_type` fields describe the artifact. [Get artifact metadata](https://platform.claude.com/docs/en/api/compliance/apps/artifacts/retrieve) computes `size_bytes` and `md5` over the UTF-8 encoding of that text, so compare them with the `content` value rather than the whole response body.
210210 
211Claude Docs documents are listed separately, by [List code artifacts](https://platform.claude.com/docs/en/api/compliance/apps/code/artifacts/list), with `artifact_type` set to `claude_docs`. A document's `versions` list is empty and its `published_version_id` is `null`. To download a document's current text, call `GET /v1/compliance/apps/code/artifacts/{artifact_id}/content?multi_file_format=zip`. It returns a ZIP archive with one Word (.docx) file for each tab that holds text. Comments, uploaded files, and edit history aren't included. Downloading Claude Docs through the Compliance API is in beta.
211Claude Docs documents are listed separately, by [List code artifacts](https://platform.claude.com/docs/en/api/compliance/apps/code/artifacts/list), with `artifact_type` set to `claude_docs`. A document’s `versions` list is empty and its `published_version_id` is `null`. To download a document’s current text, call `GET /v1/compliance/apps/code/artifacts/{artifact_id}/content?multi_file_format=zip`. It returns a ZIP archive with one Word (.docx) file for each tab that holds text. Comments, uploaded files, and edit history aren’t included. Downloading Claude Docs through the Compliance API is in beta.
212212 
213213## Retrieve projects and attachments
214214 
from line 269
269269 
270270The Compliance API exposes hard-delete endpoints for chats, files, project documents, and entire projects. A hard-deleted chat cannot be restored, and it stops appearing in list responses afterward.
271271 
272* [Delete chat](https://platform.claude.com/docs/en/api/compliance/apps/chats/delete): also deletes the chat's messages and any files attached to those messages.
272* [Delete chat](https://platform.claude.com/docs/en/api/compliance/apps/chats/delete): also deletes the chat’s messages and any files attached to those messages.
273273* [Delete file](https://platform.claude.com/docs/en/api/compliance/apps/chats/files/delete): handles both chat files and project files.
274274* [Delete project document](https://platform.claude.com/docs/en/api/compliance/apps/projects/documents/delete): deletes a single project document by ID.
275275* [Delete project](https://platform.claude.com/docs/en/api/compliance/apps/projects/delete): see [Detach chats before deleting a project](https://platform.claude.com/docs/en/manage-claude/compliance-content-data#detach-chats-before-deleting-a-project).
from line 300
300300}
301301```
302302 
303Each successful delete returns a small confirmation envelope with an `id` and a `type` discriminator. The chat endpoint returns `claude_chat_deleted`; check the `type` field before treating the delete as confirmed. See the response schema on each delete endpoint's [API reference](https://platform.claude.com/docs/en/api/compliance/apps) page for the exact `type` value the other endpoints return.
303Each successful delete returns a small confirmation envelope with an `id` and a `type` discriminator. The chat endpoint returns `claude_chat_deleted`; check the `type` field before treating the delete as confirmed. See the response schema on each delete endpoint’s [API reference](https://platform.claude.com/docs/en/api/compliance/apps) page for the exact `type` value the other endpoints return.
304304 
305305### Detach chats before deleting a project
306306 
from line 315
315315}
316316```
317317 
318To resolve, list the project's chats with `GET /v1/compliance/apps/chats?user_ids[]={user_id}&project_ids[]={project_id}` (the `project_ids[]` filter requires at least one `user_ids[]` value; enumerate IDs through [List organization users](https://platform.claude.com/docs/en/manage-claude/compliance-org-data#list-organization-users)), delete each one with `DELETE /v1/compliance/apps/chats/{claude_chat_id}` (or move it out of the project from claude.ai), and then retry the project delete.
318To resolve, list the project’s chats with `GET /v1/compliance/apps/chats?user_ids[]={user_id}&project_ids[]={project_id}` (the `project_ids[]` filter requires at least one `user_ids[]` value; enumerate IDs through [List organization users](https://platform.claude.com/docs/en/manage-claude/compliance-org-data#list-organization-users)), delete each one with `DELETE /v1/compliance/apps/chats/{claude_chat_id}` (or move it out of the project from claude.ai), and then retry the project delete.
319319 
320320## Next steps
321321 

manage-claude/compliance-errors Changed · +26 / -26 lines

from line 21
2121}
2222```
2323 
24On this page, local sessions run on users' machines and remote sessions run in the cloud; see [Retrieve session transcripts](https://platform.claude.com/docs/en/manage-claude/compliance-sessions).
24On this page, local sessions run on users’ machines and remote sessions run in the cloud; see [Retrieve session transcripts](https://platform.claude.com/docs/en/manage-claude/compliance-sessions).
2525 
2626Match on the HTTP status code and `error.type`, not on the message string. Messages are stable enough to copy into runbooks but might be reworded over time; the status codes and type values are part of the API contract. A few responses that share a status code and type are told apart by an error code in `error.details.error_code` when the response carries one, and otherwise by their message; each is called out where it applies.
2727 
from line 29
2929 
3030| Status | Retry? | When |
3131| -------------------------------------------------------------------------------------------------------------------------- | --------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
32| [400 Bad Request](https://platform.claude.com/docs/en/manage-claude/compliance-errors#400-bad-request) | No | Fix the request, or enable the Compliance API if the message says it is not enabled, then resend. If `error.details.error_code` is `transcript_page_read_limit_exceeded` (the message says a page of a session's transcript is too large to read), do not resend the same request; [Transcript page too large](https://platform.claude.com/docs/en/manage-claude/compliance-errors#transcript-page-too-large) says what to do instead. |
32| [400 Bad Request](https://platform.claude.com/docs/en/manage-claude/compliance-errors#400-bad-request) | No | Fix the request, or enable the Compliance API if the message says it is not enabled, then resend. If `error.details.error_code` is `transcript_page_read_limit_exceeded` (the message says a page of a session’s transcript is too large to read), do not resend the same request; [Transcript page too large](https://platform.claude.com/docs/en/manage-claude/compliance-errors#transcript-page-too-large) says what to do instead. |
3333| [401 Unauthorized](https://platform.claude.com/docs/en/manage-claude/compliance-errors#401-unauthorized) | No | The key is not recognized, has been deactivated, or has expired; re-enable or replace it, then resend. |
3434| [403 Forbidden](https://platform.claude.com/docs/en/manage-claude/compliance-errors#403-forbidden) | No | Add the missing scope or use the right key type, then resend. |
3535| [404 Not Found](https://platform.claude.com/docs/en/manage-claude/compliance-errors#404-not-found) | Usually no | A message that names a resource means it was deleted or never existed; remove it from your queue. The bare message `Not found` means the request did not authenticate (or the path does not exist), not that a resource is gone; see [Request not authenticated](https://platform.claude.com/docs/en/manage-claude/compliance-errors#request-not-authenticated). The session endpoints add two more cases: on the local session endpoints, the message `Local sessions are not available.` (returned on every call, including the list) means the endpoints are currently unavailable to your parent organization, not that a session is gone; keep your queued IDs and see [Local session not found](https://platform.claude.com/docs/en/manage-claude/compliance-errors#local-session-not-found). A remote session still in `pending` status 404s on its messages endpoint until it starts; see [Remote session not found](https://platform.claude.com/docs/en/manage-claude/compliance-errors#remote-session-not-found). |
36| [409 Conflict](https://platform.claude.com/docs/en/manage-claude/compliance-errors#409-conflict) | No | The request conflicts with the resource's current state; resolve the conflict (such as detaching child resources), then retry. |
36| [409 Conflict](https://platform.claude.com/docs/en/manage-claude/compliance-errors#409-conflict) | No | The request conflicts with the resource’s current state; resolve the conflict (such as detaching child resources), then retry. |
3737| [429 Too Many Requests](https://platform.claude.com/docs/en/manage-claude/compliance-errors#429-too-many-requests) | Yes, after `retry-after` | Wait the seconds in `retry-after`, then retry; do not advance your cursor. |
3838| [500 Internal Server Error](https://platform.claude.com/docs/en/manage-claude/compliance-errors#500-internal-server-error) | Depends on `x-should-retry` | Check the `x-should-retry` response header before retrying. |
3939| [502, 503, 504, 529](https://platform.claude.com/docs/en/manage-claude/compliance-errors#500-internal-server-error) | Yes, with backoff | Transient; retry with exponential backoff. Exception: some local session 503s are not transient. See [Local sessions temporarily unavailable](https://platform.claude.com/docs/en/manage-claude/compliance-errors#local-sessions-temporarily-unavailable). |
from line 64
6464 
6565**Cause:** The request included a query parameter that the endpoint does not define; the Compliance API rejects unrecognized parameters rather than ignoring them. The message names the parameter and, for near misses such as bracket notation in place of a dot or a missing `[]` suffix, suggests the defined name.
6666 
67**Fix:** Use the parameter names shown on the endpoint's [Compliance API reference](https://platform.claude.com/docs/en/api/compliance) page. Range filters use dot notation (for example, `created_at.gte`), array filters take a `[]` suffix (for example, `activity_types[]`), and the pagination parameters are `after_id`, `before_id`, or `page`, depending on the endpoint.
67**Fix:** Use the parameter names shown on the endpoint’s [Compliance API reference](https://platform.claude.com/docs/en/api/compliance) page. Range filters use dot notation (for example, `created_at.gte`), array filters take a `[]` suffix (for example, `activity_types[]`), and the pagination parameters are `after_id`, `before_id`, or `page`, depending on the endpoint.
6868 
6969### Invalid parameter value
7070 
from line 82
8282activity_types[].0: Input is not one of the permitted values.
8383```
8484 
85**Cause:** A query parameter's value failed validation. The message starts with the parameter name (followed by the element's position for an array parameter), then states the constraint that failed. Three common cases are shown: a `limit` above the endpoint's maximum (the number in the message is that endpoint's maximum), a `created_at.*` or `updated_at.*` value that cannot be parsed as a date or timestamp, and an `activity_types[]` value that is not a supported activity type.
85**Cause:** A query parameter’s value failed validation. The message starts with the parameter name (followed by the element’s position for an array parameter), then states the constraint that failed. Three common cases are shown: a `limit` above the endpoint’s maximum (the number in the message is that endpoint’s maximum), a `created_at.*` or `updated_at.*` value that cannot be parsed as a date or timestamp, and an `activity_types[]` value that is not a supported activity type.
8686 
8787**Fix:** Correct the parameter named in the message. Each list endpoint has its own `limit` range; see the parameter constraints on the corresponding [Compliance API reference](https://platform.claude.com/docs/en/api/compliance) page. Send timestamps in RFC 3339 format with an explicit UTC offset, for example, `2024-03-01T00:00:00Z` or `2024-03-01T00:00:00+00:00`; the local session list rejects a timestamp without an offset (`created_at.gte: Input should have timezone info`). For the supported `activity_types[]` values, see [Query compliance activities](https://platform.claude.com/docs/en/api/compliance/activities/list).
8888 
from line 146
146146 
147147**Fix:** Do not retry the request. If it used `order=desc`, read that session oldest first instead:
148148 
149* Restart the session's walk (one pass through its pages; see [Retrieve a local session transcript](https://platform.claude.com/docs/en/manage-claude/compliance-sessions#retrieve-a-local-session-transcript)) without `order` (or with `order=asc`) and without `page`, and follow `next_page` until it is `null`. Messages you already stored from the newest-first read keep the same `id`, so deduplicate on `id`.
150* Set your client's request timeout to at least 5 minutes for this walk.
149* Restart the session’s walk (one pass through its pages; see [Retrieve a local session transcript](https://platform.claude.com/docs/en/manage-claude/compliance-sessions#retrieve-a-local-session-transcript)) without `order` (or with `order=asc`) and without `page`, and follow `next_page` until it is `null`. Messages you already stored from the newest-first read keep the same `id`, so deduplicate on `id`.
150* Set your client’s request timeout to at least 5 minutes for this walk.
151151* Lowering `limit` is not a reliable way to avoid this error.
152152 
153153If an oldest-first request returns this error, do not retry it either. Keep the pages you have already read, record the session as incomplete, continue with the rest of your export, and contact your Anthropic representative with the `request-id` response header.
from line 172
172172API key has expired.
173173```
174174 
175**Cause:** `API key is invalid.` means the value sent does not match a usable key, for example because it was truncated or altered when it was stored. `API key has been deactivated.` means the key has been disabled or deleted. `API key has expired.` means an Admin API key's expiration date has passed; Compliance Access Keys are not created with one.
175**Cause:** `API key is invalid.` means the value sent does not match a usable key, for example because it was truncated or altered when it was stored. `API key has been deactivated.` means the key has been disabled or deleted. `API key has expired.` means an Admin API key’s expiration date has passed; Compliance Access Keys are not created with one.
176176 
177177**Fix:** For `API key is invalid.`, compare the value your client sends against the secret you stored when the key was created; the full secret is displayed only once, so if your stored copy is wrong, create a new key. For `API key has been deactivated.`, re-enable the key if it was only disabled, in [claude.ai > Organization settings > API](https://claude.ai/admin-settings/api-access) for a Compliance Access Key or on the [Admin keys](https://platform.claude.com/settings/admin-keys) page (`platform.claude.com/settings/admin-keys`) in the Claude Console for an Admin API key; a deleted key cannot be restored. For a deleted or expired key, create a new key and update your integration to use it, as described in [Manage and rotate keys](https://platform.claude.com/docs/en/manage-claude/compliance-api-access#manage-and-rotate-keys).
178178 
from line 273
273273Chat conversation not found: 'claude_chat_01H5CWunD7RpVJ5bHa8RCkja'
274274```
275275 
276**Cause:** The chat ID in the path does not match a chat readable through the Compliance API. The chat might have been hard-deleted through a previous Compliance API call or removed by your organization's retention policy, or it might belong to an organization the calling key cannot read. Chats that a user deleted in claude.ai do not return 404; they remain readable, with `deleted_at` populated, but without their message content.
276**Cause:** The chat ID in the path does not match a chat readable through the Compliance API. The chat might have been hard-deleted through a previous Compliance API call or removed by your organization’s retention policy, or it might belong to an organization the calling key cannot read. Chats that a user deleted in claude.ai do not return 404; they remain readable, with `deleted_at` populated, but without their message content.
277277 
278**Fix:** Confirm the chat ID against a recent `claude_chat_created` or `claude_chat_viewed` activity. If the activity is recent and the read still fails, the chat has been hard-deleted (through this API or by retention-policy expiry) or belongs to an organization outside your key's scope.
278**Fix:** Confirm the chat ID against a recent `claude_chat_created` or `claude_chat_viewed` activity. If the activity is recent and the read still fails, the chat has been hard-deleted (through this API or by retention-policy expiry) or belongs to an organization outside your key’s scope.
279279 
280280### File not found
281281 
from line 287
287287 
288288**Cause:** The file ID does not exist in an organization your key can read, or the file has been deleted. Deleting a chat in claude.ai also deletes the files attached to it, although the chat itself remains listed. The message identifies the file by its underlying UUID rather than by the `claude_file_...` ID sent in the request. The metadata, content, and delete endpoints return this body; it applies to both chat-attached files (`claude_file_...`) and project files.
289289 
290**Fix:** Reconcile against recent `claude_file_uploaded` or `claude_file_deleted` activities. Files deleted along with a chat have no `claude_file_deleted` activity, so check for the chat's `claude_chat_deleted` activity as well. If the file was deleted, the binary is gone; the activity records remain in the feed for the 6-year retention window.
290**Fix:** Reconcile against recent `claude_file_uploaded` or `claude_file_deleted` activities. Files deleted along with a chat have no `claude_file_deleted` activity, so check for the chat’s `claude_chat_deleted` activity as well. If the file was deleted, the binary is gone; the activity records remain in the feed for the 6-year retention window.
291291 
292292### Generated file or artifact not found
293293 
from line 307
307307 
308308**Cause:** The ID in the path does not match a tool-generated file or artifact version readable through the Compliance API. The generated-file metadata endpoint returns the first body, the content endpoint returns the second, and both artifact endpoints return the third. Generated files and artifacts are deleted with the chat they were created in, including when a user deletes the chat in claude.ai.
309309 
310**Fix:** Use [Get chat messages](https://platform.claude.com/docs/en/api/compliance/apps/chats/messages/list) to look up the chat the ID came from. If the chat's `deleted_at` is populated, or a `claude_chat_deleted` activity names the chat, the content is gone; remove the ID from your queue. Otherwise, confirm the ID against the `generated_files` and `artifacts` arrays on the chat's messages.
310**Fix:** Use [Get chat messages](https://platform.claude.com/docs/en/api/compliance/apps/chats/messages/list) to look up the chat the ID came from. If the chat’s `deleted_at` is populated, or a `claude_chat_deleted` activity names the chat, the content is gone; remove the ID from your queue. Otherwise, confirm the ID against the `generated_files` and `artifacts` arrays on the chat’s messages.
311311 
312312### Project not found
313313 
from line 323
323323 
324324**Cause:** The project ID does not exist or has been deleted. The project detail, attachments, and collaborators endpoints return the first body; `DELETE /v1/compliance/apps/projects/{project_id}` returns the second.
325325 
326**Fix:** Reconcile against recent `claude_project_created` or `claude_project_deleted` activities. The Activity Feed continues to expose the project's lifecycle events even after the project itself is gone.
326**Fix:** Reconcile against recent `claude_project_created` or `claude_project_deleted` activities. The Activity Feed continues to expose the project’s lifecycle events even after the project itself is gone.
327327 
328328### Project document not found
329329 
from line 354
354354* The ID is not a session in an organization your key can read (including IDs that belong to another parent organization).
355355* The session never existed.
356356* [Zero data retention](https://platform.claude.com/docs/en/manage-claude/api-and-data-retention#zero-data-retention-zdr-scope) is in effect for the session.
357* All of the session's activity has aged past the retention period that applies to the organization that ran it.
357* All of the session’s activity has aged past the retention period that applies to the organization that ran it.
358358 
359359The `Local session not found.` response has no transient form, because local sessions have no provisioning (`pending`) state; compare [Remote session not found](https://platform.claude.com/docs/en/manage-claude/compliance-errors#remote-session-not-found), where a `pending` session 404s until it starts. A session ID that is not a well-formed `clls_` identifier returns [400 Bad Request](https://platform.claude.com/docs/en/manage-claude/compliance-errors#400-bad-request) instead.
360360 
361361The local session endpoints, including the list endpoint, return a different 404 message, `Local sessions are not available.`, while the endpoints themselves are unavailable to your parent organization. That response does not depend on the session ID; no customer-side key, scope, or setting changes it, and it can be temporary. Both responses carry the `not_found_error` type; the message text is what tells them apart.
362362 
363**Fix:** Confirm the session ID against `GET /v1/compliance/apps/sessions/local`; see [Sessions on users' machines](https://platform.claude.com/docs/en/manage-claude/compliance-sessions#retrieve-local-sessions). If the session no longer appears in the list, its content has aged past retention (or the session is otherwise no longer in an organization your key can read) and its transcript is not retrievable; remove the ID from your queue. If every call, including the list, returns `Local sessions are not available.`, keep your queued session IDs and retry on your next scheduled run; if the response persists, contact your Anthropic representative and include the `request-id` response header.
363**Fix:** Confirm the session ID against `GET /v1/compliance/apps/sessions/local`; see [Sessions on users’ machines](https://platform.claude.com/docs/en/manage-claude/compliance-sessions#retrieve-local-sessions). If the session no longer appears in the list, its content has aged past retention (or the session is otherwise no longer in an organization your key can read) and its transcript is not retrievable; remove the ID from your queue. If every call, including the list, returns `Local sessions are not available.`, keep your queued session IDs and retry on your next scheduled run; if the response persists, contact your Anthropic representative and include the `request-id` response header.
364364 
365365### Remote session not found
366366 
from line 374
374374 
375375* The session ID (`cse_...`) does not exist or the session has been deleted.
376376* The session belongs to an organization your key cannot read.
377* The session's `status` is still `pending`: a pending session has no transcript yet, so the messages endpoint returns 404 until the session starts.
377* The session’s `status` is still `pending`: a pending session has no transcript yet, so the messages endpoint returns 404 until the session starts.
378378 
379379A session ID that is not a well-formed `cse_` identifier returns [400 Bad Request](https://platform.claude.com/docs/en/manage-claude/compliance-errors#400-bad-request) instead.
380380 
from line 404
404404 
405405**Cause:** `GET /v1/compliance/organizations/{organization_id}/settings` returns this 404 in three cases:
406406 
407* The `organization_id` is not one of your parent's linked organizations.
407* The `organization_id` is not one of your parent’s linked organizations.
408408* The `organization_id` is not a valid UUID.
409409* The settings endpoint is not yet enabled for your parent organization.
410410 
from line 414
414414 
415415## 409 Conflict
416416 
417The request is well-formed and authorized but conflicts with the resource's current state. The body carries the `invalid_request_error` type, which 400 responses also use, so distinguish a conflict by the 409 status code rather than by `error.type`.
417The request is well-formed and authorized but conflicts with the resource’s current state. The body carries the `invalid_request_error` type, which 400 responses also use, so distinguish a conflict by the 409 status code rather than by `error.type`.
418418 
419419### Project has attached chats
420420 
from line 426
426426 
427427**Cause:** `DELETE /v1/compliance/apps/projects/{project_id}` was called on a project that still has chats attached.
428428 
429**Fix:** List the project's chats with `GET /v1/compliance/apps/chats?user_ids[]={user_id}&project_ids[]={project_id}` (the `project_ids[]` filter requires at least one `user_ids[]` value; enumerate IDs through [List organization users](https://platform.claude.com/docs/en/manage-claude/compliance-org-data#list-organization-users)), delete each one with `DELETE /v1/compliance/apps/chats/{claude_chat_id}`, and then retry the project delete.
429**Fix:** List the project’s chats with `GET /v1/compliance/apps/chats?user_ids[]={user_id}&project_ids[]={project_id}` (the `project_ids[]` filter requires at least one `user_ids[]` value; enumerate IDs through [List organization users](https://platform.claude.com/docs/en/manage-claude/compliance-org-data#list-organization-users)), delete each one with `DELETE /v1/compliance/apps/chats/{claude_chat_id}`, and then retry the project delete.
430430 
431431## 429 Too Many Requests
432432 
from line 460
460460}
461461```
462462 
463**Cause:** Your parent organization (or standalone Claude Console organization) sent more than 600 requests to `/v1/compliance/*` in a 1-minute window, across all of the keys that share its budget, or it exhausted the remote session endpoints' second request budget (described later in this section).
463**Cause:** Your parent organization (or standalone Claude Console organization) sent more than 600 requests to `/v1/compliance/*` in a 1-minute window, across all of the keys that share its budget, or it exhausted the remote session endpoints’ second request budget (described later in this section).
464464 
465465**Fix:** Wait the number of seconds in the `retry-after` header, then retry. If the header is absent (for example, stripped by an intermediary), fall back to exponential backoff (start at 1 second, double up to 60 seconds). Do not advance your pagination cursor on a 429: the failed request returned no data, so the cursor from the last successful page is still correct.
466466 
467Requests that fail authentication (a missing or unrecognized key, or a Claude API key rather than a Compliance Access Key or Admin API key) are rejected before the rate limiter and do not consume quota. A valid key that lacks the endpoint's required scope consumes one quota unit before the 403 is returned.
467Requests that fail authentication (a missing or unrecognized key, or a Claude API key rather than a Compliance Access Key or Admin API key) are rejected before the rate limiter and do not consume quota. A valid key that lacks the endpoint’s required scope consumes one quota unit before the 403 is returned.
468468 
469469The [local session endpoints](https://platform.claude.com/docs/en/manage-claude/compliance-sessions#retrieve-local-sessions) count only against the shared limit. The [remote session endpoints](https://platform.claude.com/docs/en/manage-claude/compliance-sessions#retrieve-remote-sessions) also carry a second request budget, keyed to your parent organization like the shared limit, on top of it. A 429 from that budget carries a `retry-after` header that is always `1` (a minimum wait, not the actual reset time); any `anthropic-ratelimit-*` headers on that response describe the shared limit rather than this budget, so back off exponentially if the 429 repeats. One 429 comes from no request budget: [Server busy reading large transcripts](https://platform.claude.com/docs/en/manage-claude/compliance-errors#server-busy-reading-large-transcripts), which only the local session messages endpoint returns.
470470 
from line 488
488488 
489489A 500 from the Compliance API carries an `x-should-retry: false` response header when the failure is deterministic. The Claude SDK honors this header automatically. If you use a generic HTTP retry library that retries on every 5xx, suppress retries when `x-should-retry` is `false`; retrying this error fails identically on every attempt.
490490 
491A 500 without the `x-should-retry: false` header is transient: retry with exponential backoff (start at 1 second, double up to 60 seconds). The same applies to 502, 503, 504, and 529 responses. The exception is a small set of local session 503s, described next, that depend on an organization's settings or encryption key rather than on load. See [Claude API errors](https://platform.claude.com/docs/en/api/errors) for the platform-wide retry semantics.
491A 500 without the `x-should-retry: false` header is transient: retry with exponential backoff (start at 1 second, double up to 60 seconds). The same applies to 502, 503, 504, and 529 responses. The exception is a small set of local session 503s, described next, that depend on an organization’s settings or encryption key rather than on load. See [Claude API errors](https://platform.claude.com/docs/en/api/errors) for the platform-wide retry semantics.
492492 
493493### Local sessions temporarily unavailable
494494 
from line 509
509509**Cause:** The [local session endpoints](https://platform.claude.com/docs/en/manage-claude/compliance-sessions#retrieve-local-sessions) return 503 with one of these bodies. All three share the `overloaded_error` type, so this is one of the few errors on this page where you need the message text, not `error.type`, to tell the conditions apart:
510510 
511511* The `index is temporarily unavailable` body means session listings are briefly unavailable because of load or a backend condition. This is transient.
512* The `Captured content` body means a session's transcript content cannot be returned right now. This is usually transient too. In organizations that use [customer-managed encryption keys](https://platform.claude.com/docs/en/manage-claude/cmek), the messages endpoint also returns this body for every page that contains content your customer-managed key cannot decrypt, for example because you disabled, revoked, or destroyed the key, or because the key cannot be reached. In that case the error persists for as long as the key cannot be used. The message text is the same either way, so the only signal that the key is the cause is that the error keeps recurring for that organization. An unusable key is never reported as `not_captured`.
512* The `Captured content` body means a session’s transcript content cannot be returned right now. This is usually transient too. In organizations that use [customer-managed encryption keys](https://platform.claude.com/docs/en/manage-claude/cmek), the messages endpoint also returns this body for every page that contains content your customer-managed key cannot decrypt, for example because you disabled, revoked, or destroyed the key, or because the key cannot be reached. In that case the error persists for as long as the key cannot be used. The message text is the same either way, so the only signal that the key is the cause is that the error keeps recurring for that organization. An unusable key is never reported as `not_captured`.
513513* The `retention overrides` body means a retention or data-handling setting that applies to one or more sessions in the requested range could not be evaluated yet. On the retrieve and messages endpoints it reads `for this session` instead of `for this page`. It depends on the data and settings of the organization that ran the session rather than on load, and it can persist for an extended period.
514514 
515515**Fix:** Handle each body as follows:
516516 
517517* For the two `Try again shortly.` bodies, retry with exponential backoff and do not advance your `page` cursor, because the failed request returned no data.
518* If the `Captured content` body keeps recurring on the messages endpoint for an organization that uses a customer-managed key, treat it as persistent: stop walking that organization's transcripts and check the key's status in your key management service. Transcripts in other linked organizations, and session metadata everywhere, are unaffected. If you retry on a later run, restart each session's walk without `page`, because messages page cursors expire 24 hours after the walk's first page.
519* For the `Try again later.` body, do not hold a walk open waiting for it to clear. On the list endpoint, either retry later by restarting without the `page` parameter (a list page token older than 24 hours is still accepted but is re-evaluated against the current retention boundary, so a parked walk can skip sessions), or narrow the `created_at` window until the request succeeds and export the skipped range separately on a later run. On the retrieve and messages endpoints, skip that session ID, continue with the rest of your export, and retry the session on a later run. Messages page cursors expire 24 hours after the walk's first page, so restart that session's walk without `page` when you return to it.
518* If the `Captured content` body keeps recurring on the messages endpoint for an organization that uses a customer-managed key, treat it as persistent: stop walking that organization’s transcripts and check the key’s status in your key management service. Transcripts in other linked organizations, and session metadata everywhere, are unaffected. If you retry on a later run, restart each session’s walk without `page`, because messages page cursors expire 24 hours after the walk’s first page.
519* For the `Try again later.` body, do not hold a walk open waiting for it to clear. On the list endpoint, either retry later by restarting without the `page` parameter (a list page token older than 24 hours is still accepted but is re-evaluated against the current retention boundary, so a parked walk can skip sessions), or narrow the `created_at` window until the request succeeds and export the skipped range separately on a later run. On the retrieve and messages endpoints, skip that session ID, continue with the rest of your export, and retry the session on a later run. Messages page cursors expire 24 hours after the walk’s first page, so restart that session’s walk without `page` when you return to it.
520520 
521521If any of these conditions recurs across runs, contact your Anthropic representative and include the `request-id` response header. For the customer-managed key case, do this only if the error continues while that key is usable.
522522 

manage-claude/compliance-faq Changed · +14 / -14 lines

from line 27
2727 Yes. When the Compliance API is turned off (or back on) in Claude Console, the change is recorded as an `org_compliance_api_settings_updated` activity in the [Activity Feed](https://platform.claude.com/docs/en/manage-claude/compliance-activity-feed), so your audit trail shows who changed the setting and when. This activity is an exception: the disable is recorded even though other activity is not recorded while the Compliance API is off. Access Transparency events are also an exception.
2828 </Accordion>
2929 
30 <Accordion title="Why doesn't my parent organization appear in Claude Console when creating an Admin API key?">
30 <Accordion title="Why doesn’t my parent organization appear in Claude Console when creating an Admin API key?">
3131 This is expected. A Claude Enterprise parent organization centralizes identity across all linked organizations; it does not carry workloads, and it does not appear in Claude Console at all. Claude Console only ever shows the Claude Console organizations linked beneath the parent.
3232 
3333 To call the Compliance API, you create one of two key types instead:
from line 41
4141 </Accordion>
4242 
4343 <Accordion title="Why does my Admin API key return 403 on chat or file endpoints?">
44 An Admin API key's only Compliance API scope is `read:compliance_activities`, which authorizes the Activity Feed only. Every other Compliance API endpoint requires a scope that only a Compliance Access Key created in claude.ai can carry. Calling a content or directory endpoint with an Admin API key returns a 403 naming the scope that endpoint family requires: `read:compliance_user_data` for chats, files, projects, project attachments, sessions, users, and group members, and `read:compliance_org_data` for organizations, roles, groups, and effective organization settings. For example, listing chats returns the following response.
44 An Admin API key’s only Compliance API scope is `read:compliance_activities`, which authorizes the Activity Feed only. Every other Compliance API endpoint requires a scope that only a Compliance Access Key created in claude.ai can carry. Calling a content or directory endpoint with an Admin API key returns a 403 naming the scope that endpoint family requires: `read:compliance_user_data` for chats, files, projects, project attachments, sessions, users, and group members, and `read:compliance_org_data` for organizations, roles, groups, and effective organization settings. For example, listing chats returns the following response.
4545 
4646 ```json Response
4747 {
from line 60
6060 
6161<AccordionGroup>
6262 <Accordion title="How far back does the Activity Feed go?">
63 The Activity Feed retains 6 years of organization activity, and new events are queryable within 1 minute of occurring. The feed reaches back at most to the point the Compliance API was first enabled for your organization: recording is not retroactive, and activity from before enablement is not backfilled. Access Transparency events are an exception. If your organization is enrolled in [Access Transparency](https://platform.claude.com/docs/en/manage-claude/access-transparency), these events are recorded even while the Compliance API is off. The feed can therefore include some from before the Compliance API was first enabled. Activity Feed retention is independent of your organization's content retention policy: chat, file, and project content follows the retention rules configured for your organization (indefinite by default), unless a user deletes it sooner.
63 The Activity Feed retains 6 years of organization activity, and new events are queryable within 1 minute of occurring. The feed reaches back at most to the point the Compliance API was first enabled for your organization: recording is not retroactive, and activity from before enablement is not backfilled. Access Transparency events are an exception. If your organization is enrolled in [Access Transparency](https://platform.claude.com/docs/en/manage-claude/access-transparency), these events are recorded even while the Compliance API is off. The feed can therefore include some from before the Compliance API was first enabled. Activity Feed retention is independent of your organization’s content retention policy: chat, file, and project content follows the retention rules configured for your organization (indefinite by default), unless a user deletes it sooner.
6464 </Accordion>
6565 
6666 <Accordion title="Does the Activity Feed include prompt or message content?">
6767 No. The Activity Feed records who did what and when (authentication, chat creation, file uploads, project changes, administrative actions, and similar resource events), but it does not capture the prompt text or model responses inside chats or messages.
6868 
69 To retrieve message bodies and file contents, use the chat, message, and file endpoints with a Compliance Access Key carrying `read:compliance_user_data`. The same key and scope retrieve transcripts of sessions on users' machines (such as Cowork and Claude Code sessions) through the [local session endpoints](https://platform.claude.com/docs/en/manage-claude/compliance-sessions#retrieve-local-sessions), and transcripts of Cowork sessions in the cloud through the [remote session endpoints](https://platform.claude.com/docs/en/manage-claude/compliance-sessions#retrieve-remote-sessions). These endpoints serve Claude Enterprise content only; Claude Console workloads, and Claude API workloads authenticated with an API key, expose administrative and resource events through the Activity Feed but do not expose prompt text or model responses through the Compliance API.
69 To retrieve message bodies and file contents, use the chat, message, and file endpoints with a Compliance Access Key carrying `read:compliance_user_data`. The same key and scope retrieve transcripts of sessions on users’ machines (such as Cowork and Claude Code sessions) through the [local session endpoints](https://platform.claude.com/docs/en/manage-claude/compliance-sessions#retrieve-local-sessions), and transcripts of Cowork sessions in the cloud through the [remote session endpoints](https://platform.claude.com/docs/en/manage-claude/compliance-sessions#retrieve-remote-sessions). These endpoints serve Claude Enterprise content only; Claude Console workloads, and Claude API workloads authenticated with an API key, expose administrative and resource events through the Activity Feed but do not expose prompt text or model responses through the Compliance API.
7070 </Accordion>
7171 
7272 <Accordion title="Do sessions in Cowork, Claude Code, and other Claude apps and add-ins appear in the Compliance API?">
73 Yes. Cowork sessions in Claude Desktop that run on users' machines, Claude Code sessions (in the terminal, in Claude Desktop, or in an IDE extension), sessions in the Claude Science desktop app, Claude for Microsoft 365 sessions (in Excel, PowerPoint, Word, and Outlook), sessions in the Claude add-ins for Google Docs, Google Sheets, and Google Slides, and chats in the Claude in Chrome browser extension are captured while users are signed in with their Claude Enterprise account and are available through the [local session endpoints](https://platform.claude.com/docs/en/manage-claude/compliance-sessions#retrieve-local-sessions). Cowork sessions started on claude.ai web or mobile, which run in the cloud in Anthropic-managed environments, are available through the [remote session endpoints](https://platform.claude.com/docs/en/manage-claude/compliance-sessions#retrieve-remote-sessions). Each family has a list endpoint that returns session metadata and a messages endpoint that returns the session transcript (user prompts, assistant responses, and tool calls and results). The local family adds a third endpoint that retrieves one session's metadata. All of these endpoints use your existing Compliance Access Key with `read:compliance_user_data`; no new key or scope is needed.
73 Yes. Cowork sessions in Claude Desktop that run on users’ machines, Claude Code sessions (in the terminal, in Claude Desktop, or in an IDE extension), sessions in the Claude Science desktop app, Claude for Microsoft 365 sessions (in Excel, PowerPoint, Word, and Outlook), sessions in the Claude add-ins for Google Docs, Google Sheets, and Google Slides, and chats in the Claude in Chrome browser extension are captured while users are signed in with their Claude Enterprise account and are available through the [local session endpoints](https://platform.claude.com/docs/en/manage-claude/compliance-sessions#retrieve-local-sessions). Cowork sessions started on claude.ai web or mobile, which run in the cloud in Anthropic-managed environments, are available through the [remote session endpoints](https://platform.claude.com/docs/en/manage-claude/compliance-sessions#retrieve-remote-sessions). Each family has a list endpoint that returns session metadata and a messages endpoint that returns the session transcript (user prompts, assistant responses, and tool calls and results). The local family adds a third endpoint that retrieves one session’s metadata. All of these endpoints use your existing Compliance Access Key with `read:compliance_user_data`; no new key or scope is needed.
7474 
75 Local sessions are captured as their requests reach the Claude API, so nothing is installed on the device, and on-device activity that never reaches the API is not captured. Claude Code sessions authenticated with a Claude Console API key, Claude Code sessions run through a third-party cloud platform (Amazon Bedrock, Google Cloud, or Microsoft Foundry), and [Claude Code cloud sessions](https://code.claude.com/docs/en/claude-code-on-the-web), which run on cloud infrastructure instead of the user's machine, are not captured. These cloud sessions are not remote sessions, even though both run in the cloud; the remote session endpoints return Cowork sessions only. Each run of a Cowork scheduled task in the cloud is a remote session: the remote session list endpoint returns it as an [agent-owned session](https://platform.claude.com/docs/en/manage-claude/compliance-sessions#retrieve-remote-sessions) (`agent_id` is set, and `started_by_user` identifies the human who initiated the run), and the messages endpoint returns its transcript, but neither returns the task's name or schedule. Claude Code routines that run in the cloud are Claude Code cloud sessions, so the session endpoints do not return them. Organizations with [HIPAA readiness](https://platform.claude.com/docs/en/manage-claude/api-and-data-retention#hipaa-readiness) enabled get local session data for Cowork and Claude Code only, stored for 30 days, and sessions for which [zero data retention (ZDR)](https://platform.claude.com/docs/en/manage-claude/api-and-data-retention#zero-data-retention-zdr-scope) is in effect are excluded.
75 Local sessions are captured as their requests reach the Claude API, so nothing is installed on the device, and on-device activity that never reaches the API is not captured. Claude Code sessions authenticated with a Claude Console API key, Claude Code sessions run through a third-party cloud platform (Amazon Bedrock, Google Cloud, or Microsoft Foundry), and [Claude Code cloud sessions](https://code.claude.com/docs/en/claude-code-on-the-web), which run on cloud infrastructure instead of the user’s machine, are not captured. These cloud sessions are not remote sessions, even though both run in the cloud; the remote session endpoints return Cowork sessions only. Each run of a Cowork scheduled task in the cloud is a remote session: the remote session list endpoint returns it as an [agent-owned session](https://platform.claude.com/docs/en/manage-claude/compliance-sessions#retrieve-remote-sessions) (`agent_id` is set, and `started_by_user` identifies the human who initiated the run), and the messages endpoint returns its transcript, but neither returns the task’s name or schedule. Claude Code routines that run in the cloud are Claude Code cloud sessions, so the session endpoints do not return them. Organizations with [HIPAA readiness](https://platform.claude.com/docs/en/manage-claude/api-and-data-retention#hipaa-readiness) enabled get local session data for Cowork and Claude Code only, stored for 30 days, and sessions for which [zero data retention (ZDR)](https://platform.claude.com/docs/en/manage-claude/api-and-data-retention#zero-data-retention-zdr-scope) is in effect are excluded.
7676 
7777 The local and remote session endpoints are stable for Cowork, Claude Code, and Claude for Microsoft 365 sessions. Coverage of sessions in Claude Science, the Claude add-ins for Google Docs, Google Sheets, and Google Slides, and Claude in Chrome is in beta.
7878 </Accordion>
7979 
8080 <Accordion title="What do session transcripts include?">
81 Local and remote session transcripts both carry user prompts, assistant responses, and tool calls and results. For local sessions (on users' machines), that is what Claude was asked to do and what it returned, not what occurred on the device.
81 Local and remote session transcripts both carry user prompts, assistant responses, and tool calls and results. For local sessions (on users’ machines), that is what Claude was asked to do and what it returned, not what occurred on the device.
8282 
83 | Data | Local sessions (on users' machines) | Remote sessions (in the cloud) |
83 | Data | Local sessions (on users’ machines) | Remote sessions (in the cloud) |
8484 | --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
8585 | User prompts | Yes; returned as `text` blocks. | Yes; returned as `text` blocks. |
8686 | Assistant responses | Yes; text output only. | Yes; text output only. |
from line 93
9393 | Images and other non-text content | No; each image, PDF, or other binary or structured block appears as a placeholder `text` block (for example, `[image content not shown]`) with `truncated` set to `true`. Raw file bytes are never returned. | No; non-text blocks are omitted, and raw file bytes are never returned. |
9494 | Token usage, cost, and latency | No; token usage and cost are available through the [Claude Enterprise Analytics API](https://platform.claude.com/docs/en/manage-claude/analytics-api#get-access-to-the-claude-enterprise-analytics-api). | No; token usage and cost are available through the [Claude Enterprise Analytics API](https://platform.claude.com/docs/en/manage-claude/analytics-api#get-access-to-the-claude-enterprise-analytics-api). |
9595 
96 See [Sessions on users' machines](https://platform.claude.com/docs/en/manage-claude/compliance-sessions#retrieve-local-sessions) and [Sessions in the cloud](https://platform.claude.com/docs/en/manage-claude/compliance-sessions#retrieve-remote-sessions) for the endpoints and parameters.
96 See [Sessions on users’ machines](https://platform.claude.com/docs/en/manage-claude/compliance-sessions#retrieve-local-sessions) and [Sessions in the cloud](https://platform.claude.com/docs/en/manage-claude/compliance-sessions#retrieve-remote-sessions) for the endpoints and parameters.
9797 </Accordion>
9898 
9999 <Accordion title="How does session coverage compare with OpenTelemetry logging (OTEL) for Cowork and Claude Code?">
100 [Cowork's OpenTelemetry logging](https://support.claude.com/en/articles/14477985-monitor-claude-cowork-activity-with-opentelemetry) and [Claude Code monitoring](https://code.claude.com/docs/en/monitoring-usage) overlap with the session endpoints but answer different needs: OTEL streams per-event telemetry to infrastructure you run as activity occurs, whereas the Compliance API lets you retrieve retained per-session transcripts from Anthropic after the fact. OTEL can also capture prompts and responses, but Anthropic recommends the Compliance API for retrieving the content of Cowork and Claude Code sessions. For a table comparing local sessions, remote sessions, and OTEL, see the introduction to [Retrieve session transcripts](https://platform.claude.com/docs/en/manage-claude/compliance-sessions).
100 [Cowork’s OpenTelemetry logging](https://support.claude.com/en/articles/14477985-monitor-claude-cowork-activity-with-opentelemetry) and [Claude Code monitoring](https://code.claude.com/docs/en/monitoring-usage) overlap with the session endpoints but answer different needs: OTEL streams per-event telemetry to infrastructure you run as activity occurs, whereas the Compliance API lets you retrieve retained per-session transcripts from Anthropic after the fact. OTEL can also capture prompts and responses, but Anthropic recommends the Compliance API for retrieving the content of Cowork and Claude Code sessions. For a table comparing local sessions, remote sessions, and OTEL, see the introduction to [Retrieve session transcripts](https://platform.claude.com/docs/en/manage-claude/compliance-sessions).
101101 
102102 OTEL events and Compliance API records share organization and user identifiers, so you can join them.
103103 </Accordion>
from line 109
109109 <Accordion title="What does the Compliance API not capture?">
110110 The Compliance API has known coverage boundaries: the Activity Feed records resource events but not prompt or response text, Claude Console and Claude API workloads authenticated with an API key expose no message content at all, and content removed by your retention policy, deleted by a user in claude.ai, or hard-deleted through the Compliance API is not recoverable. For the full coverage boundaries and delivery contract, see [Delivery guarantees and completeness](https://platform.claude.com/docs/en/manage-claude/compliance-integration-patterns#delivery-guarantees-and-completeness).
111111 
112 Session transcripts have boundaries of their own. Local sessions are captured only as their requests reach the Claude API, so on-device activity that never reaches the API is not captured. Claude Code sessions authenticated with a Claude Console API key, Claude Code sessions run through a third-party cloud platform (Amazon Bedrock, Google Cloud, or Microsoft Foundry), and [Claude Code cloud sessions](https://code.claude.com/docs/en/claude-code-on-the-web) (including Claude Code routines that run in the cloud), which run on cloud infrastructure instead of the user's machine, are not captured either; organizations with HIPAA readiness enabled get local session data for Cowork and Claude Code only, stored for 30 days; and sessions for which zero data retention is in effect are excluded. No session transcript, local or remote, includes thinking blocks or tool definitions. Organizations that use [customer-managed encryption keys](https://platform.claude.com/docs/en/manage-claude/cmek) receive local session transcripts as usual. While the key cannot be used, the messages endpoint returns [503 Service Unavailable](https://platform.claude.com/docs/en/manage-claude/compliance-errors#local-sessions-temporarily-unavailable) instead of transcript content, and session metadata is still listed.
112 Session transcripts have boundaries of their own. Local sessions are captured only as their requests reach the Claude API, so on-device activity that never reaches the API is not captured. Claude Code sessions authenticated with a Claude Console API key, Claude Code sessions run through a third-party cloud platform (Amazon Bedrock, Google Cloud, or Microsoft Foundry), and [Claude Code cloud sessions](https://code.claude.com/docs/en/claude-code-on-the-web) (including Claude Code routines that run in the cloud), which run on cloud infrastructure instead of the user’s machine, are not captured either; organizations with HIPAA readiness enabled get local session data for Cowork and Claude Code only, stored for 30 days; and sessions for which zero data retention is in effect are excluded. No session transcript, local or remote, includes thinking blocks or tool definitions. Organizations that use [customer-managed encryption keys](https://platform.claude.com/docs/en/manage-claude/cmek) receive local session transcripts as usual. While the key cannot be used, the messages endpoint returns [503 Service Unavailable](https://platform.claude.com/docs/en/manage-claude/compliance-errors#local-sessions-temporarily-unavailable) instead of transcript content, and session metadata is still listed.
113113 
114 No Compliance API endpoint lists an organization's Cowork scheduled tasks or Claude Code routines.
114 No Compliance API endpoint lists an organization’s Cowork scheduled tasks or Claude Code routines.
115115 </Accordion>
116116</AccordionGroup>
117117 
from line 127
127127 </Accordion>
128128 
129129 <Accordion title="Are activities returned in order, and how do I detect when I have caught up to real time?">
130 Activities are returned newest first, with ties in `created_at` broken by activity ID. To catch up, walk pages forward by `before_id` until `has_more` is `false`; that final response's `first_id` is your new cursor and you have reached the present. The full loop, including initial backfill and the safety conditions on cursor persistence, is in [Cursor-driven incremental reads](https://platform.claude.com/docs/en/manage-claude/compliance-integration-patterns#cursor-driven-incremental-reads).
130 Activities are returned newest first, with ties in `created_at` broken by activity ID. To catch up, walk pages forward by `before_id` until `has_more` is `false`; that final response’s `first_id` is your new cursor and you have reached the present. The full loop, including initial backfill and the safety conditions on cursor persistence, is in [Cursor-driven incremental reads](https://platform.claude.com/docs/en/manage-claude/compliance-integration-patterns#cursor-driven-incremental-reads).
131131 </Accordion>
132132 
133133 <Accordion title="How do I get a sandbox to test the Compliance API?">
134 To test only the [Activity Feed](https://platform.claude.com/docs/en/manage-claude/compliance-activity-feed), you do not need a Claude Enterprise organization: an organization admin can [enable the Compliance API](https://platform.claude.com/docs/en/manage-claude/compliance-api-access#set-up-the-compliance-api) on an eligible standalone Claude Console test organization and query the feed with a new Admin API key. If that organization's [Compliance](https://platform.claude.com/settings/security) page (`platform.claude.com/settings/security`) in the Claude Console shows a page-not-found error, or doesn't show the **Compliance API** section, the organization is not eligible for self-service enablement.
134 To test only the [Activity Feed](https://platform.claude.com/docs/en/manage-claude/compliance-activity-feed), you do not need a Claude Enterprise organization: an organization admin can [enable the Compliance API](https://platform.claude.com/docs/en/manage-claude/compliance-api-access#set-up-the-compliance-api) on an eligible standalone Claude Console test organization and query the feed with a new Admin API key. If that organization’s [Compliance](https://platform.claude.com/settings/security) page (`platform.claude.com/settings/security`) in the Claude Console shows a page-not-found error, or doesn’t show the **Compliance API** section, the organization is not eligible for self-service enablement.
135135 
136136 To test every endpoint, set up a Claude Enterprise sandbox organization linked to a Claude Console organization under the same parent. This lets the sandbox exercise both the Activity Feed (through an Admin API key) and the chat, file, project, and session endpoints (through a Compliance Access Key).
137137 

manage-claude/compliance-integration-patterns Changed · +11 / -11 lines

from line 38
3838 
3939### Window polling
4040 
41Set `created_at.lt` at least 1 minute in the past so that every activity in the window is already queryable. Use `created_at.gte` for the lower bound and `created_at.lt` for the upper bound so that consecutive windows tile without gaps or overlap; reuse the previous window's `lt` value as the next window's `gte`.
41Set `created_at.lt` at least 1 minute in the past so that every activity in the window is already queryable. Use `created_at.gte` for the lower bound and `created_at.lt` for the upper bound so that consecutive windows tile without gaps or overlap; reuse the previous window’s `lt` value as the next window’s `gte`.
4242 
4343```bash cURL
4444curl --fail-with-body -sS -G \
from line 50
5050 --data-urlencode "limit=5000"
5151```
5252 
53When the response has `has_more: true`, the window contains more than one page of activities. Either page within the window by passing the response's `last_id` as `after_id` on the next request (stopping when `has_more` is `false`), or choose a smaller time window. See [Paginate results](https://platform.claude.com/docs/en/manage-claude/compliance-activity-feed#paginate-results) for the full contract.
53When the response has `has_more: true`, the window contains more than one page of activities. Either page within the window by passing the response’s `last_id` as `after_id` on the next request (stopping when `has_more` is `false`), or choose a smaller time window. See [Paginate results](https://platform.claude.com/docs/en/manage-claude/compliance-activity-feed#paginate-results) for the full contract.
5454 
5555Even with clean tiling, an activity that indexes after its window has closed never appears in a later window. Deduplicate on the activity `id` and either widen each new window so it overlaps the previous one by a few minutes or run a periodic reconciliation pass that re-queries an older window.
5656 
from line 88
8888Cursors survive key rotation; see [Manage and rotate keys](https://platform.claude.com/docs/en/manage-claude/compliance-api-access#manage-and-rotate-keys).
8989 
9090<Warning>
91 Each page is adjacent to the cursor you pass: the loop walks forward toward the present, one page at a time. Do not treat a single response as caught up while `has_more` is `true`. Persist the cursor only after `has_more` is `false`; the unfetched pages are the newer ones between this response's `first_id` and the present, and they stay unread until you finish the loop or run again.
91 Each page is adjacent to the cursor you pass: the loop walks forward toward the present, one page at a time. Do not treat a single response as caught up while `has_more` is `true`. Persist the cursor only after `has_more` is `false`; the unfetched pages are the newer ones between this response’s `first_id` and the present, and they stay unread until you finish the loop or run again.
9292</Warning>
9393 
9494## Correlate with your SIEM
from line 97
9797 
9898| Compliance API field | Join target |
9999| --------------------- | ----------------------------------------------------------------------- |
100| `actor.user_id` | Your identity provider's stable user identifier |
100| `actor.user_id` | Your identity provider’s stable user identifier |
101101| `actor.email_address` | Directory email when a stable ID is unavailable |
102102| `actor.ip_address` | Network, VPN, and endpoint logs |
103103| `actor.user_agent` | Endpoint and device inventory, and the client app that made the request |
104104| `created_at` | Time-window correlation across any source |
105105 
106`actor.user_id` and `actor.email_address` are present when `actor.type` is `user_actor`. `actor.ip_address` and `actor.user_agent` are absent on some actor types, such as `anthropic_actor` and `scim_directory_sync_actor`. Check the discriminator before reading any of these fields. `user_id` is a stable, opaque identifier for the user account: it is consistent across every Compliance API endpoint and activity payload, and it does not change when the user's email or display name changes. Use `user_id`, not `email_address`, as the primary join key.
106`actor.user_id` and `actor.email_address` are present when `actor.type` is `user_actor`. `actor.ip_address` and `actor.user_agent` are absent on some actor types, such as `anthropic_actor` and `scim_directory_sync_actor`. Check the discriminator before reading any of these fields. `user_id` is a stable, opaque identifier for the user account: it is consistent across every Compliance API endpoint and activity payload, and it does not change when the user’s email or display name changes. Use `user_id`, not `email_address`, as the primary join key.
107107 
108108Calls to the Compliance API itself emit `compliance_api_accessed` activities. Ingest these alongside other activity types so your SIEM records who queried compliance data, and when. Pass `activity_types[]=compliance_api_accessed` to scope the query, then in your client, read `actor.api_key_id` from each activity whose `actor.type` is `api_actor` to attribute the access to a specific Compliance Access Key or Admin API key.
109109 
from line 114
114114| Data | Retained for | Controlled by |
115115| ------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- |
116116| Activity Feed records | 6 years | Anthropic |
117| Chat, file, and project content | Your organization's claude.ai retention policy, unless a user deletes it sooner | Your organization |
118| Local session transcripts (sessions on users' machines) | 6 years by default, or your organization's custom conversation retention period when a finite one is set; 30 days in organizations with HIPAA readiness enabled | Anthropic by default; your organization when it sets a custom period |
117| Chat, file, and project content | Your organization’s claude.ai retention policy, unless a user deletes it sooner | Your organization |
118| Local session transcripts (sessions on users’ machines) | 6 years by default, or your organization’s custom conversation retention period when a finite one is set; 30 days in organizations with HIPAA readiness enabled | Anthropic by default; your organization when it sets a custom period |
119119| Remote session transcripts (sessions in the cloud) | 6 years, unless a user deletes the session sooner | Anthropic |
120120| Content hard-deleted through the Compliance API | Not retained; deletion is immediate and permanent | The caller of the `DELETE` endpoint |
121121 
from line 124
124124Decide between export-and-archive and on-demand API retrieval as follows:
125125 
126126* If your legal-hold or audit horizon exceeds 6 years for activity metadata or session transcripts, export Activity Feed pages and session transcripts to your own archive as you ingest them.
127* If your content-retention policy is shorter than your eDiscovery horizon, export chat and file content before the retention window expires; the Compliance API cannot return content that retention has already removed. The same applies to local session transcripts, which follow your organization's custom conversation retention period when a finite one is set, even when that period is shorter than 6 years. The local session endpoints stop returning messages older than your organization's current period as soon as the setting changes, and lengthening the period later does not restore transcripts that have already expired, so export any transcript you must keep beyond it.
127* If your content-retention policy is shorter than your eDiscovery horizon, export chat and file content before the retention window expires; the Compliance API cannot return content that retention has already removed. The same applies to local session transcripts, which follow your organization’s custom conversation retention period when a finite one is set, even when that period is shorter than 6 years. The local session endpoints stop returning messages older than your organization’s current period as soon as the setting changes, and lengthening the period later does not restore transcripts that have already expired, so export any transcript you must keep beyond it.
128128* If you must retain chat content or remote session transcripts after users delete them in claude.ai (for example, under a legal hold), export chat, file, artifact, and remote session content to your own archive as you ingest it; the Compliance API cannot return content that a user has already deleted.
129129* If a workflow might issue a Compliance API hard-delete (for example, DLP enforcement), retrieve and archive the target content first. There is no recovery window after a hard-delete.
130130 
from line 140
140140* The number of records exported.
141141* The run timestamp and the `request-id` of the final page.
142142 
143Activity volume is not a completeness check. The `claude_*_viewed` activity types, such as `claude_chat_viewed`, follow each app's loading pattern (see [Understand the Activity object](https://platform.claude.com/docs/en/manage-claude/compliance-activity-feed#understand-the-activity-object)). A period with chat messages but no `claude_chat_viewed` activities does not on its own indicate missing data. Rely on the traversal and the overlap or reconciliation pass described in [Window polling](https://platform.claude.com/docs/en/manage-claude/compliance-integration-patterns#window-polling) instead.
143Activity volume is not a completeness check. The `claude_*_viewed` activity types, such as `claude_chat_viewed`, follow each app’s loading pattern (see [Understand the Activity object](https://platform.claude.com/docs/en/manage-claude/compliance-activity-feed#understand-the-activity-object)). A period with chat messages but no `claude_chat_viewed` activities does not on its own indicate missing data. Rely on the traversal and the overlap or reconciliation pass described in [Window polling](https://platform.claude.com/docs/en/manage-claude/compliance-integration-patterns#window-polling) instead.
144144 
145145The content endpoints (chats, files, projects, project attachments, and local and remote session transcripts) serve Claude Enterprise data only. The Activity Feed surfaces administrative and resource events organization-wide. The Compliance API does not include:
146146 
147147* Prompt text or model responses from Claude Console, or from Claude API workloads authenticated with an API key.
148148* On-device activity in local sessions that is never sent to Anthropic, such as local files that Claude did not read.
149* Claude Code usage authenticated with a Claude Console API key, run through a third-party cloud platform (Amazon Bedrock, Google Cloud, or Microsoft Foundry), or run in a [Claude Code cloud session](https://code.claude.com/docs/en/claude-code-on-the-web), which runs on cloud infrastructure instead of the user's machine.
149* Claude Code usage authenticated with a Claude Console API key, run through a third-party cloud platform (Amazon Bedrock, Google Cloud, or Microsoft Foundry), or run in a [Claude Code cloud session](https://code.claude.com/docs/en/claude-code-on-the-web), which runs on cloud infrastructure instead of the user’s machine.
150150* Local sessions from products other than Cowork and Claude Code in organizations with [HIPAA readiness](https://platform.claude.com/docs/en/manage-claude/api-and-data-retention#hipaa-readiness) enabled, and local sessions for which [zero data retention](https://platform.claude.com/docs/en/manage-claude/api-and-data-retention#zero-data-retention-zdr-scope) is in effect.
151151* Thinking blocks, and images or other binary content, inside session transcripts (transcripts carry user prompts, assistant responses, and tool activity only; local session transcripts show a placeholder `text` block where binary content was omitted).
152152* The original file for a chat attachment that claude.ai stored as extracted text, such as some Word, PowerPoint, and PDF uploads (the file content endpoint returns the extracted text; see [Retrieve files and artifacts](https://platform.claude.com/docs/en/manage-claude/compliance-content-data#retrieve-files-and-artifacts)).
from line 153
153153* The system prompt of local sessions (a marker message stands in for it).
154154* Tool definitions and MCP server configuration in session transcripts (local or remote), and citation metadata on `text` blocks in local session transcripts.
155155* Local session transcript content in an organization whose [customer-managed encryption key](https://platform.claude.com/docs/en/manage-claude/cmek) cannot currently be used. Those requests return [503 Service Unavailable](https://platform.claude.com/docs/en/manage-claude/compliance-errors#local-sessions-temporarily-unavailable), and session metadata is still listed.
156* Content removed by your organization's retention policy.
156* Content removed by your organization’s retention policy.
157157* Content of chats that users delete in claude.ai (the chats are still listed, with `deleted_at` populated).
158158* Remote sessions that users delete (deleted sessions are no longer listed, and the messages endpoint returns 404 for them).
159159* Content hard-deleted through the Compliance API.

manage-claude/compliance-org-data Changed · +15 / -15 lines

from line 70
7070 
7171See [List organization users](https://platform.claude.com/docs/en/api/compliance/organizations/users/list) in the API reference for the `limit` and `page` query parameter defaults and ranges.
7272 
73Results are sorted by organization join date ascending. Unlike the Activity Feed's `before_id`/`after_id` cursors (see [Paginate results](https://platform.claude.com/docs/en/manage-claude/compliance-activity-feed#paginate-results)), the directory endpoints paginate with a `next_page` token: when `has_more` is `true`, pass `next_page` back unchanged as the `page` query parameter on the next request.
73Results are sorted by organization join date ascending. Unlike the Activity Feed’s `before_id`/`after_id` cursors (see [Paginate results](https://platform.claude.com/docs/en/manage-claude/compliance-activity-feed#paginate-results)), the directory endpoints paginate with a `next_page` token: when `has_more` is `true`, pass `next_page` back unchanged as the `page` query parameter on the next request.
7474 
7575```bash cURL
7676curl --fail-with-body -sS -G \
from line 96
9696}
9797```
9898 
99The user IDs returned here are the same `user_...` identifiers accepted by the [Query the Activity Feed](https://platform.claude.com/docs/en/manage-claude/compliance-activity-feed) `actor_ids[]` filter. The `user_ids[]` filters on [Retrieve chats and messages](https://platform.claude.com/docs/en/manage-claude/compliance-content-data#retrieve-chats-and-messages) and the [remote session list](https://platform.claude.com/docs/en/manage-claude/compliance-sessions#retrieve-remote-sessions) accept the same identifiers. The [local session list](https://platform.claude.com/docs/en/manage-claude/compliance-sessions#retrieve-local-sessions) has no user filter, so attribute local sessions by the `user.id` on each session object. The `organization_role` field carries the user's built-in membership level within the listed organization (one of `admin`, `billing`, `claude_code_user`, `developer`, `managed`, `membership_admin`, `owner`, `primary_owner`, or `user`), an axis independent of any custom RBAC role assignments returned by [List roles](https://platform.claude.com/docs/en/manage-claude/compliance-org-data#list-roles). A typical eDiscovery flow lists users for one or more organizations, filters against your own external records, and feeds the resulting IDs into chat and project queries.
99The user IDs returned here are the same `user_...` identifiers accepted by the [Query the Activity Feed](https://platform.claude.com/docs/en/manage-claude/compliance-activity-feed) `actor_ids[]` filter. The `user_ids[]` filters on [Retrieve chats and messages](https://platform.claude.com/docs/en/manage-claude/compliance-content-data#retrieve-chats-and-messages) and the [remote session list](https://platform.claude.com/docs/en/manage-claude/compliance-sessions#retrieve-remote-sessions) accept the same identifiers. The [local session list](https://platform.claude.com/docs/en/manage-claude/compliance-sessions#retrieve-local-sessions) has no user filter, so attribute local sessions by the `user.id` on each session object. The `organization_role` field carries the user’s built-in membership level within the listed organization (one of `admin`, `billing`, `claude_code_user`, `developer`, `managed`, `membership_admin`, `owner`, `primary_owner`, or `user`), an axis independent of any custom RBAC role assignments returned by [List roles](https://platform.claude.com/docs/en/manage-claude/compliance-org-data#list-roles). A typical eDiscovery flow lists users for one or more organizations, filters against your own external records, and feeds the resulting IDs into chat and project queries.
100100 
101101A user only appears here while they are an active member of the organization. Removed users are dropped from the list immediately. Their historical activity remains queryable through the Activity Feed for the full retention window, indexed by the same `user_...` ID.
102102 
from line 222
222222}
223223```
224224 
225See the [List Compliance Group Members](https://platform.claude.com/docs/en/api/compliance/groups/members/list) response schema for the full member record shape. The `user_id` field is the same `user_...` identifier that the Activity Feed, chat list, and remote session list accept; it also matches `user.id` on local session objects and on user-owned remote session objects (agent-owned remote sessions carry the human's ID in `started_by_user.id` instead). To get a member's full name, look it up through the organization users list.
225See the [List Compliance Group Members](https://platform.claude.com/docs/en/api/compliance/groups/members/list) response schema for the full member record shape. The `user_id` field is the same `user_...` identifier that the Activity Feed, chat list, and remote session list accept; it also matches `user.id` on local session objects and on user-owned remote session objects (agent-owned remote sessions carry the human’s ID in `started_by_user.id` instead). To get a member’s full name, look it up through the organization users list.
226226 
227227## Get effective organization settings
228228 
229229The [Get effective organization settings](https://platform.claude.com/docs/en/api/compliance/organizations/settings/retrieve) endpoint returns the settings in force for one organization under your parent: the enforced state after regulatory restrictions (such as HIPAA), feature-availability rules, organization-type defaults, and inter-feature dependencies are applied, which can differ from what an administrator configured. Use it to attest that retention windows, content redaction, single sign-on enforcement, the IP allowlist, and session-duration controls match your documented baseline, without administrator Console access.
230230 
231This endpoint requires `read:compliance_org_data`; a key without that scope returns [403 Forbidden](https://platform.claude.com/docs/en/manage-claude/compliance-errors#403-forbidden). The target must be one of the parent's linked organizations: the parent organization itself is not a valid target. All of the following return the same [404 Not Found](https://platform.claude.com/docs/en/manage-claude/compliance-errors#404-not-found):
231This endpoint requires `read:compliance_org_data`; a key without that scope returns [403 Forbidden](https://platform.claude.com/docs/en/manage-claude/compliance-errors#403-forbidden). The target must be one of the parent’s linked organizations: the parent organization itself is not a valid target. All of the following return the same [404 Not Found](https://platform.claude.com/docs/en/manage-claude/compliance-errors#404-not-found):
232232 
233233* An unknown organization
234234* An organization ID that is not a valid UUID
235* An organization outside your parent's tree
235* An organization outside your parent’s tree
236236* A parent organization that does not yet have access to this endpoint
237237 
238238A 404 therefore does not reveal whether an organization exists. The settings endpoint is enabled per parent organization separately from the rest of the Compliance API; if every request returns 404, contact your Anthropic representative.
from line 248
248248 -H "anthropic-version: 2023-06-01"
249249```
250250 
251The response is a list of typed setting rows, and which rows appear varies by organization: a setting the organization's administrators cannot change, because it is controlled by Anthropic policy or not available to the organization, is omitted from the list. Treat a missing row as "not controllable by this organization's administrators", not as "off". The following abridged example shows three of the rows a response can contain:
251The response is a list of typed setting rows, and which rows appear varies by organization: a setting the organization’s administrators cannot change, because it is controlled by Anthropic policy or not available to the organization, is omitted from the list. Treat a missing row as “not controllable by this organization’s administrators”, not as “off”. The following abridged example shows three of the rows a response can contain:
252252 
253253```json Response
254254{
from line 294
294294 
295295Each row carries `name`, `type`, and `value`; the `type` field (`boolean`, `integer`, `string_list`, `provisioning_mode`, or `data_retention`) tells you the shape of `value`. The full list of setting names, and the `value` schema for each type, is in [Get effective organization settings](https://platform.claude.com/docs/en/api/compliance/organizations/settings/retrieve) in the API reference.
296296 
297The `api_keys` array lists every Compliance Access Key configured for your parent organization, so the same list is returned regardless of which linked organization you query. Each entry carries the key's `type` (`compliance_api_key`), `id`, `name`, `scopes`, `is_active` flag, `created_at` and `expires_at` timestamps, and `created_by_id` (the ID of the user who created the key, or `null`). The key's secret value is never returned. Deactivated keys are included with `is_active: false` so you can review keys that previously had access, and keys that carry only the retired `read:compliance_org_settings` scope remain in the list for audit and cleanup visibility even though that scope no longer grants access.
297The `api_keys` array lists every Compliance Access Key configured for your parent organization, so the same list is returned regardless of which linked organization you query. Each entry carries the key’s `type` (`compliance_api_key`), `id`, `name`, `scopes`, `is_active` flag, `created_at` and `expires_at` timestamps, and `created_by_id` (the ID of the user who created the key, or `null`). The key’s secret value is never returned. Deactivated keys are included with `is_active: false` so you can review keys that previously had access, and keys that carry only the retired `read:compliance_org_settings` scope remain in the list for audit and cleanup visibility even though that scope no longer grants access.
298298 
299The top-level `organization_id` is the organization's bare UUID: the same value as `uuid` in the organizations list, not the `org_`-prefixed form that `organization_id` carries on Activity Feed, chat, and project records (see the [organization identifier table](https://platform.claude.com/docs/en/manage-claude/compliance-org-data#list-organizations)).
299The top-level `organization_id` is the organization’s bare UUID: the same value as `uuid` in the organizations list, not the `org_`-prefixed form that `organization_id` carries on Activity Feed, chat, and project records (see the [organization identifier table](https://platform.claude.com/docs/en/manage-claude/compliance-org-data#list-organizations)).
300300 
301301Rows reflect the enforced state rather than the last-stored configuration, as in these examples:
302302 
from line 308
308308 
309309## Read plugins and plugin marketplaces
310310 
311Your organization's plugins and plugin marketplaces are part of the [Admin API](https://platform.claude.com/docs/en/manage-claude/plugins-api) rather than the Compliance API, but a Compliance Access Key with `read:compliance_org_data` can call the Plugins API's read endpoints directly:
311Your organization’s plugins and plugin marketplaces are part of the [Admin API](https://platform.claude.com/docs/en/manage-claude/plugins-api) rather than the Compliance API, but a Compliance Access Key with `read:compliance_org_data` can call the Plugins API’s read endpoints directly:
312312 
313313* List plugins and retrieve a plugin
314* List a plugin's versions, retrieve a version, and download a version's files
315* List a plugin's installation settings and its shares
314* List a plugin’s versions, retrieve a version, and download a version’s files
315* List a plugin’s installation settings and its shares
316316* List plugin marketplaces and retrieve a marketplace
317317 
318Send the `anthropic-beta: ce-plugins-2026-09-01` header on every request; without it these endpoints return [404 Not Found](https://platform.claude.com/docs/en/manage-claude/plugins-api#error-responses). Each call reads one organization: a key that covers the parent organization reads the linked organization it was created in unless you pass the `organization_id` query parameter (a linked organization's UUID or its `org_`-prefixed ID) to [read a different one](https://platform.claude.com/docs/en/manage-claude/plugins-api#reading-another-organization-under-the-same-parent), and a key restricted to one organization reads only that organization. These calls count against the Admin API's [rate limits](https://platform.claude.com/docs/en/manage-claude/plugins-api#rate-limiting), not the Compliance API's.
318Send the `anthropic-beta: ce-plugins-2026-09-01` header on every request; without it these endpoints return [404 Not Found](https://platform.claude.com/docs/en/manage-claude/plugins-api#error-responses). Each call reads one organization: a key that covers the parent organization reads the linked organization it was created in unless you pass the `organization_id` query parameter (a linked organization’s UUID or its `org_`-prefixed ID) to [read a different one](https://platform.claude.com/docs/en/manage-claude/plugins-api#reading-another-organization-under-the-same-parent), and a key restricted to one organization reads only that organization. These calls count against the Admin API’s [rate limits](https://platform.claude.com/docs/en/manage-claude/plugins-api#rate-limiting), not the Compliance API’s.
319319 
320Creating or changing plugins, their installation settings, or a marketplace's settings requires an Admin API key with `write:plugins`. Of the read calls, only downloading the files of a plugin in a member's personal marketplace records an [Activity Feed](https://platform.claude.com/docs/en/manage-claude/compliance-activity-feed) event (`claude_plugin_archive_accessed`). See the [Plugins API guide](https://platform.claude.com/docs/en/manage-claude/plugins-api) for each endpoint, request examples, and the [events the API records](https://platform.claude.com/docs/en/manage-claude/plugins-api#activity-feed-events).
320Creating or changing plugins, their installation settings, or a marketplace’s settings requires an Admin API key with `write:plugins`. Of the read calls, only downloading the files of a plugin in a member’s personal marketplace records an [Activity Feed](https://platform.claude.com/docs/en/manage-claude/compliance-activity-feed) event (`claude_plugin_archive_accessed`). See the [Plugins API guide](https://platform.claude.com/docs/en/manage-claude/plugins-api) for each endpoint, request examples, and the [events the API records](https://platform.claude.com/docs/en/manage-claude/plugins-api#activity-feed-events).
321321 
322322## Next steps
323323 

manage-claude/compliance-sessions Changed · +47 / -47 lines

## Sessions on users’ machines (local sessions) ## Sessions on users' machines (local sessions)

from line 16
1616 
1717The endpoints on this page expose session transcripts from your Claude Enterprise organizations to compliance reviewers. The transcripts cover the sessions your users run in Claude apps and agents (today: Cowork, Claude Code, Claude Science, Claude for Microsoft 365, the Claude add-ins for Google Docs, Google Sheets, and Google Slides, and Claude in Chrome). Each session is a single conversation with Claude; its transcript is the sequence of user prompts, assistant responses, and tool calls and results in that conversation. The endpoints support eDiscovery (electronic discovery) exports and data loss prevention (DLP) enforcement.
1818 
19The Compliance API groups sessions into two endpoint families according to where they run: local session endpoints for sessions on users' machines, and remote session endpoints for sessions that run in the cloud in Anthropic-managed environments. Both families are read-only, and neither is available to Admin API keys (`sk-ant-admin01-...`): calls authenticated with an Admin API key return [403 Forbidden](https://platform.claude.com/docs/en/manage-claude/compliance-errors#403-forbidden).
19The Compliance API groups sessions into two endpoint families according to where they run: local session endpoints for sessions on users’ machines, and remote session endpoints for sessions that run in the cloud in Anthropic-managed environments. Both families are read-only, and neither is available to Admin API keys (`sk-ant-admin01-...`): calls authenticated with an Admin API key return [403 Forbidden](https://platform.claude.com/docs/en/manage-claude/compliance-errors#403-forbidden).
2020 
2121The following table maps each product, and where it runs, to the endpoint family that returns its sessions and the `product_surface` value that identifies them in responses. Products are added to this table as coverage expands.
2222 
2323| Product and where it runs | Endpoint family | `product_surface` |
2424| ---------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- |
25| Cowork in Claude Desktop, running on the user's machine | Local session endpoints (`/v1/compliance/apps/sessions/local`) | `cowork` |
26| Claude Code in the terminal, in Claude Desktop, or in an IDE extension, running on the user's machine | Local session endpoints | `claude_code` |
27| Claude Science desktop app, running on the user's machine | Local session endpoints | `claude_science` |
25| Cowork in Claude Desktop, running on the user’s machine | Local session endpoints (`/v1/compliance/apps/sessions/local`) | `cowork` |
26| Claude Code in the terminal, in Claude Desktop, or in an IDE extension, running on the user’s machine | Local session endpoints | `claude_code` |
27| Claude Science desktop app, running on the user’s machine | Local session endpoints | `claude_science` |
2828| Claude for Microsoft 365 (the Claude add-ins for Excel, PowerPoint, Word, and Outlook), running in the Microsoft 365 desktop or web apps | Local session endpoints | `office_agents/excel`, `office_agents/powerpoint`, `office_agents/word`, or `office_agents/outlook` |
2929| The Claude add-ins for Google Docs, Google Sheets, and Google Slides, running in those Google apps | Local session endpoints | `office_agents/google_docs`, `office_agents/google_sheets`, or `office_agents/google_slides` |
30| Claude in Chrome (the browser extension's built-in chat), running on the user's machine | Local session endpoints | `claude_in_chrome` |
30| Claude in Chrome (the browser extension’s built-in chat), running on the user’s machine | Local session endpoints | `claude_in_chrome` |
3131| Cowork sessions started on claude.ai web or mobile, running in the cloud in Anthropic-managed environments | Remote session endpoints (`/v1/compliance/apps/sessions/remote`) | `cowork_remote` |
3232 
33`office_agents` alone does not say which app the session came from, and it can come from Claude for Microsoft 365 or the Google add-ins. See the `product_surface` description under [Sessions on users' machines](https://platform.claude.com/docs/en/manage-claude/compliance-sessions#retrieve-local-sessions).
33`office_agents` alone does not say which app the session came from, and it can come from Claude for Microsoft 365 or the Google add-ins. See the `product_surface` description under [Sessions on users’ machines](https://platform.claude.com/docs/en/manage-claude/compliance-sessions#retrieve-local-sessions).
3434 
3535Capture of local sessions is tied to the Compliance API being enabled for your organization and applies while users are signed in with their Claude Enterprise account. The session endpoints do not return the following:
3636 
3737* Claude Code sessions authenticated with a Claude Console API key, or run through a third-party cloud platform such as Amazon Bedrock, Google Cloud, or Microsoft Foundry.
38* [Claude Code cloud sessions](https://code.claude.com/docs/en/claude-code-on-the-web) (including Claude Code routines that run in the cloud), which run on cloud infrastructure instead of the user's machine. These cloud sessions are not remote sessions, even though both run in the cloud; the remote session endpoints return Cowork sessions only.
38* [Claude Code cloud sessions](https://code.claude.com/docs/en/claude-code-on-the-web) (including Claude Code routines that run in the cloud), which run on cloud infrastructure instead of the user’s machine. These cloud sessions are not remote sessions, even though both run in the cloud; the remote session endpoints return Cowork sessions only.
3939* Local sessions from products other than Cowork and Claude Code in organizations with [HIPAA readiness](https://platform.claude.com/docs/en/manage-claude/api-and-data-retention#hipaa-readiness) enabled. In those organizations, the local session endpoints return Cowork and Claude Code sessions only, and captured session content is stored for 30 days.
4040* Local sessions for which [zero data retention (ZDR)](https://platform.claude.com/docs/en/manage-claude/api-and-data-retention#zero-data-retention-zdr-scope) is in effect. These sessions are excluded from list results, and the retrieve and messages endpoints return 404 for them.
4141 
42Anthropic recommends the Compliance API for retrieving session content. The following table compares [local sessions](https://platform.claude.com/docs/en/manage-claude/compliance-sessions#retrieve-local-sessions) and [remote sessions](https://platform.claude.com/docs/en/manage-claude/compliance-sessions#retrieve-remote-sessions) with the OpenTelemetry-based alternatives available for Cowork and Claude Code, [Cowork's OpenTelemetry logging](https://support.claude.com/en/articles/14477985-monitor-claude-cowork-activity-with-opentelemetry) and [Claude Code monitoring](https://code.claude.com/docs/en/monitoring-usage).
42Anthropic recommends the Compliance API for retrieving session content. The following table compares [local sessions](https://platform.claude.com/docs/en/manage-claude/compliance-sessions#retrieve-local-sessions) and [remote sessions](https://platform.claude.com/docs/en/manage-claude/compliance-sessions#retrieve-remote-sessions) with the OpenTelemetry-based alternatives available for Cowork and Claude Code, [Cowork’s OpenTelemetry logging](https://support.claude.com/en/articles/14477985-monitor-claude-cowork-activity-with-opentelemetry) and [Claude Code monitoring](https://code.claude.com/docs/en/monitoring-usage).
4343 
44| | Local sessions (on users' machines) | Remote sessions (in the cloud) | OpenTelemetry logging |
44| | Local sessions (on users’ machines) | Remote sessions (in the cloud) | OpenTelemetry logging |
4545| --------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------- |
4646| Delivery | Pull: query and export over HTTPS | Pull: query and export over HTTPS | Push: streamed to your OTLP collector |
4747| Setup | Works with your existing Compliance Access Key | Works with your existing Compliance Access Key | Admin configures an OTLP endpoint and content-capture settings |
from line 48
4848| Infrastructure | Anthropic-hosted | Anthropic-hosted | You run the collector and storage |
4949| ID prefix | `clls_` | `cse_` | N/A |
5050| `product_surface` values | `cowork`, `claude_code`, `claude_science`, `claude_in_chrome`, and values starting with `office_agents` | `cowork_remote` | N/A |
51| Retention | 6 years by default, or your organization's custom conversation retention period when a finite one is set; 30 days in organizations with HIPAA readiness enabled; held by Anthropic | 6 years, unless a user deletes the session sooner; held by Anthropic | Your infrastructure, your policies |
51| Retention | 6 years by default, or your organization’s custom conversation retention period when a finite one is set; 30 days in organizations with HIPAA readiness enabled; held by Anthropic | 6 years, unless a user deletes the session sooner; held by Anthropic | Your infrastructure, your policies |
5252| User prompts and assistant responses | Yes | Yes | Yes, subject to content-capture settings |
5353| Tool inputs | Truncated to 10,000 bytes per input by default; up to about 1 MiB on request | Truncated to 10,000 bytes per input by default; up to about 1 MiB on request | Truncated summaries |
5454| Tool result content | Each text entry truncated to 10,000 bytes by default; up to about 1 MiB on request | Each text entry truncated to 10,000 bytes by default; up to about 1 MiB on request | Metadata such as size and success; Claude Code can also capture content with an optional, size-capped setting |
from line 56
5656| Host and device metadata (terminal type, workspace paths) | No | No | Yes |
5757| Token usage and cost | No; available through the [Claude Enterprise Analytics API](https://platform.claude.com/docs/en/manage-claude/analytics-api#get-access-to-the-claude-enterprise-analytics-api) | No; available through the [Claude Enterprise Analytics API](https://platform.claude.com/docs/en/manage-claude/analytics-api#get-access-to-the-claude-enterprise-analytics-api) | Yes |
5858 
59## Sessions on users' machines (local sessions)
59## Sessions on users’ machines (local sessions)
6060 
61Local sessions run on users' machines while they are signed in with their Claude Enterprise account, today in the following products:
61Local sessions run on users’ machines while they are signed in with their Claude Enterprise account, today in the following products:
6262 
6363* Cowork in Claude Desktop
6464* Claude Code (in the terminal, in Claude Desktop, or in an IDE extension)
from line 67
6767* The Claude add-ins for Google Docs, Google Sheets, and Google Slides
6868* The Claude in Chrome browser extension
6969 
70The Compliance API exposes local sessions through three endpoints: `GET /v1/compliance/apps/sessions/local` lists session metadata, `GET /v1/compliance/apps/sessions/local/{session_id}` retrieves one session's metadata, and `GET /v1/compliance/apps/sessions/local/{session_id}/messages` returns one session's transcript. All three require the `read:compliance_user_data` scope and count only against the shared Compliance API rate limit; they are not subject to the second request budget that applies to the remote session endpoints. See [429 Too Many Requests](https://platform.claude.com/docs/en/manage-claude/compliance-errors#429-too-many-requests). If local sessions are not available to your parent organization, all three endpoints return 404 with the message `Local sessions are not available.` (see [Local session not found](https://platform.claude.com/docs/en/manage-claude/compliance-errors#local-session-not-found)); while session listings or captured content are temporarily unavailable, they return 503 (see [Local sessions temporarily unavailable](https://platform.claude.com/docs/en/manage-claude/compliance-errors#local-sessions-temporarily-unavailable)).
70The Compliance API exposes local sessions through three endpoints: `GET /v1/compliance/apps/sessions/local` lists session metadata, `GET /v1/compliance/apps/sessions/local/{session_id}` retrieves one session’s metadata, and `GET /v1/compliance/apps/sessions/local/{session_id}/messages` returns one session’s transcript. All three require the `read:compliance_user_data` scope and count only against the shared Compliance API rate limit; they are not subject to the second request budget that applies to the remote session endpoints. See [429 Too Many Requests](https://platform.claude.com/docs/en/manage-claude/compliance-errors#429-too-many-requests). If local sessions are not available to your parent organization, all three endpoints return 404 with the message `Local sessions are not available.` (see [Local session not found](https://platform.claude.com/docs/en/manage-claude/compliance-errors#local-session-not-found)); while session listings or captured content are temporarily unavailable, they return 503 (see [Local sessions temporarily unavailable](https://platform.claude.com/docs/en/manage-claude/compliance-errors#local-sessions-temporarily-unavailable)).
7171 
7272For local sessions, Anthropic records each conversation server-side as its requests reach the Claude API; nothing is installed on the device, and nothing is collected beyond the requests the client already sends to the Claude API. Local session transcripts show what Claude was asked to do and what it returned, not what occurred on the device. File and network activity is visible only through the tool calls and tool results in the transcript, so activity that never reaches the API (for example, local files the session never sent) is not captured.
7373 
from line 118
118118}
119119```
120120 
121Results are sorted in reverse chronological order (newest first) by `created_at`, with ties broken in a fixed server-side order, and capped at `limit` results for each response (default 100, max 500). The endpoint paginates forward only with `page` and `next_page` tokens (see [Paginate results](https://platform.claude.com/docs/en/manage-claude/compliance-activity-feed#paginate-results)): pass the response's `next_page` value back as the `page` query parameter on the next request, and stop when `next_page` is `null`. The response has no `has_more` field. Complete a list walk within 24 hours of starting it; an older list cursor is still accepted but is re-evaluated against the current retention boundary, so sessions whose oldest retained activity is about to age out of the retention period can be skipped.
121Results are sorted in reverse chronological order (newest first) by `created_at`, with ties broken in a fixed server-side order, and capped at `limit` results for each response (default 100, max 500). The endpoint paginates forward only with `page` and `next_page` tokens (see [Paginate results](https://platform.claude.com/docs/en/manage-claude/compliance-activity-feed#paginate-results)): pass the response’s `next_page` value back as the `page` query parameter on the next request, and stop when `next_page` is `null`. The response has no `has_more` field. Complete a list walk within 24 hours of starting it; an older list cursor is still accepted but is re-evaluated against the current retention boundary, so sessions whose oldest retained activity is about to age out of the retention period can be skipped.
122122 
123In each session object, `user.id` is always set and survives account deletion; `user.email_address` is `null` when the user's account has been deleted or the user is no longer a member of an organization your key can read. `workspace_id` is `null` when the session was not associated with a workspace. A local session corresponds to one client session ID: opening a new conversation in the client, or clearing its context, starts a new session record. For Claude Science, the list can also include separate sessions for the app's own background work (for example, naming the conversation; on newer app versions also its reviewer and delegation tracks), and on older app versions some of that background work appears as extra messages inside the conversation's own transcript. A Claude Science conversation that continues across some app updates appears as two sessions. These behaviors are expected. Treat `id` values as opaque strings; the format may change without notice.
123In each session object, `user.id` is always set and survives account deletion; `user.email_address` is `null` when the user’s account has been deleted or the user is no longer a member of an organization your key can read. `workspace_id` is `null` when the session was not associated with a workspace. A local session corresponds to one client session ID: opening a new conversation in the client, or clearing its context, starts a new session record. For Claude Science, the list can also include separate sessions for the app’s own background work (for example, naming the conversation; on newer app versions also its reviewer and delegation tracks), and on older app versions some of that background work appears as extra messages inside the conversation’s own transcript. A Claude Science conversation that continues across some app updates appears as two sessions. These behaviors are expected. Treat `id` values as opaque strings; the format may change without notice.
124124 
125125For Claude for Microsoft 365 and the Claude add-ins for Google Docs, Google Sheets, and Google Slides, deleting a conversation in the add-in occurs only on the client, so it is not reflected in the API: local sessions have no `deleted_at` field, and the session stays listed until retention removes it.
126126 
127Local sessions carry an `updated_at` but no `status`: a local session has no server-side lifecycle status, and its visibility is governed by retention instead. A local session is captured as the series of Claude API calls (inference calls) that the client makes during the session, and retention applies to each captured call individually. `created_at` is the timestamp of the session's earliest retained call and `updated_at` the timestamp of its last, both UTC. As older calls age past the retention period, `created_at` advances accordingly, and once every call in a session has aged out, the session is no longer returned; `updated_at` tracks the most recent call and is unaffected until then. Because `created_at` can shift between runs, deduplicate on `id` when you re-walk the list over time. To keep transcripts current as sessions gain messages, poll with the `updated_at.gte` filter, overlapping consecutive windows. On the list endpoint `updated_at` is a lower bound: for a session still active at a page boundary or the upper end of a `created_at` window, it can momentarily lag the session's true last activity, and a new call only becomes queryable after the short processing delay noted earlier. Because of that lag, set each run's `updated_at.gte` a few minutes before your previous run's start time, not to the previous run's time exactly. A bound set to the exact previous time silently and permanently drops a session whose final call was still indexing at that moment, because once the bound advances past that call no later run returns it. Deduplicate the returned sessions on `id`, re-fetch their transcripts, and deduplicate messages on `id`. Retrieving a session, or its messages, always reflects the exact latest retained call, so a periodic reconciliation pass over an older window is a more thorough alternative to widening the overlap.
127Local sessions carry an `updated_at` but no `status`: a local session has no server-side lifecycle status, and its visibility is governed by retention instead. A local session is captured as the series of Claude API calls (inference calls) that the client makes during the session, and retention applies to each captured call individually. `created_at` is the timestamp of the session’s earliest retained call and `updated_at` the timestamp of its last, both UTC. As older calls age past the retention period, `created_at` advances accordingly, and once every call in a session has aged out, the session is no longer returned; `updated_at` tracks the most recent call and is unaffected until then. Because `created_at` can shift between runs, deduplicate on `id` when you re-walk the list over time. To keep transcripts current as sessions gain messages, poll with the `updated_at.gte` filter, overlapping consecutive windows. On the list endpoint `updated_at` is a lower bound: for a session still active at a page boundary or the upper end of a `created_at` window, it can momentarily lag the session’s true last activity, and a new call only becomes queryable after the short processing delay noted earlier. Because of that lag, set each run’s `updated_at.gte` a few minutes before your previous run’s start time, not to the previous run’s time exactly. A bound set to the exact previous time silently and permanently drops a session whose final call was still indexing at that moment, because once the bound advances past that call no later run returns it. Deduplicate the returned sessions on `id`, re-fetch their transcripts, and deduplicate messages on `id`. Retrieving a session, or its messages, always reflects the exact latest retained call, so a periodic reconciliation pass over an older window is a more thorough alternative to widening the overlap.
128128 
129129The list is built from session activity metadata, so it can include sessions whose transcript content was not captured, for example sessions that ran before capture started for your organization (as far back as your retention period allows); the transcript of such a session returns each message with its content marked unavailable (see [Retrieve a local session transcript](https://platform.claude.com/docs/en/manage-claude/compliance-sessions#retrieve-a-local-session-transcript)).
130130 
131Captured local session content is stored for 6 years from capture by default. If the organization that ran the session has set a finite custom conversation retention period in [claude.ai > Organization settings > Data and privacy](https://claude.ai/admin-settings/data-privacy-controls), that period applies instead, whether it is shorter or longer than the default; when the organization has more than one custom retention period configured, the shortest applies. A change to that setting takes effect in two different ways: the endpoints stop returning activity older than the organization's current period as soon as the setting changes, whereas each captured message is stored for the period that was in effect when it was captured, so lengthening the period later does not restore content that has already expired. In organizations with [HIPAA readiness](https://platform.claude.com/docs/en/manage-claude/api-and-data-retention#hipaa-readiness) enabled, captured local session content is stored for 30 days from capture, or for the organization's custom conversation retention period when that is shorter; the 6-year default does not apply.
131Captured local session content is stored for 6 years from capture by default. If the organization that ran the session has set a finite custom conversation retention period in [claude.ai > Organization settings > Data and privacy](https://claude.ai/admin-settings/data-privacy-controls), that period applies instead, whether it is shorter or longer than the default; when the organization has more than one custom retention period configured, the shortest applies. A change to that setting takes effect in two different ways: the endpoints stop returning activity older than the organization’s current period as soon as the setting changes, whereas each captured message is stored for the period that was in effect when it was captured, so lengthening the period later does not restore content that has already expired. In organizations with [HIPAA readiness](https://platform.claude.com/docs/en/manage-claude/api-and-data-retention#hipaa-readiness) enabled, captured local session content is stored for 30 days from capture, or for the organization’s custom conversation retention period when that is shorter; the 6-year default does not apply.
132132 
133To fetch one session's metadata directly, pass its ID to `GET /v1/compliance/apps/sessions/local/{session_id}`. The response is the same session object the list endpoint returns, with no envelope and no transcript content. A malformed session ID returns [400 Bad Request](https://platform.claude.com/docs/en/manage-claude/compliance-errors#400-bad-request). A single [404 Not Found](https://platform.claude.com/docs/en/manage-claude/compliance-errors#404-not-found) covers four cases that the response does not distinguish:
133To fetch one session’s metadata directly, pass its ID to `GET /v1/compliance/apps/sessions/local/{session_id}`. The response is the same session object the list endpoint returns, with no envelope and no transcript content. A malformed session ID returns [400 Bad Request](https://platform.claude.com/docs/en/manage-claude/compliance-errors#400-bad-request). A single [404 Not Found](https://platform.claude.com/docs/en/manage-claude/compliance-errors#404-not-found) covers four cases that the response does not distinguish:
134134 
135135* The session is not in an organization your key can read (including sessions under another parent organization).
136136* The session does not exist.
from line 139
139139 
140140`product_surface` (string or `null`) tells you which product the session came from. It is `null` if the product was not recorded. Otherwise, it is one of these values:
141141 
142* `cowork`: Cowork in Claude Desktop on the user's machine
142* `cowork`: Cowork in Claude Desktop on the user’s machine
143143* `claude_code`: Claude Code
144144* `claude_science`: Claude Science
145145* `claude_in_chrome`: the built-in chat in the Claude in Chrome browser extension
from line 149
149149 
150150If a session shows `office_agents` on its own, nothing else in the response tells you which of these products it came from. Do not assume it is Claude for Microsoft 365.
151151 
152The value comes from the session's most recent activity, so it can change over time. The API started recording the Google values on October 5, 2026. A Google add-in session whose most recent activity occurred on or before that date can show `office_agents`. If the user works in that session again, it switches to the matching Google value.
152The value comes from the session’s most recent activity, so it can change over time. The API started recording the Google values on October 5, 2026. A Google add-in session whose most recent activity occurred on or before that date can show `office_agents`. If the user works in that session again, it switches to the matching Google value.
153153 
154154New values appear as these endpoints cover more products.
155155 
from line 159
159159 
160160### Retrieve a local session transcript
161161 
162The messages endpoint returns the session's transcript, reconstructed from the captured Claude API calls: user prompts, assistant text, tool calls, and the text portions of tool results, all returned as they were sent apart from size truncation. Nothing masks URLs, credentials, or personal data in that content, so treat transcripts as sensitive. The transcript omits or replaces the following:
162The messages endpoint returns the session’s transcript, reconstructed from the captured Claude API calls: user prompts, assistant text, tool calls, and the text portions of tool results, all returned as they were sent apart from size truncation. Nothing masks URLs, credentials, or personal data in that content, so treat transcripts as sensitive. The transcript omits or replaces the following:
163163 
164164* Thinking blocks are never included.
165* The request's system prompt is never returned. A marker message reading `[system prompt content not shown]` stands in for it (normally once for each session; a session with no captured content carries no marker).
165* The request’s system prompt is never returned. A marker message reading `[system prompt content not shown]` stands in for it (normally once for each session; a session with no captured content carries no marker).
166166* Tool definitions and MCP server configuration are not part of the transcript.
167* Images, PDFs, and other binary or structured blocks are not returned. Each appears as a `text` block reading `[<block type> content not shown]` (for example, `[image content not shown]`) with `truncated` set to `true`. Non-text items inside a tool result, such as [web search](https://platform.claude.com/docs/en/agents-and-tools/tool-use/web-search-tool) results or the output of the [code execution tool](https://platform.claude.com/docs/en/agents-and-tools/tool-use/code-execution-tool), are replaced by one `[N non-text item(s) not shown]` entry, and the tool result block's `truncated` is `true`. The matching tool call, with the search query or the code in its `input`, is still returned.
167* Images, PDFs, and other binary or structured blocks are not returned. Each appears as a `text` block reading `[<block type> content not shown]` (for example, `[image content not shown]`) with `truncated` set to `true`. Non-text items inside a tool result, such as [web search](https://platform.claude.com/docs/en/agents-and-tools/tool-use/web-search-tool) results or the output of the [code execution tool](https://platform.claude.com/docs/en/agents-and-tools/tool-use/code-execution-tool), are replaced by one `[N non-text item(s) not shown]` entry, and the tool result block’s `truncated` is `true`. The matching tool call, with the search query or the code in its `input`, is still returned.
168168* Citation metadata on `text` blocks, such as the source citations on an answer that draws on web search results, is omitted. The text itself is returned, and the block carries `truncated` set to `true`.
169169 
170Project instruction files such as `CLAUDE.md` appear as ordinary user-role content. Skill content appears when the client sends it as message content and is not distinguished from other user text. For a coverage summary, see the [Compliance API FAQ](https://platform.claude.com/docs/en/manage-claude/compliance-faq#data-coverage-and-retention); for a table comparing local sessions with remote sessions and OpenTelemetry logging, see this page's introduction.
170Project instruction files such as `CLAUDE.md` appear as ordinary user-role content. Skill content appears when the client sends it as message content and is not distinguished from other user text. For a coverage summary, see the [Compliance API FAQ](https://platform.claude.com/docs/en/manage-claude/compliance-faq#data-coverage-and-retention); for a table comparing local sessions with remote sessions and OpenTelemetry logging, see this page’s introduction.
171171 
172172```bash cURL
173173curl --fail-with-body -sS \
from line 289
289289}
290290```
291291 
292The response embeds a `session` envelope alongside the paginated `data` array. The first record in this example is the marker that stands in for the request's system prompt; its `provenance` is described later in this section. On this endpoint `user.email_address` is always `null`: the messages endpoint does not resolve email addresses, so a `null` here does not mean the user's account was deleted. To attribute a session to an email address, join `user.id` against the [list endpoint](https://platform.claude.com/docs/en/manage-claude/compliance-sessions#retrieve-local-sessions) or the retrieve endpoint (`GET /v1/compliance/apps/sessions/local/{session_id}`).
292The response embeds a `session` envelope alongside the paginated `data` array. The first record in this example is the marker that stands in for the request’s system prompt; its `provenance` is described later in this section. On this endpoint `user.email_address` is always `null`: the messages endpoint does not resolve email addresses, so a `null` here does not mean the user’s account was deleted. To attribute a session to an email address, join `user.id` against the [list endpoint](https://platform.claude.com/docs/en/manage-claude/compliance-sessions#retrieve-local-sessions) or the retrieve endpoint (`GET /v1/compliance/apps/sessions/local/{session_id}`).
293293 
294Messages are returned oldest first by default; pass `order=desc` to reverse. Pagination uses the same `page`/`next_page` scheme as the list endpoint, with a `limit` default of 100 and a max of 1,000. A page can end early when the response reaches its size limit, so a page with fewer than `limit` messages does not mean you have reached the end; keep paginating until `next_page` is `null`. Page cursors are bound to the session and sort order they were issued under, and a walk's cursors expire 24 hours after its first page: an expired cursor returns [400 Bad Request](https://platform.claude.com/docs/en/manage-claude/compliance-errors#400-bad-request) telling you to restart without the `page` parameter, and the restarted walk reflects the current retention boundary. A cursor issued for a different session or `order` also returns 400, as an invalid cursor.
294Messages are returned oldest first by default; pass `order=desc` to reverse. Pagination uses the same `page`/`next_page` scheme as the list endpoint, with a `limit` default of 100 and a max of 1,000. A page can end early when the response reaches its size limit, so a page with fewer than `limit` messages does not mean you have reached the end; keep paginating until `next_page` is `null`. Page cursors are bound to the session and sort order they were issued under, and a walk’s cursors expire 24 hours after its first page: an expired cursor returns [400 Bad Request](https://platform.claude.com/docs/en/manage-claude/compliance-errors#400-bad-request) telling you to restart without the `page` parameter, and the restarted walk reflects the current retention boundary. A cursor issued for a different session or `order` also returns 400, as an invalid cursor.
295295 
296On a very large session, the messages endpoint can return a 400 for a page, with a message saying that the page is too large to read; see [Transcript page too large](https://platform.claude.com/docs/en/manage-claude/compliance-errors#transcript-page-too-large). Do not retry that request. If it used `order=desc`, read that session oldest first from its first page instead, with no `order` and no `page`, and set your client's request timeout to at least 5 minutes. If an oldest-first page returns the same error, that errors guide entry says what to do.
296On a very large session, the messages endpoint can return a 400 for a page, with a message saying that the page is too large to read; see [Transcript page too large](https://platform.claude.com/docs/en/manage-claude/compliance-errors#transcript-page-too-large). Do not retry that request. If it used `order=desc`, read that session oldest first from its first page instead, with no `order` and no `page`, and set your client’s request timeout to at least 5 minutes. If an oldest-first page returns the same error, that errors guide entry says what to do.
297297 
298298On a very large session, the messages endpoint might also return a 429 whose `error.details.error_code` is `transcript_read_server_busy`. It does not mean that your organization exceeded a rate limit. Unlike the 400, retry it: wait the number of seconds in the `retry-after` header, then send the same request again, unchanged (with the same `page` value, if it had one). See [Server busy reading large transcripts](https://platform.claude.com/docs/en/manage-claude/compliance-errors#server-busy-reading-large-transcripts).
299299 
300Each message carries a `role` (`user` or `assistant`) and a `content` array of `text`, `tool_use`, and `tool_result` blocks. It also carries a `model`: on an assistant turn captured from the Claude API, this is the model that served the turn. The `model` is `null` on user messages and on any assistant message whose `provenance` is set, because client-asserted history and synthetic markers were not produced by a model and the serving model is unknown for unavailable content. A `text` block carries `text` and `truncated`. A `tool_use` block carries `id`, `name`, `input`, and `truncated`, where `input` is a JSON-encoded string rather than an object. A `tool_result` block carries `tool_use_id`, `name`, `is_error`, a `content` array of `text` entries, and `truncated`. MCP tool calls and results, and most server tool calls and results, are normalized into these same `tool_use` and `tool_result` shapes; any other block type appears as a `[<block type> content not shown]` placeholder. A message `id` is stable while the turn is retained. Every message reconstructed from the same inference call carries that call's timestamp, so consecutive messages often share a `created_at` value; preserve the returned order rather than re-sorting by timestamp.
300Each message carries a `role` (`user` or `assistant`) and a `content` array of `text`, `tool_use`, and `tool_result` blocks. It also carries a `model`: on an assistant turn captured from the Claude API, this is the model that served the turn. The `model` is `null` on user messages and on any assistant message whose `provenance` is set, because client-asserted history and synthetic markers were not produced by a model and the serving model is unknown for unavailable content. A `text` block carries `text` and `truncated`. A `tool_use` block carries `id`, `name`, `input`, and `truncated`, where `input` is a JSON-encoded string rather than an object. A `tool_result` block carries `tool_use_id`, `name`, `is_error`, a `content` array of `text` entries, and `truncated`. MCP tool calls and results, and most server tool calls and results, are normalized into these same `tool_use` and `tool_result` shapes; any other block type appears as a `[<block type> content not shown]` placeholder. A message `id` is stable while the turn is retained. Every message reconstructed from the same inference call carries that call’s timestamp, so consecutive messages often share a `created_at` value; preserve the returned order rather than re-sorting by timestamp.
301301 
302302Each message also carries a `provenance` field describing how its content was captured. `provenance` is `null` for verified content captured by the Claude API, which is the common case. Otherwise it is an object whose `type` marks the exception:
303303 
304* `content_unavailable` means the content cannot be returned. The `content` array is empty, and `provenance.reason` states why. `not_captured` means no content is available for the turn. It does not prove that no record was stored: content that Anthropic's data-handling policies withhold from the Compliance API is reported with the same reason, and so are individual turns within an otherwise captured session that are unavailable for such reasons. An unusable customer-managed key is the one exception and returns [503 Service Unavailable](https://platform.claude.com/docs/en/manage-claude/compliance-errors#local-sessions-temporarily-unavailable) instead. `client_aborted` means the client closed the connection or canceled the request before the response completed, so the turn's response was not captured; any partial output already streamed to the client is not included, and this reason applies to assistant-role turns only. `cmek_key_revoked` is reserved for content encrypted under your organization's customer-managed key when that key is unavailable (for example, revoked). It is not currently returned, because an unusable key produces a 503 instead, but handle it for forward compatibility. `retention_elapsed` means the content aged past retention. `oversize` means a single message exceeded the per-message size bound; the message is still returned, with an empty `content` array.
304* `content_unavailable` means the content cannot be returned. The `content` array is empty, and `provenance.reason` states why. `not_captured` means no content is available for the turn. It does not prove that no record was stored: content that Anthropic’s data-handling policies withhold from the Compliance API is reported with the same reason, and so are individual turns within an otherwise captured session that are unavailable for such reasons. An unusable customer-managed key is the one exception and returns [503 Service Unavailable](https://platform.claude.com/docs/en/manage-claude/compliance-errors#local-sessions-temporarily-unavailable) instead. `client_aborted` means the client closed the connection or canceled the request before the response completed, so the turn’s response was not captured; any partial output already streamed to the client is not included, and this reason applies to assistant-role turns only. `cmek_key_revoked` is reserved for content encrypted under your organization’s customer-managed key when that key is unavailable (for example, revoked). It is not currently returned, because an unusable key produces a 503 instead, but handle it for forward compatibility. `retention_elapsed` means the content aged past retention. `oversize` means a single message exceeded the per-message size bound; the message is still returned, with an empty `content` array.
305305* `client_asserted` marks assistant messages that the client supplied as conversation history and that could not be matched to a captured response; their authorship is not verified.
306306* `synthetic_marker` marks records generated by the endpoint itself, such as the marker that stands in for the system prompt. When the client rewrites or compacts its conversation history mid-session (for example, after context compaction), the transcript inserts a marker message at that point and continues with the new content the client sent. When your organization has a finite retention period and that new content includes assistant messages, the transcript withholds the new content up to and including its last assistant message (a second marker notes this) and shows only the user messages after that point, followed by the rest of the session.
307307 
from line 309
309309 
310310Two parameters cap how many bytes of each tool block are returned: `tool_use_input_max_bytes` and `tool_result_max_bytes`, both defaulting to 10,000 bytes. Pass `-1` for the server maximum (about 1 MiB for each string); `0` returns [400 Bad Request](https://platform.claude.com/docs/en/manage-claude/compliance-errors#400-bad-request), and values above the maximum are clamped to it. A string cut off by either cap is cut on a character boundary and has an in-band suffix appended (for example, `…[truncated; pass tool_result_max_bytes=-1 for the server max]`), and its block carries `"truncated": true`. A truncated `tool_use` `input` is therefore no longer valid JSON, so parse tool inputs only from untruncated blocks (or raise the cap and refetch). Blocks of type `text` are always capped at the same server maximum of about 1 MiB; no parameter raises it, and a `text` block at the bound also carries `"truncated": true`.
311311 
312Claude Science calls connectors (MCP servers) from code that it runs through its `repl` tool, not as separately named tools, so no block in a Claude Science transcript is named after a connector. Each connector call appears in the code inside a `repl` `tool_use` block's `input` (for example, a `host.mcp("<server>", "<tool>", ...)` call), and connector output appears in the matching `tool_result` only where that code printed it. Cowork and Claude Code sessions differ: they call each connector tool under its own `mcp__<server>__<tool>` name, which is the `name` of the `tool_use` block. To monitor connector use in Claude Science sessions, parse the `input` string and match on the code it contains rather than on a tool name. Pass `tool_use_input_max_bytes=-1` for these sessions so that a long code input is returned up to the server maximum instead of being cut at the 10,000-byte default before the connector call appears.
312Claude Science calls connectors (MCP servers) from code that it runs through its `repl` tool, not as separately named tools, so no block in a Claude Science transcript is named after a connector. Each connector call appears in the code inside a `repl` `tool_use` block’s `input` (for example, a `host.mcp("<server>", "<tool>", ...)` call), and connector output appears in the matching `tool_result` only where that code printed it. Cowork and Claude Code sessions differ: they call each connector tool under its own `mcp__<server>__<tool>` name, which is the `name` of the `tool_use` block. To monitor connector use in Claude Science sessions, parse the `input` string and match on the code it contains rather than on a tool name. Pass `tool_use_input_max_bytes=-1` for these sessions so that a long code input is returned up to the server maximum instead of being cut at the 10,000-byte default before the connector call appears.
313313 
314Transcript content honors the retention period described under [Sessions on users' machines](https://platform.claude.com/docs/en/manage-claude/compliance-sessions#retrieve-local-sessions). When a session's earliest calls have aged past it, the transcript starts with a single `content_unavailable` placeholder with `reason` of `retention_elapsed`, and the retained messages follow. When every call in a session has aged out, the messages endpoint returns [404 Not Found](https://platform.claude.com/docs/en/manage-claude/compliance-errors#404-not-found), as it does for sessions in organizations your key cannot read, sessions that do not exist, and sessions for which zero data retention is in effect. A malformed session ID returns [400 Bad Request](https://platform.claude.com/docs/en/manage-claude/compliance-errors#400-bad-request).
314Transcript content honors the retention period described under [Sessions on users’ machines](https://platform.claude.com/docs/en/manage-claude/compliance-sessions#retrieve-local-sessions). When a session’s earliest calls have aged past it, the transcript starts with a single `content_unavailable` placeholder with `reason` of `retention_elapsed`, and the retained messages follow. When every call in a session has aged out, the messages endpoint returns [404 Not Found](https://platform.claude.com/docs/en/manage-claude/compliance-errors#404-not-found), as it does for sessions in organizations your key cannot read, sessions that do not exist, and sessions for which zero data retention is in effect. A malformed session ID returns [400 Bad Request](https://platform.claude.com/docs/en/manage-claude/compliance-errors#400-bad-request).
315315 
316316## Sessions in the cloud (remote sessions)
317317 
318Cowork sessions started on claude.ai web or mobile run in the cloud in Anthropic-managed environments. The Compliance API exposes these remote sessions through two endpoints: `GET /v1/compliance/apps/sessions/remote` lists session metadata, and `GET /v1/compliance/apps/sessions/remote/{session_id}/messages` returns one session's transcript. Both require the `read:compliance_user_data` scope, and both count against the shared Compliance API rate limit plus a second request budget specific to these endpoints; see [429 Too Many Requests](https://platform.claude.com/docs/en/manage-claude/compliance-errors#429-too-many-requests).
318Cowork sessions started on claude.ai web or mobile run in the cloud in Anthropic-managed environments. The Compliance API exposes these remote sessions through two endpoints: `GET /v1/compliance/apps/sessions/remote` lists session metadata, and `GET /v1/compliance/apps/sessions/remote/{session_id}/messages` returns one session’s transcript. Both require the `read:compliance_user_data` scope, and both count against the shared Compliance API rate limit plus a second request budget specific to these endpoints; see [429 Too Many Requests](https://platform.claude.com/docs/en/manage-claude/compliance-errors#429-too-many-requests).
319319 
320The list endpoint defaults to organization-wide scope: leave off `organization_ids[]` to include every claude.ai organization your key can read, or pass up to 500 values to narrow the scope. To scope the list to specific users instead, pass 1–10 `user_ids[]` values (obtain the IDs from [List organization users](https://platform.claude.com/docs/en/manage-claude/compliance-org-data#list-organization-users)); the filter matches the session's owning user, so agent-owned sessions are excluded whenever `user_ids[]` is set. Bound the results in time with `created_at` range parameters (`gte`, `gt`, `lt`, `lte`, in RFC 3339 format). There is no `updated_at` filter. The following request lists sessions created since a given date.
320The list endpoint defaults to organization-wide scope: leave off `organization_ids[]` to include every claude.ai organization your key can read, or pass up to 500 values to narrow the scope. To scope the list to specific users instead, pass 1–10 `user_ids[]` values (obtain the IDs from [List organization users](https://platform.claude.com/docs/en/manage-claude/compliance-org-data#list-organization-users)); the filter matches the session’s owning user, so agent-owned sessions are excluded whenever `user_ids[]` is set. Bound the results in time with `created_at` range parameters (`gte`, `gt`, `lt`, `lte`, in RFC 3339 format). There is no `updated_at` filter. The following request lists sessions created since a given date.
321321 
322322```bash cURL
323323curl --fail-with-body -sS -G \
from line 366
366366}
367367```
368368 
369Results are sorted in reverse chronological order (newest first) by `created_at` and capped at `limit` results for each response (default 100, max 500). The endpoint paginates with `page` and `next_page` tokens (see [Paginate results](https://platform.claude.com/docs/en/manage-claude/compliance-activity-feed#paginate-results)): pass the response's `next_page` value back as the `page` query parameter on the next request, and stop when `next_page` is `null`.
369Results are sorted in reverse chronological order (newest first) by `created_at` and capped at `limit` results for each response (default 100, max 500). The endpoint paginates with `page` and `next_page` tokens (see [Paginate results](https://platform.claude.com/docs/en/manage-claude/compliance-activity-feed#paginate-results)): pass the response’s `next_page` value back as the `page` query parameter on the next request, and stop when `next_page` is `null`.
370370 
371A session is owned by either a user or an agent, never both. For user-owned sessions, `user` carries the owner's ID and email address (`email_address` is `null` when the user is no longer a member of an organization your key can read) and `agent_id` is `null`. For agent-owned sessions (for example, runs of a Cowork scheduled task in the cloud), `user` is `null`, `agent_id` carries the agent's ID (prefix `cagt_`), and `started_by_user` identifies the human who initiated the run; on user-owned sessions, `started_by_user` is `null`. Each run of a scheduled task is a separate session, and no session field carries the task's name or schedule.
371A session is owned by either a user or an agent, never both. For user-owned sessions, `user` carries the owner’s ID and email address (`email_address` is `null` when the user is no longer a member of an organization your key can read) and `agent_id` is `null`. For agent-owned sessions (for example, runs of a Cowork scheduled task in the cloud), `user` is `null`, `agent_id` carries the agent’s ID (prefix `cagt_`), and `started_by_user` identifies the human who initiated the run; on user-owned sessions, `started_by_user` is `null`. Each run of a scheduled task is a separate session, and no session field carries the task’s name or schedule.
372372 
373373`claude_project_id` is the ID of the claude.ai [project](https://platform.claude.com/docs/en/manage-claude/compliance-content-data#retrieve-projects-and-attachments) the session belongs to (prefix `claude_proj_`), or `null` when the session is not in a project.
374374 
from line 384
384384 
385385### Retrieve a remote session transcript
386386 
387The messages endpoint returns the session's transcript: user prompts, assistant responses, and tool calls and results. Thinking blocks and images are not included. For a coverage summary, see the [Compliance API FAQ](https://platform.claude.com/docs/en/manage-claude/compliance-faq#data-coverage-and-retention); for a table comparing remote sessions with local sessions and Cowork's OpenTelemetry logging, see this page's introduction.
387The messages endpoint returns the session’s transcript: user prompts, assistant responses, and tool calls and results. Thinking blocks and images are not included. For a coverage summary, see the [Compliance API FAQ](https://platform.claude.com/docs/en/manage-claude/compliance-faq#data-coverage-and-retention); for a table comparing remote sessions with local sessions and Cowork’s OpenTelemetry logging, see this page’s introduction.
388388 
389389```bash cURL
390390curl --fail-with-body -sS \
from line 448
448448 
449449Messages are returned oldest first by default; pass `order=desc` to reverse. Pagination uses the same `page`/`next_page` scheme as the list endpoint, with a `limit` default of 100 and a max of 1,000. A page can end early when the response reaches its size limit, so a page with fewer than `limit` messages does not mean you have reached the end; keep paginating until `next_page` is `null`.
450450 
451Each message carries a `role` (`user` or `assistant`) and a `content` array of `text`, `tool_use`, and `tool_result` blocks. Message `created_at` values are commit timestamps: consecutive messages can share a timestamp or slightly invert, so preserve the returned order rather than re-sorting by `created_at`. On agent-owned sessions, `sent_by_user_id` records the user who sent a given user message when one is attributable; it is `null` otherwise, including on all assistant messages. When a message's content cannot be returned at all (for example, it exceeds size bounds), the message carries `content_unavailable` set to `true`.
451Each message carries a `role` (`user` or `assistant`) and a `content` array of `text`, `tool_use`, and `tool_result` blocks. Message `created_at` values are commit timestamps: consecutive messages can share a timestamp or slightly invert, so preserve the returned order rather than re-sorting by `created_at`. On agent-owned sessions, `sent_by_user_id` records the user who sent a given user message when one is attributable; it is `null` otherwise, including on all assistant messages. When a message’s content cannot be returned at all (for example, it exceeds size bounds), the message carries `content_unavailable` set to `true`.
452452 
453453Two parameters cap how many bytes of each tool block are returned: `tool_use_input_max_bytes` and `tool_result_max_bytes`, both defaulting to 10,000 bytes. Pass `-1` for the server maximum (about 1 MiB for each string); `0` returns [400 Bad Request](https://platform.claude.com/docs/en/manage-claude/compliance-errors#400-bad-request). A block cut off by either cap carries `"truncated": true`, and a truncated `tool_use` input is no longer valid JSON, so parse tool inputs only from untruncated blocks (or raise the cap and refetch).
454454 
from line 456
456456 
457457## Retention and deletion
458458 
459The session endpoints are read-only; local and remote sessions cannot be deleted through the Compliance API. Local session transcripts are retained for 6 years by default, or your organization's custom conversation retention period when a finite one is set, or 30 days in organizations with HIPAA readiness enabled, as described under [Sessions on users' machines](https://platform.claude.com/docs/en/manage-claude/compliance-sessions#retrieve-local-sessions). Remote session transcripts are retained for 6 years, unless a user deletes the session sooner. The remote session endpoints no longer return a session once a user deletes it, and its transcript is not recoverable through the Compliance API. To learn how these periods sit alongside Anthropic's other retention arrangements, see [API and data retention](https://platform.claude.com/docs/en/manage-claude/api-and-data-retention).
459The session endpoints are read-only; local and remote sessions cannot be deleted through the Compliance API. Local session transcripts are retained for 6 years by default, or your organization’s custom conversation retention period when a finite one is set, or 30 days in organizations with HIPAA readiness enabled, as described under [Sessions on users’ machines](https://platform.claude.com/docs/en/manage-claude/compliance-sessions#retrieve-local-sessions). Remote session transcripts are retained for 6 years, unless a user deletes the session sooner. The remote session endpoints no longer return a session once a user deletes it, and its transcript is not recoverable through the Compliance API. To learn how these periods sit alongside Anthropic’s other retention arrangements, see [API and data retention](https://platform.claude.com/docs/en/manage-claude/api-and-data-retention).
460460 
461461## Next steps
462462 

manage-claude/data-residency Changed · +7 / -7 lines

from line 10
1010* **Workspace geo:** Controls where data is stored at rest and where endpoint processing (such as image transcoding and code execution) occurs. Configured at the workspace level in the [Claude Console](https://platform.claude.com/).
1111 
1212<Note>
13 [Claude Managed Agents](https://platform.claude.com/docs/en/managed-agents/overview) supports geographic pinning at the agent level: `inference_geo` on an [agent's model configuration](https://platform.claude.com/docs/en/managed-agents/agent-setup#pin-the-inference-geo) pins the geography that serves model requests for sessions running that agent, with [per-session overrides](https://platform.claude.com/docs/en/managed-agents/sessions#pin-the-inference-geo-for-a-session) at session create. Agents without a pin follow the workspace's default inference geo on each request. Managed Agents also respects the Workspace geo configured in Console, and with [self-hosted sandboxes](https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes), tool execution and the sandbox filesystem stay on infrastructure you control; the contents of attached [memory stores](https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes-memory) remain stored by Anthropic and are copied to your sandbox for the session.
13 [Claude Managed Agents](https://platform.claude.com/docs/en/managed-agents/overview) supports geographic pinning at the agent level: `inference_geo` on an [agent’s model configuration](https://platform.claude.com/docs/en/managed-agents/agent-setup#pin-the-inference-geo) pins the geography that serves model requests for sessions running that agent, with [per-session overrides](https://platform.claude.com/docs/en/managed-agents/sessions#pin-the-inference-geo-for-a-session) at session create. Agents without a pin follow the workspace’s default inference geo on each request. Managed Agents also respects the Workspace geo configured in Console, and with [self-hosted sandboxes](https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes), tool execution and the sandbox filesystem stay on infrastructure you control; the contents of attached [memory stores](https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes-memory) remain stored by Anthropic and are copied to your sandbox for the session.
1414</Note>
1515 
1616## Inference geo
from line 241
241241 
242242## Workspace geo
243243 
244Workspace geo is set when you create a workspace and can't be changed afterward. Currently, `"us"` is the only available workspace geo.
244Workspace geo is set when you create a workspace and can’t be changed afterward. Currently, `"us"` is the only available workspace geo.
245245 
246246To set workspace geo, create a new workspace in the [Console](https://platform.claude.com/):
247247 
from line 254
254254</Note>
255255 
256256<Note>
257 **Claude Models on Google Cloud (Anthropic managed):** Workspace geo is not configurable. Every workspace uses `"us"` as its workspace geo, and the **Workspace geo** field doesn't appear in the Claude Console.
257 **Claude Models on Google Cloud (Anthropic managed):** Workspace geo is not configurable. Every workspace uses `"us"` as its workspace geo, and the **Workspace geo** field doesn’t appear in the Claude Console.
258258</Note>
259259 
260260## Pricing
from line 263
263263 
264264* **Claude 4.6 and later models:** US-only inference (`inference_geo: "us"`) is priced at 1.1x the standard rate across all token pricing categories (input tokens, output tokens, cache writes, and cache reads). On Claude Haiku 5.5, the multiplier also applies to the higher prices for prompts over 100,000 tokens (see [Long context pricing](https://platform.claude.com/docs/en/about-claude/pricing#long-context-pricing)).
265265* **Global routing (`inference_geo: "global"`):** Standard pricing applies.
266* **Older models:** Don't support `inference_geo` (see [Model availability](https://platform.claude.com/docs/en/manage-claude/data-residency#model-availability)). Standard pricing applies. Requests that include the parameter return a 400 error.
266* **Older models:** Don’t support `inference_geo` (see [Model availability](https://platform.claude.com/docs/en/manage-claude/data-residency#model-availability)). Standard pricing applies. Requests that include the parameter return a 400 error.
267267 
268268This pricing applies to the Claude API (first-party), Claude Platform on AWS, and Claude Models on Google Cloud (Anthropic managed). On Claude in Microsoft Foundry, the same 1.1x multiplier applies to deployments hosted on Azure that use the US Data Zone Standard deployment type. Partner-operated platforms, Bedrock and Claude Models on Google Cloud (Google managed), have their own regional pricing. See [Data residency pricing](https://platform.claude.com/docs/en/about-claude/pricing#data-residency-pricing) for details.
269269 
270The same multiplier applies to [Claude Managed Agents](https://platform.claude.com/docs/en/managed-agents/overview): when an agent's [model configuration](https://platform.claude.com/docs/en/managed-agents/agent-setup) pins `inference_geo` to `"us"`, model requests in sessions running that agent are priced at 1.1x the standard rate.
270The same multiplier applies to [Claude Managed Agents](https://platform.claude.com/docs/en/managed-agents/overview): when an agent’s [model configuration](https://platform.claude.com/docs/en/managed-agents/agent-setup) pins `inference_geo` to `"us"`, model requests in sessions running that agent are priced at 1.1x the standard rate.
271271 
272272<Note>
273273 If you have a [Priority Tier](https://platform.claude.com/docs/en/api/service-tiers) commitment, the 1.1x multiplier for US-only inference also affects how tokens are counted against your Priority Tier capacity. Each token consumed with `inference_geo: "us"` draws down 1.1 tokens from your committed TPM, consistent with how other pricing multipliers (such as prompt caching) affect burndown rates.
from line 300
300300 
301301### If you want to use global routing
302302 
303If your data residency requirements have changed and you want to take advantage of global routing for better performance and availability, update your workspace's inference geo settings to include `"global"` in the allowed geos and set `default_inference_geo` to `"global"`. See [Workspace-level restrictions](https://platform.claude.com/docs/en/manage-claude/data-residency#workspace-level-restrictions) for details.
303If your data residency requirements have changed and you want to take advantage of global routing for better performance and availability, update your workspace’s inference geo settings to include `"global"` in the allowed geos and set `default_inference_geo` to `"global"`. See [Workspace-level restrictions](https://platform.claude.com/docs/en/manage-claude/data-residency#workspace-level-restrictions) for details.
304304 
305305### Pricing impact
306306 
from line 310
310310 
311311* **Shared rate limits:** Rate limits are shared across all geos.
312312* **Inference geo:** Only `"us"` and `"global"` are available.
313* **Workspace geo:** Only `"us"` is currently available. Workspace geo can't be changed after workspace creation.
313* **Workspace geo:** Only `"us"` is currently available. Workspace geo can’t be changed after workspace creation.
314314 
315315## Next steps
316316 

manage-claude/inference-hooks Changed · +16 / -16 lines

from line 10
1010 
1111Inference hooks let a Claude Enterprise organization route every governed prompt through an AI security server, an HTTPS service that the organization or its security vendor operates, before inference runs. When a user submits a prompt, Anthropic sends the conversation transcript to your AI security server and waits for an allow or deny verdict; a denied request never reaches the model. Security and compliance teams use Inference hooks to enforce data policies inline, and developers build the AI security server that evaluates each request.
1212 
13Because the hook runs on Anthropic's servers, after the request leaves the client and before the model runs, it applies to every governed request uniformly, across all Claude products in your organization, with nothing to install or deploy on user devices.
13Because the hook runs on Anthropic’s servers, after the request leaves the client and before the model runs, it applies to every governed request uniformly, across all Claude products in your organization, with nothing to install or deploy on user devices.
1414 
15There are two hook events. `prompt` fires once for each governed inference request, before inference starts. `tool_call` fires when Claude's response contains tool calls, before any of them runs, in organizations that have **Validate tool calls** on.
15There are two hook events. `prompt` fires once for each governed inference request, before inference starts. `tool_call` fires when Claude’s response contains tool calls, before any of them runs, in organizations that have **Validate tool calls** on.
1616 
1717***
1818 
from line 19
1919## How Inference hooks work
2020 
21211. A user submits a prompt on a governed surface.
222. Anthropic sends an HTTPS `POST` to your organization's configured AI security server endpoint. The request body carries the conversation transcript, and each request is signed according to the [Standard Webhooks](https://www.standardwebhooks.com/) specification once your organization generates its signing secret, so your server can verify it came from Anthropic.
222. Anthropic sends an HTTPS `POST` to your organization’s configured AI security server endpoint. The request body carries the conversation transcript, and each request is signed according to the [Standard Webhooks](https://www.standardwebhooks.com/) specification once your organization generates its signing secret, so your server can verify it came from Anthropic.
23233. Your AI security server evaluates the content and responds with a verdict within the verdict timeout your organization configures (5 seconds by default).
244. On `allow`, inference proceeds normally. On `deny`, the request is rejected and the user sees a blocked-by-policy message assembled from two parts: the per-request reason your AI security server supplied in the verdict's `deny_reason` field, followed by a standing message your administrators configure (for example, who to contact or where to request an exception). If your administrators haven't configured one, a built-in default directs the user to contact them. Each denial is also recorded in your organization's [Activity Feed](https://platform.claude.com/docs/en/manage-claude/compliance-activity-feed).
244. On `allow`, inference proceeds normally. On `deny`, the request is rejected and the user sees a blocked-by-policy message assembled from two parts: the per-request reason your AI security server supplied in the verdict’s `deny_reason` field, followed by a standing message your administrators configure (for example, who to contact or where to request an exception). If your administrators haven’t configured one, a built-in default directs the user to contact them. Each denial is also recorded in your organization’s [Activity Feed](https://platform.claude.com/docs/en/manage-claude/compliance-activity-feed).
2525 
26The following diagram traces one example (a Cowork request where Claude also calls an O365 tool) to illustrate which parts of the flow are hooked. The hooked points are the diagram's steps 1, 2, and 3, where the prompt arrives, Claude calls the tool, and the tool result returns. At each one, your AI security server returns a verdict before the flow continues. Step 2 is hooked only with **Validate tool calls** on, and its one verdict covers all the tool calls in a response.
26The following diagram traces one example (a Cowork request where Claude also calls an O365 tool) to illustrate which parts of the flow are hooked. The hooked points are the diagram’s steps 1, 2, and 3, where the prompt arrives, Claude calls the tool, and the tool result returns. At each one, your AI security server returns a verdict before the flow continues. Step 2 is hooked only with **Validate tool calls** on, and its one verdict covers all the tool calls in a response.
2727 
2828<Frame>
2929 ![Flow diagram: the prompt, the tool call, and the tool result are each checked by the AI security server; the response is not](https://platform.claude.com/docs/images/inference-hooks-flow-2.svg)
from line 33
3333 
3434Your AI security server sees what the user sees: transcript text, tool calls and their results, and text extracted from attachments. It never receives raw file or image bytes, system prompts, or Anthropic-internal context.
3535 
36The Inference hooks system doesn't keep its own copy of prompt or response content. It stores only your hook configuration and metadata about hook activity, such as verdicts, timestamps, and request identifiers. The Claude product you use stores prompts and responses under its own data retention rules, whether or not hooks are on. For example, a message that a hook blocks on claude.ai stays in the conversation.
36The Inference hooks system doesn’t keep its own copy of prompt or response content. It stores only your hook configuration and metadata about hook activity, such as verdicts, timestamps, and request identifiers. The Claude product you use stores prompts and responses under its own data retention rules, whether or not hooks are on. For example, a message that a hook blocks on claude.ai stays in the conversation.
3737 
38If your AI security server is unreachable, returns an error, or doesn't respond within the timeout, your organization's failure handling setting determines the outcome: block the request, or allow it to proceed without inspection. Sustained failures attributable to your server trip a circuit breaker: Anthropic stops contacting it and applies your failure handling setting to every request, then resets the breaker automatically once it detects that your server is returning verdicts again; see [Circuit breaker](https://platform.claude.com/docs/en/manage-claude/inference-hooks-configuration#circuit-breaker).
38If your AI security server is unreachable, returns an error, or doesn’t respond within the timeout, your organization’s failure handling setting determines the outcome: block the request, or allow it to proceed without inspection. Sustained failures attributable to your server trip a circuit breaker: Anthropic stops contacting it and applies your failure handling setting to every request, then resets the breaker automatically once it detects that your server is returning verdicts again; see [Circuit breaker](https://platform.claude.com/docs/en/manage-claude/inference-hooks-configuration#circuit-breaker).
3939 
4040Enforcement can roll out at your pace, so nobody has to be blocked on day one: shadow mode observes verdicts on live traffic without blocking anything, a rollout percentage inspects a chosen fraction of requests, and exclusions exempt members of chosen roles entirely. See [Configure Inference hooks](https://platform.claude.com/docs/en/manage-claude/inference-hooks-configuration).
4141 
from line 49
4949 
5050The steps depend on the app:
5151 
52* **claude.ai, including Claude Desktop and the mobile apps.** The user edits the denied message, or an earlier one, rather than sending a corrected copy as a new message. On the web and in Claude Desktop, the edit resends the message's attachments unless the user removes them. A new chat also works.
52* **claude.ai, including Claude Desktop and the mobile apps.** The user edits the denied message, or an earlier one, rather than sending a corrected copy as a new message. On the web and in Claude Desktop, the edit resends the message’s attachments unless the user removes them. A new chat also works.
5353* **Claude Code.** The user runs `/rewind` and selects the prompt that first brought the content in. If asked, they select **Restore conversation**, then edit or clear the prompt that returns to the input field. `/clear` starts over. See [Checkpointing](https://code.claude.com/docs/en/checkpointing).
5454* **Cowork.** The user edits the denied message if it is their latest one. The edit resends attached files, and **Restart from here** resends the whole message unchanged. If the content is in a file or an earlier message, the user selects **New task**.
55* **Claude Tag.** In Slack, the user first edits the denied message, or deletes it if it is a reply. They then send `@Claude !restart` on its own where Claude was answering: in that thread, or at the channel's top level. The new session rereads the messages still in Slack, so the edit or deletion comes first. See the [`!restart` command](https://claude.com/docs/claude-tag/users/commands#restart-a-stuck-or-wrong-context-session).
55* **Claude Tag.** In Slack, the user first edits the denied message, or deletes it if it is a reply. They then send `@Claude !restart` on its own where Claude was answering: in that thread, or at the channel’s top level. The new session rereads the messages still in Slack, so the edit or deletion comes first. See the [`!restart` command](https://claude.com/docs/claude-tag/users/commands#restart-a-stuck-or-wrong-context-session).
5656 
5757***
5858 
from line 79
7979 
8080One hook governs conversations across all Claude products in your Claude Enterprise organization, including, but not limited to, claude.ai, Cowork, Claude Code, Claude for Microsoft 365, Claude Tag, and Claude in Chrome, whether they run on the web, in the desktop or mobile apps, in the CLI, or in Slack. Inference hooks are not available on Amazon Bedrock or Google Cloud.
8181 
82Governed requests are the inference requests behind the user's conversation or session. System prompts and tool definitions are never included in what is sent. In voice mode, prompts and tool calls are sent to your endpoint too, though a small share of tool calls isn't, so don't rely on Inference hooks as your only control for voice. If your endpoint denies a request in voice mode, the voice call usually ends with a general error message, and your deny reason isn't shown.
82Governed requests are the inference requests behind the user’s conversation or session. System prompts and tool definitions are never included in what is sent. In voice mode, prompts and tool calls are sent to your endpoint too, though a small share of tool calls isn’t, so don’t rely on Inference hooks as your only control for voice. If your endpoint denies a request in voice mode, the voice call usually ends with a general error message, and your deny reason isn’t shown.
8383 
84With **Validate tool calls** on, `tool_call` events might leave out calls to some of claude.ai's own tools, such as tools that do the following:
84With **Validate tool calls** on, `tool_call` events might leave out calls to some of claude.ai’s own tools, such as tools that do the following:
8585 
8686* List, search for, or suggest connectors, plugins, or skills
8787* Suggest starting research or turning on web search
from line 88
8888* Search for other tools
8989* Switch to a larger model
9090* End the chat
91* Give Claude the user's local time
92* Read the user's own past chats and saved memory
91* Give Claude the user’s local time
92* Read the user’s own past chats and saved memory
9393 
9494These calls and their results stay in the conversation, so the next `prompt` event from that conversation, if there is one, includes them.
9595 
96Some features that Anthropic runs for your organization make model calls of their own. Your organization sees the results of those calls but not their transcripts. These calls aren't governed requests and aren't sent to your endpoint. They include the following:
96Some features that Anthropic runs for your organization make model calls of their own. Your organization sees the results of those calls but not their transcripts. These calls aren’t governed requests and aren’t sent to your endpoint. They include the following:
9797 
9898* **Claude Security scans (beta).** [Claude Security](https://claude.com/product/claude-security) runs hosted scans on your connected repositories. A session a user opens to fix a finding, and the Claude Security plugin in Claude Code, are governed.
9999* **Code Review (research preview).** [Code Review](https://code.claude.com/docs/en/code-review) runs reviews on your GitHub pull requests. A review a user runs locally in Claude Code with `/code-review` is governed.
100* **Smart reports (beta).** Anthropic makes model calls to build your organization's [smart reports](https://support.claude.com/en/articles/16893491-get-started-with-smart-reports). What a user types or uploads when creating a report is governed.
100* **Smart reports (beta).** Anthropic makes model calls to build your organization’s [smart reports](https://support.claude.com/en/articles/16893491-get-started-with-smart-reports). What a user types or uploads when creating a report is governed.
101101 
102102***
103103 
from line 109
109109| ------------ | --------------------------------------------------- | ----------------------------------------------------------------------------------------------- |
110110| When it acts | Inline, before inference runs | After the fact |
111111| What it does | Allows or denies each governed request in real time | Retrieves activity, chats, files, projects, session transcripts, and users for audit and export |
112| Direction | Anthropic calls your AI security server | You call Anthropic's API |
112| Direction | Anthropic calls your AI security server | You call Anthropic’s API |
113113 
114114Use Inference hooks to stop a request before it reaches the model, and the [Compliance API](https://platform.claude.com/docs/en/manage-claude/compliance-api) to audit what occurred afterward.
115115 

manage-claude/inference-hooks-configuration Changed · +22 / -22 lines

from line 14
1414 
1515You need:
1616 
17* The `organization:manage` permission in claude.ai, which only the **Owner** and **Primary owner** roles hold. The **Admin** role doesn't have it.
18* An AI security server HTTPS endpoint that accepts verdict requests: an `https://` URL on port 443, on a publicly routable host, reachable without redirects. Reverse-tunnel hosts (ngrok and similar tunnel services) are not supported: Anthropic's network policy blocks them. Don't test through a tunnel; host your server on a domain you control. For the full [hosting requirements](https://platform.claude.com/docs/en/manage-claude/inference-hooks-endpoint#receive-a-request), and to build the server and verify signed requests, see [Develop an Inference hooks integration](https://platform.claude.com/docs/en/manage-claude/inference-hooks-endpoint).
17* The `organization:manage` permission in claude.ai, which only the **Owner** and **Primary owner** roles hold. The **Admin** role doesn’t have it.
18* An AI security server HTTPS endpoint that accepts verdict requests: an `https://` URL on port 443, on a publicly routable host, reachable without redirects. Reverse-tunnel hosts (ngrok and similar tunnel services) are not supported: Anthropic’s network policy blocks them. Don’t test through a tunnel; host your server on a domain you control. For the full [hosting requirements](https://platform.claude.com/docs/en/manage-claude/inference-hooks-endpoint#receive-a-request), and to build the server and verify signed requests, see [Develop an Inference hooks integration](https://platform.claude.com/docs/en/manage-claude/inference-hooks-endpoint).
1919 
2020## Set up Inference hooks
2121 
from line 35
3535 </Step>
3636 
3737 <Step title="Open the Inference hooks settings page">
38 Still in **Data and privacy**, open the **Inference hooks** section to reach the Inference hooks settings page. It lives under **Data and privacy** rather than as its own entry in the settings nav, so its breadcrumb reads **Data and privacy / Inference hooks**. Until you save an endpoint, the page warns that prompts aren't being inspected yet, and **Enforce verdicts** stays off with a **Requires endpoint** badge.
38 Still in **Data and privacy**, open the **Inference hooks** section to reach the Inference hooks settings page. It lives under **Data and privacy** rather than as its own entry in the settings nav, so its breadcrumb reads **Data and privacy / Inference hooks**. Until you save an endpoint, the page warns that prompts aren’t being inspected yet, and **Enforce verdicts** stays off with a **Requires endpoint** badge.
3939 </Step>
4040 
4141 <Step title="Configure your endpoint">
from line 63
6363 | Result | What to check |
6464 | ----------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
6565 | URL rejected | The URL failed a structural check. Use an `https://` URL on port 443. |
66 | Private or internal IP | The URL's host is a private or internal IP address, an IPv6 address, or `localhost`. Use a publicly routable host. |
66 | Private or internal IP | The URL’s host is a private or internal IP address, an IPv6 address, or `localhost`. Use a publicly routable host. |
6767 | Timeout | The AI security server did not return a verdict within the timeout. |
6868 | Transport error | DNS resolution, the TLS handshake, or the connection failed, or the hostname resolves to a private address. |
6969 | Non-200 status | The AI security server responded with a status other than 200. Verdicts must come back as HTTP 200; redirects are not followed and count as failures. |
from line 74
7474 <Step title="Choose failure handling and timeout">
7575 Under **Failure handling**, set **Mode** to choose what occurs while the AI security server is unreachable or verdicts time out:
7676 
77 * **Block the request:** stop inference when your AI security server can't deliver a verdict (fail closed).
77 * **Block the request:** stop inference when your AI security server can’t deliver a verdict (fail closed).
7878 * **Allow the request:** let the request proceed to the model without inspection (fail open).
7979 
80 The dropdown menu's third option, **Shadow mode**, is a rollout tool rather than a failure policy; see [Shadow mode](https://platform.claude.com/docs/en/manage-claude/inference-hooks-configuration#shadow-mode).
80 The dropdown menu’s third option, **Shadow mode**, is a rollout tool rather than a failure policy; see [Shadow mode](https://platform.claude.com/docs/en/manage-claude/inference-hooks-configuration#shadow-mode).
8181 
8282 Then set **Prompt verdict timeout (ms)**: 1 to 10,000ms, with a default of 5,000ms. The budget covers the entire exchange, and a slower verdict counts as an unreachable server, so set the lowest value your server can reliably meet.
8383 
from line 93
9393 <Step title="Turn on Enforce verdicts">
9494 To evaluate verdicts against live traffic without blocking anyone at first, set **Mode** to **Shadow mode** (step 6) before turning on enforcement; see [Shadow mode](https://platform.claude.com/docs/en/manage-claude/inference-hooks-configuration#shadow-mode).
9595 
96 Turn on **Enforce verdicts** to gate Claude on your AI security server's verdict for every governed prompt, then confirm in the dialog box, which restates your failure handling choice. Allow about a minute for the change to reach every Anthropic server; requests already in flight complete under the old setting. Turning it off stops prompts from being sent to your AI security server, again within about a minute; your configuration is kept.
96 Turn on **Enforce verdicts** to gate Claude on your AI security server’s verdict for every governed prompt, then confirm in the dialog box, which restates your failure handling choice. Allow about a minute for the change to reach every Anthropic server; requests already in flight complete under the old setting. Turning it off stops prompts from being sent to your AI security server, again within about a minute; your configuration is kept.
9797 
98 **Validate tool calls**, below **Enforce verdicts**, also sends the tool calls in each of Claude's responses to your AI security server and waits for its verdict before they run; see [The tool call frame](https://platform.claude.com/docs/en/manage-claude/inference-hooks-endpoint#the-tool-call-frame). It is on by default in a new configuration. It has no effect while **Enforce verdicts** is off, and a change to it takes about a minute to reach every Anthropic server, as with **Enforce verdicts**.
98 **Validate tool calls**, below **Enforce verdicts**, also sends the tool calls in each of Claude’s responses to your AI security server and waits for its verdict before they run; see [The tool call frame](https://platform.claude.com/docs/en/manage-claude/inference-hooks-endpoint#the-tool-call-frame). It is on by default in a new configuration. It has no effect while **Enforce verdicts** is off, and a change to it takes about a minute to reach every Anthropic server, as with **Enforce verdicts**.
9999 </Step>
100100</Steps>
101101 
102102## Shadow mode
103103 
104Shadow mode runs your hook against live traffic without blocking anything. Your AI security server receives governed prompts and returns verdicts exactly as it would when enforcing, but nothing is blocked: every request proceeds to the model, even when your server denies it or can't be reached, and the end user sees nothing. Use it to tune your policy against your organization's real traffic before you start enforcing. With **Validate tool calls** on, your server also receives tool call frames in shadow mode, and no tool call is blocked.
104Shadow mode runs your hook against live traffic without blocking anything. Your AI security server receives governed prompts and returns verdicts exactly as it would when enforcing, but nothing is blocked: every request proceeds to the model, even when your server denies it or can’t be reached, and the end user sees nothing. Use it to tune your policy against your organization’s real traffic before you start enforcing. With **Validate tool calls** on, your server also receives tool call frames in shadow mode, and no tool call is blocked.
105105 
106106To use shadow mode, set **Mode** to **Shadow mode** under **Failure handling**, then turn on **Enforce verdicts** so prompts flow to your AI security server. While it is active, the settings page shows a **Shadow mode — not blocking** badge. To leave shadow mode, set **Mode** back to **Allow the request** or **Block the request**; verdicts are enforced again once enforcement is on.
107107 
108108## Exclusions
109109 
110Under **Exclusions**, select roles whose members are not covered by Inference hooks: their prompts are never sent to your AI security server. Only custom roles your organization created can be excluded; the built-in roles aren't offered. Select them in the role selector, whose placeholder reads **Select roles to exclude**, and manage who holds each role from the roles admin page (**Manage roles**); changing exclusions requires identity management permission. The list is empty by default, and with no roles excluded, every governed request is inspected.
110Under **Exclusions**, select roles whose members are not covered by Inference hooks: their prompts are never sent to your AI security server. Only custom roles your organization created can be excluded; the built-in roles aren’t offered. Select them in the role selector, whose placeholder reads **Select roles to exclude**, and manage who holds each role from the roles admin page (**Manage roles**); changing exclusions requires identity management permission. The list is empty by default, and with no roles excluded, every governed request is inspected.
111111 
112Exclusion applies to a user's interactive sessions. Changes to the exclusion list are recorded in your organization's [Activity Feed](https://platform.claude.com/docs/en/manage-claude/compliance-activity-feed) as role permission changes (`rbac_role_permission_added` and `rbac_role_permission_removed`).
112Exclusion applies to a user’s interactive sessions. Changes to the exclusion list are recorded in your organization’s [Activity Feed](https://platform.claude.com/docs/en/manage-claude/compliance-activity-feed) as role permission changes (`rbac_role_permission_added` and `rbac_role_permission_removed`).
113113 
114114## Custom blocked prompt message
115115 
116Under **Custom blocked prompt message**, set custom text of up to 500 characters that is appended to the error an end user sees when your AI security server denies a request (typically who to contact or where to request an exception). The final message is your AI security server's per-request `deny_reason` (when present), a blank line, then this text. With no custom text configured, a built-in default directs the user to contact their administrators; you can also switch the appended message off entirely so the user sees only the `deny_reason`.
116Under **Custom blocked prompt message**, set custom text of up to 500 characters that is appended to the error an end user sees when your AI security server denies a request (typically who to contact or where to request an exception). The final message is your AI security server’s per-request `deny_reason` (when present), a blank line, then this text. With no custom text configured, a built-in default directs the user to contact their administrators; you can also switch the appended message off entirely so the user sees only the `deny_reason`.
117117 
118118## Monitor your AI security server
119119 
from line 121
121121 
122122* **Endpoint status:** Healthy, Tripped, Not enforcing, or Not configured before an endpoint is saved.
123123* **Failures per minute:** webhook failures over the last 2 minutes, averaged.
124* **Block rate:** denials as a share of your AI security server's verdicts, shown while the rollout percentage is below 100.
124* **Block rate:** denials as a share of your AI security server’s verdicts, shown while the rollout percentage is below 100.
125125* **Circuit breaker tripped:** when the breaker last tripped, if it has.
126* **Recent errors:** each entry shows when the failure occurred, an error type, and a category. The category is `webhook_error` for a problem with your endpoint or the connection to it, or `relay_error` for a failure inside Anthropic's systems. Entries never include request content or your endpoint URL. The list keeps the 10 most recent failures and clears an hour after the last one.
126* **Recent errors:** each entry shows when the failure occurred, an error type, and a category. The category is `webhook_error` for a problem with your endpoint or the connection to it, or `relay_error` for a failure inside Anthropic’s systems. A `DlpWebhookStatusError` entry can also show the HTTP status your AI security server returned and the size of the request body Anthropic sent, such as `HTTP 413` · `1.3 MB`. Entries never include request content or your endpoint URL. The list keeps the 10 most recent failures and clears an hour after the last one.
127127 
128128The error types in **Recent errors** mean:
129129 
130130| Error shown | What it means | Counts toward the circuit breaker |
131131| ---------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------- |
132| `DlpWebhookTimeoutError` · `webhook_error` | Your AI security server didn't return a verdict within the **Prompt verdict timeout (ms)** you set. | Yes |
132| `DlpWebhookTimeoutError` · `webhook_error` | Your AI security server didn’t return a verdict within the **Prompt verdict timeout (ms)** you set. | Yes |
133133| `DlpWebhookStatusError` · `webhook_error` | Your AI security server answered with an HTTP status other than 200, such as a redirect. | Yes |
134| `DlpWebhookResponseError` · `webhook_error` | Your AI security server answered 200, but the body isn't a valid verdict or is larger than 64 KiB. | Yes |
135| `DlpWebhookTransportError` · `webhook_error` | The connection failed or dropped before a complete answer arrived: for example, the hostname didn't resolve or resolved to a private address, the connection was refused or reset, or the TLS handshake failed. A network problem on Anthropic's side can also show up this way. | No |
136| `DlpWebhookDisallowedAddressError` · `webhook_error` | The endpoint URL's host is a private or internal IP address, an IPv6 address, or `localhost`. A hostname that resolves to such an address shows as a transport error instead. | Yes |
137| `DlpWebhookBlockedError` · `webhook_error` | The endpoint URL isn't an `https://` URL on port 443, or can't be parsed, so no request was sent. | No |
138| `DlpWebhookRelayError` · `relay_error` | The failure was inside Anthropic's systems, and your AI security server usually wasn't contacted. | No |
134| `DlpWebhookResponseError` · `webhook_error` | Your AI security server answered 200, but the body isn’t a valid verdict or is larger than 64 KiB. | Yes |
135| `DlpWebhookTransportError` · `webhook_error` | The connection failed or dropped before a complete answer arrived: for example, the hostname didn’t resolve or resolved to a private address, the connection was refused or reset, or the TLS handshake failed. A network problem on Anthropic’s side can also show up this way. | No |
136| `DlpWebhookDisallowedAddressError` · `webhook_error` | The endpoint URL’s host is a private or internal IP address, an IPv6 address, or `localhost`. A hostname that resolves to such an address shows as a transport error instead. | Yes |
137| `DlpWebhookBlockedError` · `webhook_error` | The endpoint URL isn’t an `https://` URL on port 443, or can’t be parsed, so no request was sent. | No |
138| `DlpWebhookRelayError` · `relay_error` | The failure was inside Anthropic’s systems, and your AI security server usually wasn’t contacted. | No |
139139 
140140In shadow mode, no error counts toward the circuit breaker.
141141 
from line 145
145145 
146146Sustained webhook failures attributable to your AI security server trip the circuit breaker, which stops enforcement: your server is no longer contacted, and your **Failure handling** choice applies to every inspected request. With **Block the request** selected, users in your organization are blocked until the breaker resets. When the breaker trips, administrators are also notified in the claude.ai notification center.
147147 
148Each trip is also recorded in your organization's [Activity Feed](https://platform.claude.com/docs/en/manage-claude/compliance-activity-feed) as an `inference_hooks_circuit_breaker_tripped` activity, so your security team or vendor can alert on trips from monitoring they already run, such as a SIEM that ingests the feed. One activity is recorded for each trip, not one for each affected request. Recording requires the Compliance API to be enabled for your organization; see [Set up the Compliance API](https://platform.claude.com/docs/en/manage-claude/compliance-api-access).
148Each trip is also recorded in your organization’s [Activity Feed](https://platform.claude.com/docs/en/manage-claude/compliance-activity-feed) as an `inference_hooks_circuit_breaker_tripped` activity, so your security team or vendor can alert on trips from monitoring they already run, such as a SIEM that ingests the feed. One activity is recorded for each trip, not one for each affected request. Recording requires the Compliance API to be enabled for your organization; see [Set up the Compliance API](https://platform.claude.com/docs/en/manage-claude/compliance-api-access).
149149 
150150To recover, fix the server, then turn **Enforce verdicts** back on to reset the breaker.
151151 
from line 161
161161 
162162## Audit trail
163163 
164Inference hooks activity is recorded in your organization's [Activity Feed](https://platform.claude.com/docs/en/manage-claude/compliance-activity-feed): configuration changes, denials, circuit breaker trips, and requests that proceeded without inspection because no verdict could be obtained. That last kind is recorded only while **Enforce verdicts** is on and **Mode** is **Allow the request**. Its reason is `endpoint_timeout`, `endpoint_error` for any other problem calling your AI security server, or `internal_error` for a failure on Anthropic's side. Under **Block the request** or **Shadow mode**, failed requests aren't recorded individually. The circuit breaker's automatic recovery isn't recorded in any mode. While the circuit breaker is tripped, no per-request Inference hooks activities are recorded; the trip activity is the feed's record of that window. Denial records carry identifiers that let you join each denial to the matching record in your own system.
164Inference hooks activity is recorded in your organization’s [Activity Feed](https://platform.claude.com/docs/en/manage-claude/compliance-activity-feed): configuration changes, denials, circuit breaker trips, and requests that proceeded without inspection because no verdict could be obtained. That last kind is recorded only while **Enforce verdicts** is on and **Mode** is **Allow the request**. Its reason is `endpoint_timeout`, `endpoint_error` for any other problem calling your AI security server, or `internal_error` for a failure on Anthropic’s side. Under **Block the request** or **Shadow mode**, failed requests aren’t recorded individually. The circuit breaker’s automatic recovery isn’t recorded in any mode. While the circuit breaker is tripped, no per-request Inference hooks activities are recorded; the trip activity is the feed’s record of that window. Denial records carry identifiers that let you join each denial to the matching record in your own system.
165165 
166166## Turn Inference hooks off
167167 

manage-claude/inference-hooks-endpoint Changed · +55 / -55 lines

from line 148
148148 
149149Anthropic sends an HTTPS `POST` to the URL your administrator configures. The whole configured URL is the endpoint: there is no fixed path suffix, so choose any path that suits your server.
150150 
151Host your AI security server where Anthropic can reach it: an `https://` URL on port 443, on a publicly routable host. Private, loopback, and carrier-grade NAT ranges are refused at connect time. The server must have a certificate that validates against the public CA trust store, and it must respond without redirects. The host must have an IPv4 address, which Anthropic uses even when the host also has IPv6 addresses; a URL whose host is `localhost` or an IPv6 address is refused. The configured URL must be the final destination. Reverse-tunnel hosts (ngrok and similar tunnel services) are not supported: Anthropic's network policy blocks them. Host your server on a domain you control. [Configure Inference hooks](https://platform.claude.com/docs/en/manage-claude/inference-hooks-configuration) covers how your administrator sets and tests the URL.
151Host your AI security server where Anthropic can reach it: an `https://` URL on port 443, on a publicly routable host. Private, loopback, and carrier-grade NAT ranges are refused at connect time. The server must have a certificate that validates against the public CA trust store, and it must respond without redirects. The host must have an IPv4 address, which Anthropic uses even when the host also has IPv6 addresses; a URL whose host is `localhost` or an IPv6 address is refused. The configured URL must be the final destination. Reverse-tunnel hosts (ngrok and similar tunnel services) are not supported: Anthropic’s network policy blocks them. Host your server on a domain you control. [Configure Inference hooks](https://platform.claude.com/docs/en/manage-claude/inference-hooks-configuration) covers how your administrator sets and tests the URL.
152152 
153153Every request carries these fixed headers, along with any [custom request headers](https://platform.claude.com/docs/en/manage-claude/inference-hooks-configuration) your administrator configured and, once your organization has a signing secret, the `webhook-*` signature headers described in [Verify the signature](https://platform.claude.com/docs/en/manage-claude/inference-hooks-endpoint#verify-the-signature):
154154 
from line 172
172172| `actor` | object | The principal the request is attributed to, discriminated on `type` (`"user"` is the only value sent today): `id` (a tagged identifier, stable across requests for the same account) and `email_address` (when available). Both `id` and `email_address` can be null. |
173173| `source` | object | The originating application: `application` (see [Source values](https://platform.claude.com/docs/en/manage-claude/inference-hooks-endpoint#source-values)). |
174174| `messages` | array | The conversation transcript up to the point of inference. See [Content blocks](https://platform.claude.com/docs/en/manage-claude/inference-hooks-endpoint#content-blocks). |
175| `session_id` | string or null | Opaque conversation identifier, when one exists. Don't parse it. For Claude Code it is a best-effort, client-asserted session identifier. |
175| `session_id` | string or null | Opaque conversation identifier, when one exists. Don’t parse it. For Claude Code it is a best-effort, client-asserted session identifier. |
176176| `model` | string or null | Public model identifier for this request, when available. |
177177| `metadata` | object | Reserved extension map of string keys to string values, sent empty today. Require nothing from it, and tolerate its absence, its presence, and any keys that appear. |
178178 
from line 222
222222| Block `type` | Fields |
223223| ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
224224| `text` | `text`: the text content. |
225| `tool_use` | `id`: the identifier the matching tool result references. `tool_name`: the tool's name. `input`: the arguments the model passed to the tool. `tool_info`: on a tool call frame only (left out elsewhere, never `null`), an object that says who runs or provides the tool; see [The tool call frame](https://platform.claude.com/docs/en/manage-claude/inference-hooks-endpoint#the-tool-call-frame). |
226| `tool_result` | `content`: the tool's output as text, with parts joined by newlines; binary parts such as images are replaced by placeholder markers, and raw bytes are never sent. `is_error`: whether the tool call failed. `tool_name`: the tool's name, so a policy can condition on tool identity without cross-referencing an earlier block. `tool_use_id`: the `id` of the matching `tool_use` block. |
227| `attachment` | `file_name`: the original file name or path. `media_type`: the attachment's media type. `size_bytes`: the size of the original file. `text`: the text content of the attachment when available, such as extracted document text, an audio transcript, or link metadata. Raw attachment bytes are never sent. |
225| `tool_use` | `id`: the identifier the matching tool result references. `tool_name`: the tool’s name. `input`: the arguments the model passed to the tool. `tool_info`: on a tool call frame only (left out elsewhere, never `null`), an object that says who runs or provides the tool; see [The tool call frame](https://platform.claude.com/docs/en/manage-claude/inference-hooks-endpoint#the-tool-call-frame). |
226| `tool_result` | `content`: the tool’s output as text, with parts joined by newlines; binary parts such as images are replaced by placeholder markers, and raw bytes are never sent. `is_error`: whether the tool call failed. `tool_name`: the tool’s name, so a policy can condition on tool identity without cross-referencing an earlier block. `tool_use_id`: the `id` of the matching `tool_use` block. |
227| `attachment` | `file_name`: the original file name or path. `media_type`: the attachment’s media type. `size_bytes`: the size of the original file. `text`: the text content of the attachment when available, such as extracted document text, an audio transcript, or link metadata. Raw attachment bytes are never sent. |
228228 
229Apart from `type`, a `text` block's `text`, and a `tool_result` block's `content` and `is_error`, any of these fields can be `null` when the value isn't known; for example, an image arrives as an `attachment` block with `file_name` and `text` set to `null`.
229Apart from `type`, a `text` block’s `text`, and a `tool_result` block’s `content` and `is_error`, any of these fields can be `null` when the value isn’t known; for example, an image arrives as an `attachment` block with `file_name` and `text` set to `null`.
230230 
231A block whose `type` you don't recognize is a forward-compatible addition. The only field it guarantees is `type`; your policy may inspect whatever other fields are present, but must not reject the request because of an unrecognized type.
231A block whose `type` you don’t recognize is a forward-compatible addition. The only field it guarantees is `type`; your policy may inspect whatever other fields are present, but must not reject the request because of an unrecognized type.
232232 
233233### What the transcript contains
234234 
235The transcript is the conversation as the end user sees it, up to the point of inference: transcript text, tool calls and their results, extracted attachment text, and prior turns. It never includes system prompts, tool definitions, Anthropic-internal context, Claude's hidden reasoning, or raw file bytes.
235The transcript is the conversation as the end user sees it, up to the point of inference: transcript text, tool calls and their results, extracted attachment text, and prior turns. It never includes system prompts, tool definitions, Anthropic-internal context, Claude’s hidden reasoning, or raw file bytes.
236236 
237A turn whose every block is excluded is omitted entirely, so don't assume strict user and assistant alternation.
237A turn whose every block is excluded is omitted entirely, so don’t assume strict user and assistant alternation.
238238 
239Transcripts are sent untruncated, so a long conversation with large attachments produces a large request body. In practice the model's context window keeps bodies under about 10 MB, but the protocol allows up to 64 MiB. Several common defaults are much smaller, including nginx `client_max_body_size` at 1 MB and Express `express.json()` at 100 kB, and a rejected body counts as a webhook failure, so under **Allow the request** failure handling an oversized prompt would reach the model uninspected.
239Transcripts are sent untruncated, so a long conversation with large attachments produces a large request body. In practice the model’s context window keeps bodies under about 10 MB, but the protocol allows up to 64 MiB. Several common defaults are much smaller, including nginx `client_max_body_size` at 1 MB and Express `express.json()` at 100 kB, and a rejected body counts as a webhook failure, so under **Allow the request** failure handling an oversized prompt would reach the model uninspected.
240240 
241241### Source values
242242 
243`source.application` is an open string, not a closed enum. Common values are `claude-ai`, `claude-code`, and `cowork`; [connection tests](https://platform.claude.com/docs/en/manage-claude/inference-hooks-configuration) and automatic circuit-breaker [recovery checks](https://platform.claude.com/docs/en/manage-claude/inference-hooks-endpoint#circuit-breaker) use `config-test`. New values may appear, and your server must not reject a request because of one it doesn't recognize.
243`source.application` is an open string, not a closed enum. Common values are `claude-ai`, `claude-code`, and `cowork`; [connection tests](https://platform.claude.com/docs/en/manage-claude/inference-hooks-configuration) and automatic circuit-breaker [recovery checks](https://platform.claude.com/docs/en/manage-claude/inference-hooks-endpoint#circuit-breaker) use `config-test`. New values may appear, and your server must not reject a request because of one it doesn’t recognize.
244244 
245Treat `source.application` as advisory routing metadata, not a trust boundary: don't rest a security-critical policy decision on it alone.
245Treat `source.application` as advisory routing metadata, not a trust boundary: don’t rest a security-critical policy decision on it alone.
246246 
247247## The tool call frame
248248 
249When Claude produces tool calls, Anthropic sends one tool call frame that lists them. Calls to some of claude.ai's own tools may be left out, and a response whose only tool calls are left out doesn't produce a tool call frame; see [Availability](https://platform.claude.com/docs/en/manage-claude/inference-hooks#availability). One verdict covers the whole frame: you can't allow some tool calls and deny others. The frame goes to the same endpoint as the prompt frame, with the same headers, signature, and top-level fields. Tool calls made by code that Claude runs in the code execution tool are sent the same way, in separate tool call frames, before they run.
249When Claude produces tool calls, Anthropic sends one tool call frame that lists them. Calls to some of claude.ai’s own tools may be left out, and a response whose only tool calls are left out doesn’t produce a tool call frame; see [Availability](https://platform.claude.com/docs/en/manage-claude/inference-hooks#availability). One verdict covers the whole frame: you can’t allow some tool calls and deny others. The frame goes to the same endpoint as the prompt frame, with the same headers, signature, and top-level fields. Tool calls made by code that Claude runs in the code execution tool are sent the same way, in separate tool call frames, before they run.
250250 
251251It differs from the prompt frame in three ways:
252252 
from line 254
254254* `messages` holds only the latest message, the `assistant` message Claude just produced: any `text` blocks and one `tool_use` block for each tool call the frame lists, in the order the model produced them. Earlier conversation is left out, because the prompt frame sent before that model call carried it. Read the last entry of `messages`, because the protocol may later add earlier messages before it.
255255* Each `tool_use` block carries a `tool_info` object that says who runs or provides the tool.
256256 
257Where `session_id` is set, it is the same on both frames. The tool call frame has its own `request_id`, which is opaque like the prompt frame's.
257Where `session_id` is set, it is the same on both frames. The tool call frame has its own `request_id`, which is opaque like the prompt frame’s.
258258 
259`tool_info` says who runs or provides the tool, not what the tool can reach. It is one of four kinds, told apart by its `type` field, and each kind carries its own fields. Anthropic sends the first of the following kinds that fits the tool. New kinds may appear: accept a `type` you don't recognize, and for such a kind rely only on `type`.
259`tool_info` says who runs or provides the tool, not what the tool can reach. It is one of four kinds, told apart by its `type` field, and each kind carries its own fields. Anthropic sends the first of the following kinds that fits the tool. New kinds may appear: accept a `type` you don’t recognize, and for such a kind rely only on `type`.
260260 
261An optional field that doesn't apply is left out, never `null`, so a `tool_info` can be just `{"type": "client"}`. `tool_name` is chosen by whoever defined the tool, and a server's `toolset_name` by whoever wrote the request or named the connector. Don't treat either as a trust boundary.
261An optional field that doesn’t apply is left out, never `null`, so a `tool_info` can be just `{"type": "client"}`. `tool_name` is chosen by whoever defined the tool, and a server’s `toolset_name` by whoever wrote the request or named the connector. Don’t treat either as a trust boundary.
262262 
263263### Platform tools
264264 
from line 267
267267| Field | Present | Description |
268268| -------------- | -------- | ------------------------------------------------------------------------------------------------------------------- |
269269| `type` | Always | `"platform"` |
270| `tool_type` | Always | The tool's versioned type, such as `web_search_20250305`. Match it exactly; don't parse a name or a date out of it. |
270| `tool_type` | Always | The tool’s versioned type, such as `web_search_20250305`. Match it exactly; don’t parse a name or a date out of it. |
271271| `toolset_name` | Optional | The group of tools it belongs to. |
272272 
273273### Application tools
274274 
275An application tool is one that the Anthropic application making the request provides itself, such as claude.ai's own tools.
275An application tool is one that the Anthropic application making the request provides itself, such as claude.ai’s own tools.
276276 
277277| Field | Present | Description |
278278| -------------- | -------- | --------------------------------- |
from line 295
295295}
296296```
297297 
298claude.ai doesn't always name this tool `web_search`, so don't match on the name alone. `input` always includes the search query and can hold other fields.
298claude.ai doesn’t always name this tool `web_search`, so don’t match on the name alone. `input` always includes the search query and can hold other fields.
299299 
300300### Third-party tools
301301 
302A third-party tool is one on a server that Anthropic knows of, such as a claude.ai connector or an MCP server that the request names in `mcp_servers`. This doesn't mean Anthropic has vetted the server. In voice mode, a call to a claude.ai connector's tool is `"client"` instead.
302A third-party tool is one on a server that Anthropic knows of, such as a claude.ai connector or an MCP server that the request names in `mcp_servers`. This doesn’t mean Anthropic has vetted the server. In voice mode, a call to a claude.ai connector’s tool is `"client"` instead.
303303 
304304| Field | Present | Description |
305305| ----------------- | -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
306306| `type` | Always | `"third_party"` |
307| `toolset_name` | Optional | For a server in `mcp_servers`, the name the request gives the server. For any other server, such as a claude.ai connector, the server's name, copied from `tool_name`. |
308| `origin` | Optional | The scheme, host, and non-default port of the server's URL. It can be a private or local address, `localhost` included. An absent `origin` means unknown, not safe. |
309| `verified_origin` | Whenever `origin` is | `true` only when Anthropic's servers connect to the server themselves. Treat `false` as an origin that Anthropic hasn't confirmed. |
307| `toolset_name` | Optional | For a server in `mcp_servers`, the name the request gives the server. For any other server, such as a claude.ai connector, the server’s name, copied from `tool_name`. |
308| `origin` | Optional | The scheme, host, and non-default port of the server’s URL. It can be a private or local address, `localhost` included. An absent `origin` means unknown, not safe. |
309| `verified_origin` | Whenever `origin` is | `true` only when Anthropic’s servers connect to the server themselves. Treat `false` as an origin that Anthropic hasn’t confirmed. |
310310 
311311A `tool_use` block for a tool on an MCP server that the request names `crm` in `mcp_servers`:
312312 
from line 346
346346}
347347```
348348 
349For a claude.ai connector, `verified_origin` can be `false` even when Anthropic's servers connect to the server themselves.
349For a claude.ai connector, `verified_origin` can be `false` even when Anthropic’s servers connect to the server themselves.
350350 
351A name copied from `tool_name` can differ from the name the user sees: `mcp__Google_Drive__search_files` gives `Google_Drive`, not `Google Drive`. It can also end in a short suffix (`Gmail-1a2b3c4d`), for example when another of the user's connectors has the same name. The name isn't a stable identifier and doesn't prove which server the tool is on. When `tool_name` has no server name in it, `toolset_name` is left out.
351A name copied from `tool_name` can differ from the name the user sees: `mcp__Google_Drive__search_files` gives `Google_Drive`, not `Google Drive`. It can also end in a short suffix (`Gmail-1a2b3c4d`), for example when another of the user’s connectors has the same name. The name isn’t a stable identifier and doesn’t prove which server the tool is on. When `tool_name` has no server name in it, `toolset_name` is left out.
352352 
353353### Client tools
354354 
355A client tool is any other tool, usually one that the application calling Claude runs. A tool that Anthropic defines but the calling application runs, such as bash or computer use, is a client tool too, and carries its versioned type in `tool_type`. A call to a tool the request doesn't declare is also `"client"`.
355A client tool is any other tool, usually one that the application calling Claude runs. A tool that Anthropic defines but the calling application runs, such as bash or computer use, is a client tool too, and carries its versioned type in `tool_type`. A call to a tool the request doesn’t declare is also `"client"`.
356356 
357A tool on an MCP server that Claude Code connects to directly from the user's computer, such as a local MCP server, is a client tool. Its `tool_info` is `{"type": "client"}`, and its `tool_name` is the name Claude Code gives it, in the form `mcp__<server>__<tool>`.
357A tool on an MCP server that Claude Code connects to directly from the user’s computer, such as a local MCP server, is a client tool. Its `tool_info` is `{"type": "client"}`, and its `tool_name` is the name Claude Code gives it, in the form `mcp__<server>__<tool>`.
358358 
359A deny stops the call before Claude Code runs it. The exchange between Claude Code and a local server doesn't pass through Anthropic, so your AI security server sees the tool's result only when Claude Code sends it back. Its text is then in a `tool_result` block in the next prompt frame.
359A deny stops the call before Claude Code runs it. The exchange between Claude Code and a local server doesn’t pass through Anthropic, so your AI security server sees the tool’s result only when Claude Code sends it back. Its text is then in a `tool_result` block in the next prompt frame.
360360 
361361| Field | Present | Description |
362362| -------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
363363| `type` | Always | `"client"` |
364| `tool_type` | Optional | The tool's versioned type, such as `bash_20250124`, when Anthropic defines the tool. Match it exactly; don't parse a name or a date out of it. |
364| `tool_type` | Optional | The tool’s versioned type, such as `bash_20250124`, when Anthropic defines the tool. Match it exactly; don’t parse a name or a date out of it. |
365365| `toolset_name` | Optional | The group of tools it belongs to, such as `browser`. |
366366 
367367A `tool_use` block for a tool that the calling application declares:
from line 421
421421| -------------- | --------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
422422| `action` | `"allow"` or `"deny"`; required | `allow` lets inference proceed; `deny` rejects it. |
423423| `deny_reason` | string or null; at most 500 characters, longer values truncated | Shown to the end user when `action` is `deny`; ignored on `allow`. |
424| `reference_id` | string or null; at most 50 characters from `[A-Za-z0-9._:/-]` | Your own identifier for this evaluation. It's recorded on the denial's `inference_hooks_request_denied` [compliance activity](https://platform.claude.com/docs/en/manage-claude/compliance-activity-feed) and never shown to the end user. Keep it opaque: no request content and no personal data. |
424| `reference_id` | string or null; at most 50 characters from `[A-Za-z0-9._:/-]` | Your own identifier for this evaluation. It’s recorded on the denial’s `inference_hooks_request_denied` [compliance activity](https://platform.claude.com/docs/en/manage-claude/compliance-activity-feed) and never shown to the end user. Keep it opaque: no request content and no personal data. |
425425 
426426A deny is never discarded over a formatting problem: an oversize `deny_reason` is truncated, a malformed `reference_id` is silently dropped, and the `action` is still honored.
427427 
428The reverse doesn't hold. Anything other than HTTP 200 with a parseable verdict is a webhook failure, and your organization's [failure handling](https://platform.claude.com/docs/en/manage-claude/inference-hooks-configuration) applies instead of a verdict. In particular:
428The reverse doesn’t hold. Anything other than HTTP 200 with a parseable verdict is a webhook failure, and your organization’s [failure handling](https://platform.claude.com/docs/en/manage-claude/inference-hooks-configuration) applies instead of a verdict. In particular:
429429 
430* Don't signal a deny with an error status. A non-200 response is a failure, not a deny.
430* Don’t signal a deny with an error status. A non-200 response is a failure, not a deny.
431431* Any `action` value other than `allow` or `deny` is treated as a webhook failure.
432432 
433433Anthropic reads at most 64 KiB of the response body, and the body must be uncompressed. Redirects are not followed, and cookies are ignored. Unknown fields in the verdict body are ignored, so you can return a richer object alongside the fields documented here.
from line 440
440440 
441441| Header | Contents |
442442| ------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
443| `webhook-id` | Unique identifier for this delivery. Equals the body's `request_id`. Use it as an idempotency key and as the first component of the signed payload. |
444| `webhook-timestamp` | Unix time in seconds, as a decimal string, when the request was signed. Reject a timestamp more than 5 minutes from your server's clock, in either direction. |
443| `webhook-id` | Unique identifier for this delivery. Equals the body’s `request_id`. Use it as an idempotency key and as the first component of the signed payload. |
444| `webhook-timestamp` | Unix time in seconds, as a decimal string, when the request was signed. Reject a timestamp more than 5 minutes from your server’s clock, in either direction. |
445445| `webhook-signature` | One or more space-separated `v1,<base64>` values, each an HMAC-SHA256 over `{webhook-id}.{webhook-timestamp}.{raw body bytes}`. Accept the request if any value matches yours, using a constant-time comparison. |
446446 
447447Two details cause most verification bugs:
from line 451
451451 
452452Once your organization has a signing secret, every request Anthropic sends is signed, including the connection test, because the setup flow generates the secret before the first test. [Enabling Inference hooks requires a secret](https://platform.claude.com/docs/en/manage-claude/inference-hooks-configuration), so reject any request that arrives unsigned. One exception: an organization that enabled Inference hooks before the secret was required keeps sending unsigned requests until its administrator generates one. Accept unsigned requests only until your administrator confirms the secret exists, then reject them.
453453 
454[Rotating the secret](https://platform.claude.com/docs/en/manage-claude/inference-hooks-configuration#rotate-your-signing-secret) is an immediate cutover, but requests signed with the previous secret can still arrive for about a minute afterward, plus anything already in flight. Have your AI security server accept signatures from both secrets during the switchover so those stragglers aren't rejected.
454[Rotating the secret](https://platform.claude.com/docs/en/manage-claude/inference-hooks-configuration#rotate-your-signing-secret) is an immediate cutover, but requests signed with the previous secret can still arrive for about a minute afterward, plus anything already in flight. Have your AI security server accept signatures from both secrets during the switchover so those stragglers aren’t rejected.
455455 
456The following samples are server implementations, so there is no shell tab: an AI security server is a long-running HTTPS service rather than a one-shot request. Each sample uses only the language's standard library; the [Standard Webhooks](https://www.standardwebhooks.com/) project also publishes verification libraries for most languages.
456The following samples are server implementations, so there is no shell tab: an AI security server is a long-running HTTPS service rather than a one-shot request. Each sample uses only the language’s standard library; the [Standard Webhooks](https://www.standardwebhooks.com/) project also publishes verification libraries for most languages.
457457 
458458<CodeGroup exclude="shell">
459459 ```python Python
from line 836
836836 
837837### Webhook failures
838838 
839Timeouts, non-200 statuses (redirects included), unparseable or oversized response bodies, and unreachable endpoints are all webhook failures. A webhook failure never becomes a deny; instead, your organization's [failure handling](https://platform.claude.com/docs/en/manage-claude/inference-hooks-configuration) setting determines whether the affected request is blocked or proceeds without inspection.
839Timeouts, non-200 statuses (redirects included), unparseable or oversized response bodies, and unreachable endpoints are all webhook failures. A webhook failure never becomes a deny; instead, your organization’s [failure handling](https://platform.claude.com/docs/en/manage-claude/inference-hooks-configuration) setting determines whether the affected request is blocked or proceeds without inspection.
840840 
841841### Circuit breaker
842842 
from line 846
846846 
847847Prompt frames and tool call frames share one circuit breaker, and failures on either count toward it.
848848 
849Each trip is recorded as an `inference_hooks_circuit_breaker_tripped` activity in the [Activity Feed](https://platform.claude.com/docs/en/manage-claude/compliance-activity-feed), one activity for each trip. While the breaker is tripped, no per-request Inference hooks activities are recorded, so the trip activity is the feed's only record of the tripped window.
849Each trip is recorded as an `inference_hooks_circuit_breaker_tripped` activity in the [Activity Feed](https://platform.claude.com/docs/en/manage-claude/compliance-activity-feed), one activity for each trip. While the breaker is tripped, no per-request Inference hooks activities are recorded, so the trip activity is the feed’s only record of the tripped window.
850850 
851851### Latency
852852 
853Enforcement adds your AI security server's round trip to the latency of every governed request in your organization. With **Validate tool calls** on, a response that produces a tool call frame also waits for its verdict, in shadow mode as well. Keep the verdict fast, and load-test your server before rolling it out to a large organization.
853Enforcement adds your AI security server’s round trip to the latency of every governed request in your organization. With **Validate tool calls** on, a response that produces a tool call frame also waits for its verdict, in shadow mode as well. Keep the verdict fast, and load-test your server before rolling it out to a large organization.
854854 
855855### Source IP addresses
856856 
857Requests to your AI security server originate from `160.79.106.0/24`, part of Anthropic's published [outbound IP ranges](https://platform.claude.com/docs/en/api/ip-addresses). Allowlist that block, not the inbound ranges on the same page, which don't cover it. Allowlisting narrows your server's exposure, but it is not a substitute for signature verification: the block carries Anthropic egress traffic beyond Inference hooks.
857Requests to your AI security server originate from `160.79.106.0/24`, part of Anthropic’s published [outbound IP ranges](https://platform.claude.com/docs/en/api/ip-addresses). Allowlist that block, not the inbound ranges on the same page, which don’t cover it. Allowlisting narrows your server’s exposure, but it is not a substitute for signature verification: the block carries Anthropic egress traffic beyond Inference hooks.
858858 
859859## Forward compatibility
860860 
from line 869
869869 
870870Never reject a request because of an unrecognized block type or field; read the fields you know and skip the rest.
871871 
872Other hook event types will be introduced in the future. A new event type is an addition your server can't handle by skipping a field: the request still needs a verdict. When the top-level `type` is a value you don't recognize, return an allow verdict rather than an error status; an error response is a [webhook failure](https://platform.claude.com/docs/en/manage-claude/inference-hooks-endpoint#webhook-failures), and sustained failures trip the [circuit breaker](https://platform.claude.com/docs/en/manage-claude/inference-hooks-endpoint#circuit-breaker).
872Other hook event types will be introduced in the future. A new event type is an addition your server can’t handle by skipping a field: the request still needs a verdict. When the top-level `type` is a value you don’t recognize, return an allow verdict rather than an error status; an error response is a [webhook failure](https://platform.claude.com/docs/en/manage-claude/inference-hooks-endpoint#webhook-failures), and sustained failures trip the [circuit breaker](https://platform.claude.com/docs/en/manage-claude/inference-hooks-endpoint#circuit-breaker).
873873 
874874## Design your integration
875875 
876876A production AI security server makes a few design choices beyond the wire protocol.
877877 
878**Deduplicate on `webhook-id`.** The `webhook-id` header is unique for each delivery and equals the body's `request_id`, and a connection-failure retry reuses it, so it works as an idempotency key. If you record verdicts, key the records on it.
878**Deduplicate on `webhook-id`.** The `webhook-id` header is unique for each delivery and equals the body’s `request_id`, and a connection-failure retry reuses it, so it works as an idempotency key. If you record verdicts, key the records on it.
879879 
880880**Record verdicts and join denials.** Store each verdict you return along with its `reference_id`. Every denial is recorded as an `inference_hooks_request_denied` compliance activity carrying the `reference_id` your server returned, so you can join denials in the [Activity Feed](https://platform.claude.com/docs/en/manage-claude/compliance-activity-feed) to the matching records in your own system.
881881 
882**Archive with an always-allow server.** To capture transcripts in real time without policing them, return `{"action": "allow"}` unconditionally and persist the frame after responding. This is a push-based alternative to polling the [Compliance API](https://platform.claude.com/docs/en/manage-claude/compliance-api), and answering before you persist keeps your round trip out of the user's critical path.
882**Archive with an always-allow server.** To capture transcripts in real time without policing them, return `{"action": "allow"}` unconditionally and persist the frame after responding. This is a push-based alternative to polling the [Compliance API](https://platform.claude.com/docs/en/manage-claude/compliance-api), and answering before you persist keeps your round trip out of the user’s critical path.
883883 
884884**Write `deny_reason` for the end user.** The text you return is what the user sees when their request is blocked, truncated at 500 characters. Tell them what to change, such as which kind of content to remove, rather than emitting a scanner code that only your team can interpret.
885885 

manage-claude/opentelemetry Changed · +24 / -24 lines

from line 10
1010---
1111 
1212<Note>
13 OpenTelemetry export is in beta. It's provided under your agreement with Anthropic, including the Beta Services section of the [Service Specific Terms](https://www.anthropic.com/legal/service-specific-terms).
13 OpenTelemetry export is in beta. It’s provided under your agreement with Anthropic, including the Beta Services section of the [Service Specific Terms](https://www.anthropic.com/legal/service-specific-terms).
1414</Note>
1515 
1616<video aria-label="Trace agents with OpenTelemetry on the Claude Platform">
from line 19
1919 <source src="https://media.platform.claude.com/docs/opentelemetry/tracing/overview-480p.mp4" type="video/mp4" />
2020</video>
2121 
22The Claude API and the SDK can trace your Messages API requests, tool uses, and Managed Agents sessions with [OpenTelemetry](https://opentelemetry.io/) (OTel). You can view these traces in the observability platform you already have. Use them to debug failed or slow requests, track token spend and latency, and build evals from real traffic. You can also see each request inside your application's own traces, linked to the user or feature that sent it.
22The Claude API and the SDK can trace your Messages API requests, tool uses, and Managed Agents sessions with [OpenTelemetry](https://opentelemetry.io/) (OTel). You can view these traces in the observability platform you already have. Use them to debug failed or slow requests, track token spend and latency, and build evals from real traffic. You can also see each request inside your application’s own traces, linked to the user or feature that sent it.
2323 
2424OpenTelemetry is a vendor-neutral standard that most observability platforms support. A *trace* is the full record of one request through your system. A *span* is one step in a trace, such as a model request or a tool use. The API and the SDK use attributes from the [GenAI semantic conventions](https://github.com/open-telemetry/semantic-conventions-genai), so platforms that support the conventions can recognize the spans without extra setup.
2525 
2626## Get started
2727 
28You can set up SDK tracing, API tracing, or both. Set up both to see a request's SDK and API spans in one trace, as in the [example traces](https://platform.claude.com/docs/en/manage-claude/opentelemetry#example-traces-and-how-to-read-them).
28You can set up SDK tracing, API tracing, or both. Set up both to see a request’s SDK and API spans in one trace, as in the [example traces](https://platform.claude.com/docs/en/manage-claude/opentelemetry#example-traces-and-how-to-read-them).
2929 
3030Let Claude Code set up this feature for you
3131 
from line 145
145145With Full content, you can also see why a run failed or was slow, read full conversations, and build evals from real traces. In the [OpenTelemetry span reference](https://platform.claude.com/docs/en/api/opentelemetry/spans), attributes that hold prompts and responses are tagged <Badge>Content</Badge>.
146146 
147147<Info>
148 Your observability platform stores this content under its own access and retention settings, so check that they meet your organization's requirements.
148 Your observability platform stores this content under its own access and retention settings, so check that they meet your organization’s requirements.
149149</Info>
150150 
151If your organization has a HIPAA, FERPA, or K-12 data-handling restriction with Anthropic, destinations export only metadata regardless of their content mode. SDK spans aren't affected.
151If your organization has a HIPAA, FERPA, or K-12 data-handling restriction with Anthropic, destinations export only metadata regardless of their content mode. SDK spans aren’t affected.
152152 
153With [zero data retention](https://platform.claude.com/docs/en/manage-claude/api-and-data-retention), you can still use Full content. For Messages API requests, the API holds the exported content only in memory until it delivers it to the destination. [Claude Managed Agents](https://platform.claude.com/docs/en/managed-agents/overview) isn't eligible for zero data retention, and its data retention stays the same when you use OpenTelemetry.
153With [zero data retention](https://platform.claude.com/docs/en/manage-claude/api-and-data-retention), you can still use Full content. For Messages API requests, the API holds the exported content only in memory until it delivers it to the destination. [Claude Managed Agents](https://platform.claude.com/docs/en/managed-agents/overview) isn’t eligible for zero data retention, and its data retention stays the same when you use OpenTelemetry.
154154 
155155### Content limits
156156 
from line 182
182182 
183183![Example Messages tool runner trace: two requests with client and server spans, model requests, web\_search, and get\_weather](https://platform.claude.com/docs/images/opentelemetry-sdk-trace-shape.svg)
184184 
185The SDK in your application emits the [`anthropic.messages.tool_runner`](https://platform.claude.com/docs/en/api/opentelemetry/spans#anthropic-messages-tool-runner) span, the [`anthropic.custom_tool_use`](https://platform.claude.com/docs/en/api/opentelemetry/spans#anthropic-tool-use-anthropic-mcp-tool-use-and-anthropic-custom-tool-use) span, and each request's client span. To get these spans, [set up SDK tracing](https://platform.claude.com/docs/en/manage-claude/opentelemetry/sdk).
185The SDK in your application emits the [`anthropic.messages.tool_runner`](https://platform.claude.com/docs/en/api/opentelemetry/spans#anthropic-messages-tool-runner) span, the [`anthropic.custom_tool_use`](https://platform.claude.com/docs/en/api/opentelemetry/spans#anthropic-tool-use-anthropic-mcp-tool-use-and-anthropic-custom-tool-use) span, and each request’s client span. To get these spans, [set up SDK tracing](https://platform.claude.com/docs/en/manage-claude/opentelemetry/sdk).
186186 
187187Each request has its token usage on several of its spans. To count each token once, see [Counting tokens](https://platform.claude.com/docs/en/manage-claude/opentelemetry#count-tokens).
188188 
189With [Full content](https://platform.claude.com/docs/en/manage-claude/opentelemetry#choose-a-content-mode), the `anthropic.messages.create` server span has the prompt and the response. The system prompt is in `gen_ai.system_instructions`, the request's messages in `gen_ai.input.messages`, and the response in `gen_ai.output.messages`.
189With [Full content](https://platform.claude.com/docs/en/manage-claude/opentelemetry#choose-a-content-mode), the `anthropic.messages.create` server span has the prompt and the response. The system prompt is in `gen_ai.system_instructions`, the request’s messages in `gen_ai.input.messages`, and the response in `gen_ai.output.messages`.
190190 
191191For each span and its attributes, see the [OpenTelemetry span reference](https://platform.claude.com/docs/en/api/opentelemetry/spans).
192192 
193193### A Managed Agents session
194194 
195A session has a span for each Sessions API request and a turn span for each agent turn. A turn that a request starts is a child of that request's span. A turn contains a span for each model request and each tool that the API runs, except in the [cases listed in the tool span reference](https://platform.claude.com/docs/en/api/opentelemetry/spans#anthropic-tool-use-anthropic-mcp-tool-use-and-anthropic-custom-tool-use). It also contains a span for each outcome evaluation.
195A session has a span for each Sessions API request and a turn span for each agent turn. A turn that a request starts is a child of that request’s span. A turn contains a span for each model request and each tool that the API runs, except in the [cases listed in the tool span reference](https://platform.claude.com/docs/en/api/opentelemetry/spans#anthropic-tool-use-anthropic-mcp-tool-use-and-anthropic-custom-tool-use). It also contains a span for each outcome evaluation.
196196 
197197This example follows one chat request, in which your application sends a message to a session and runs a custom tool. The trace has spans from both your application and the API, in the following order:
198198 
1991991. Your application receives a `POST /chat` request from a user.
2002. Your application starts the SDK's session tool runner, which lists and streams the session's events (shown as the `anthropic.sessions.events.stream` and `anthropic.sessions.events.list` spans).
2013. Your application sends the user's message to the session by calling `sessions.events.send`.
2002. Your application starts the SDK’s session tool runner, which lists and streams the session’s events (shown as the `anthropic.sessions.events.stream` and `anthropic.sessions.events.list` spans).
2013. Your application sends the user’s message to the session by calling `sessions.events.send`.
2022024. A turn starts and includes model requests, a `bash` tool use, and a turn on another thread (shown as the first `anthropic.session.turn` span and the spans under it).
2032035. The model asks to use the [custom tool](https://platform.claude.com/docs/en/managed-agents/tools) `list_issues`, so the turn ends with the stop reason `requires_action`.
2042046. The session tool runner runs `list_issues` (shown as the `anthropic.custom_tool_use list_issues` span) and sends its result by calling `sessions.events.send`.
from line 206
206206 
207207![Example Managed Agents session trace: POST /chat, four session event requests, three turns, a bash tool use, and list\_issues](https://platform.claude.com/docs/images/opentelemetry-trace-shape.svg)
208208 
209The SDK in your application emits the [`anthropic.custom_tool_use`](https://platform.claude.com/docs/en/api/opentelemetry/spans#anthropic-tool-use-anthropic-mcp-tool-use-and-anthropic-custom-tool-use) span and each request's client span. To get these spans, [set up SDK tracing](https://platform.claude.com/docs/en/manage-claude/opentelemetry/sdk).
209The SDK in your application emits the [`anthropic.custom_tool_use`](https://platform.claude.com/docs/en/api/opentelemetry/spans#anthropic-tool-use-anthropic-mcp-tool-use-and-anthropic-custom-tool-use) span and each request’s client span. To get these spans, [set up SDK tracing](https://platform.claude.com/docs/en/manage-claude/opentelemetry/sdk).
210210 
211A session's spans can be in several traces, for example when you send a later request from a new root trace. With [multiagent](https://platform.claude.com/docs/en/managed-agents/multiagent-orchestration) on, a session can also have several threads. To find the spans you need, group them by an ID.
211A session’s spans can be in several traces, for example when you send a later request from a new root trace. With [multiagent](https://platform.claude.com/docs/en/managed-agents/multiagent-orchestration) on, a session can also have several threads. To find the spans you need, group them by an ID.
212212 
213213* **One thread:** Group spans by `gen_ai.conversation.id`, which holds the session thread ID. Sort them by start time to read the thread as a transcript.
214214* **A whole session, with all its threads:** Group spans by `anthropic.session.id`, across traces.
215215 
216With [Full content](https://platform.claude.com/docs/en/manage-claude/opentelemetry#choose-a-content-mode), you can read a session's content from its spans.
216With [Full content](https://platform.claude.com/docs/en/manage-claude/opentelemetry#choose-a-content-mode), you can read a session’s content from its spans.
217217 
218* To read a turn's content, use its [turn span](https://platform.claude.com/docs/en/api/opentelemetry/spans#anthropic-session-turn). The system prompt is in `gen_ai.system_instructions` on a thread's first turn span, the input in `gen_ai.input.messages` (your messages and tool results, `system.message` events, and messages from other threads), and the output in `gen_ai.output.messages` (the agent's messages, tool uses, and tool results).
218* To read a turn’s content, use its [turn span](https://platform.claude.com/docs/en/api/opentelemetry/spans#anthropic-session-turn). The system prompt is in `gen_ai.system_instructions` on a thread’s first turn span, the input in `gen_ai.input.messages` (your messages and tool results, `system.message` events, and messages from other threads), and the output in `gen_ai.output.messages` (the agent’s messages, tool uses, and tool results).
219219* To see the arguments and result of a tool use, read its [tool span](https://platform.claude.com/docs/en/api/opentelemetry/spans#anthropic-tool-use-anthropic-mcp-tool-use-and-anthropic-custom-tool-use). The arguments are in `gen_ai.tool.call.arguments`, and the result is in `anthropic.tool_result.content`.
220220 
221221For each span and its attributes, see the [OpenTelemetry span reference](https://platform.claude.com/docs/en/api/opentelemetry/spans).
from line 226
226226 
227227For each source, sum only the following spans, because some usage attributes repeat on more than one level of the API spans:
228228 
229* **SDK spans:** Sum the [`anthropic.messages.create`](https://platform.claude.com/docs/en/api/opentelemetry/spans#anthropic-messages-create) spans. If a request has [compactions](https://platform.claude.com/docs/en/build-with-claude/compaction), also add the span's `anthropic.usage.compaction.input_tokens` and `anthropic.usage.compaction.output_tokens`, because the `gen_ai.usage.*` attributes don't include compaction tokens. If a [fallback model](https://platform.claude.com/docs/en/build-with-claude/refusals-and-fallback) served a request, its span has the usage of only the model that served the response.
230* **API spans for a Messages API request:** Sum either the [`anthropic.messages.create`](https://platform.claude.com/docs/en/api/opentelemetry/spans#anthropic-messages-create) spans or their [`anthropic.model_request`](https://platform.claude.com/docs/en/api/opentelemetry/spans#anthropic-model-request) spans, not both. If a request has compactions, also add its [`anthropic.compaction`](https://platform.claude.com/docs/en/api/opentelemetry/spans#anthropic-compaction) spans. Don't add the `anthropic.usage.compaction.*` attributes of the `anthropic.messages.create` span as well, because they hold the same tokens.
229* **SDK spans:** Sum the [`anthropic.messages.create`](https://platform.claude.com/docs/en/api/opentelemetry/spans#anthropic-messages-create) spans. If a request has [compactions](https://platform.claude.com/docs/en/build-with-claude/compaction), also add the span’s `anthropic.usage.compaction.input_tokens` and `anthropic.usage.compaction.output_tokens`, because the `gen_ai.usage.*` attributes don’t include compaction tokens. If a [fallback model](https://platform.claude.com/docs/en/build-with-claude/refusals-and-fallback) served a request, its span has the usage of only the model that served the response.
230* **API spans for a Messages API request:** Sum either the [`anthropic.messages.create`](https://platform.claude.com/docs/en/api/opentelemetry/spans#anthropic-messages-create) spans or their [`anthropic.model_request`](https://platform.claude.com/docs/en/api/opentelemetry/spans#anthropic-model-request) spans, not both. If a request has compactions, also add its [`anthropic.compaction`](https://platform.claude.com/docs/en/api/opentelemetry/spans#anthropic-compaction) spans. Don’t add the `anthropic.usage.compaction.*` attributes of the `anthropic.messages.create` span as well, because they hold the same tokens.
231231* **API spans for a Managed Agents session:** Sum the `anthropic.model_request` and [`anthropic.session.outcome_evaluation`](https://platform.claude.com/docs/en/api/opentelemetry/spans#anthropic-session-outcome-evaluation) spans.
232232 
233Spans can arrive more than once, for example when a delivery is retried. If your observability platform doesn't remove duplicates, count each span once by its trace ID and span ID.
233Spans can arrive more than once, for example when a delivery is retried. If your observability platform doesn’t remove duplicates, count each span once by its trace ID and span ID.
234234 
235`gen_ai.usage.input_tokens` already includes the tokens read from and written to the prompt cache, so don't add the cache attributes to it. For all usage attributes, see [Token usage](https://platform.claude.com/docs/en/api/opentelemetry/spans#token-usage).
235`gen_ai.usage.input_tokens` already includes the tokens read from and written to the prompt cache, so don’t add the cache attributes to it. For all usage attributes, see [Token usage](https://platform.claude.com/docs/en/api/opentelemetry/spans#token-usage).
236236 
237237<Note>
238 Exported spans aren't guaranteed to be a complete record of your API usage. Their delivery is [best effort](https://platform.claude.com/docs/en/manage-claude/opentelemetry/api#delivery-and-health), so a span can be lost. A caller can also leave out a request's spans by turning off the sampled flag in the request's [`traceparent` header](https://platform.claude.com/docs/en/manage-claude/opentelemetry/api#connect-api-spans-to-your-own-traces). To track each API key's usage, for example to spot a leaked key, use the [Usage API](https://platform.claude.com/docs/en/manage-claude/usage-cost-api#usage-api), which also counts the usage of requests without spans.
238 Exported spans aren’t guaranteed to be a complete record of your API usage. Their delivery is [best effort](https://platform.claude.com/docs/en/manage-claude/opentelemetry/api#delivery-and-health), so a span can be lost. A caller can also leave out a request’s spans by turning off the sampled flag in the request’s [`traceparent` header](https://platform.claude.com/docs/en/manage-claude/opentelemetry/api#connect-api-spans-to-your-own-traces). To track each API key’s usage, for example to spot a leaked key, use the [Usage API](https://platform.claude.com/docs/en/manage-claude/usage-cost-api#usage-api), which also counts the usage of requests without spans.
239239</Note>
240240 

manage-claude/opentelemetry/api Changed · +33 / -33 lines

from line 22
2222 
2323With OpenTelemetry, the Claude API can emit a span for each model request and each tool use that it runs. You can view these spans in your observability platform without changing your code.
2424 
25The API emits spans for your Messages API requests and Managed Agents sessions. To receive them, add a *destination* in the Claude Console. A destination tells the API your observability platform's OTLP endpoint and how to authenticate with it.
25The API emits spans for your Messages API requests and Managed Agents sessions. To receive them, add a *destination* in the Claude Console. A destination tells the API your observability platform’s OTLP endpoint and how to authenticate with it.
2626 
2727## What you need
2828 
from line 33
3333## 1. Add a destination
3434 
3535<Info>
36 When you add a telemetry destination, Anthropic will send traces of Claude Platform activity in your organization to the third-party provider's OTLP/HTTP endpoint that you specify, in accordance with your provider terms and access controls. After delivery, the data is held by the service that you chose, outside Anthropic, under that service's retention and access controls.
36 When you add a telemetry destination, Anthropic will send traces of Claude Platform activity in your organization to the third-party provider’s OTLP/HTTP endpoint that you specify, in accordance with your provider terms and access controls. After delivery, the data is held by the service that you chose, outside Anthropic, under that service’s retention and access controls.
3737</Info>
3838 
391. In the Console, open your organization's [OpenTelemetry settings page](https://platform.claude.com/settings/telemetry-destinations) and click **Add destination**.
391. In the Console, open your organization’s [OpenTelemetry settings page](https://platform.claude.com/settings/telemetry-destinations) and click **Add destination**.
4040 
41412. Configure the destination:
4242 
4343 | Field | What to enter |
4444 | ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
45 | **Provider** | Your observability platform, or **Custom** if it isn't listed. If you select a listed platform, the Console asks for its details, such as an API key, instead of the **OTLP endpoint URL**, **Request headers**, and **OTLP traces endpoint URL**. |
46 | **Name** | Optional. For example, "Acme's observability platform." |
47 | **OTLP endpoint URL** | The base HTTPS URL of your observability platform's OTLP/HTTP endpoint, with a hostname, not an IP address. It can have a path prefix, for example `https://gateway.example.com/otlp`. Don't add `/v1/traces`, because the API adds it. If you set an **OTLP traces endpoint URL**, the API uses that URL instead. |
48 | **Request headers** | The headers that the API sends with each request, for example your observability platform's API key header. Put credentials only in header values. After you save, the Console doesn't show the values again. |
45 | **Provider** | Your observability platform, or **Custom** if it isn’t listed. If you select a listed platform, the Console asks for its details, such as an API key, instead of the **OTLP endpoint URL**, **Request headers**, and **OTLP traces endpoint URL**. |
46 | **Name** | Optional. For example, “Acme’s observability platform.” |
47 | **OTLP endpoint URL** | The base HTTPS URL of your observability platform’s OTLP/HTTP endpoint, with a hostname, not an IP address. It can have a path prefix, for example `https://gateway.example.com/otlp`. Don’t add `/v1/traces`, because the API adds it. If you set an **OTLP traces endpoint URL**, the API uses that URL instead. |
48 | **Request headers** | The headers that the API sends with each request, for example your observability platform’s API key header. Put credentials only in header values. After you save, the Console doesn’t show the values again. |
4949 | **Content mode** | **Metadata only** or **Full content**. See [how the content modes differ](https://platform.claude.com/docs/en/manage-claude/opentelemetry#choose-a-content-mode). |
5050 | **Workspaces** | The workspaces whose spans the destination receives: **All**, **Selected**, or **All except**. See [Choose workspaces for a destination](https://platform.claude.com/docs/en/manage-claude/opentelemetry/api#choose-workspaces-for-a-destination). |
51 | **OTLP traces endpoint URL** | Optional, under **Advanced settings**. The full URL of your observability platform's traces endpoint, for example `https://gateway.example.com/custom/traces`. Set it when the platform receives traces at a URL other than the OTLP endpoint URL plus `/v1/traces`. It must have the same host as the OTLP endpoint URL. |
51 | **OTLP traces endpoint URL** | Optional, under **Advanced settings**. The full URL of your observability platform’s traces endpoint, for example `https://gateway.example.com/custom/traces`. Set it when the platform receives traces at a URL other than the OTLP endpoint URL plus `/v1/traces`. It must have the same host as the OTLP endpoint URL. |
5252 | **Maximum content size in MB** | Optional, under **Advanced settings** when the content mode is **Full content**. The most content that the API sends in each span. The Console fills it in based on the **Provider** you select. Change it to fit what your observability platform accepts. Leave it empty to send as much as the API allows. See [Content limits](https://platform.claude.com/docs/en/manage-claude/opentelemetry#content-limits). |
5353 
54543. Click **Add destination** to save.
5555 
564. Click **Test** in the destination's **More actions** menu. You will see a message that the test span was delivered to your collector, or how the delivery failed (see [Delivery errors](https://platform.claude.com/docs/en/manage-claude/opentelemetry/api#delivery-errors)).
564. Click **Test** in the destination’s **More actions** menu. You will see a message that the test span was delivered to your collector, or how the delivery failed (see [Delivery errors](https://platform.claude.com/docs/en/manage-claude/opentelemetry/api#delivery-errors)).
5757 
58585. Check that the `anthropic.test` span arrived in your observability platform.
5959 
from line 211
211211 ```
212212</CodeGroup>
213213 
214A create request takes the Console's settings except **Provider**, so enter your observability platform's endpoint URL and headers yourself. Set `traces.max_content_bytes` (csharp, go: `Traces.MaxContentBytes`; java, php: `traces.maxContentBytes`), in bytes, to fit what your observability platform accepts (see [Content limits](https://platform.claude.com/docs/en/manage-claude/opentelemetry#content-limits)). To list, change, or delete destinations, or to add or remove one workspace, use the other methods of the [telemetry destinations API](https://platform.claude.com/docs/en/api/beta/organization/telemetry_destinations).
214A create request takes the Console’s settings except **Provider**, so enter your observability platform’s endpoint URL and headers yourself. Set `traces.max_content_bytes` (csharp, go: `Traces.MaxContentBytes`; java, php: `traces.maxContentBytes`), in bytes, to fit what your observability platform accepts (see [Content limits](https://platform.claude.com/docs/en/manage-claude/opentelemetry#content-limits)). To list, change, or delete destinations, or to add or remove one workspace, use the other methods of the [telemetry destinations API](https://platform.claude.com/docs/en/api/beta/organization/telemetry_destinations).
215215 
216216## 2. Choose workspaces for a destination
217217 
from line 221
221221* **Selected:** Only the workspaces that you select.
222222* **All except:** Like **All**, but without the workspaces that you select.
223223 
224For **Selected** or **All except**, select the workspaces in the search box that appears under the options. To change a destination's workspaces later, open its **More actions** menu on the [OpenTelemetry settings page](https://platform.claude.com/settings/telemetry-destinations) in the Console while the **Workspace** filter shows **All**. Click **Edit**, then select another **Workspaces** option or change the workspaces in the search box.
224For **Selected** or **All except**, select the workspaces in the search box that appears under the options. To change a destination’s workspaces later, open its **More actions** menu on the [OpenTelemetry settings page](https://platform.claude.com/settings/telemetry-destinations) in the Console while the **Workspace** filter shows **All**. Click **Edit**, then select another **Workspaces** option or change the workspaces in the search box.
225225 
226If you have the developer role in the organization and the Workspace Admin role in a workspace, you can add that workspace to a **Selected** destination or remove it. Set the **Workspace** filter to that workspace, then open the destination's **More actions** menu. On Claude Platform on AWS, the Console has no Workspace Admin role. There, your [IAM policy](https://platform.claude.com/docs/en/api/claude-platform-on-aws-iam-actions) determines who can add a workspace to a destination or remove it.
226If you have the developer role in the organization and the Workspace Admin role in a workspace, you can add that workspace to a **Selected** destination or remove it. Set the **Workspace** filter to that workspace, then open the destination’s **More actions** menu. On Claude Platform on AWS, the Console has no Workspace Admin role. There, your [IAM policy](https://platform.claude.com/docs/en/api/claude-platform-on-aws-iam-actions) determines who can add a workspace to a destination or remove it.
227227 
228228The API sends spans to every enabled destination that covers the [workspace where the request or session runs](https://platform.claude.com/docs/en/manage-claude/workspaces#api-keys-and-resource-scoping).
229229 
from line 231
231231 
2322321. In the Console, select a workspace that the destination covers and send a Messages API request in [playground](https://platform.claude.com/playground). You can also send a Messages API request from your application or start a Managed Agents session in that workspace. To start a session, you can follow the steps in [Get started with Claude Managed Agents](https://platform.claude.com/docs/en/managed-agents/quickstart).
2332332. In the Console, on the [OpenTelemetry settings page](https://platform.claude.com/settings/telemetry-destinations), check that the **Delivery** column shows **Healthy** for the destination. This can take about a minute.
2343. In your observability platform, filter on `service.name` = `claude-platform` to find the request's spans.
2343. In your observability platform, filter on `service.name` = `claude-platform` to find the request’s spans.
235235 
236236If the column shows **Failing**, hover over it to see the last error. To find the likely cause, see [Delivery errors](https://platform.claude.com/docs/en/manage-claude/opentelemetry/api#delivery-errors).
237237 
238238## 4. Connect API spans to your own traces
239239 
240By default, the API spans for a Messages API request or a Managed Agents session are in their own traces. Connect them to your application's traces, so that they nest under your own spans.
240By default, the API spans for a Messages API request or a Managed Agents session are in their own traces. Connect them to your application’s traces, so that they nest under your own spans.
241241 
242The API reads each request's trace context from the W3C [`traceparent` header](https://www.w3.org/TR/trace-context/). If the sampled flag in the header is off, the API doesn't emit the request's span or the spans under it.
242The API reads each request’s trace context from the W3C [`traceparent` header](https://www.w3.org/TR/trace-context/). If the sampled flag in the header is off, the API doesn’t emit the request’s span or the spans under it.
243243 
244244<Tabs>
245245 <Tab title="With the Claude SDK">
from line 363
363363 ```
364364 </CodeGroup>
365365 
366 The SDK writes the `traceparent` header with your application's propagator, and the sampled flag in it follows your sampler. If your application uses a propagator other than W3C trace context, such as B3, also add the W3C trace context propagator.
366 The SDK writes the `traceparent` header with your application’s propagator, and the sampled flag in it follows your sampler. If your application uses a propagator other than W3C trace context, such as B3, also add the W3C trace context propagator.
367367 </Tab>
368368 
369369 <Tab title="With other clients">
370 Copy the current span's trace context into the request headers, for example when you create a Managed Agents session or send a user message:
370 Copy the current span’s trace context into the request headers, for example when you create a Managed Agents session or send a user message:
371371 
372372 <CodeGroup exclude="shell:CLI">
373373 ```bash cURL
from line 620
620620 </Tab>
621621</Tabs>
622622 
623When you connect your MCP server with the [Messages API's MCP connector](https://platform.claude.com/docs/en/agents-and-tools/mcp-connector) or the [Managed Agents MCP connector](https://platform.claude.com/docs/en/managed-agents/mcp-connector), the API also passes the trace on to your server. The server can then put its own spans under the API spans. In `params._meta` of a `tools/call` request, the API sends a W3C `traceparent` that references the [`anthropic.mcp_tool_use`](https://platform.claude.com/docs/en/api/opentelemetry/spans#anthropic-tool-use-anthropic-mcp-tool-use-and-anthropic-custom-tool-use) span for that tool use. With the Messages API's MCP connector, the other requests and notifications to your MCP server have a `traceparent` too, which references the [`anthropic.messages.create`](https://platform.claude.com/docs/en/api/opentelemetry/spans#anthropic-messages-create) span. If the API doesn't trace your Messages API request, such as when its `traceparent` header has the sampled flag off, your MCP server gets no `traceparent`.
623When you connect your MCP server with the [Messages API’s MCP connector](https://platform.claude.com/docs/en/agents-and-tools/mcp-connector) or the [Managed Agents MCP connector](https://platform.claude.com/docs/en/managed-agents/mcp-connector), the API also passes the trace on to your server. The server can then put its own spans under the API spans. In `params._meta` of a `tools/call` request, the API sends a W3C `traceparent` that references the [`anthropic.mcp_tool_use`](https://platform.claude.com/docs/en/api/opentelemetry/spans#anthropic-tool-use-anthropic-mcp-tool-use-and-anthropic-custom-tool-use) span for that tool use. With the Messages API’s MCP connector, the other requests and notifications to your MCP server have a `traceparent` too, which references the [`anthropic.messages.create`](https://platform.claude.com/docs/en/api/opentelemetry/spans#anthropic-messages-create) span. If the API doesn’t trace your Messages API request, such as when its `traceparent` header has the sampled flag off, your MCP server gets no `traceparent`.
624624 
625625## Next steps
626626 
from line 639
639639The following rules apply to the spans that the API sends to your destinations.
640640 
641641* **At least once:** A destination can receive the same span more than once. To remove duplicates, use the trace ID and span ID.
642* **Best effort:** A span can be lost before delivery. The API can't send a lost span again.
643* **Compression:** The API compresses requests with gzip and sets the header `Content-Encoding: gzip`. If your endpoint answers a compressed request with a `400`, `406`, `415`, or `422` response, the API sends the same spans again right away without compression. It then usually sends that destination's later requests without compression for about a day.
644* **Retries:** The API retries a delivery later, a limited number of times, after a timeout, a connection, TLS, or DNS failure, an invalid address, or a `408`, `429`, or `5xx` response. It doesn't retry other failures.
642* **Best effort:** A span can be lost before delivery. The API can’t send a lost span again.
643* **Compression:** The API compresses requests with gzip and sets the header `Content-Encoding: gzip`. If your endpoint answers a compressed request with a `400`, `406`, `415`, or `422` response, the API sends the same spans again right away without compression. It then usually sends that destination’s later requests without compression for about a day.
644* **Retries:** The API retries a delivery later, a limited number of times, after a timeout, a connection, TLS, or DNS failure, an invalid address, or a `408`, `429`, or `5xx` response. It doesn’t retry other failures.
645645* **Timeouts:** For each request, your endpoint must complete the TLS handshake within 5 seconds and send the response headers within 5 seconds. Each delivery times out after 10 seconds in total, including any resend.
646646* **User agent:** Each request has the header `User-Agent: Claude-Platform`.
647647 
648The **Delivery** column shows each destination's state. The state can be up to a minute late.
648The **Delivery** column shows each destination’s state. The state can be up to a minute late.
649649 
650650| Delivery state | Meaning |
651651| -------------- | --------------------------------------------------------------------------- |
652652| **Healthy** | The last delivery succeeded. |
653653| **Failing** | The last delivery failed. To see the error, hover over **Failing**. |
654| **No data** | The API hasn't tried a delivery yet. |
655| **Disabled** | The destination doesn't receive spans. To see why, hover over **Disabled**. |
654| **No data** | The API hasn’t tried a delivery yet. |
655| **Disabled** | The destination doesn’t receive spans. To see why, hover over **Disabled**. |
656656 
657657The API disables a destination when:
658658 
from line 659
659659* The endpoint sends a `3xx` redirect.
660660* All deliveries fail for 24 hours.
661661 
662While a destination is disabled, the API drops the spans for it, and they aren't sent after you enable it again. To resume export, fix the cause and check the fix with **Test** in the destination's **More actions** menu. Then, on the [OpenTelemetry settings page](https://platform.claude.com/settings/telemetry-destinations) in the Console, click **Enable** in the same menu while the **Workspace** filter shows **All**. Export starts again within about a minute. Until the next delivery, the **Delivery** column can still show **Failing** with the old error.
662While a destination is disabled, the API drops the spans for it, and they aren’t sent after you enable it again. To resume export, fix the cause and check the fix with **Test** in the destination’s **More actions** menu. Then, on the [OpenTelemetry settings page](https://platform.claude.com/settings/telemetry-destinations) in the Console, click **Enable** in the same menu while the **Workspace** filter shows **All**. Export starts again within about a minute. Until the next delivery, the **Delivery** column can still show **Failing** with the old error.
663663 
664664To change a destination, open its **More actions** menu while the **Workspace** filter shows **All**. Then click **Edit**, **Disable**, **Enable**, or **Delete**. If you change the host of the **OTLP endpoint URL**, enter the header values again. If the destination has an **OTLP traces endpoint URL**, give it the same new host, or clear it.
665665 
from line 692
692692| -------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
693693| HTTP error (status 401) or HTTP error (status 403) | A wrong authentication header |
694694| HTTP error (status 404) | A wrong path in the **OTLP endpoint URL** or the **OTLP traces endpoint URL** |
695| Invalid address | The endpoint's hostname doesn't exist or doesn't resolve to a public IP address |
696| Temporary DNS failure | The DNS lookup of the endpoint's hostname failed, for example because its DNS server returned an error |
697| TLS failure | A TLS problem, for example with the endpoint's certificate |
698| Timeout | The endpoint didn't respond in time. See [the delivery timeouts](https://platform.claude.com/docs/en/manage-claude/opentelemetry/api#delivery-and-health) |
699| Connection failure | The API couldn't connect to the endpoint |
700| Redirect (status 3xx) | The endpoint redirected the request. The API doesn't follow redirects, so use the URL it redirects to |
695| Invalid address | The endpoint’s hostname doesn’t exist or doesn’t resolve to a public IP address |
696| Temporary DNS failure | The DNS lookup of the endpoint’s hostname failed, for example because its DNS server returned an error |
697| TLS failure | A TLS problem, for example with the endpoint’s certificate |
698| Timeout | The endpoint didn’t respond in time. See [the delivery timeouts](https://platform.claude.com/docs/en/manage-claude/opentelemetry/api#delivery-and-health) |
699| Connection failure | The API couldn’t connect to the endpoint |
700| Redirect (status 3xx) | The endpoint redirected the request. The API doesn’t follow redirects, so use the URL it redirects to |
701701| HTTP error (status 408, 429, or 5xx) | The endpoint was overloaded, limited the rate of requests, or had an error |
702702| HTTP error (another 4xx status) | The endpoint refused the request, for example because of its size or format |
703703 

manage-claude/opentelemetry/sdk Changed · +24 / -24 lines

from line 20
2020 
2121With OpenTelemetry, the Claude SDK can emit a span for each request that it sends and each tool use that the [tool runner](https://platform.claude.com/docs/en/agents-and-tools/tool-use/tool-runner) runs. You can view these spans in your observability platform, nested in your own traces.
2222 
23The SDK emits spans in your application. Your application's OpenTelemetry exporter sends them to your observability platform.
23The SDK emits spans in your application. Your application’s OpenTelemetry exporter sends them to your observability platform.
2424 
2525<Note>
2626 During the beta, the SDK options and the span schema can change in ways that break your code, your queries, or your dashboards. For example, a new version of the SDK can rename a span, an attribute, an option, or an environment variable. Pin the SDK version in your dependencies to choose when you adopt the changes.
from line 36
3636 pip install --upgrade anthropic
3737 ```
3838 
39 If your application doesn't use the OpenTelemetry SDK yet, install it with a console exporter, which you use in the next step to print spans:
39 If your application doesn’t use the OpenTelemetry SDK yet, install it with a console exporter, which you use in the next step to print spans:
4040 
4141 ```bash
4242 pip install opentelemetry-sdk
from line 48
4848 npm install @anthropic-ai/sdk@latest
4949 ```
5050 
51 If your application doesn't use the OpenTelemetry SDK yet, install it with a console exporter, which you use in the next step to print spans:
51 If your application doesn’t use the OpenTelemetry SDK yet, install it with a console exporter, which you use in the next step to print spans:
5252 
5353 ```bash
5454 npm install @opentelemetry/sdk-trace-node
from line 60
6060 dotnet add package Anthropic
6161 ```
6262 
63 If your application doesn't use the OpenTelemetry SDK yet, install it with a console exporter, which you use in the next step to print spans:
63 If your application doesn’t use the OpenTelemetry SDK yet, install it with a console exporter, which you use in the next step to print spans:
6464 
6565 ```bash
6666 dotnet add package OpenTelemetry.Exporter.Console
from line 72
7272 go get github.com/anthropics/anthropic-sdk-go/v2@latest
7373 ```
7474 
75 If your application doesn't use the OpenTelemetry SDK yet, install it with a console exporter, which you use in the next step to print spans:
75 If your application doesn’t use the OpenTelemetry SDK yet, install it with a console exporter, which you use in the next step to print spans:
7676 
7777 ```bash
7878 go get go.opentelemetry.io/otel/sdk go.opentelemetry.io/otel/exporters/stdout/stdouttrace
from line 96
9696 ```
9797 </CodeGroup>
9898 
99 If your application doesn't use the OpenTelemetry SDK yet, install it with a console exporter, which you use in the next step to print spans. Add `io.opentelemetry:opentelemetry-sdk` and `io.opentelemetry:opentelemetry-exporter-logging` to your build, both at the latest version on [Maven Central](https://central.sonatype.com/artifact/io.opentelemetry/opentelemetry-sdk).
99 If your application doesn’t use the OpenTelemetry SDK yet, install it with a console exporter, which you use in the next step to print spans. Add `io.opentelemetry:opentelemetry-sdk` and `io.opentelemetry:opentelemetry-exporter-logging` to your build, both at the latest version on [Maven Central](https://central.sonatype.com/artifact/io.opentelemetry/opentelemetry-sdk).
100100 </Tab>
101101 
102102 <Tab title="PHP">
from line 104
104104 composer require "anthropic-ai/sdk" "guzzlehttp/guzzle:^7"
105105 ```
106106 
107 If your application doesn't use the OpenTelemetry SDK yet, install it with a console exporter, which you use in the next step to print spans:
107 If your application doesn’t use the OpenTelemetry SDK yet, install it with a console exporter, which you use in the next step to print spans:
108108 
109109 ```bash
110110 composer require open-telemetry/sdk
from line 112
112112 </Tab>
113113 
114114 <Tab title="Ruby">
115 If your `Gemfile` doesn't list `anthropic` yet, add the gem:
115 If your `Gemfile` doesn’t list `anthropic` yet, add the gem:
116116 
117117 ```bash
118118 bundle add anthropic
from line 124
124124 bundle update anthropic
125125 ```
126126 
127 If your application doesn't use the OpenTelemetry SDK yet, install it with a console exporter, which you use in the next step to print spans:
127 If your application doesn’t use the OpenTelemetry SDK yet, install it with a console exporter, which you use in the next step to print spans:
128128 
129129 ```bash
130130 bundle add opentelemetry-sdk
from line 354
354354Use the following options to decide what goes into your spans and where they are sent. You can set an option in your code or, if it has one, with the environment variable under its name.
355355 
356356<Note>
357 If you pass `open_telemetry` (typescript, java, php: `openTelemetry`; csharp: `OpenTelemetry`; go: `option.With…()`) to the client, it overrides that option's environment variables as a whole, including nested keys. Any nested key that you leave out uses its default from the table, even if its environment variable is set.
357 If you pass `open_telemetry` (typescript, java, php: `openTelemetry`; csharp: `OpenTelemetry`; go: `option.With…()`) to the client, it overrides that option’s environment variables as a whole, including nested keys. Any nested key that you leave out uses its default from the table, even if its environment variable is set.
358358</Note>
359359 
360360| Option | Use it to | Default |
from line 361
361361| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
362362| `traces.content_mode` (typescript, java, php: `traces.contentMode`; csharp: `Traces.ContentMode`; go: `option.WithOpenTelemetryTracesContentMode()`)<br />`ANTHROPIC_OPEN_TELEMETRY_TRACES_CONTENT_MODE=content` | Include prompts and responses in spans. See [Content modes](https://platform.claude.com/docs/en/manage-claude/opentelemetry#choose-a-content-mode). | `metadata_only` |
363363| `traces.max_content_bytes` (typescript, java, php: `traces.maxContentBytes`; csharp: `Traces.MaxContentBytes`; go: `option.WithOpenTelemetryTracesMaxContentBytes()`)<br />`ANTHROPIC_OPEN_TELEMETRY_TRACES_MAX_CONTENT_BYTES` | Change the content limit of each span. See [Content limits](https://platform.claude.com/docs/en/manage-claude/opentelemetry#content-limits). | 0.75 MB |
364| `conversation_id` (typescript, java, php: `conversationId`; csharp: `ConversationId`; go: `option.WithOpenTelemetryConversationID()`) | Link several calls into one conversation. The SDK writes the ID to `gen_ai.conversation.id`. The ID is exported in both content modes, so don't put personal data or secrets in it. | None |
365| `tracer_provider` (typescript, java, php: `tracerProvider`; csharp: `AddSource("com.anthropic.sdk.csharp*")`; go: `option.WithTracerProvider()`) | Choose the tracer provider that gets the SDK's spans. | The tracer provider you set up in [Register a tracer provider](https://platform.claude.com/docs/en/manage-claude/opentelemetry/sdk#register-a-tracer-provider) |
364| `conversation_id` (typescript, java, php: `conversationId`; csharp: `ConversationId`; go: `option.WithOpenTelemetryConversationID()`) | Link several calls into one conversation. The SDK writes the ID to `gen_ai.conversation.id`. The ID is exported in both content modes, so don’t put personal data or secrets in it. | None |
365| `tracer_provider` (typescript, java, php: `tracerProvider`; csharp: `AddSource("com.anthropic.sdk.csharp*")`; go: `option.WithTracerProvider()`) | Choose the tracer provider that gets the SDK’s spans. | The tracer provider you set up in [Register a tracer provider](https://platform.claude.com/docs/en/manage-claude/opentelemetry/sdk#register-a-tracer-provider) |
366366| `propagation` (go: `option.WithOpenTelemetryPropagation()`)<br />`ANTHROPIC_OPEN_TELEMETRY_PROPAGATION=false` | Stop sending trace context and baggage headers with requests, for example when your HTTP client instrumentation already sends them. The SDK still emits spans. Available in the Python, TypeScript, Go, Java, Ruby, and PHP SDKs. | On |
367367| `open_telemetry` (typescript, java, php: `openTelemetry`; csharp: `OpenTelemetry`; go: `option.WithoutOpenTelemetry()`)<br />`ANTHROPIC_OPEN_TELEMETRY=false` | Turn spans off for one client, for example when another library already traces the SDK. | On |
368368 
from line 555
555555 
556556## Tracing a stream
557557 
558A stream's `anthropic.messages.create` span ends when your code has read the whole stream or closed it, so close a stream that you stop reading early. In content mode, the span has the model response only when you read the stream with `messages.stream()` (go: `Messages.NewStreaming()`; java: `messages().createStreaming()`; csharp: `Messages.CreateStreaming()`; php: `messages->createStream()`).
558A stream’s `anthropic.messages.create` span ends when your code has read the whole stream or closed it, so close a stream that you stop reading early. In content mode, the span has the model response only when you read the stream with `messages.stream()` (go: `Messages.NewStreaming()`; java: `messages().createStreaming()`; csharp: `Messages.CreateStreaming()`; php: `messages->createStream()`).
559559 
560560Spans that you start while you read a stream are siblings of the SDK span, not its children. To group them with the request, start your own span around both the call and the read loop.
561561 
from line 568
5685681. In the process that runs the worker, [set up SDK tracing](https://platform.claude.com/docs/en/manage-claude/opentelemetry/sdk#install-the-sdk) as in steps 1 to 4.
5695692. Allow network traffic from the sandbox to your observability platform or OpenTelemetry Collector.
570570 
571When the worker sends a tool result, that request's API span is nested under its SDK span.
571When the worker sends a tool result, that request’s API span is nested under its SDK span.
572572 
573573## Trace context and baggage
574574 
575With each request, the SDK uses your application's propagator to send the trace context to the API in headers such as `traceparent`. If that propagator also writes baggage, the SDK sends your baggage too. To send the trace context without baggage, register only the W3C trace context propagator.
575With each request, the SDK uses your application’s propagator to send the trace context to the API in headers such as `traceparent`. If that propagator also writes baggage, the SDK sends your baggage too. To send the trace context without baggage, register only the W3C trace context propagator.
576576 
577To stop the SDK from sending these headers, for example when your HTTP client instrumentation already sends them, turn off the SDK's propagation:
577To stop the SDK from sending these headers, for example when your HTTP client instrumentation already sends them, turn off the SDK’s propagation:
578578 
579579<CodeGroup exclude="shell">
580580 ```python Python
from line 645
645645 ```
646646</CodeGroup>
647647 
648While the SDK calls an [MCP tool](https://platform.claude.com/docs/en/agents-and-tools/mcp-connector#client-side-mcp-helpers), the SDK's tool span is the current span. Some MCP client libraries send the trace context to the MCP server in `_meta`, so a server that reads it can add its spans to your trace under that tool span. The Python `mcp` package from version 2.0 and the C# `ModelContextProtocol` package do this. The TypeScript, Go, Java, Ruby, and PHP MCP SDKs don't do it on their own.
648While the SDK calls an [MCP tool](https://platform.claude.com/docs/en/agents-and-tools/mcp-connector#client-side-mcp-helpers), the SDK’s tool span is the current span. Some MCP client libraries send the trace context to the MCP server in `_meta`, so a server that reads it can add its spans to your trace under that tool span. The Python `mcp` package from version 2.0 and the C# `ModelContextProtocol` package do this. The TypeScript, Go, Java, Ruby, and PHP MCP SDKs don’t do it on their own.
649649 
650650## Troubleshooting
651651 
652652| Problem | What to check |
653653| ------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
654| No spans from the SDK | Register the tracer provider before the first call. Make sure that you installed the SDK as in [Install the SDK](https://platform.claude.com/docs/en/manage-claude/opentelemetry/sdk#install-the-sdk) and that `ANTHROPIC_OPEN_TELEMETRY` isn't `false`. |
655| The Java SDK doesn't send spans to the registered tracer provider, or doesn't send trace context to the API | Another dependency sets `opentelemetry-api` below 1.57.0. Upgrade `opentelemetry-api` to 1.57.0 or later. |
656| The SDK spans don't nest under your spans, or the spans that your tool creates don't nest under the tool span | Call the SDK from inside one of your own spans, as the example in [Connect API spans to your own traces](https://platform.claude.com/docs/en/manage-claude/opentelemetry/api#connect-api-spans-to-your-own-traces) does. In Go, start the spans that your tool creates from the `ctx` that the tool runner passes to it. |
657| Requests from the SDK don't have a `traceparent` header | Register the W3C trace context propagator with OpenTelemetry. The SDK writes the headers with your application's propagator. |
658| A stream's SDK span doesn't end or doesn't have the response | See [Tracing a stream](https://platform.claude.com/docs/en/manage-claude/opentelemetry/sdk#trace-a-stream). |
659| Each request appears twice | A request's SDK span and API span have the same name. Use the span kind or `service.name` to tell them apart. If another library also traces the SDK, turn off one of the two. |
654| No spans from the SDK | Register the tracer provider before the first call. Make sure that you installed the SDK as in [Install the SDK](https://platform.claude.com/docs/en/manage-claude/opentelemetry/sdk#install-the-sdk) and that `ANTHROPIC_OPEN_TELEMETRY` isn’t `false`. |
655| The Java SDK doesn’t send spans to the registered tracer provider, or doesn’t send trace context to the API | Another dependency sets `opentelemetry-api` below 1.57.0. Upgrade `opentelemetry-api` to 1.57.0 or later. |
656| The SDK spans don’t nest under your spans, or the spans that your tool creates don’t nest under the tool span | Call the SDK from inside one of your own spans, as the example in [Connect API spans to your own traces](https://platform.claude.com/docs/en/manage-claude/opentelemetry/api#connect-api-spans-to-your-own-traces) does. In Go, start the spans that your tool creates from the `ctx` that the tool runner passes to it. |
657| Requests from the SDK don’t have a `traceparent` header | Register the W3C trace context propagator with OpenTelemetry. The SDK writes the headers with your application’s propagator. |
658| A stream’s SDK span doesn’t end or doesn’t have the response | See [Tracing a stream](https://platform.claude.com/docs/en/manage-claude/opentelemetry/sdk#trace-a-stream). |
659| Each request appears twice | A request’s SDK span and API span have the same name. Use the span kind or `service.name` to tell them apart. If another library also traces the SDK, turn off one of the two. |
660660 

manage-claude/organization-webhooks Changed · +24 / -24 lines

from line 9
99 Claude API: beta
1010---
1111 
12An organization webhook endpoint receives an event when Anthropic restricts or bans one of your organization's [user profiles](https://platform.claude.com/docs/en/manage-claude/user-profiles), and when the restriction or ban ends. You manage it with the Admin API under `/v1/organizations/webhooks`.
12An organization webhook endpoint receives an event when Anthropic restricts or bans one of your organization’s [user profiles](https://platform.claude.com/docs/en/manage-claude/user-profiles), and when the restriction or ban ends. You manage it with the Admin API under `/v1/organizations/webhooks`.
1313 
1414<Note>
15 Event delivery isn't live: Anthropic doesn't send the two events, so an endpoint you register receives nothing. You can register endpoints and build your handler from the event format on this page.
15 Event delivery isn’t live: Anthropic doesn’t send the two events, so an endpoint you register receives nothing. You can register endpoints and build your handler from the event format on this page.
1616</Note>
1717 
1818Any member of your organization can list and view organization webhook endpoints with the API, but only members with the admin, owner, or primary owner role can create, change, or delete them, or replace their signing secret.
from line 21
2121 
2222You need the following:
2323 
24* An organization on the Claude API that has organization webhooks turned on and doesn't have [HIPAA readiness](https://platform.claude.com/docs/en/manage-claude/api-and-data-retention#hipaa-readiness) enabled. To request access, contact your Anthropic account team.
24* An organization on the Claude API that has organization webhooks turned on and doesn’t have [HIPAA readiness](https://platform.claude.com/docs/en/manage-claude/api-and-data-retention#hipaa-readiness) enabled. To request access, contact your Anthropic account team.
2525 
2626* One of these credentials:
2727 
2828 * An [Admin API key](https://platform.claude.com/docs/en/manage-claude/admin-api-keys).
2929 * An [OAuth bearer token](https://platform.claude.com/docs/en/manage-claude/admin-api#oauth-bearer-token) with the `org:admin` scope.
30 * A [personal or service account key](https://platform.claude.com/docs/en/manage-claude/authentication#key-types) that isn't scoped to a workspace.
30 * A [personal or service account key](https://platform.claude.com/docs/en/manage-claude/authentication#key-types) that isn’t scoped to a workspace.
3131 
3232## Event types
3333 
from line 44
4444 
4545In any request whose `anthropic-beta` header has `user-profiles-2026-09-04` or an earlier value, responses leave out the `enforcement_status` and `enforcement_actions` fields and the `enforcement_status[]` list filter returns a `400`. To get the fields, remove that value from your requests.
4646 
47If an enforcement action opened before Anthropic turned on event delivery for your organization, or before you registered your endpoint, you don't get a `user_profile.enforcement_action_opened` event for it. The action still appears on the profile. To find these actions, [list your profiles](https://platform.claude.com/docs/en/api/user_profiles/list) with `enforcement_status[]=restricted` and `enforcement_status[]=banned`. A response might return fewer profiles than `limit`, or none, before the list ends, so keep requesting pages until `next_page` is `null`.
47If an enforcement action opened before Anthropic turned on event delivery for your organization, or before you registered your endpoint, you don’t get a `user_profile.enforcement_action_opened` event for it. The action still appears on the profile. To find these actions, [list your profiles](https://platform.claude.com/docs/en/api/user_profiles/list) with `enforcement_status[]=restricted` and `enforcement_status[]=banned`. A response might return fewer profiles than `limit`, or none, before the list ends, so keep requesting pages until `next_page` is `null`.
4848 
4949### What an event contains
5050 
51Events carry IDs, not the action or the profile. `data.id` is the profile's ID, and `data.enforcement_action_id` is the action's ID, which starts with `enac_`:
51Events carry IDs, not the action or the profile. `data.id` is the profile’s ID, and `data.enforcement_action_id` is the action’s ID, which starts with `enac_`:
5252 
5353```json
5454{
from line 66
6666 
6767To see what changed, [retrieve the profile](https://platform.claude.com/docs/en/api/user_profiles/retrieve) with `GET /v1/user_profiles/{id}` (python, ruby: `client.user_profiles.retrieve()`; typescript: `client.userProfiles.retrieve()`; go: `client.UserProfiles.Get()`; java: `client.userProfiles().retrieve()`; csharp: `client.UserProfiles.Retrieve()`; php: `$client->userProfiles->retrieve()`; cli: `ant user-profiles retrieve`), using `data.id`. Its `enforcement_actions` list shows its open actions. Each action has a `type` (`restriction` or `ban`), an `id`, a `reason`, an `opened_at` time, and an `expires_at` time or `null`. `enforcement_status` summarizes them: `banned` while a ban is open, `restricted` while any other action is open, and `unrestricted` when none is. Treat any other value as `restricted`.
6868 
69Anthropic sends an event only after the profile shows the change, so the profile you retrieve shows that change or a later one. Events might arrive late or out of order, so use the profile's current state, not the order events arrive in. After `user_profile.enforcement_action_resolved`, the resolved action is no longer in the list. A `404` means the profile was deleted.
69Anthropic sends an event only after the profile shows the change, so the profile you retrieve shows that change or a later one. Events might arrive late or out of order, so use the profile’s current state, not the order events arrive in. After `user_profile.enforcement_action_resolved`, the resolved action is no longer in the list. A `404` means the profile was deleted.
7070 
7171## Endpoint fields
7272 
from line 74
7474 
7575| Field | Type | Description |
7676| ----------------- | ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
77| `id` | string | The endpoint's ID, which starts with `wep_`. Set by Anthropic. |
78| `url` | string | Where Anthropic sends events. Must be HTTPS on port 443, with a public domain name, not an IP address. Two enabled organization webhook endpoints in your organization can't share a URL. |
77| `id` | string | The endpoint’s ID, which starts with `wep_`. Set by Anthropic. |
78| `url` | string | Where Anthropic sends events. Must be HTTPS on port 443, with a public domain name, not an IP address. Two enabled organization webhook endpoints in your organization can’t share a URL. |
7979| `enabled_events` | array of strings | The [event types](https://platform.claude.com/docs/en/manage-claude/organization-webhooks#event-types) this endpoint receives. A create request must list at least one. |
8080| `name` | string | An optional label for your own use. |
8181| `description` | string | An optional description for your own use. |
from line 106
106106 
107107## Deliveries
108108 
109Deliveries follow the [Standard Webhooks](https://www.standardwebhooks.com/) specification. Each one carries the `webhook-id`, `webhook-timestamp`, and `webhook-signature` headers. Before you trust an event, verify its signature with the endpoint's signing secret, using any Standard Webhooks library.
109Deliveries follow the [Standard Webhooks](https://www.standardwebhooks.com/) specification. Each one carries the `webhook-id`, `webhook-timestamp`, and `webhook-signature` headers. Before you trust an event, verify its signature with the endpoint’s signing secret, using any Standard Webhooks library.
110110 
111111Return any `2xx` status within 5 seconds, and do slow work afterward. Any other response, or no response, counts as a failed attempt.
112112 
from line 120
120120 * Its URL resolves to a non-public IP address.
121121 * Its deliveries keep failing.
122122 
123 Anthropic skips events for a disabled endpoint and doesn't send them later.
123 Anthropic skips events for a disabled endpoint and doesn’t send them later.
124124 
125125## Manage endpoints
126126 
from line 128
128128 
129129| Task | Request |
130130| ------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
131| List your organization's endpoints | [`GET /v1/organizations/webhooks`](https://platform.claude.com/docs/en/api/beta/organization/webhooks/list) |
131| List your organization’s endpoints | [`GET /v1/organizations/webhooks`](https://platform.claude.com/docs/en/api/beta/organization/webhooks/list) |
132132| Create an endpoint | [`POST /v1/organizations/webhooks`](https://platform.claude.com/docs/en/api/beta/organization/webhooks/create) |
133133| Get one endpoint | [`GET /v1/organizations/webhooks/{webhook_endpoint_id}`](https://platform.claude.com/docs/en/api/beta/organization/webhooks/retrieve) |
134| Update an endpoint's `url`, `name`, `description`, `enabled_events`, or `state` | [`POST /v1/organizations/webhooks/{webhook_endpoint_id}`](https://platform.claude.com/docs/en/api/beta/organization/webhooks/update) |
134| Update an endpoint’s `url`, `name`, `description`, `enabled_events`, or `state` | [`POST /v1/organizations/webhooks/{webhook_endpoint_id}`](https://platform.claude.com/docs/en/api/beta/organization/webhooks/update) |
135135| Delete an endpoint | [`DELETE /v1/organizations/webhooks/{webhook_endpoint_id}`](https://platform.claude.com/docs/en/api/beta/organization/webhooks/delete) |
136136| Replace the signing secret | [`POST /v1/organizations/webhooks/{webhook_endpoint_id}/regenerate_signing_secret`](https://platform.claude.com/docs/en/api/beta/organization/webhooks/regenerate_signing_secret) |
137137 
138In an update, `enabled_events` replaces the endpoint's whole list of event types. An empty list doesn't clear the list: the endpoint keeps the event types it had. To stop deliveries, send `"state": "disabled"` or delete the endpoint.
138In an update, `enabled_events` replaces the endpoint’s whole list of event types. An empty list doesn’t clear the list: the endpoint keeps the event types it had. To stop deliveries, send `"state": "disabled"` or delete the endpoint.
139139 
140140To turn an endpoint back on, including after Anthropic disabled it, send `"state": "enabled"` in an update request.
141141 
142142When you replace the signing secret, the old secret stops working at once. Deliveries from then on, including retries of earlier events, are signed with the new secret, so update your receiver right away.
143143 
144Send the `anthropic-beta: webhooks-2026-10-07` header with every request. The SDK and the CLI send it for you. This example lists your organization's endpoints, using an Admin API key from `ANTHROPIC_API_KEY`.
144Send the `anthropic-beta: webhooks-2026-10-07` header with every request. The SDK and the CLI send it for you. This example lists your organization’s endpoints, using an Admin API key from `ANTHROPIC_API_KEY`.
145145 
146146<CodeGroup>
147147 ```bash cURL
from line 239
239239}
240240```
241241 
242A list returns up to 20 endpoints by default. Set `limit` to get up to 100. If `has_more` is `true`, pass the response's `last_id` as `after_id` to get the next page.
242A list returns up to 20 endpoints by default. Set `limit` to get up to 100. If `has_more` is `true`, pass the response’s `last_id` as `after_id` to get the next page.
243243 
244244This example creates an endpoint that receives both event types:
245245 
from line 391
391391 
392392A request returns a `400` if:
393393 
394* Its `url` doesn't meet the rules in [Endpoint fields](https://platform.claude.com/docs/en/manage-claude/organization-webhooks#endpoint-fields), or a create request lists no event types. The error message says what's wrong.
394* Its `url` doesn’t meet the rules in [Endpoint fields](https://platform.claude.com/docs/en/manage-claude/organization-webhooks#endpoint-fields), or a create request lists no event types. The error message says what’s wrong.
395395* Your organization has no default workspace.
396* Organization webhooks aren't available for your organization because its default workspace uses a [customer-managed encryption key](https://platform.claude.com/docs/en/manage-claude/cmek). The error message says so.
396* Organization webhooks aren’t available for your organization because its default workspace uses a [customer-managed encryption key](https://platform.claude.com/docs/en/manage-claude/cmek). The error message says so.
397397* It would give your organization more than 32 organization webhook endpoints.
398398* It puts an event type other than the two in [Event types](https://platform.claude.com/docs/en/manage-claude/organization-webhooks#event-types) in `enabled_events`. The error message lists the accepted types.
399399 
400A request returns a `403` if your account's role doesn't include the permission the request needs. The error names that permission.
400A request returns a `403` if your account’s role doesn’t include the permission the request needs. The error names that permission.
401401 
402402A request returns a `404` if:
403403 
404* It doesn't send the `anthropic-beta: webhooks-2026-10-07` header.
405* Anthropic hasn't turned on organization webhooks for your organization.
404* It doesn’t send the `anthropic-beta: webhooks-2026-10-07` header.
405* Anthropic hasn’t turned on organization webhooks for your organization.
406406* Your organization has HIPAA readiness enabled.
407* It uses a kind of credential these requests don't accept.
408* Its `webhook_endpoint_id` doesn't match an endpoint in your organization.
407* It uses a kind of credential these requests don’t accept.
408* Its `webhook_endpoint_id` doesn’t match an endpoint in your organization.
409409 
410410A request returns a `409` if:
411411 
412412* It would make two enabled organization webhook endpoints share a URL.
413* Another request changed your organization's endpoints at the same time. Retry the request.
413* Another request changed your organization’s endpoints at the same time. Retry the request.
414414 

manage-claude/plugins-api Changed · +122 / -122 lines

### Access to members’ plugin files ### List a plugin’s versions ### Download a version’s files ### List a plugin’s installation settings ### List a plugin’s shares ### Set a marketplace’s default installation setting ### Access to members' plugin files ### List a plugin's versions ### Download a version's files ### List a plugin's installation settings ### List a plugin's shares ### Set a marketplace's default installation setting

from line 34
3434| Resource | Endpoints |
3535| ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
3636| **Plugins:** list every plugin in the organization, upload a new one, look one up, choose the version members are served (roll back or promote), delete one | `GET /v1/organizations/plugins`<br />`POST /v1/organizations/plugins`<br />`GET /v1/organizations/plugins/{plugin_id}`<br />`POST /v1/organizations/plugins/{plugin_id}`<br />`DELETE /v1/organizations/plugins/{plugin_id}` |
37| **Plugin versions:** list a plugin's version history, upload a new version, look one up, download a version's files | `GET /v1/organizations/plugins/{plugin_id}/versions`<br />`POST /v1/organizations/plugins/{plugin_id}/versions`<br />`GET /v1/organizations/plugins/{plugin_id}/versions/{version}`<br />`GET /v1/organizations/plugins/{plugin_id}/versions/{version}/content` |
37| **Plugin versions:** list a plugin’s version history, upload a new version, look one up, download a version’s files | `GET /v1/organizations/plugins/{plugin_id}/versions`<br />`POST /v1/organizations/plugins/{plugin_id}/versions`<br />`GET /v1/organizations/plugins/{plugin_id}/versions/{version}`<br />`GET /v1/organizations/plugins/{plugin_id}/versions/{version}/content` |
3838| **Installation settings:** read who can use an organization-owned plugin, set it for the whole organization or for one group, remove either setting | `GET /v1/organizations/plugins/{plugin_id}/installation_settings`<br />`POST /v1/organizations/plugins/{plugin_id}/installation_settings/{target}`<br />`DELETE /v1/organizations/plugins/{plugin_id}/installation_settings/{target}` |
3939| **Shares:** read who a member has shared their own plugin with (read-only) | `GET /v1/organizations/plugins/{plugin_id}/shares` |
40| **Plugin marketplaces:** find a marketplace's ID, look one up, set the default installation setting for its plugins, check marketplace content before connecting it | `GET /v1/organizations/plugin_marketplaces`<br />`GET /v1/organizations/plugin_marketplaces/{marketplace_id}`<br />`POST /v1/organizations/plugin_marketplaces/{marketplace_id}`<br />`POST /v1/organizations/plugin_marketplaces/validate_repository`<br />`POST /v1/organizations/plugin_marketplaces/validate_archive` |
40| **Plugin marketplaces:** find a marketplace’s ID, look one up, set the default installation setting for its plugins, check marketplace content before connecting it | `GET /v1/organizations/plugin_marketplaces`<br />`GET /v1/organizations/plugin_marketplaces/{marketplace_id}`<br />`POST /v1/organizations/plugin_marketplaces/{marketplace_id}`<br />`POST /v1/organizations/plugin_marketplaces/validate_repository`<br />`POST /v1/organizations/plugin_marketplaces/validate_archive` |
4141 
4242This release does not include standalone skills (skills a member writes in the skills editor or uploads as a single skill in claude.ai). They do not appear in the inventory and cannot be created here. Plugins that Anthropic publishes are not inventoried either; their usage is reported by the [Analytics APIs](https://platform.claude.com/docs/en/manage-claude/analytics-api). Marketplaces are created, connected to repositories, and deleted in claude.ai, not through this API.
4343 
from line 53
5353 
5454## Quick start
5555 
56List the plugins in your organization's own marketplaces, newest first:
56List the plugins in your organization’s own marketplaces, newest first:
5757 
5858<CodeGroup>
5959 ```bash cURL
from line 211
211211| Scope | Grants |
212212| -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
213213| `read:plugins` | Every `GET` endpoint on this page, including archive downloads, plus marketplace validation. |
214| `write:plugins` | Every `POST` and `DELETE` endpoint on this page: create a plugin, create a version, change the served version, delete a plugin, set and remove installation settings, and set a marketplace's default, plus marketplace validation. It does not grant reads. |
214| `write:plugins` | Every `POST` and `DELETE` endpoint on this page: create a plugin, create a version, change the served version, delete a plugin, set and remove installation settings, and set a marketplace’s default, plus marketplace validation. It does not grant reads. |
215215| `read:org_audit` | A read-only scope for security-audit integrations: every `GET` endpoint on this page, including archive downloads, plus the [user management](https://platform.claude.com/docs/en/manage-claude/user-management) and [Compliance API](https://platform.claude.com/docs/en/manage-claude/compliance-api) read endpoints. It does not grant marketplace validation or any write. |
216| `read:compliance_org_data` | The Compliance API's scope for organization metadata (names, types, roles, and groups) and effective settings. Grants every `GET` endpoint on this page, exactly as `read:org_audit` does, so a Compliance Access Key can read plugins without a second key. It does not grant marketplace validation or any write. |
216| `read:compliance_org_data` | The Compliance API’s scope for organization metadata (names, types, roles, and groups) and effective settings. Grants every `GET` endpoint on this page, exactly as `read:org_audit` does, so a Compliance Access Key can read plugins without a second key. It does not grant marketplace validation or any write. |
217217 
218218A key can carry several scopes. An integration that uploads a plugin and then reads it back needs both `read:plugins` and `write:plugins`. Wherever this page says an endpoint requires the `read:plugins` scope, a key with `read:org_audit` or `read:compliance_org_data` works too.
219219 
220### Access to members' plugin files
220### Access to members’ plugin files
221221 
222Each of these read scopes (`read:plugins`, `read:org_audit`, and `read:compliance_org_data`) can download the files of plugins in members' personal marketplaces, including files that claude.ai's admin settings do not show, and a `read:org_audit` or `read:compliance_org_data` key bound to your parent organization can do this in any organization under it that has access to this API, by passing `organization_id` (see [Reading another organization under the same parent](https://platform.claude.com/docs/en/manage-claude/plugins-api#reading-another-organization-under-the-same-parent)). Each such download records a `claude_plugin_archive_accessed` event on the [Compliance API Activity Feed](https://platform.claude.com/docs/en/manage-claude/compliance-activity-feed), identifying the key, the plugin, the version, and the member (see [Activity Feed events](https://platform.claude.com/docs/en/manage-claude/plugins-api#activity-feed-events)). Downloads of organization-owned plugins are not recorded.
222Each of these read scopes (`read:plugins`, `read:org_audit`, and `read:compliance_org_data`) can download the files of plugins in members’ personal marketplaces, including files that claude.ai’s admin settings do not show, and a `read:org_audit` or `read:compliance_org_data` key bound to your parent organization can do this in any organization under it that has access to this API, by passing `organization_id` (see [Reading another organization under the same parent](https://platform.claude.com/docs/en/manage-claude/plugins-api#reading-another-organization-under-the-same-parent)). Each such download records a `claude_plugin_archive_accessed` event on the [Compliance API Activity Feed](https://platform.claude.com/docs/en/manage-claude/compliance-activity-feed), identifying the key, the plugin, the version, and the member (see [Activity Feed events](https://platform.claude.com/docs/en/manage-claude/plugins-api#activity-feed-events)). Downloads of organization-owned plugins are not recorded.
223223 
224224### Reading another organization under the same parent
225225 
226`read:plugins` and `write:plugins` keys read and write only the organization they were created in. If your company has several Claude organizations linked under one parent organization, the parent's primary owner can create a `read:org_audit` or `read:compliance_org_data` key for all linked organizations (see [Create a key for a Claude Enterprise organization](https://platform.claude.com/docs/en/manage-claude/admin-api-keys#create-a-key-for-a-claude-enterprise-organization)). That key can also read any linked organization that has access to this API. To read one, pass its ID in the `organization_id` query parameter on any `GET` endpoint on this page. The ID is the organization UUID shown in claude.ai's settings (its `org_`-prefixed form is accepted too). Without the parameter, the key reads the organization it was created in. A `404` means the named organization is not under the key's parent or the API is not available to it; a value that is not a UUID or `org_` ID returns `400`. Any other key that names an organization other than its own gets `404`. Writes do not accept `organization_id`.
226`read:plugins` and `write:plugins` keys read and write only the organization they were created in. If your company has several Claude organizations linked under one parent organization, the parent’s primary owner can create a `read:org_audit` or `read:compliance_org_data` key for all linked organizations (see [Create a key for a Claude Enterprise organization](https://platform.claude.com/docs/en/manage-claude/admin-api-keys#create-a-key-for-a-claude-enterprise-organization)). That key can also read any linked organization that has access to this API. To read one, pass its ID in the `organization_id` query parameter on any `GET` endpoint on this page. The ID is the organization UUID shown in claude.ai’s settings (its `org_`-prefixed form is accepted too). Without the parameter, the key reads the organization it was created in. A `404` means the named organization is not under the key’s parent or the API is not available to it; a value that is not a UUID or `org_` ID returns `400`. Any other key that names an organization other than its own gets `404`. Writes do not accept `organization_id`.
227227 
228228## Key concepts
229229 
230230### Plugins and components
231231 
232A **plugin** is a package that extends Claude for your organization's members. It contains any combination of these components:
232A **plugin** is a package that extends Claude for your organization’s members. It contains any combination of these components:
233233 
234234| Component | What it is |
235235| ---------- | ------------------------------------------------------------------------------------------------------- |
236236| Skill | Instructions and files that Claude loads when a task calls for it. |
237| Command | A saved prompt a member runs by typing `/` followed by the command's name. |
237| Command | A saved prompt a member runs by typing `/` followed by the command’s name. |
238238| Agent | A helper assistant with its own instructions, to which Claude can hand part of a task. |
239239| Hook | A command that runs automatically when an event occurs in a session, such as before Claude uses a tool. |
240240| MCP server | A connection from Claude to tools and data in another system (Model Context Protocol). |
241241| CLI | A command-line program that the plugin lets Claude run. |
242242 
243Every plugin has a manifest at `.claude-plugin/plugin.json`. The manifest's `name` becomes the plugin's `name`: a lowercase identifier that is unique within its marketplace.
243Every plugin has a manifest at `.claude-plugin/plugin.json`. The manifest’s `name` becomes the plugin’s `name`: a lowercase identifier that is unique within its marketplace.
244244 
245245### Marketplaces
246246 
from line 249
249249* **Owner.** The organization owns its marketplaces. Each member can also have personal marketplaces.
250250* **Source.** `manual` means plugins are uploaded, in claude.ai or, for an organization marketplace, through this API. `github`, `gitlab`, and `public_git` mean plugins are synchronized from a Git repository the owner connected. Nothing can be uploaded to a synchronized marketplace, and this API cannot delete its plugins, because the next synchronization would undo either change. Change the repository instead.
251251 
252Your organization's **library marketplace** is the organization-owned `manual` marketplace that uploads go to when you do not name a marketplace. It is created the first time something is uploaded to it.
252Your organization’s **library marketplace** is the organization-owned `manual` marketplace that uploads go to when you do not name a marketplace. It is created the first time something is uploaded to it.
253253 
254254### Organization-owned and member-owned plugins
255255 
256A plugin's `owner.type` says whose marketplace it lives in:
256A plugin’s `owner.type` says whose marketplace it lives in:
257257 
258258* `organization`: you can manage it through this API, except that a plugin in a marketplace synchronized from Git cannot receive uploads or be deleted here.
259* `user`: it lives in one member's personal marketplace. You can read its details and download its files, and delete it if its marketplace is `manual`. Uploading versions and choosing the served version return `403`. Sharing is managed only by the member, in claude.ai.
259* `user`: it lives in one member’s personal marketplace. You can read its details and download its files, and delete it if its marketplace is `manual`. Uploading versions and choosing the served version return `403`. Sharing is managed only by the member, in claude.ai.
260260 
261Removing a member from the organization does not remove their plugins. They stay in the inventory under the member's `user_id`, and the `owner_user_id` filter still finds them, so you can review and remove a departed member's content. They are removed from the inventory when the member's account is deleted.
261Removing a member from the organization does not remove their plugins. They stay in the inventory under the member’s `user_id`, and the `owner_user_id` filter still finds them, so you can review and remove a departed member’s content. They are removed from the inventory when the member’s account is deleted.
262262 
263263### Versions and the served version
264264 
from line 267
267267* `latest_version_id`: the newest version
268268* `served_version_id`: the version members are served
269269 
270By default `served_version_pinned` is `false`: the served version normally follows the newest one. When content scanning is on, a version saved in claude.ai might **wait** for its content scan: it is stored but not served at once. This page uses "wait" only for a version saved in claude.ai, not for one that a member or an administrator publishes into a plugin. While scanning is on, a waiting version is served only when its `content_scan` reads `completed` with `pass` or `warn`. While a version waits, `served_version_id` names an earlier version than `latest_version_id`. Do not poll until the two IDs match: they might stay different, for example when the scan fails.
270By default `served_version_pinned` is `false`: the served version normally follows the newest one. When content scanning is on, a version saved in claude.ai might **wait** for its content scan: it is stored but not served at once. This page uses “wait” only for a version saved in claude.ai, not for one that a member or an administrator publishes into a plugin. While scanning is on, a waiting version is served only when its `content_scan` reads `completed` with `pass` or `warn`. While a version waits, `served_version_id` names an earlier version than `latest_version_id`. Do not poll until the two IDs match: they might stay different, for example when the scan fails.
271271 
272Choosing a version with `POST /v1/organizations/plugins/{plugin_id}` **pins** the plugin (`served_version_pinned: true`). So does an administrator choosing a version in claude.ai, or accepting a member's request to publish into the plugin. From then on, new uploads are stored and advance `latest_version_id`, but members keep the pinned version until you point `served_version_id` at another one. A plugin whose two pointers differ has a stored version that is not being served.
272Choosing a version with `POST /v1/organizations/plugins/{plugin_id}` **pins** the plugin (`served_version_pinned: true`). So does an administrator choosing a version in claude.ai, or accepting a member’s request to publish into the plugin. From then on, new uploads are stored and advance `latest_version_id`, but members keep the pinned version until you point `served_version_id` at another one. A plugin whose two pointers differ has a stored version that is not being served.
273273 
274This lets a release pipeline upload each build, test it, and then promote it. To have your pipeline determine when each build is served, pin the plugin once by setting `served_version_id` to its current version; from then on, promote each build you want served. With content scanning on, that first pin returns `409 scan_pending` while the current version's `content_scan` reads `processing`, and `400 scan_failed` if the scan reads `fail`, `unknown`, or `errored` (`warn` is accepted). A pinned plugin cannot be unpinned, here or in claude.ai.
274This lets a release pipeline upload each build, test it, and then promote it. To have your pipeline determine when each build is served, pin the plugin once by setting `served_version_id` to its current version; from then on, promote each build you want served. With content scanning on, that first pin returns `409 scan_pending` while the current version’s `content_scan` reads `processing`, and `400 scan_failed` if the scan reads `fail`, `unknown`, or `errored` (`warn` is accepted). A pinned plugin cannot be unpinned, here or in claude.ai.
275275 
276276To roll back, set `served_version_id` to an earlier version. Roll forward the same way.
277277 
278These rules describe organization-owned plugins. A member-owned plugin's served version is controlled by its owner in claude.ai.
278These rules describe organization-owned plugins. A member-owned plugin’s served version is controlled by its owner in claude.ai.
279279 
280280### Installation settings
281281 
from line 290
290290 
291291A plugin can hold an organization-wide setting and one setting for each group (the role-based access control [groups managed in User management](https://platform.claude.com/docs/en/manage-claude/user-management#groups)). A member gets a value by these rules:
292292 
2931. The organization-wide value is the plugin's own organization-wide setting if it has one, otherwise its marketplace's default, otherwise `not_available`. The plugin reports this value in `organization_installation_preference`, with `organization_installation_preference_inherited: true` while it comes from the marketplace default.
2931. The organization-wide value is the plugin’s own organization-wide setting if it has one, otherwise its marketplace’s default, otherwise `not_available`. The plugin reports this value in `organization_installation_preference`, with `organization_installation_preference_inherited: true` while it comes from the marketplace default.
2942942. A member who belongs to no group holding a setting for the plugin gets the organization-wide value.
2953. A member who belongs to one or more groups holding a setting gets the most permissive of those groups' settings instead, ranked `required`, `auto_install`, `available`, `not_available`.
2953. A member who belongs to one or more groups holding a setting gets the most permissive of those groups’ settings instead, ranked `required`, `auto_install`, `available`, `not_available`.
296296 
297A group's setting replaces the organization-wide value for its members; it does not add to it. For example, if the organization-wide value is `required` and the Pilot group holds `available`, Pilot members get `available`. When you move a plugin from a pilot group to the whole organization, set the organization-wide value and then remove the group's setting. Setting the organization-wide value stops the plugin from inheriting its marketplace default; [removing the organization-wide setting](https://platform.claude.com/docs/en/manage-claude/plugins-api#remove-an-installation-setting) returns the plugin to that default.
297A group’s setting replaces the organization-wide value for its members; it does not add to it. For example, if the organization-wide value is `required` and the Pilot group holds `available`, Pilot members get `available`. When you move a plugin from a pilot group to the whole organization, set the organization-wide value and then remove the group’s setting. Setting the organization-wide value stops the plugin from inheriting its marketplace default; [removing the organization-wide setting](https://platform.claude.com/docs/en/manage-claude/plugins-api#remove-an-installation-setting) returns the plugin to that default.
298298 
299A plugin created through this API starts with no settings of its own, so it inherits its marketplace's default: `not_available` unless someone has set a default. Deleting a group removes its settings from every plugin.
299A plugin created through this API starts with no settings of its own, so it inherits its marketplace’s default: `not_available` unless someone has set a default. Deleting a group removes its settings from every plugin.
300300 
301301### Shares
302302 
from line 308
308308 
309309Content scanning is an organization setting in claude.ai. When it is on, newly stored versions are scanned (claude.ai exempts a few) and the result is reported in `content_scan`; a version that was not scanned, for example one stored before scanning was turned on, has `content_scan: null`. Scanning is not offered to organizations that use customer-managed encryption keys or zero data retention.
310310 
311While scanning is on, members are served a plugin only when its served version's scan is `completed` with `pass` or `warn`. While the scan is `processing` or `errored`, or reads `fail` or `unknown`, the plugin is withheld from members, and an earlier version is not served in its place. A version that was never scanned (`content_scan: null`) is served normally.
311While scanning is on, members are served a plugin only when its served version’s scan is `completed` with `pass` or `warn`. While the scan is `processing` or `errored`, or reads `fail` or `unknown`, the plugin is withheld from members, and an earlier version is not served in its place. A version that was never scanned (`content_scan: null`) is served normally.
312312 
313313A version you upload through this API never waits for its content scan. When it becomes the served version, members lose the plugin until its `content_scan` reads `completed` with `pass` or `warn`. If members should keep the current version while a new one is scanned, pin the plugin first (see [Versions and the served version](https://platform.claude.com/docs/en/manage-claude/plugins-api#versions-and-the-served-version)).
314314 
315While a version saved in claude.ai waits for its scan, the served version does not change. When your API upload becomes the served version, any wait ends: the waiting version is served only if someone chooses it. To see a waiting version's scan, read the version (see [List a plugin's versions](https://platform.claude.com/docs/en/manage-claude/plugins-api#list-a-plugins-versions)).
315While a version saved in claude.ai waits for its scan, the served version does not change. When your API upload becomes the served version, any wait ends: the waiting version is served only if someone chooses it. To see a waiting version’s scan, read the version (see [List a plugin’s versions](https://platform.claude.com/docs/en/manage-claude/plugins-api#list-a-plugins-versions)).
316316 
317After an upload, `content_scan.status` is `processing` and the verdict arrives asynchronously. Read the version to see it; the plugin object shows only its served version's scan. While scanning is on, changing the served version to a version whose `content_scan` reads `processing` returns `409 scan_pending`, and changing it to one whose scan reads `fail`, `unknown`, or `errored` returns `400 scan_failed`.
317After an upload, `content_scan.status` is `processing` and the verdict arrives asynchronously. Read the version to see it; the plugin object shows only its served version’s scan. While scanning is on, changing the served version to a version whose `content_scan` reads `processing` returns `409 scan_pending`, and changing it to one whose scan reads `fail`, `unknown`, or `errored` returns `400 scan_failed`.
318318 
319319#### Failed scans allowed in claude.ai
320320 
321In claude.ai, organization owners can allow a version whose scan failed. So can members whose [custom role](https://platform.claude.com/docs/en/manage-claude/user-management#custom-roles) can manage **Libraries**. This API can then report that scan as `completed` with `warn` and the failed scan's `reason`. While it does, the rules for `warn` apply: the version can be served to members, and you can make it the served version. Nothing in the response shows that it was allowed, so a `warn` is either a warning or a failed scan that was allowed. Allowing a version whose scan reads `warn` does not change its `content_scan`. When a version stops being allowed, this API reports the verdict of its newest completed scan. A served version whose scan then reads `fail` or `unknown` is withheld from members.
321In claude.ai, organization owners can allow a version whose scan failed. So can members whose [custom role](https://platform.claude.com/docs/en/manage-claude/user-management#custom-roles) can manage **Libraries**. This API can then report that scan as `completed` with `warn` and the failed scan’s `reason`. While it does, the rules for `warn` apply: the version can be served to members, and you can make it the served version. Nothing in the response shows that it was allowed, so a `warn` is either a warning or a failed scan that was allowed. Allowing a version whose scan reads `warn` does not change its `content_scan`. When a version stops being allowed, this API reports the verdict of its newest completed scan. A served version whose scan then reads `fail` or `unknown` is withheld from members.
322322 
323323### Reach
324324 
325`reach` summarizes, in one value, how far a version reaches on members' machines and beyond:
325`reach` summarizes, in one value, how far a version reaches on members’ machines and beyond:
326326 
327327| Value | Meaning |
328328| ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
329329| `remote` | Declares an MCP server or a CLI, whatever else it declares. |
330| `privileged` | Declares no MCP server or CLI, but declares a hook, a monitor (a background command that keeps running during a session), an LSP (Language Server Protocol) server, or settings the plugin applies to the member's app, or contains a skill, command, or any other Markdown file whose frontmatter pre-approves tools (`allowed-tools`). These run, or take effect, on the member's own computer. |
330| `privileged` | Declares no MCP server or CLI, but declares a hook, a monitor (a background command that keeps running during a session), an LSP (Language Server Protocol) server, or settings the plugin applies to the member’s app, or contains a skill, command, or any other Markdown file whose frontmatter pre-approves tools (`allowed-tools`). These run, or take effect, on the member’s own computer. |
331331| `contained` | Declares no MCP server, CLI, hook, monitor, LSP server, or app settings, and none of its Markdown files pre-approves tools (for example, a plugin that holds only skills, commands, and agents, none with `allowed-tools`). |
332332 
333333`reach` counts everything the version declares, including monitors, LSP servers, and app settings, which `components` does not list, so a version with an empty `components` list can still be `privileged`. It is `null` for a version stored before components were recorded, and for a version whose reach could not be determined because the `SKILL.md` of one of its skills, or one of its command files, could not be read; treat `null` as unclassified.
from line 356
356356Upload every tagged build from CI, and let the pipeline determine when a build is served.
357357 
3583581. Find the marketplace to upload into with `GET /v1/organizations/plugin_marketplaces?owner_type=organization`, or omit `marketplace_id` to use the library marketplace.
3592. On the first release, [create the plugin](https://platform.claude.com/docs/en/manage-claude/plugins-api#create-a-plugin) with `POST /v1/organizations/plugins`. On every later release, record the plugin's `latest_version_id`, then [upload a version](https://platform.claude.com/docs/en/manage-claude/plugins-api#create-a-version) with `POST /v1/organizations/plugins/{plugin_id}/versions`. If the upload's response is lost, read the plugin and retry only if `latest_version_id` is unchanged (see [Retrying uploads](https://platform.claude.com/docs/en/manage-claude/plugins-api#retrying-uploads)).
3592. On the first release, [create the plugin](https://platform.claude.com/docs/en/manage-claude/plugins-api#create-a-plugin) with `POST /v1/organizations/plugins`. On every later release, record the plugin’s `latest_version_id`, then [upload a version](https://platform.claude.com/docs/en/manage-claude/plugins-api#create-a-version) with `POST /v1/organizations/plugins/{plugin_id}/versions`. If the upload’s response is lost, read the plugin and retry only if `latest_version_id` is unchanged (see [Retrying uploads](https://platform.claude.com/docs/en/manage-claude/plugins-api#retrying-uploads)).
3603603. To keep members on the current version while each new build is checked, pin the plugin once by setting `served_version_id` to its current version. From then on each upload is stored without being served, and the pin cannot be undone: every build you want served needs step 5.
3613614. When content scanning is on, poll `GET /v1/organizations/plugins/{plugin_id}/versions/{version}` until `content_scan.status` is no longer `processing`, and promote only when it is `completed` with `pass` or `warn`.
3625. [Promote the build](https://platform.claude.com/docs/en/manage-claude/plugins-api#change-the-served-version) with `POST /v1/organizations/plugins/{plugin_id}` and `{"served_version_id": "<the new version's ID>"}`. To roll back, send the previous version's ID the same way.
3625. [Promote the build](https://platform.claude.com/docs/en/manage-claude/plugins-api#change-the-served-version) with `POST /v1/organizations/plugins/{plugin_id}` and `{"served_version_id": "<the new version's ID>"}`. To roll back, send the previous version’s ID the same way.
363363 
364364### Roll a plugin out to a pilot group, then to everyone
365365 
3661. Look up the pilot group's ID with `GET /v1/organizations/rbac_groups`. That call needs the `read:rbac_groups` scope, which requires a key created for all linked organizations (see [Groups in User management](https://platform.claude.com/docs/en/manage-claude/user-management#groups)). The next steps need `write:plugins`, which acts only on the organization its key was created in, so in an enterprise with several linked organizations, create this key in the organization that holds the plugin and give it both scopes, or use a second key created there for those steps.
3661. Look up the pilot group’s ID with `GET /v1/organizations/rbac_groups`. That call needs the `read:rbac_groups` scope, which requires a key created for all linked organizations (see [Groups in User management](https://platform.claude.com/docs/en/manage-claude/user-management#groups)). The next steps need `write:plugins`, which acts only on the organization its key was created in, so in an enterprise with several linked organizations, create this key in the organization that holds the plugin and give it both scopes, or use a second key created there for those steps.
367367 
3682. [Give the group its own setting](https://platform.claude.com/docs/en/manage-claude/plugins-api#set-an-installation-setting), for example `auto_install`, with `POST /v1/organizations/plugins/{plugin_id}/installation_settings/{target}`, where `{target}` is the group's `rbac_group_` ID, while the organization-wide value stays `not_available`. Only the group's members get the plugin.
3682. [Give the group its own setting](https://platform.claude.com/docs/en/manage-claude/plugins-api#set-an-installation-setting), for example `auto_install`, with `POST /v1/organizations/plugins/{plugin_id}/installation_settings/{target}`, where `{target}` is the group’s `rbac_group_` ID, while the organization-wide value stays `not_available`. Only the group’s members get the plugin.
369369 
3703. When the pilot ends, set the organization-wide value with the following call, then remove the group's setting so the group follows the organization again. Setting the organization-wide value stops the plugin from inheriting its marketplace default; [removing the organization-wide setting](https://platform.claude.com/docs/en/manage-claude/plugins-api#remove-an-installation-setting) later returns the plugin to that default.
3703. When the pilot ends, set the organization-wide value with the following call, then remove the group’s setting so the group follows the organization again. Setting the organization-wide value stops the plugin from inheriting its marketplace default; [removing the organization-wide setting](https://platform.claude.com/docs/en/manage-claude/plugins-api#remove-an-installation-setting) later returns the plugin to that default.
371371 
372372 <CodeGroup>
373373 ```bash cURL
from line 500
500500 ```
501501 </CodeGroup>
502502 
503 Then remove the group's setting with `DELETE /v1/organizations/plugins/{plugin_id}/installation_settings/{target}`, where `{target}` is the group's ID. A group's setting replaces the organization-wide value for its members rather than adding to it, so a leftover group setting of `available` would keep those members on `available`.
503 Then remove the group’s setting with `DELETE /v1/organizations/plugins/{plugin_id}/installation_settings/{target}`, where `{target}` is the group’s ID. A group’s setting replaces the organization-wide value for its members rather than adding to it, so a leftover group setting of `available` would keep those members on `available`.
504504 
505505### Keep a security inventory in sync
506506 
507Run a nightly job that flags plugins that reach outside the member's session or whose content scan reads `warn`, `fail`, or `unknown`.
507Run a nightly job that flags plugins that reach outside the member’s session or whose content scan reads `warn`, `fail`, or `unknown`.
508508 
5091. Page through [`GET /v1/organizations/plugins?limit=100`](https://platform.claude.com/docs/en/manage-claude/plugins-api#list-plugins) until `next_page` is `null` (see [Pagination](https://platform.claude.com/docs/en/manage-claude/plugins-api#pagination)). Read each plugin's `reach` and `content_scan` from that list on every run: a change to `content_scan` alone, such as a verdict that arrives later, does not move `updated_at`. `updated_at` normally tells you which plugins have new content or a new served version since the last run (worth a fresh archive download). A waiting version (see [Versions and the served version](https://platform.claude.com/docs/en/manage-claude/plugins-api#versions-and-the-served-version)) moves `updated_at` when it becomes the served version, not necessarily when it is stored. To notice one, compare `latest_version_id` with the value from your last run. The full re-list is also what catches removals, because a plugin removed by a Git synchronization or an account deletion disappears without an event.
5102. Flag each plugin whose `reach` is `remote` (it declares an MCP server or a CLI), or whose `content_scan.assessment` is `warn`, `fail`, or `unknown`. A `warn` can also be a [failed scan that was allowed in claude.ai](https://platform.claude.com/docs/en/manage-claude/plugins-api#failed-scans-allowed-in-claude-ai). Leave `warn` out only if you accept every failed scan that is allowed there. These fields describe the served version. To also check a newer version that is not served, list the plugin's versions when `latest_version_id` differs from `served_version_id` (see [List a plugin's versions](https://platform.claude.com/docs/en/manage-claude/plugins-api#list-a-plugins-versions)).
5113. For each flagged plugin, download the served version's archive for review with `GET /v1/organizations/plugins/{plugin_id}/versions/{served_version_id}/content` (see [Download a version's files](https://platform.claude.com/docs/en/manage-claude/plugins-api#download-a-versions-files)). Also download any unserved version that meets step 2's test, by its ID.
5091. Page through [`GET /v1/organizations/plugins?limit=100`](https://platform.claude.com/docs/en/manage-claude/plugins-api#list-plugins) until `next_page` is `null` (see [Pagination](https://platform.claude.com/docs/en/manage-claude/plugins-api#pagination)). Read each plugin’s `reach` and `content_scan` from that list on every run: a change to `content_scan` alone, such as a verdict that arrives later, does not move `updated_at`. `updated_at` normally tells you which plugins have new content or a new served version since the last run (worth a fresh archive download). A waiting version (see [Versions and the served version](https://platform.claude.com/docs/en/manage-claude/plugins-api#versions-and-the-served-version)) moves `updated_at` when it becomes the served version, not necessarily when it is stored. To notice one, compare `latest_version_id` with the value from your last run. The full re-list is also what catches removals, because a plugin removed by a Git synchronization or an account deletion disappears without an event.
5102. Flag each plugin whose `reach` is `remote` (it declares an MCP server or a CLI), or whose `content_scan.assessment` is `warn`, `fail`, or `unknown`. A `warn` can also be a [failed scan that was allowed in claude.ai](https://platform.claude.com/docs/en/manage-claude/plugins-api#failed-scans-allowed-in-claude-ai). Leave `warn` out only if you accept every failed scan that is allowed there. These fields describe the served version. To also check a newer version that is not served, list the plugin’s versions when `latest_version_id` differs from `served_version_id` (see [List a plugin’s versions](https://platform.claude.com/docs/en/manage-claude/plugins-api#list-a-plugins-versions)).
5113. For each flagged plugin, download the served version’s archive for review with `GET /v1/organizations/plugins/{plugin_id}/versions/{served_version_id}/content` (see [Download a version’s files](https://platform.claude.com/docs/en/manage-claude/plugins-api#download-a-versions-files)). Also download any unserved version that meets step 2’s test, by its ID.
5125124. To take a plugin away from members while you review it, see [Delete a plugin](https://platform.claude.com/docs/en/manage-claude/plugins-api#delete-a-plugin) for the reversible (organization-owned) and permanent options.
513513 
514514## Plugins
515515 
516The plugin object describes a plugin in one of your organization's marketplaces or in a member's personal marketplace (the [Quick start](https://platform.claude.com/docs/en/manage-claude/plugins-api#quick-start) response shows a complete one). Its `display_name`, `description`, `manifest_version`, `content_scan`, `components`, and `reach` describe its **served** version, so one list call shows what members are being served.
516The plugin object describes a plugin in one of your organization’s marketplaces or in a member’s personal marketplace (the [Quick start](https://platform.claude.com/docs/en/manage-claude/plugins-api#quick-start) response shows a complete one). Its `display_name`, `description`, `manifest_version`, `content_scan`, `components`, and `reach` describe its **served** version, so one list call shows what members are being served.
517517 
518518| Field | Description |
519519| ---------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
520520| `id` | Prefixed `plugin_`. |
521521| `name` | From the manifest. Unique within its marketplace, not across the organization. Fixed for an organization-owned plugin; changes if a member renames their own plugin in claude.ai. |
522| `display_name`, `description`, `manifest_version` | The served version's manifest `displayName`, `description`, and `version`; each is `null` when the manifest declares none. `manifest_version` is normalized for display: one leading `v` or `V` is dropped, so a manifest `version` of `"v1.4.0"` is returned as `"1.4.0"`. It is also `null` for a value that does not look like a version number, such as `"latest"`, and for a plugin version created before claude.ai started recording this field in August 2026. An upload is never refused because of its `version`, and `manifest_version` is not unique. |
522| `display_name`, `description`, `manifest_version` | The served version’s manifest `displayName`, `description`, and `version`; each is `null` when the manifest declares none. `manifest_version` is normalized for display: one leading `v` or `V` is dropped, so a manifest `version` of `"v1.4.0"` is returned as `"1.4.0"`. It is also `null` for a value that does not look like a version number, such as `"latest"`, and for a plugin version created before claude.ai started recording this field in August 2026. An upload is never refused because of its `version`, and `manifest_version` is not unique. |
523523| `served_version_id`, `latest_version_id` | Prefixed `pluginver_`: the version members are served, and the newest version. See [Versions and the served version](https://platform.claude.com/docs/en/manage-claude/plugins-api#versions-and-the-served-version). |
524524| `served_version_pinned` | `false` until the plugin is pinned (see [Versions and the served version](https://platform.claude.com/docs/en/manage-claude/plugins-api#versions-and-the-served-version)); `true` from then on. |
525| `owner` | `{"type": "organization"}`, or `{"type": "user", "user_id": "user_..."}` for a member's personal marketplace. |
525| `owner` | `{"type": "organization"}`, or `{"type": "user", "user_id": "user_..."}` for a member’s personal marketplace. |
526526| `marketplace_id` | Prefixed `marketplace_`. |
527527| `created_by` | Who created the plugin: `{"type": "user_actor", "user_id": "user_...", "email_address": "..."}` for a person in claude.ai (`email_address` might be `null`), or `{"type": "api_actor", "api_key_id": "apikey_..."}` for an API key. Other actor types may appear. `null` when no creator is recorded, such as for plugins synchronized from Git. |
528| `organization_installation_preference`, `organization_installation_preference_inherited` | Organization-owned: the organization-wide value, and whether it comes from the marketplace's default (see [Installation settings](https://platform.claude.com/docs/en/manage-claude/plugins-api#installation-settings)). Member-owned: both `null`. |
529| `content_scan` | The served version's scan result, an object with `status`, `assessment`, and `reason` (described after this table). `null` when it was never scanned. |
530| `components` | The served version's components, each `{"type", "name", "description"}` with `type` one of `skill`, `mcp_server`, `command`, `agent`, `hook`, or `cli`, listed in that type order and then by name. For an MCP server, `name` is its key in the manifest; for a hook, the event it runs on; for a CLI, the executable's name. `description` is always `null` for MCP servers, hooks, and CLIs. `null` when not recorded. |
528| `organization_installation_preference`, `organization_installation_preference_inherited` | Organization-owned: the organization-wide value, and whether it comes from the marketplace’s default (see [Installation settings](https://platform.claude.com/docs/en/manage-claude/plugins-api#installation-settings)). Member-owned: both `null`. |
529| `content_scan` | The served version’s scan result, an object with `status`, `assessment`, and `reason` (described after this table). `null` when it was never scanned. |
530| `components` | The served version’s components, each `{"type", "name", "description"}` with `type` one of `skill`, `mcp_server`, `command`, `agent`, `hook`, or `cli`, listed in that type order and then by name. For an MCP server, `name` is its key in the manifest; for a hook, the event it runs on; for a CLI, the executable’s name. `description` is always `null` for MCP servers, hooks, and CLIs. `null` when not recorded. |
531531| `reach` | `contained`, `privileged`, or `remote`. See [Reach](https://platform.claude.com/docs/en/manage-claude/plugins-api#reach). |
532532| `updated_at` | Changes when the served version changes, when the plugin becomes pinned, and normally when a new version is stored. A waiting version (see [Versions and the served version](https://platform.claude.com/docs/en/manage-claude/plugins-api#versions-and-the-served-version)) changes it when it becomes the served version, not necessarily when it is stored. It does not change for installation settings, shares, or a change to `content_scan` alone. |
533533 
from line 545
545545 | `covert-usage-telemetry` | Tells Claude to send information about the member or their usage to an outside address without telling them. |
546546 | `undisclosed-data-destination` | Sends files, emails, documents, or other content to a fixed outside destination the member is not shown and does not control. |
547547 | `remote-code-instruction-loader` | Tells Claude to download and run, or follow instructions from, outside content that can change after the plugin is installed. |
548 | `credential-exposure` | Contains live credentials, or collects credentials or tokens from the member's environment. |
549 | `guardrail-tampering` | Weakens the member's safeguards, for example by pre-approving every permission prompt. |
550 | `system-prompt-spoofing` | Imitates or attempts to replace Claude's system instructions. |
548 | `credential-exposure` | Contains live credentials, or collects credentials or tokens from the member’s environment. |
549 | `guardrail-tampering` | Weakens the member’s safeguards, for example by pre-approving every permission prompt. |
550 | `system-prompt-spoofing` | Imitates or attempts to replace Claude’s system instructions. |
551551 | `covert-record-tampering` | Quietly changes, hides, or deletes information the member would otherwise see. |
552 | `covert-behavior-override` | Changes Claude's behavior beyond the plugin's purpose and hides the change from the member. |
552 | `covert-behavior-override` | Changes Claude’s behavior beyond the plugin’s purpose and hides the change from the member. |
553553 | `hidden-code-execution` | Runs bundled code while telling Claude not to reveal what it does. |
554 | `undisclosed-promotion-injection` | Inserts undisclosed promotional content into Claude's output. |
554 | `undisclosed-promotion-injection` | Inserts undisclosed promotional content into Claude’s output. |
555555 | `hidden-identity-gate` | Changes or stops its behavior depending on which account runs it, without saying why. |
556 | `destructive-persistence` | Can delete or corrupt the member's files, or install programs that remain after the plugin. |
556 | `destructive-persistence` | Can delete or corrupt the member’s files, or install programs that remain after the plugin. |
557557 | `unanalyzable-binary` | Includes a compiled or unreadable program, so the scan could not verify what it does. |
558558 | `other` | Any other concern, including one newer than this list. |
559559</Accordion>
from line 562
562562 
563563### List plugins
564564 
565`GET /v1/organizations/plugins` lists every plugin in your organization, in the organization's marketplaces and in members' personal marketplaces, ordered by `created_at` descending. Filter by `owner_type` (`organization` or `user`), `owner_user_id` (an ID prefixed `user_`, which finds a member's plugins, including after the member leaves the organization), `marketplace_id`, and `created_at[gte]`, `created_at[gt]`, `created_at[lte]`, `created_at[lt]` (RFC 3339 timestamps). Filters combine with AND. A `marketplace_id` or `owner_user_id` that matches nothing in your organization returns an empty page, not an error. The response has the shape shown in [Quick start](https://platform.claude.com/docs/en/manage-claude/plugins-api#quick-start). Requires the `read:plugins` scope.
565`GET /v1/organizations/plugins` lists every plugin in your organization, in the organization’s marketplaces and in members’ personal marketplaces, ordered by `created_at` descending. Filter by `owner_type` (`organization` or `user`), `owner_user_id` (an ID prefixed `user_`, which finds a member’s plugins, including after the member leaves the organization), `marketplace_id`, and `created_at[gte]`, `created_at[gt]`, `created_at[lte]`, `created_at[lt]` (RFC 3339 timestamps). Filters combine with AND. A `marketplace_id` or `owner_user_id` that matches nothing in your organization returns an empty page, not an error. The response has the shape shown in [Quick start](https://platform.claude.com/docs/en/manage-claude/plugins-api#quick-start). Requires the `read:plugins` scope.
566566 
567567<CodeGroup>
568568 ```bash cURL
from line 679
679679 
680680### Create a plugin
681681 
682`POST /v1/organizations/plugins` creates an organization-owned plugin and its first version in one call; the version becomes the served version. The body is `multipart/form-data`: `files[]` is either one `.zip` or `.plugin` archive, or one part for each file, where each part's file name is the file's path within the plugin (for example `.claude-plugin/plugin.json`). Optional fields are `marketplace_id` (an organization-owned `manual` marketplace, or by default your library marketplace, which is created on first use) and `release_notes` (up to 5,000 characters, shown in claude.ai's version history and returned on the version). The plugin's `name`, `display_name`, `description`, and `manifest_version` come from the uploaded manifest, and the upload must meet the [upload requirements](https://platform.claude.com/docs/en/manage-claude/plugins-api#upload-requirements). When content scanning is on, the response's `content_scan.status` is `processing` and the verdict arrives asynchronously. Returns the plugin. Requires the `write:plugins` scope.
682`POST /v1/organizations/plugins` creates an organization-owned plugin and its first version in one call; the version becomes the served version. The body is `multipart/form-data`: `files[]` is either one `.zip` or `.plugin` archive, or one part for each file, where each part’s file name is the file’s path within the plugin (for example `.claude-plugin/plugin.json`). Optional fields are `marketplace_id` (an organization-owned `manual` marketplace, or by default your library marketplace, which is created on first use) and `release_notes` (up to 5,000 characters, shown in claude.ai’s version history and returned on the version). The plugin’s `name`, `display_name`, `description`, and `manifest_version` come from the uploaded manifest, and the upload must meet the [upload requirements](https://platform.claude.com/docs/en/manage-claude/plugins-api#upload-requirements). When content scanning is on, the response’s `content_scan.status` is `processing` and the verdict arrives asynchronously. Returns the plugin. Requires the `write:plugins` scope.
683683 
684684Upload an archive:
685685 
from line 1041
10411041 ```
10421042</CodeGroup>
10431043 
1044Besides a `400` for an upload that breaks the [upload requirements](https://platform.claude.com/docs/en/manage-claude/plugins-api#upload-requirements) (`413` for a request body over 200 MB) and the shared responses (a `403` when `marketplace_id` is a member's personal marketplace; see [Error responses](https://platform.claude.com/docs/en/manage-claude/plugins-api#error-responses)), a create can fail with:
1044Besides a `400` for an upload that breaks the [upload requirements](https://platform.claude.com/docs/en/manage-claude/plugins-api#upload-requirements) (`413` for a request body over 200 MB) and the shared responses (a `403` when `marketplace_id` is a member’s personal marketplace; see [Error responses](https://platform.claude.com/docs/en/manage-claude/plugins-api#error-responses)), a create can fail with:
10451045 
10461046| Status | Cause | What to do |
10471047| -------------------------- | -------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
from line 1048
10481048| 404 | `marketplace_id` is not a marketplace of your organization. | Take the ID from [List marketplaces](https://platform.claude.com/docs/en/manage-claude/plugins-api#list-marketplaces). |
10491049| 400 | The marketplace is synchronized from Git, or already holds 500 plugins and skills. | Upload to a `manual` marketplace, or change the repository instead. |
10501050| 409 `plugin_name_taken` | The name is taken in that marketplace. | Upload a version to `details.plugin_id` only if it is the plugin you meant to update, because someone else might have made it. Otherwise, upload under another name (change the manifest `name`). |
1051| 409 `skill_name_taken` | The plugin is going into the library marketplace and one of its skills has an organization skill's name. | Rename the skill, or remove the organization skill in claude.ai. |
1051| 409 `skill_name_taken` | The plugin is going into the library marketplace and one of its skills has an organization skill’s name. | Rename the skill, or remove the organization skill in claude.ai. |
10521052| 409 (no `error_code`) | Another upload with the same name to the same marketplace is still in progress. | Retry shortly. |
10531053| 503 `registration_pending` | The plugin was created but its registration did not complete. | Do not resend; upload the same files as a version of `details.plugin_id` (see [Retrying uploads](https://platform.claude.com/docs/en/manage-claude/plugins-api#retrying-uploads)). |
10541054 
from line 1304
13041304| Status | Cause | What to do |
13051305| ---------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
13061306| 400 | The body omits `served_version_id`, sets it to `null`, or contains any other field; or the value lacks the `pluginver_` prefix or is `latest`. | Send exactly `{"served_version_id": "pluginver_..."}`. |
1307| 404 | `served_version_id` is not a version of this plugin. | Take the ID from [List a plugin's versions](https://platform.claude.com/docs/en/manage-claude/plugins-api#list-a-plugins-versions). |
1307| 404 | `served_version_id` is not a version of this plugin. | Take the ID from [List a plugin’s versions](https://platform.claude.com/docs/en/manage-claude/plugins-api#list-a-plugins-versions). |
13081308| 409 (no `error_code`) | An upload to this plugin or another served-version change is still in progress. | Retry shortly. |
13091309| 409 `skill_name_taken` | The plugin is in the library marketplace and the version has a skill whose name an organization skill now uses. | Choose another version, or rename one of the skills. |
13101310 
13111311### Delete a plugin
13121312 
1313`DELETE /v1/organizations/plugins/{plugin_id}` permanently deletes a plugin and every version it holds, just as an administrator's delete in claude.ai does. It works on any plugin in a `manual` marketplace, including a member's plugin, even if that member has since left the organization. When the delete returns, the plugin, its versions, and their files are gone from every read, and members are no longer served it. An organization-owned plugin's installation settings are removed with it; a member-owned plugin's shares are withdrawn, and it disappears for its owner too. A plugin in a marketplace synchronized from Git returns `400`: remove it from the repository, or remove the marketplace in claude.ai. Requires the `write:plugins` scope.
1313`DELETE /v1/organizations/plugins/{plugin_id}` permanently deletes a plugin and every version it holds, just as an administrator’s delete in claude.ai does. It works on any plugin in a `manual` marketplace, including a member’s plugin, even if that member has since left the organization. When the delete returns, the plugin, its versions, and their files are gone from every read, and members are no longer served it. An organization-owned plugin’s installation settings are removed with it; a member-owned plugin’s shares are withdrawn, and it disappears for its owner too. A plugin in a marketplace synchronized from Git returns `400`: remove it from the repository, or remove the marketplace in claude.ai. Requires the `write:plugins` scope.
13141314 
1315Deletion cannot be undone, and there is no per-version delete. To withhold an organization-owned plugin reversibly instead, set its organization-wide installation setting to `not_available` (a plugin that was inheriting its marketplace's default gets a setting of its own, and [removing that organization-wide setting](https://platform.claude.com/docs/en/manage-claude/plugins-api#remove-an-installation-setting) later returns the plugin to the default), and remove (or set to `not_available`) every group setting that `GET /v1/organizations/plugins/{plugin_id}/installation_settings` lists, because a group's setting overrides the organization-wide value for its members. Send these writes one after another, not in parallel (see [Set an installation setting](https://platform.claude.com/docs/en/manage-claude/plugins-api#set-an-installation-setting)). A member-owned plugin cannot be withheld through this API except by deleting it, and only if its marketplace is `manual`.
1315Deletion cannot be undone, and there is no per-version delete. To withhold an organization-owned plugin reversibly instead, set its organization-wide installation setting to `not_available` (a plugin that was inheriting its marketplace’s default gets a setting of its own, and [removing that organization-wide setting](https://platform.claude.com/docs/en/manage-claude/plugins-api#remove-an-installation-setting) later returns the plugin to the default), and remove (or set to `not_available`) every group setting that `GET /v1/organizations/plugins/{plugin_id}/installation_settings` lists, because a group’s setting overrides the organization-wide value for its members. Send these writes one after another, not in parallel (see [Set an installation setting](https://platform.claude.com/docs/en/manage-claude/plugins-api#set-an-installation-setting)). A member-owned plugin cannot be withheld through this API except by deleting it, and only if its marketplace is `manual`.
13161316 
13171317<CodeGroup>
13181318 ```bash cURL
from line 1406
14061406 
14071407## Plugin versions
14081408 
1409A plugin version is an immutable snapshot of a plugin's files from one upload (the [Create a version](https://platform.claude.com/docs/en/manage-claude/plugins-api#create-a-version) response shows a complete object). Its fields mirror the plugin's served-version fields (`display_name`, `description`, `manifest_version`, `content_scan`, `components`, `reach`) for this version, plus `release_notes` (as supplied with the upload and shown in claude.ai's version history) and `created_by` (who uploaded it).
1409A plugin version is an immutable snapshot of a plugin’s files from one upload (the [Create a version](https://platform.claude.com/docs/en/manage-claude/plugins-api#create-a-version) response shows a complete object). Its fields mirror the plugin’s served-version fields (`display_name`, `description`, `manifest_version`, `content_scan`, `components`, `reach`) for this version, plus `release_notes` (as supplied with the upload and shown in claude.ai’s version history) and `created_by` (who uploaded it).
14101410 
14111411A `{version}` that lacks the `pluginver_` prefix returns `400` (except the literal `latest` where noted). One that carries the prefix but does not identify a version of that plugin returns `404`.
14121412 
1413### List a plugin's versions
1413### List a plugin’s versions
14141414 
1415`GET /v1/organizations/plugins/{plugin_id}/versions` lists a plugin's versions, ordered by `created_at` descending; the first item is the version `latest_version_id` identifies. `limit` is 1 to 1,000. Requires the `read:plugins` scope.
1415`GET /v1/organizations/plugins/{plugin_id}/versions` lists a plugin’s versions, ordered by `created_at` descending; the first item is the version `latest_version_id` identifies. `limit` is 1 to 1,000. Requires the `read:plugins` scope.
14161416 
14171417<CodeGroup>
14181418 ```bash cURL
from line 1533
15331533 
15341534### Create a version
15351535 
1536`POST /v1/organizations/plugins/{plugin_id}/versions` adds a version to an organization-owned plugin in a `manual` marketplace. The body is `multipart/form-data`, with the same `files[]` and `release_notes` fields, [upload requirements](https://platform.claude.com/docs/en/manage-claude/plugins-api#upload-requirements), and file, manifest, archive, and size errors as [Create a plugin](https://platform.claude.com/docs/en/manage-claude/plugins-api#create-a-plugin). The uploaded name (the manifest's `name`) must equal the plugin's `name`. If the plugin is not pinned, the new version is normally served as soon as it is stored; if it is pinned, the version is stored but not served until you change the served version to it. To check, compare the response's `id` with the plugin's `served_version_id`. Returns the version. Requires the `write:plugins` scope.
1536`POST /v1/organizations/plugins/{plugin_id}/versions` adds a version to an organization-owned plugin in a `manual` marketplace. The body is `multipart/form-data`, with the same `files[]` and `release_notes` fields, [upload requirements](https://platform.claude.com/docs/en/manage-claude/plugins-api#upload-requirements), and file, manifest, archive, and size errors as [Create a plugin](https://platform.claude.com/docs/en/manage-claude/plugins-api#create-a-plugin). The uploaded name (the manifest’s `name`) must equal the plugin’s `name`. If the plugin is not pinned, the new version is normally served as soon as it is stored; if it is pinned, the version is stored but not served until you change the served version to it. To check, compare the response’s `id` with the plugin’s `served_version_id`. Returns the version. Requires the `write:plugins` scope.
15371537 
15381538<CodeGroup>
15391539 ```bash cURL
from line 1715
17151715 
17161716| Status | Cause | What to do |
17171717| -------------------------- | -------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
1718| 400 | The plugin is in a marketplace synchronized from Git, or the uploaded name differs from the plugin's. | Change the repository instead, or fix the manifest `name`. |
1718| 400 | The plugin is in a marketplace synchronized from Git, or the uploaded name differs from the plugin’s. | Change the repository instead, or fix the manifest `name`. |
17191719| 409 (no `error_code`) | Another upload to this plugin, or a served-version change, is still in progress. | Retry shortly. |
1720| 409 `skill_name_taken` | The plugin is in the library marketplace and the version adds a skill with an organization skill's name. | Rename the skill, or remove the organization skill in claude.ai. |
1720| 409 `skill_name_taken` | The plugin is in the library marketplace and the version adds a skill with an organization skill’s name. | Rename the skill, or remove the organization skill in claude.ai. |
17211721| 503 `registration_pending` | The version was stored but its registration did not complete. | Resend the same request when the response carries `x-should-retry: true` (see [Retrying uploads](https://platform.claude.com/docs/en/manage-claude/plugins-api#retrying-uploads)). |
17221722 
17231723### Get a version
from line 1831
18311831 ```
18321832</CodeGroup>
18331833 
1834### Download a version's files
1834### Download a version’s files
18351835 
1836`GET /v1/organizations/plugins/{plugin_id}/versions/{version}/content` downloads a version's files as the stored `.zip` archive (`Content-Type: application/zip`). The archive is returned whatever its content-scan result, so you can inspect versions withheld from members. It is served exactly as stored, so for an organization-owned plugin in a `manual` marketplace you can re-upload it unchanged as a new version, provided it meets the current upload requirements. `{version}` must be a version ID, not `latest`: read the plugin's `served_version_id` or `latest_version_id` first, or resolve `latest` with `GET /v1/organizations/plugins/{plugin_id}/versions/latest`. The `Content-Disposition` file name is derived from the plugin's name and is not unique; name saved files by plugin and version ID. Requires the `read:plugins` scope.
1836`GET /v1/organizations/plugins/{plugin_id}/versions/{version}/content` downloads a version’s files as the stored `.zip` archive (`Content-Type: application/zip`). The archive is returned whatever its content-scan result, so you can inspect versions withheld from members. It is served exactly as stored, so for an organization-owned plugin in a `manual` marketplace you can re-upload it unchanged as a new version, provided it meets the current upload requirements. `{version}` must be a version ID, not `latest`: read the plugin’s `served_version_id` or `latest_version_id` first, or resolve `latest` with `GET /v1/organizations/plugins/{plugin_id}/versions/latest`. The `Content-Disposition` file name is derived from the plugin’s name and is not unique; name saved files by plugin and version ID. Requires the `read:plugins` scope.
18371837 
1838Downloading a **member-owned** plugin's archive records a `claude_plugin_archive_accessed` event on the Compliance API Activity Feed, identifying the key (as `api_actor`), the plugin and its marketplace, the version, and the owning member by ID; it carries no names. Downloading an organization-owned plugin's archive records nothing.
1838Downloading a **member-owned** plugin’s archive records a `claude_plugin_archive_accessed` event on the Compliance API Activity Feed, identifying the key (as `api_actor`), the plugin and its marketplace, the version, and the owning member by ID; it carries no names. Downloading an organization-owned plugin’s archive records nothing.
18391839 
18401840<CodeGroup>
18411841 ```bash cURL
from line 1977
19771977 
19781978## Plugin installation settings
19791979 
1980These endpoints apply to organization-owned plugins. They return `404` for a member-owned plugin, which has shares instead (see [Plugin shares](https://platform.claude.com/docs/en/manage-claude/plugins-api#plugin-shares)). `{target}` is the literal `organization` for the plugin's organization-wide setting, or a group's `rbac_group_` ID for that group's setting; any other value returns `400`. Group IDs come from `GET /v1/organizations/rbac_groups` (scope `read:rbac_groups`; see [Groups in User management](https://platform.claude.com/docs/en/manage-claude/user-management#groups)). A setting has no `id` of its own: it is addressed by `(plugin_id, target)`, and no actor is recorded on it (the actor is on its `plugin_installation_preference_updated` activity event).
1980These endpoints apply to organization-owned plugins. They return `404` for a member-owned plugin, which has shares instead (see [Plugin shares](https://platform.claude.com/docs/en/manage-claude/plugins-api#plugin-shares)). `{target}` is the literal `organization` for the plugin’s organization-wide setting, or a group’s `rbac_group_` ID for that group’s setting; any other value returns `400`. Group IDs come from `GET /v1/organizations/rbac_groups` (scope `read:rbac_groups`; see [Groups in User management](https://platform.claude.com/docs/en/manage-claude/user-management#groups)). A setting has no `id` of its own: it is addressed by `(plugin_id, target)`, and no actor is recorded on it (the actor is on its `plugin_installation_preference_updated` activity event).
19811981 
1982### List a plugin's installation settings
1982### List a plugin’s installation settings
19831983 
1984`GET /v1/organizations/plugins/{plugin_id}/installation_settings` lists the settings an organization-owned plugin holds, ordered by `created_at` descending: its own organization-wide setting (absent while it inherits its marketplace's default) and each group's setting. Filter by `target_type` (`organization` or `rbac_group`). Requires the `read:plugins` scope.
1984`GET /v1/organizations/plugins/{plugin_id}/installation_settings` lists the settings an organization-owned plugin holds, ordered by `created_at` descending: its own organization-wide setting (absent while it inherits its marketplace’s default) and each group’s setting. Filter by `target_type` (`organization` or `rbac_group`). Requires the `read:plugins` scope.
19851985 
19861986<CodeGroup>
19871987 ```bash cURL
from line 2089
20892089 
20902090### Set an installation setting
20912091 
2092`POST /v1/organizations/plugins/{plugin_id}/installation_settings/{target}` sets one target's installation setting for an organization-owned plugin, creating it or changing the value it already holds. The body's only field is `installation_preference` (`required`, `auto_install`, `available`, or `not_available`), and it is required. Setting the value the target already holds changes nothing. Setting the `organization` target stops the plugin inheriting its marketplace's default (`organization_installation_preference_inherited` becomes `false`), even when the value is the same as the default, so the plugin no longer follows later changes to the marketplace default. To return the plugin to its marketplace's default, [remove the organization-wide setting](https://platform.claude.com/docs/en/manage-claude/plugins-api#remove-an-installation-setting); group settings are unaffected. A group target must be a group your organization can see in `GET /v1/organizations/rbac_groups`, or the request returns `404`. The change does not alter the plugin's `updated_at`; it is recorded on the Activity Feed. Returns the setting. Requires the `write:plugins` scope.
2092`POST /v1/organizations/plugins/{plugin_id}/installation_settings/{target}` sets one target’s installation setting for an organization-owned plugin, creating it or changing the value it already holds. The body’s only field is `installation_preference` (`required`, `auto_install`, `available`, or `not_available`), and it is required. Setting the value the target already holds changes nothing. Setting the `organization` target stops the plugin inheriting its marketplace’s default (`organization_installation_preference_inherited` becomes `false`), even when the value is the same as the default, so the plugin no longer follows later changes to the marketplace default. To return the plugin to its marketplace’s default, [remove the organization-wide setting](https://platform.claude.com/docs/en/manage-claude/plugins-api#remove-an-installation-setting); group settings are unaffected. A group target must be a group your organization can see in `GET /v1/organizations/rbac_groups`, or the request returns `404`. The change does not alter the plugin’s `updated_at`; it is recorded on the Activity Feed. Returns the setting. Requires the `write:plugins` scope.
20932093 
2094Send a plugin's installation-setting writes one at a time. If several writes for the same plugin arrive at the same time, the server handles them one after another and can answer some of them with `503` instead of applying them. That `503` carries `x-should-retry: true`, and the write is safe to repeat: wait a second or two, then send it again.
2094Send a plugin’s installation-setting writes one at a time. If several writes for the same plugin arrive at the same time, the server handles them one after another and can answer some of them with `503` instead of applying them. That `503` carries `x-should-retry: true`, and the write is safe to repeat: wait a second or two, then send it again.
20952095 
20962096<CodeGroup>
20972097 ```bash cURL
from line 2238
22382238 
22392239### Remove an installation setting
22402240 
2241`DELETE /v1/organizations/plugins/{plugin_id}/installation_settings/{target}` removes one target's installation setting for an organization-owned plugin. With `{target}` of `organization` it removes the plugin's own organization-wide setting. The plugin then inherits its marketplace's default again (`organization_installation_preference_inherited` becomes `true`) and follows later changes to that default; group settings are unaffected. With a group's `rbac_group_` ID it removes that group's setting: the group's members fall back to the organization-wide value, or to another of their groups' settings. A target that holds no setting of its own returns `404`; that includes the `organization` target of a plugin that already inherits its marketplace's default. The change does not alter the plugin's `updated_at`; it is recorded on the Activity Feed. The response carries the composite key in place of an `id`; for the `organization` target its `target` is `{"type": "organization"}`. Requires the `write:plugins` scope.
2241`DELETE /v1/organizations/plugins/{plugin_id}/installation_settings/{target}` removes one target’s installation setting for an organization-owned plugin. With `{target}` of `organization` it removes the plugin’s own organization-wide setting. The plugin then inherits its marketplace’s default again (`organization_installation_preference_inherited` becomes `true`) and follows later changes to that default; group settings are unaffected. With a group’s `rbac_group_` ID it removes that group’s setting: the group’s members fall back to the organization-wide value, or to another of their groups’ settings. A target that holds no setting of its own returns `404`; that includes the `organization` target of a plugin that already inherits its marketplace’s default. The change does not alter the plugin’s `updated_at`; it is recorded on the Activity Feed. The response carries the composite key in place of an `id`; for the `organization` target its `target` is `{"type": "organization"}`. Requires the `write:plugins` scope.
22422242 
22432243<CodeGroup>
22442244 ```bash cURL
from line 2357
23572357 
23582358Shares exist only on member-owned plugins and are read-only in this API (see [Shares](https://platform.claude.com/docs/en/manage-claude/plugins-api#shares)).
23592359 
2360### List a plugin's shares
2360### List a plugin’s shares
23612361 
23622362`GET /v1/organizations/plugins/{plugin_id}/shares` lists who the owner of a member-owned plugin has shared it with, ordered by `granted_at` descending: every member (`organization`), a group (`rbac_group`), or a named member (`organization_member`). Filter by `target_type`. A plugin its owner has not shared returns an empty list; an organization-owned plugin returns `404`. Shares are read-only on this API, and a listed share gives access only while that kind of sharing is turned on for your organization in claude.ai (see [Shares](https://platform.claude.com/docs/en/manage-claude/plugins-api#shares)). `granted_at` is when the share was given; if the owner later changes the share in claude.ai, it is the time of that change. Requires the `read:plugins` scope.
23632363 
from line 2477
24772477 
24782478## Plugin marketplaces
24792479 
2480This API reads [marketplaces](https://platform.claude.com/docs/en/manage-claude/plugins-api#marketplaces) and sets an organization marketplace's default installation setting; marketplaces themselves are created, connected to a repository, and deleted in claude.ai.
2480This API reads [marketplaces](https://platform.claude.com/docs/en/manage-claude/plugins-api#marketplaces) and sets an organization marketplace’s default installation setting; marketplaces themselves are created, connected to a repository, and deleted in claude.ai.
24812481 
24822482```json
24832483{
from line 2496
24962496 
24972497| Field | Description |
24982498| --------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
2499| `name` | The marketplace's name. Fixed for its lifetime. |
2499| `name` | The marketplace’s name. Fixed for its lifetime. |
25002500| `owner` | Same shape as on the plugin. |
25012501| `source` | `manual`, `github`, `gitlab`, or `public_git`. See [Marketplaces](https://platform.claude.com/docs/en/manage-claude/plugins-api#marketplaces). |
25022502| `sync_status` | Outcome of the most recent synchronization: `success`, `in_progress`, `failed_content`, `failed_transient`, `failed_auth`, or `failed_limits`. `null` until a synchronization is first attempted, which never occurs for a marketplace whose source is `manual`. |
from line 2508
25082508 
25092509### List marketplaces
25102510 
2511`GET /v1/organizations/plugin_marketplaces` lists your organization's marketplaces and members' personal marketplaces, ordered by `created_at` descending. Use it to find a marketplace's ID, to filter the plugin list by it or to upload into it, before it holds any plugin. The library marketplace appears once something has first been created in it, in claude.ai or through this API. Filter by `owner_type` (`organization` or `user`) and `source`. `limit` is 1 to 1,000. Requires the `read:plugins` scope.
2511`GET /v1/organizations/plugin_marketplaces` lists your organization’s marketplaces and members’ personal marketplaces, ordered by `created_at` descending. Use it to find a marketplace’s ID, to filter the plugin list by it or to upload into it, before it holds any plugin. The library marketplace appears once something has first been created in it, in claude.ai or through this API. Filter by `owner_type` (`organization` or `user`) and `source`. `limit` is 1 to 1,000. Requires the `read:plugins` scope.
25122512 
25132513<CodeGroup>
25142514 ```bash cURL
from line 2722
27222722 ```
27232723</CodeGroup>
27242724 
2725### Set a marketplace's default installation setting
2725### Set a marketplace’s default installation setting
27262726 
2727`POST /v1/organizations/plugin_marketplaces/{marketplace_id}` sets the default installation setting of an organization-owned marketplace. Every plugin in the marketplace without its own organization-wide setting reports this default as its `organization_installation_preference`, including plugins added later. It works for `manual` and synchronized marketplaces; a member's personal marketplace returns `403`. The only updatable field is `default_installation_preference`, and it is required. It cannot be set back to `null`: once a marketplace has a default, it keeps one, as in claude.ai. A change is recorded as one `marketplace_updated` event with no per-plugin events, and does not alter any plugin's `updated_at`. Setting the value already set changes nothing, with one exception: a marketplace whose default was never set reports `not_available` but holds no setting, so its first write (even `not_available`) counts as a change. Returns the marketplace. Requires the `write:plugins` scope.
2727`POST /v1/organizations/plugin_marketplaces/{marketplace_id}` sets the default installation setting of an organization-owned marketplace. Every plugin in the marketplace without its own organization-wide setting reports this default as its `organization_installation_preference`, including plugins added later. It works for `manual` and synchronized marketplaces; a member’s personal marketplace returns `403`. The only updatable field is `default_installation_preference`, and it is required. It cannot be set back to `null`: once a marketplace has a default, it keeps one, as in claude.ai. A change is recorded as one `marketplace_updated` event with no per-plugin events, and does not alter any plugin’s `updated_at`. Setting the value already set changes nothing, with one exception: a marketplace whose default was never set reports `not_available` but holds no setting, so its first write (even `not_available`) counts as a change. Returns the marketplace. Requires the `write:plugins` scope.
27282728 
27292729<CodeGroup>
27302730 ```bash cURL
from line 2849
28492849 
28502850### Validate marketplace content
28512851 
2852Two endpoints report what a synchronization of the given marketplace content would do, without connecting or storing anything: `POST /v1/organizations/plugin_marketplaces/validate_repository` reads a public GitHub repository, and `POST /v1/organizations/plugin_marketplaces/validate_archive` reads a `.zip` of the marketplace directory that you upload. Both return the same report: whether `marketplace.json` is well-formed, which plugins would be skipped and why, and which plugins would synchronize with some contents left out. The checks are the ones a real synchronization runs. Problems with the content come back in the report, not as HTTP errors: the request succeeds with `valid: false`, even when the repository or archive cannot be read at all. A validation counts as a read, and the two endpoints together are additionally limited to 10 validations a minute for each organization (see [Rate limiting](https://platform.claude.com/docs/en/manage-claude/plugins-api#rate-limiting)); they record nothing on the Activity Feed. A validation can take up to 120 seconds before it returns, so set your client's timeout above that. Both endpoints require the `read:plugins` or `write:plugins` scope (`read:org_audit` and `read:compliance_org_data` do not grant them).
2852Two endpoints report what a synchronization of the given marketplace content would do, without connecting or storing anything: `POST /v1/organizations/plugin_marketplaces/validate_repository` reads a public GitHub repository, and `POST /v1/organizations/plugin_marketplaces/validate_archive` reads a `.zip` of the marketplace directory that you upload. Both return the same report: whether `marketplace.json` is well-formed, which plugins would be skipped and why, and which plugins would synchronize with some contents left out. The checks are the ones a real synchronization runs. Problems with the content come back in the report, not as HTTP errors: the request succeeds with `valid: false`, even when the repository or archive cannot be read at all. A validation counts as a read, and the two endpoints together are additionally limited to 10 validations a minute for each organization (see [Rate limiting](https://platform.claude.com/docs/en/manage-claude/plugins-api#rate-limiting)); they record nothing on the Activity Feed. A validation can take up to 120 seconds before it returns, so set your client’s timeout above that. Both endpoints require the `read:plugins` or `write:plugins` scope (`read:org_audit` and `read:compliance_org_data` do not grant them).
28532853 
28542854Validation reads the repository anonymously. It does the same for any plugin source that is on GitHub but outside the repository. As a result, validation reports a private repository or a private plugin source as not found or as needing a GitHub sign-in. When validation reports that a GitHub sign-in is needed, the report code is `marketplace_repo_sign_in_required`.
28552855 
from line 2861
28612861* Validation reports unpinned sources and sources on unsupported hosts as plugin errors.
28622862* For `validate_repository`, the branch that validation reads defaults to the branch that the marketplace synchronizes from.
28632863 
2864`validate_repository` takes a JSON body with two fields: `repository_url`, the `https://` URL of a public repository on github.com (required), and `ref`, a branch name or a full 40-character commit SHA (optional). When `ref` is omitted or `null`, it defaults to the branch a synchronization would read, usually the repository's default branch. `validate_archive` takes `multipart/form-data` with exactly one part, `archive`, sent as a file part with a file name. The file is a `.zip` of the marketplace directory, at most 32 MB, that uses DEFLATE or STORE compression only. The archive's contents sit at the root or are wrapped in one folder (as a Git host's download produces). No other form field is accepted.
2864`validate_repository` takes a JSON body with two fields: `repository_url`, the `https://` URL of a public repository on github.com (required), and `ref`, a branch name or a full 40-character commit SHA (optional). When `ref` is omitted or `null`, it defaults to the branch a synchronization would read, usually the repository’s default branch. `validate_archive` takes `multipart/form-data` with exactly one part, `archive`, sent as a file part with a file name. The file is a `.zip` of the marketplace directory, at most 32 MB, that uses DEFLATE or STORE compression only. The archive’s contents sit at the root or are wrapped in one folder (as a Git host’s download produces). No other form field is accepted.
28652865 
28662866Validate a public repository at a branch:
28672867 
from line 3014
30143014| --------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
30153015| `valid` | `true` when `marketplace.json` is well-formed and no plugin would be skipped. Warnings do not make it `false`. |
30163016| `ref` | The branch that was read, by name; `null` when no branch was named and the default branch was read, for a commit SHA, or for an archive. |
3017| `commit_sha` | The commit that was validated. For an archive downloaded from a Git host, the commit the host recorded in the ZIP file's comment field, if any (not verified). |
3017| `commit_sha` | The commit that was validated. For an archive downloaded from a Git host, the commit the host recorded in the ZIP file’s comment field, if any (not verified). |
30183018| `total_plugin_count` | How many plugins `marketplace.json` declares; `0` when it could not be read. |
30193019| `manifest_error`, `manifest_error_code` | Set when nothing could be validated: the source could not be read, or `marketplace.json` is missing, malformed, or over a limit. Validation that did not complete within 120 seconds reports `manifest_error_code: "marketplace_validate_deadline_exceeded"`. |
30203020| `plugin_errors` | One `{name, error, error_code}` per plugin a synchronization would skip. |
from line 3141
31413141 
31423142| Status | Cause | What to do |
31433143| ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------ |
3144| 400 | On `validate_repository`: the body is not a JSON object; `repository_url` is missing, is longer than 2,048 characters, carries credentials, or is not of the form `https://github.com/{owner}/{repo}` (a `.git` suffix is accepted; another host, a longer path such as a branch page's `/tree/main`, or a port other than 443 or 80 is not); `ref` is empty, is longer than 255 characters, contains `..`, or contains a character other than ASCII letters, digits, `.`, `_`, `-`, `+`, and `/`; or another field is present. A `ref` that passes these checks but names a branch the repository does not have is not refused: the request succeeds with `valid: false` and `manifest_error` says the branch was not found. On `validate_archive`: the body is not `multipart/form-data`, the `archive` part is missing, repeated, or not sent as a file part with a file name, or another form field is present. | Fix the request and resend. |
3145| 413 | On `validate_archive`: the `archive` part, or the request's declared body length, exceeds 32 MB. | Validate the repository by URL instead, or trim the archive. |
3144| 400 | On `validate_repository`: the body is not a JSON object; `repository_url` is missing, is longer than 2,048 characters, carries credentials, or is not of the form `https://github.com/{owner}/{repo}` (a `.git` suffix is accepted; another host, a longer path such as a branch page’s `/tree/main`, or a port other than 443 or 80 is not); `ref` is empty, is longer than 255 characters, contains `..`, or contains a character other than ASCII letters, digits, `.`, `_`, `-`, `+`, and `/`; or another field is present. A `ref` that passes these checks but names a branch the repository does not have is not refused: the request succeeds with `valid: false` and `manifest_error` says the branch was not found. On `validate_archive`: the body is not `multipart/form-data`, the `archive` part is missing, repeated, or not sent as a file part with a file name, or another form field is present. | Fix the request and resend. |
3145| 413 | On `validate_archive`: the `archive` part, or the request’s declared body length, exceeds 32 MB. | Validate the repository by URL instead, or trim the archive. |
31463146 
31473147#### Report codes
31483148 
3149Each finding in a report has a stable code: `manifest_error_code` when nothing could be validated, `error_code` on each `plugin_errors` entry, and `error_code` on each warning. When a plugin has several problems, `error_code` is the first one's and `error` joins their messages. New codes may be added; an unrecognized `manifest_error_code` still means the content could not be validated, one on a `plugin_errors` entry still means the plugin would be skipped, and one on a warning still means the plugin would synchronize. These codes indicate transient conditions, so the same request might succeed later: `marketplace_host_rate_limited`, `marketplace_host_server_error`, `marketplace_host_timeout`, `marketplace_host_unreachable`, `marketplace_repo_access_denied`, `marketplace_sync_transient_fetch_budget_exhausted`, `marketplace_validate_network_error`, and usually `marketplace_validate_deadline_exceeded`.
3149Each finding in a report has a stable code: `manifest_error_code` when nothing could be validated, `error_code` on each `plugin_errors` entry, and `error_code` on each warning. When a plugin has several problems, `error_code` is the first one’s and `error` joins their messages. New codes may be added; an unrecognized `manifest_error_code` still means the content could not be validated, one on a `plugin_errors` entry still means the plugin would be skipped, and one on a warning still means the plugin would synchronize. These codes indicate transient conditions, so the same request might succeed later: `marketplace_host_rate_limited`, `marketplace_host_server_error`, `marketplace_host_timeout`, `marketplace_host_unreachable`, `marketplace_repo_access_denied`, `marketplace_sync_transient_fetch_budget_exhausted`, `marketplace_validate_network_error`, and usually `marketplace_validate_deadline_exceeded`.
31503150 
31513151## Unrecognized values
31523152 
from line 3154
31543154 
31553155## Rate limiting
31563156 
3157Read requests (every `GET` endpoint on this page) share a limit of **300 requests per minute** for each organization. Write requests (creating a plugin or version, changing the served version, deleting, setting or removing an installation setting, and updating a marketplace) share a limit of **60 requests per minute** for each organization. A marketplace validation (either endpoint) counts as a read, and validations are additionally limited to 10 a minute for each organization across both endpoints; both limits are checked before the request body is read. These limits are counted across all of your organization's keys and are separate from your organization's other Admin API limits. Requests over a limit return **429 Too Many Requests** with a `retry-after` header. Responses include `anthropic-ratelimit-requests-*` headers for the limit that applies (on marketplace validation, its 10-per-minute limit; on a `429`, whichever limit refused the request).
3157Read requests (every `GET` endpoint on this page) share a limit of **300 requests per minute** for each organization. Write requests (creating a plugin or version, changing the served version, deleting, setting or removing an installation setting, and updating a marketplace) share a limit of **60 requests per minute** for each organization. A marketplace validation (either endpoint) counts as a read, and validations are additionally limited to 10 a minute for each organization across both endpoints; both limits are checked before the request body is read. These limits are counted across all of your organization’s keys and are separate from your organization’s other Admin API limits. Requests over a limit return **429 Too Many Requests** with a `retry-after` header. Responses include `anthropic-ratelimit-requests-*` headers for the limit that applies (on marketplace validation, its 10-per-minute limit; on a `429`, whichever limit refused the request).
31583158 
31593159An upload, a served-version change, or a validation can also return `429` with `retry-after` when the service briefly has no capacity for another one, and an upload returns `429` when your organization has exceeded its content-scan rate. Handle all of these the same way: wait for `retry-after`, then retry. Separately from these limits, send installation-setting writes for the same plugin one at a time: when several arrive at the same time, some can be answered with `503` and `x-should-retry: true`, and those are safe to send again after a second or two (see [Set an installation setting](https://platform.claude.com/docs/en/manage-claude/plugins-api#set-an-installation-setting)).
31603160 
31613161## Pagination
31623162 
3163List endpoints use an **opaque cursor**. The first request returns up to `limit` rows plus a `next_page` cursor; pass the cursor unchanged as the `page` parameter on the next request, and repeat until `next_page` is `null`. Treat the cursor string as opaque: don't parse, modify, or construct it yourself. [List plugins](https://platform.claude.com/docs/en/manage-claude/plugins-api#list-plugins) can return a page with fewer than `limit` plugins, or none, while `next_page` is still set, so keep requesting pages until `next_page` is `null`. The Python, TypeScript, C#, Go, Java, and Ruby SDKs' list iterators and the CLI (except with `--format raw`) do that for you. They request the next page while `next_page` is set, so a short or empty page does not end them. In PHP and curl, request each page yourself and pass its `next_page` as `page`.
3163List endpoints use an **opaque cursor**. The first request returns up to `limit` rows plus a `next_page` cursor; pass the cursor unchanged as the `page` parameter on the next request, and repeat until `next_page` is `null`. Treat the cursor string as opaque: don’t parse, modify, or construct it yourself. [List plugins](https://platform.claude.com/docs/en/manage-claude/plugins-api#list-plugins) can return a page with fewer than `limit` plugins, or none, while `next_page` is still set, so keep requesting pages until `next_page` is `null`. The Python, TypeScript, C#, Go, Java, and Ruby SDKs’ list iterators and the CLI (except with `--format raw`) do that for you. They request the next page while `next_page` is set, so a short or empty page does not end them. In PHP and curl, request each page yourself and pass its `next_page` as `page`.
31643164 
31653165`limit` defaults to 20 and has a minimum of 1. The maximum is 100 for plugins, installation settings, and shares, and 1,000 for versions and marketplaces. Every list is ordered newest first.
31663166 
from line 3170
31703170 
31713171| Status | Meaning |
31723172| ------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
3173| 400 | Invalid input, or the operation does not apply to this plugin or marketplace (see each endpoint's section). Also returned for a query parameter the endpoint does not recognize, and for an organization that is not a Claude Enterprise organization (`this endpoint is not supported for this organization type`). |
3173| 400 | Invalid input, or the operation does not apply to this plugin or marketplace (see each endpoint’s section). Also returned for a query parameter the endpoint does not recognize, and for an organization that is not a Claude Enterprise organization (`this endpoint is not supported for this organization type`). |
31743174| 401 | Missing `x-api-key` header, or the key is not recognized. |
3175| 403 | The key is missing the required scope, or the request uploads to, changes the served version of, or sets the default for a member's plugin or personal marketplace. (Deleting a member's plugin is allowed.) |
3175| 403 | The key is missing the required scope, or the request uploads to, changes the served version of, or sets the default for a member’s plugin or personal marketplace. (Deleting a member’s plugin is allowed.) |
31763176| 404 | Resource not found. Also returned when the request omits the `anthropic-beta` value, or the API is not enabled for your organization, so that the endpoints read as nonexistent. |
3177| 409 | A name is taken, a version's `content_scan` reads `processing`, or a conflicting upload is in progress. |
3177| 409 | A name is taken, a version’s `content_scan` reads `processing`, or a conflicting upload is in progress. |
31783178| 413 | The request body is over the size limit: 200 MB for an upload, 32 MB for marketplace validation. |
31793179| 429 | Rate limit exceeded. See [Rate limiting](https://platform.claude.com/docs/en/manage-claude/plugins-api#rate-limiting). |
31803180| 500 | Internal error. |
from line 3201
32013201| ----------------------------------------------- | ------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
32023202| `plugin_name_taken` | 409 | A plugin with this name already exists in the marketplace. `details.plugin_id` is that plugin, and someone else might have made it. To see who, [get the plugin](https://platform.claude.com/docs/en/manage-claude/plugins-api#get-a-plugin) and read its `created_by`, which is `null` when no creator is recorded. Upload versions to it only if it is the plugin you meant to update. Otherwise, upload under another name. When `plugin_id` is absent, the name is held by a standalone skill: upload under another name, or delete the skill in claude.ai. |
32033203| `skill_name_taken` | 409 | The plugin is in the library marketplace and one of its skills has the same name as an organization skill (a skill an administrator uploaded for the whole organization in claude.ai). `details.skill_name` names it. Rename or remove one of them. |
3204| `registration_pending` | 503 | The files were stored, but the plugin's skills could not yet be made available to members. See [Retrying uploads](https://platform.claude.com/docs/en/manage-claude/plugins-api#retrying-uploads). |
3205| `scan_pending` | 409 | The version's `content_scan` reads `processing`. Retry once the scan finishes. |
3206| `scan_failed` | 400 | The version's `content_scan` reads `fail`, `unknown`, or `errored`, so it cannot be served. Choose another version. |
3207| `cmek_key_disabled`, `cmek_key_network_blocked` | 400 | Your organization's customer-managed encryption key is unavailable. See [Customer-managed encryption keys](https://platform.claude.com/docs/en/manage-claude/plugins-api#customer-managed-encryption-keys). |
3208| `unsupported_charset` | 400 | On an upload or `validate_archive`, the request's `Content-Type` header names a charset other than UTF-8, ISO-8859-1, or US-ASCII. Send the request with no charset, or with one of these. |
3204| `registration_pending` | 503 | The files were stored, but the plugin’s skills could not yet be made available to members. See [Retrying uploads](https://platform.claude.com/docs/en/manage-claude/plugins-api#retrying-uploads). |
3205| `scan_pending` | 409 | The version’s `content_scan` reads `processing`. Retry once the scan finishes. |
3206| `scan_failed` | 400 | The version’s `content_scan` reads `fail`, `unknown`, or `errored`, so it cannot be served. Choose another version. |
3207| `cmek_key_disabled`, `cmek_key_network_blocked` | 400 | Your organization’s customer-managed encryption key is unavailable. See [Customer-managed encryption keys](https://platform.claude.com/docs/en/manage-claude/plugins-api#customer-managed-encryption-keys). |
3208| `unsupported_charset` | 400 | On an upload or `validate_archive`, the request’s `Content-Type` header names a charset other than UTF-8, ISO-8859-1, or US-ASCII. Send the request with no charset, or with one of these. |
32093209 
32103210New codes may be added. Treat a code you do not recognize the way you treat its status.
32113211 
from line 3213
32133213 
32143214No endpoint accepts an `Idempotency-Key`. Changing the served version, setting an installation setting, and setting a marketplace default are safe to repeat. A repeated delete, or a repeated removal of an installation setting, returns `404`.
32153215 
3216An upload that returns an error stored nothing, with one exception: `503` with `error_code: "registration_pending"`. After storing an upload's files, the server registers the new version's skills with claude.ai, which is what makes them usable by members; `registration_pending` means the files were stored but that last step did not complete. Uploading the same files once more completes it (and stores one more, identical version):
3216An upload that returns an error stored nothing, with one exception: `503` with `error_code: "registration_pending"`. After storing an upload’s files, the server registers the new version’s skills with claude.ai, which is what makes them usable by members; `registration_pending` means the files were stored but that last step did not complete. Uploading the same files once more completes it (and stores one more, identical version):
32173217 
32183218* On `POST /v1/organizations/plugins`, the plugin *was* created, and the response carries `x-should-retry: false`: do not resend the create (a resend returns `409 plugin_name_taken`); instead upload the same files as a version of `details.plugin_id`.
32193219* On `POST /v1/organizations/plugins/{plugin_id}/versions`, the version *was* stored (`details.plugin_version_id`); resend the same request when the response carries `x-should-retry: true`, and do not when it carries `false`.
32203220 
3221If a create's response is lost, send the create again. A `409 plugin_name_taken` means either that the first attempt stored the plugin or that the name was already taken. Your lost create made the plugin in `details.plugin_id` only if its `created_by` is an `api_actor` with your key's `api_key_id`. Check that before you upload to it (see `plugin_name_taken` in the preceding table). Retrying a version create whose response was lost stores a second, identical version. To avoid that, record the plugin's `latest_version_id` before each upload; if a response is lost, read the plugin and retry only if `latest_version_id` is unchanged.
3221If a create’s response is lost, send the create again. A `409 plugin_name_taken` means either that the first attempt stored the plugin or that the name was already taken. Your lost create made the plugin in `details.plugin_id` only if its `created_by` is an `api_actor` with your key’s `api_key_id`. Check that before you upload to it (see `plugin_name_taken` in the preceding table). Retrying a version create whose response was lost stores a second, identical version. To avoid that, record the plugin’s `latest_version_id` before each upload; if a response is lost, read the plugin and retry only if `latest_version_id` is unchanged.
32223222 
32233223## Activity Feed events
32243224 
3225Every write through this API is recorded on your organization's [Compliance API Activity Feed](https://platform.claude.com/docs/en/manage-claude/compliance-activity-feed), attributed to the API key as an `api_actor` carrying its `apikey_` ID. The same actor appears in `created_by` on the plugins and versions the key creates.
3225Every write through this API is recorded on your organization’s [Compliance API Activity Feed](https://platform.claude.com/docs/en/manage-claude/compliance-activity-feed), attributed to the API key as an `api_actor` carrying its `apikey_` ID. The same actor appears in `created_by` on the plugins and versions the key creates.
32263226 
32273227| Event | Emitted when |
32283228| ---------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
from line 3233
32333233| `claude_plugin_deleted` | A plugin is deleted on its own, here or in claude.ai. |
32343234| `plugin_installation_preference_updated` | An installation setting is set or removed. |
32353235| `marketplace_created` | The first upload creates the library marketplace. |
3236| `marketplace_updated` | A marketplace's default installation setting changes, or an administrator or owner starts a synchronization in claude.ai. |
3236| `marketplace_updated` | A marketplace’s default installation setting changes, or an administrator or owner starts a synchronization in claude.ai. |
32373237| `marketplace_deleted` | A marketplace is deleted in claude.ai together with its plugins (no per-plugin events). |
3238| `claude_plugin_archive_accessed` | A member-owned plugin's archive is downloaded. |
3238| `claude_plugin_archive_accessed` | A member-owned plugin’s archive is downloaded. |
32393239| `claude_plugin_security_scan_completed` | A content scan completes. |
32403240 
32413241The plugin, version, and marketplace IDs in these events are the same IDs this API returns. `plugin_installation_preference_updated` identifies the plugin by its `name` and `marketplace_id` rather than its `id`. In `claude_plugin_security_scan_completed`, `plugin_version` is not a version ID, and no field of a [plugin version](https://platform.claude.com/docs/en/manage-claude/plugins-api#plugin-versions) corresponds to it.
32423242 
3243Changing a marketplace's default records one `marketplace_updated` event and no per-plugin events, even though it changes the value of every plugin that inherits the default. Reads are not recorded, except downloads of a member-owned plugin's archive. A write that changes nothing records nothing.
3243Changing a marketplace’s default records one `marketplace_updated` event and no per-plugin events, even though it changes the value of every plugin that inherits the default. Reads are not recorded, except downloads of a member-owned plugin’s archive. A write that changes nothing records nothing.
32443244 
3245Shares given or withdrawn in claude.ai appear on the feed as `role_assignment_granted` and `role_assignment_revoked` events. This API does not report deletions: a deleted plugin is absent from the next list. A plugin removed by a Git synchronization, by deleting its marketplace (one `marketplace_deleted` event), or by deleting a member's account or the organization emits no per-plugin event, so re-list the full inventory periodically to catch removals.
3245Shares given or withdrawn in claude.ai appear on the feed as `role_assignment_granted` and `role_assignment_revoked` events. This API does not report deletions: a deleted plugin is absent from the next list. A plugin removed by a Git synchronization, by deleting its marketplace (one `marketplace_deleted` event), or by deleting a member’s account or the organization emits no per-plugin event, so re-list the full inventory periodically to catch removals.
32463246 
32473247## Customer-managed encryption keys
32483248 
3249If your organization uses a [customer-managed encryption key](https://platform.claude.com/docs/en/manage-claude/cmek), a version's `description`, `release_notes`, `components`, and files are encrypted with it. While the key is unavailable:
3249If your organization uses a [customer-managed encryption key](https://platform.claude.com/docs/en/manage-claude/cmek), a version’s `description`, `release_notes`, `components`, and files are encrypted with it. While the key is unavailable:
32503250 
32513251* Reads and lists still succeed, with `description`, `release_notes`, and `components` returned as `null`.
32523252* Archive downloads, creates, version creates, and served-version changes return `400` with `cmek_key_disabled` or `cmek_key_network_blocked`.

manage-claude/rate-limits-api Changed · +12 / -12 lines

from line 17
1717* **Audit workspace configuration:** Verify that workspace overrides match what your provisioning automation expects.
1818 
1919<Check>
20 **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.
20 **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.
2121</Check>
2222 
2323The 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.
from line 152
152152### Key concepts
153153 
154154* **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.
155* **`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`.
156* **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.
155* **`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`.
156* **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.
157157* **`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.
158* **`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`.
158* **`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`.
159159* **`limits` list:** Each group carries a list of `{type, value}` pairs. The `type` field identifies the limiter (such as `requests_per_minute`, `input_tokens_per_minute`, or `output_tokens_per_minute`) and `value` is the configured limit. See [Rate limits](https://platform.claude.com/docs/en/api/rate-limits) for how each limiter is measured and enforced.
160160* **`source` on workspace limits:** On the workspace endpoint, every limit value also carries `source`, which says where `value` comes from: `{"type": "workspace"}` for an override stored on the workspace, or `{"type": "organization"}` for a value inherited from the organization. By default, the workspace endpoint returns overrides only, so `source.type` is always `workspace` there; inherited values appear when you pass `include_inherited=true`. See [Workspace rate limits](https://platform.claude.com/docs/en/manage-claude/rate-limits-api#workspace-rate-limits).
161161 
from line 478
478478 ```
479479</CodeGroup>
480480 
481If the model string doesn't match any group, the endpoint returns a 404 error. Any model your organization has access to matches its group. The `model` parameter is supported on the organization endpoint only; the workspace endpoint doesn't accept it.
481If the model string doesn’t match any group, the endpoint returns a 404 error. Any model your organization has access to matches its group. The `model` parameter is supported on the organization endpoint only; the workspace endpoint doesn’t accept it.
482482 
483483## Workspace rate limits
484484 
from line 493
493493For complete parameter details and response schemas, see the [Workspace Rate Limits API reference](https://platform.claude.com/docs/en/api/organization/workspaces/rate_limits/list).
494494 
495495<Tip>
496 To retrieve your organization's workspace IDs, use the [List Workspaces](https://platform.claude.com/docs/en/api/organization/workspaces/list) endpoint, or find them under [Workspaces in the Claude Console](https://platform.claude.com/settings/workspaces). List Workspaces includes the default workspace only when you pass `include_default=true`.
496 To retrieve your organization’s workspace IDs, use the [List Workspaces](https://platform.claude.com/docs/en/api/organization/workspaces/list) endpoint, or find them under [Workspaces in the Claude Console](https://platform.claude.com/settings/workspaces). List Workspaces includes the default workspace only when you pass `include_default=true`.
497497</Tip>
498498 
499499<CodeGroup>
from line 698
698698 
699699### Include inherited values
700700 
701To read a workspace's applicable limits in one request, add the optional `include_inherited` query parameter. It defaults to `false`; a value that isn't a Boolean returns a 400 error. With `include_inherited=true`:
701To read a workspace’s applicable limits in one request, add the optional `include_inherited` query parameter. It defaults to `false`; a value that isn’t a Boolean returns a 400 error. With `include_inherited=true`:
702702 
703703* `data` has one entry for each group that applies to the workspace and has an organization-level value, even if the workspace overrides none of it. A model group applies when the workspace can access at least one of its models.
704* Each entry's `limits[]` lists every limiter type the organization has a value for on that group, plus any type the workspace overrides. Each type appears once, with the workspace's override where one is stored and the organization's value otherwise, so one entry can mix the two.
705* Each value's `source` tells them apart: `{"type": "workspace"}` is a stored override, and `{"type": "organization"}` is an inherited value, where `value` equals `org_limit`.
704* Each entry’s `limits[]` lists every limiter type the organization has a value for on that group, plus any type the workspace overrides. Each type appears once, with the workspace’s override where one is stored and the organization’s value otherwise, so one entry can mix the two.
705* Each value’s `source` tells them apart: `{"type": "workspace"}` is a stored override, and `{"type": "organization"}` is an inherited value, where `value` equals `org_limit`.
706706 
707707<CodeGroup>
708708 ```bash cURL
from line 1099
10991099 
11001100### Which model strings appear in the `models` list?
11011101 
1102Every model ID and alias that counts against the group, including dated IDs (such as `claude-sonnet-4-5-20250929`) and undated aliases (such as `claude-sonnet-4-5`). Look up any model string you pass to the Messages API and you'll find it in exactly one `model_group` entry.
1102Every model ID and alias that counts against the group, including dated IDs (such as `claude-sonnet-4-5-20250929`) and undated aliases (such as `claude-sonnet-4-5`). Look up any model string you pass to the Messages API and you’ll find it in exactly one `model_group` entry.
11031103 
11041104The list covers the models your organization has access to, so it can differ among organizations.
11051105 
11061106### What does it mean if a group is missing from the workspace response?
11071107 
1108By 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.
1108By 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.
11091109 
11101110### Can I update rate limits with this API?
11111111 
1112**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. 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.
1112**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. 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.
11131113 
11141114**For an organization:** No. To request higher limits, see [Requesting higher limits](https://platform.claude.com/docs/en/api/rate-limits#requesting-higher-limits).
11151115 

manage-claude/spend-limits-api Changed · +36 / -36 lines

### List each member’s effective spend limit ### Temporarily raise a member’s spend limit during an incident ### Does setting a spend limit directly resolve a member’s pending increase request? ### List each member's effective spend limit ### Temporarily raise a member's spend limit during an incident ### Does setting a spend limit directly resolve a member's pending increase request?

from line 4
44description: Set a spend limit on each Claude Enterprise member, see where each member's spend limit is inherited from, and review or act on members' requests for a higher limit.
55---
66 
7The Spend Limits API lets you set a spend limit on each Claude Enterprise member, see where each member's spend limit is inherited from, and review or act on members' requests for a higher limit.
7The Spend Limits API lets you set a spend limit on each Claude Enterprise member, see where each member’s spend limit is inherited from, and review or act on members’ requests for a higher limit.
88 
99For per-user and time-bucketed usage and cost *reporting*, see [Analytics APIs](https://platform.claude.com/docs/en/manage-claude/analytics-api).
1010 
from line 24
2424 
2525| Resource | Endpoints | Use for |
2626| --------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- |
27| **Spend limits** | `GET /v1/organizations/spend_limits/effective`<br />`GET /v1/organizations/spend_limits/{spend_limit_id}`<br />`POST /v1/organizations/spend_limits`<br />`DELETE /v1/organizations/spend_limits/{spend_limit_id}` | Read each member's effective spend limit and period-to-date spend; set or clear a per-user override. |
28| **Spend limit increase requests** | `GET /v1/organizations/spend_limit_increase_requests`<br />`GET /v1/organizations/spend_limit_increase_requests/{id}`<br />`POST /v1/organizations/spend_limit_increase_requests/{id}/approve`<br />`POST /v1/organizations/spend_limit_increase_requests/{id}/deny` | List members' requests for a higher spend limit, with the context needed to decide; approve or deny each request. |
27| **Spend limits** | `GET /v1/organizations/spend_limits/effective`<br />`GET /v1/organizations/spend_limits/{spend_limit_id}`<br />`POST /v1/organizations/spend_limits`<br />`DELETE /v1/organizations/spend_limits/{spend_limit_id}` | Read each member’s effective spend limit and period-to-date spend; set or clear a per-user override. |
28| **Spend limit increase requests** | `GET /v1/organizations/spend_limit_increase_requests`<br />`GET /v1/organizations/spend_limit_increase_requests/{id}`<br />`POST /v1/organizations/spend_limit_increase_requests/{id}/approve`<br />`POST /v1/organizations/spend_limit_increase_requests/{id}/deny` | List members’ requests for a higher spend limit, with the context needed to decide; approve or deny each request. |
2929 
30Use the **spend limits** endpoints to answer "what spend limit applies to each member, where does it come from, and how close are they to it?" and to set a per-user override. Use the **spend limit increase requests** endpoints to work the queue of member-submitted requests.
30Use the **spend limits** endpoints to answer “what spend limit applies to each member, where does it come from, and how close are they to it?” and to set a per-user override. Use the **spend limit increase requests** endpoints to work the queue of member-submitted requests.
3131 
3232## Prerequisites
3333 
from line 38
3838 
3939## Quick start
4040 
41List every member's effective monthly spend limit and period-to-date spend:
41List every member’s effective monthly spend limit and period-to-date spend:
4242 
4343<CodeGroup>
4444 ```bash cURL
from line 174
174174 
175175### The spend limit hierarchy
176176 
177An **effective spend limit** applies to each member's spend, resolved from a hierarchy of scope levels. When a member has no per-user override, they inherit the spend limit configured for their group (if your organization uses group-based limits), their seat tier, or the organization-wide default. A group spend limit is a per-member default: each member inheriting it is gated against their own spend, not a pooled group budget.
177An **effective spend limit** applies to each member’s spend, resolved from a hierarchy of scope levels. When a member has no per-user override, they inherit the spend limit configured for their group (if your organization uses group-based limits), their seat tier, or the organization-wide default. A group spend limit is a per-member default: each member inheriting it is gated against their own spend, not a pooled group budget.
178178 
179179Reading `GET /v1/organizations/spend_limits/effective` returns every current member with their resolved effective spend limit, where that limit was resolved from (`source`), and their period-to-date spend. Setting a per-user override with `POST /v1/organizations/spend_limits` pins a member to a specific spend limit regardless of what they would otherwise inherit. Deleting the override returns them to the inherited spend limit (or leaves them unlimited if none exists).
180180 
181The `source` field on each member's row tells you which level their spend limit resolved from: `user` (a per-user override), `seat_tier`, `rbac_group`, or `organization`. Treat scope types as an open set; fall through on unknown values rather than failing.
181The `source` field on each member’s row tells you which level their spend limit resolved from: `user` (a per-user override), `seat_tier`, `rbac_group`, or `organization`. Treat scope types as an open set; fall through on unknown values rather than failing.
182182 
183183### Period
184184 
from line 186
186186 
187187### Amounts and currency
188188 
189All monetary values are strings in **minor units of the organization's billing currency** (cents, for USD). For example, `"50000"` represents $500.00 USD. Parse as a decimal and divide by 100 to display dollars; avoid binary floating-point for large values.
189All monetary values are strings in **minor units of the organization’s billing currency** (cents, for USD). For example, `"50000"` represents $500.00 USD. Parse as a decimal and divide by 100 to display dollars; avoid binary floating-point for large values.
190190 
191`amount` is **nullable**. In a member's effective row, `null` means **unlimited** (no spend limit) and `"0"` means the member cannot use Claude beyond their plan's included usage. On a configured spend-limit row (as returned by `GET /v1/organizations/spend_limits/{id}`), `null` only means no numeric spend limit is set; read the member's effective row to distinguish unlimited from included-usage-only.
191`amount` is **nullable**. In a member’s effective row, `null` means **unlimited** (no spend limit) and `"0"` means the member cannot use Claude beyond their plan’s included usage. On a configured spend-limit row (as returned by `GET /v1/organizations/spend_limits/{id}`), `null` only means no numeric spend limit is set; read the member’s effective row to distinguish unlimited from included-usage-only.
192192 
193`period_to_date_spend` is the member's spend accrued since the start of the current `period`, in the same minor-unit format; it might include a fractional part (for example, `"41280.125"`). It might read as `"0"` if the spend reading is temporarily unavailable; treat it as informational, not transactional.
193`period_to_date_spend` is the member’s spend accrued since the start of the current `period`, in the same minor-unit format; it might include a fractional part (for example, `"41280.125"`). It might read as `"0"` if the spend reading is temporarily unavailable; treat it as informational, not transactional.
194194 
195195### Increase request lifecycle
196196 
197A **spend limit increase request** is created when a member clicks **Request more usage** in claude.ai. Requests are not created through this API. A request's `status` is one of:
197A **spend limit increase request** is created when a member clicks **Request more usage** in claude.ai. Requests are not created through this API. A request’s `status` is one of:
198198 
199199| Status | Meaning |
200200| ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
201| `pending` | Awaiting admin action. The request normally carries a live `spend_summary` so you can see the member's current effective spend limit and period-to-date spend while deciding; `spend_summary` might be `null` if it could not be computed. |
202| `approved` | The request was resolved with approval: either an admin approved it explicitly, another admin action raised the member's spend limit, or Anthropic support raised a spend limit on the organization's behalf. `spend_summary` is `null`. |
203| `denied` | An admin declined. `spend_summary` is `null`. The member can send a new request right away; only a `pending` request blocks a new one. An admin can still raise the member's spend limit directly at any time. |
201| `pending` | Awaiting admin action. The request normally carries a live `spend_summary` so you can see the member’s current effective spend limit and period-to-date spend while deciding; `spend_summary` might be `null` if it could not be computed. |
202| `approved` | The request was resolved with approval: either an admin approved it explicitly, another admin action raised the member’s spend limit, or Anthropic support raised a spend limit on the organization’s behalf. `spend_summary` is `null`. |
203| `denied` | An admin declined. `spend_summary` is `null`. The member can send a new request right away; only a `pending` request blocks a new one. An admin can still raise the member’s spend limit directly at any time. |
204204 
205205Both `approved` and `denied` are terminal. A member has at most one `pending` request at a time.
206206 
from line 220
220220 
221221`GET /v1/organizations/spend_limits/effective` and `GET /v1/organizations/spend_limit_increase_requests` are paginated with an **opaque cursor**. The first request returns up to `limit` rows plus a `next_page` cursor; pass that cursor unchanged as the `page` parameter on the next request, and repeat until `next_page` is `null`.
222222 
223**Do not change query parameters mid-sequence.** Cursors are bound to the filters that issued them. If you change `user_ids[]`, `period[]`, `status[]`, or `actor_ids[]` and pass an old cursor, you'll get a 400 with *"cursor does not match current query parameters"*. Start a new sequence from the first page instead.
223**Do not change query parameters mid-sequence.** Cursors are bound to the filters that issued them. If you change `user_ids[]`, `period[]`, `status[]`, or `actor_ids[]` and pass an old cursor, you’ll get a 400 with *“cursor does not match current query parameters”*. Start a new sequence from the first page instead.
224224 
225225## Serializing list parameters
226226 
from line 236
236236 
237237## Spend limits
238238 
239### List each member's effective spend limit
239### List each member’s effective spend limit
240240 
241`GET /v1/organizations/spend_limits/effective` returns one row per current member, reflecting each member's effective spend limit, its `source` in the scope hierarchy, and their `period_to_date_spend`. Requires the `read:spend_limits` scope.
241`GET /v1/organizations/spend_limits/effective` returns one row per current member, reflecting each member’s effective spend limit, its `source` in the scope hierarchy, and their `period_to_date_spend`. Requires the `read:spend_limits` scope.
242242 
243243For complete parameter details and response schemas, see [List effective spend limits](https://platform.claude.com/docs/en/api/beta/organization/spend_limits/effective/list) in the API reference.
244244 
from line 843
843843 ```
844844</CodeGroup>
845845 
846Each pending request carries a live `spend_summary` showing the requester's current effective spend limit and period-to-date spend, enough to decide without a separate lookup.
846Each pending request carries a live `spend_summary` showing the requester’s current effective spend limit and period-to-date spend, enough to decide without a separate lookup.
847847 
848848### Get a single increase request
849849 
from line 1187
11871187 
11881188Some of these workflows combine the Spend Limits API with the [Analytics APIs](https://platform.claude.com/docs/en/manage-claude/analytics-api) cost endpoints. The Analytics cost endpoints are designed for organization-wide spend reporting across a date range. `GET /spend_limits/effective` returns the cap that currently applies to each member. Start a sweep with Analytics to discover which members to look at, then read their current caps with `/effective`.
11891189 
1190Spend Limits endpoints require the `spend_limits` scopes and Analytics cost endpoints require `read:analytics`; see [Analytics APIs](https://platform.claude.com/docs/en/manage-claude/analytics-api) for how to provision access. The examples use one Admin API key that has the scopes of every API they call. A primary owner [selects these scopes when creating the key](https://platform.claude.com/docs/en/manage-claude/admin-api-keys#choose-scopes-for-a-claude-enterprise-key). All monetary values on both are decimal strings in minor units (cents). Both APIs paginate with an opaque cursor. Set an explicit `limit` and page through `next_page` until it's `null` to cover the whole organization.
1190Spend Limits endpoints require the `spend_limits` scopes and Analytics cost endpoints require `read:analytics`; see [Analytics APIs](https://platform.claude.com/docs/en/manage-claude/analytics-api) for how to provision access. The examples use one Admin API key that has the scopes of every API they call. A primary owner [selects these scopes when creating the key](https://platform.claude.com/docs/en/manage-claude/admin-api-keys#choose-scopes-for-a-claude-enterprise-key). All monetary values on both are decimal strings in minor units (cents). Both APIs paginate with an opaque cursor. Set an explicit `limit` and page through `next_page` until it’s `null` to cover the whole organization.
11911191 
11921192### Automate the increase-request review flow
11931193 
1194Run a scheduled job that fetches pending requests, applies your organization's approval policy, and resolves each one.
1194Run a scheduled job that fetches pending requests, applies your organization’s approval policy, and resolves each one.
11951195 
119611961. List pending requests:
11971197 
from line 1307
13071307 ```
13081308 </CodeGroup>
13091309 
1310 Each request carries the requester's `actor.user_id` and a live `spend_summary` with their current effective `amount` and `period_to_date_spend`, enough to decide without a separate lookup.
1310 Each request carries the requester’s `actor.user_id` and a live `spend_summary` with their current effective `amount` and `period_to_date_spend`, enough to decide without a separate lookup.
13111311 
13122. Apply your policy. For example, auto-approve when the member's current `amount` is below a threshold, and route larger caps for manual review.
13122. Apply your policy. For example, auto-approve when the member’s current `amount` is below a threshold, and route larger caps for manual review.
13131313 
131413143. Resolve each request. To approve, supply the new cap:
13151315 
from line 1435
14351435 
14361436### Identify members close to their spend limit
14371437 
1438Find members approaching their cap so you can raise it before they're blocked.
1438Find members approaching their cap so you can raise it before they’re blocked.
14391439 
14401. Pull each member's month-to-date spend from the Analytics API (one row for each member, highest spend first by default):
14401. Pull each member’s month-to-date spend from the Analytics API (one row for each member, highest spend first by default):
14411441 
14421442 <CodeGroup>
14431443 ```bash cURL
from line 1556
15561556 ```
15571557 </CodeGroup>
15581558 
1559 Each row contains `actor.user_id`, `actor.email_address`, and `amount` (the member's spend in cents). Page through `next_page` to cover the whole organization.
1559 Each row contains `actor.user_id`, `actor.email_address`, and `amount` (the member’s spend in cents). Page through `next_page` to cover the whole organization.
15601560 
156115612. For the top spenders (or everyone above a dollar threshold), fetch effective caps in batches:
15621562 
from line 1854
18541854 ```
18551855 </CodeGroup>
18561856 
1857 With `bucket_width` set, each member spans one row for each day with usage. Page through `next_page` to collect every member's full series.
1857 With `bucket_width` set, each member spans one row for each day with usage. Page through `next_page` to collect every member’s full series.
18581858 
185918592. Group rows by `actor.user_id`. For each member, sum the most recent 7 days and the prior 7 days. Flag members whose recent week exceeds the prior week by your chosen multiple (for example, three). Recent-day cost is provisional and can be revised upward; for repeatable comparisons, set `ending_at` at or before a previously returned `data_refreshed_at` (see [Data availability and freshness](https://platform.claude.com/docs/en/manage-claude/analytics-api#data-availability-and-freshness)).
18601860 
186118613. Act on flagged members: adjust the cap with `POST /v1/organizations/spend_limits`, or contact the member.
18621862 
1863### Temporarily raise a member's spend limit during an incident
1863### Temporarily raise a member’s spend limit during an incident
18641864 
18651865Give an incident responder room to work while an incident is open: raise their spend cap when the incident starts, and roll it back after the incident closes. Gate the raise on your incident management system, for example, by requiring a live incident ID with the member assigned to it.
18661866 
18671. Read the member's current cap, and record it for the rollback:
18671. Read the member’s current cap, and record it for the rollback:
18681868 
18691869 <CodeGroup>
18701870 ```bash cURL
from line 2264
22642264 
22652265## Frequently asked questions
22662266 
2267### Does setting a spend limit directly resolve a member's pending increase request?
2267### Does setting a spend limit directly resolve a member’s pending increase request?
22682268 
22692269No. `POST /v1/organizations/spend_limits` writes the override but leaves the pending request untouched. Use `POST /v1/organizations/spend_limit_increase_requests/{id}/approve` to resolve the request and write the override in one call.
22702270 
22712271### What happens when I delete a per-user override?
22722272 
2273The member falls back to whatever they'd inherit from the hierarchy: their group, seat-tier, or organization default. If no default exists at any level, the member is unlimited.
2273The member falls back to whatever they’d inherit from the hierarchy: their group, seat-tier, or organization default. If no default exists at any level, the member is unlimited.
22742274 
22752275### Can I set a seat-tier or organization-wide default through this API?
22762276 

manage-claude/usage-cost-api Changed · +9 / -9 lines

### What’s the recommended polling frequency? ### What's the recommended polling frequency?

from line 16
1616* **Cost reconciliation:** Match internal records with Anthropic billing for finance and accounting teams
1717* **Product performance and improvement:** Monitor product performance while measuring if changes to the system have improved it, or set up alerting
1818* **[Rate limit](https://platform.claude.com/docs/en/api/rate-limits) optimization:** Optimize features such as [prompt caching](https://platform.claude.com/docs/en/build-with-claude/prompt-caching) or specific prompts to use your allocated capacity efficiently.
19* **Advanced analysis:** Perform deeper data analysis than what's available in Console
19* **Advanced analysis:** Perform deeper data analysis than what’s available in Console
2020 
2121<Check>
22 **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.
22 **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.
2323</Check>
2424 
2525Claude Enterprise organizations use an Analytics API key with a different API instead; see [Which API do you need?](https://platform.claude.com/docs/en/manage-claude/usage-cost-api#which-api-do-you-need).
from line 79
7979 
8080## Quick start
8181 
82Get your organization's daily usage for the last 7 days:
82Get your organization’s daily usage for the last 7 days:
8383 
8484```bash cURL
8585curl "https://api.anthropic.com/v1/organizations/usage_report/messages?\
from line 93
9393<Tip>
9494 **Set a User-Agent header for integrations**
9595 
96 If you're building an integration, set your User-Agent header to help Anthropic understand usage patterns:
96 If you’re building an integration, set your User-Agent header to help Anthropic understand usage patterns:
9797 
9898 ```text wrap
9999 User-Agent: YourApp/1.0.0 (https://yourapp.com)
from line 157
157157```
158158 
159159<Tip>
160 To retrieve your organization's API key IDs, use the [List API Keys](https://platform.claude.com/docs/en/api/organization/api_keys/list) endpoint.
160 To retrieve your organization’s API key IDs, use the [List API Keys](https://platform.claude.com/docs/en/api/organization/api_keys/list) endpoint.
161161 
162 To retrieve your organization's workspace IDs, use the [List Workspaces](https://platform.claude.com/docs/en/api/organization/workspaces/list) endpoint, or find your organization's workspace IDs in the Claude Console.
162 To retrieve your organization’s workspace IDs, use the [List Workspaces](https://platform.claude.com/docs/en/api/organization/workspaces/list) endpoint, or find your organization’s workspace IDs in the Claude Console.
163163</Tip>
164164 
165165#### Data residency
from line 191
191191```
192192 
193193<Note>
194 Models released before February 2026 (prior to Claude Opus 4.6 and Claude Sonnet 4.6) don't support the `inference_geo` request parameter, so their usage reports return `"not_available"` for this dimension. You can use `not_available` as a filter value in `inference_geos[]` to target those models.
194 Models released before February 2026 (prior to Claude Opus 4.6 and Claude Sonnet 4.6) don’t support the `inference_geo` request parameter, so their usage reports return `"not_available"` for this dimension. You can use `not_available` as a filter value in `inference_geos[]` to target those models.
195195</Note>
196196 
197197#### Fast mode
from line 304
304304 
305305Usage and cost data typically appears within 5 minutes of API request completion, though delays might occasionally be longer.
306306 
307### What's the recommended polling frequency?
307### What’s the recommended polling frequency?
308308 
309309The API supports polling once per minute for sustained use. For short bursts (for example, downloading paginated data), more frequent polling is acceptable. Cache results for dashboards that need frequent updates.
310310 

manage-claude/user-management Changed · +45 / -45 lines

### Change a member’s role ### List a group’s members ### List a role’s permissions ### Change a member's role ### List a group's members ### List a role's permissions

from line 7
77This page covers managing the people in your **Claude Enterprise** (claude.ai) organization programmatically, using the [Admin API](https://platform.claude.com/docs/en/api/beta/organization):
88 
99* List members and look them up by email address
10* Change a member's role
10* Change a member’s role
1111* Remove members
1212* Send and withdraw invites
13* Manage your enterprise's groups and their membership
14* Read your organization's custom roles
13* Manage your enterprise’s groups and their membership
14* Read your organization’s custom roles
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 
1818<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 still send it are accepted and behave identically.
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 still send it are accepted and behave identically.
2020</Note>
2121 
2222## Which endpoints can your organization use?
from line 47
4747 
4848| Resource | Endpoints | Use for |
4949| ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------- |
50| **Members** | `GET /v1/organizations/users`<br />`GET /v1/organizations/users/{user_id}`<br />`POST /v1/organizations/users/{user_id}`<br />`DELETE /v1/organizations/users/{user_id}` | List the organization's members or look one up by email; change a member's role; remove a member. |
51| **Invites** | `POST /v1/organizations/invites`<br />`GET /v1/organizations/invites`<br />`GET /v1/organizations/invites/{invite_id}`<br />`DELETE /v1/organizations/invites/{invite_id}` | Invite a person to the organization, track the invitation's status, and withdraw it before it is accepted. |
52| **Groups** | `GET /v1/organizations/rbac_groups`<br />`GET /v1/organizations/rbac_groups/{rbac_group_id}`<br />`POST /v1/organizations/rbac_groups`<br />`POST /v1/organizations/rbac_groups/{rbac_group_id}`<br />`DELETE /v1/organizations/rbac_groups/{rbac_group_id}` | Read your enterprise's groups and the custom roles attached to each; create, rename, and delete groups. |
53| **Group members** | `GET /v1/organizations/rbac_groups/{rbac_group_id}/members`<br />`POST /v1/organizations/rbac_groups/{rbac_group_id}/members`<br />`DELETE /v1/organizations/rbac_groups/{rbac_group_id}/members/{user_id}` | Read a group's members; add and remove members. |
54| **Custom roles** | `GET /v1/organizations/rbac_roles`<br />`GET /v1/organizations/rbac_roles/{rbac_role_id}`<br />`GET /v1/organizations/rbac_roles/{rbac_role_id}/permissions` | Read your organization's custom roles and the permissions each role grants. |
50| **Members** | `GET /v1/organizations/users`<br />`GET /v1/organizations/users/{user_id}`<br />`POST /v1/organizations/users/{user_id}`<br />`DELETE /v1/organizations/users/{user_id}` | List the organization’s members or look one up by email; change a member’s role; remove a member. |
51| **Invites** | `POST /v1/organizations/invites`<br />`GET /v1/organizations/invites`<br />`GET /v1/organizations/invites/{invite_id}`<br />`DELETE /v1/organizations/invites/{invite_id}` | Invite a person to the organization, track the invitation’s status, and withdraw it before it is accepted. |
52| **Groups** | `GET /v1/organizations/rbac_groups`<br />`GET /v1/organizations/rbac_groups/{rbac_group_id}`<br />`POST /v1/organizations/rbac_groups`<br />`POST /v1/organizations/rbac_groups/{rbac_group_id}`<br />`DELETE /v1/organizations/rbac_groups/{rbac_group_id}` | Read your enterprise’s groups and the custom roles attached to each; create, rename, and delete groups. |
53| **Group members** | `GET /v1/organizations/rbac_groups/{rbac_group_id}/members`<br />`POST /v1/organizations/rbac_groups/{rbac_group_id}/members`<br />`DELETE /v1/organizations/rbac_groups/{rbac_group_id}/members/{user_id}` | Read a group’s members; add and remove members. |
54| **Custom roles** | `GET /v1/organizations/rbac_roles`<br />`GET /v1/organizations/rbac_roles/{rbac_role_id}`<br />`GET /v1/organizations/rbac_roles/{rbac_role_id}/permissions` | Read your organization’s custom roles and the permissions each role grants. |
5555 
5656Custom roles and their group attachments are managed in [claude.ai organization settings](https://claude.ai/admin-settings); the API reads them but cannot change them.
5757 
from line 59
5959 
6060Set the `ANTHROPIC_API_KEY` environment variable to your Admin API key. The examples on this page read the key from it. The SDK and the `ant` CLI send the `Authorization` and `anthropic-version` headers for you.
6161 
62List the organization's members, newest first:
62List the organization’s members, newest first:
6363 
6464<CodeGroup>
6565 ```bash cURL
from line 178
178178 
179179### Organization roles
180180 
181Every member has exactly one organization role. Reads return the member's role as one of five values:
181Every member has exactly one organization role. Reads return the member’s role as one of five values:
182182 
183183| Role | Meaning |
184184| ------------------ | ----------------------------------------------------------------------------------------- |
from line 185
185185| `user` | A standard member. |
186186| `managed` | A member whose permissions are granted through the custom roles attached to their groups. |
187187| `owner` | An organization owner. |
188| `membership_admin` | A member who can manage the organization's members. |
189| `primary_owner` | The organization's primary owner. There is exactly one. |
188| `membership_admin` | A member who can manage the organization’s members. |
189| `primary_owner` | The organization’s primary owner. There is exactly one. |
190190 
191The API can assign only the `user` and `managed` roles, on invite creation and on role updates. Assigning `managed` requires the `write:rbac_groups` scope in addition to `write:members`, because a managed member's permissions come from the custom roles attached to their groups. The administrative roles (`owner`, `membership_admin`, and `primary_owner`) are assigned in claude.ai organization settings, and members holding them cannot be modified or removed through this API.
191The API can assign only the `user` and `managed` roles, on invite creation and on role updates. Assigning `managed` requires the `write:rbac_groups` scope in addition to `write:members`, because a managed member’s permissions come from the custom roles attached to their groups. The administrative roles (`owner`, `membership_admin`, and `primary_owner`) are assigned in claude.ai organization settings, and members holding them cannot be modified or removed through this API.
192192 
193193### Members and invites
194194 
195A person becomes a member by accepting an invite (or through your organization's single sign-on, where configured). Creating an invite sends an invitation email; the invite then reads as `pending` until the recipient accepts (`accepted`) or its server-assigned `expires_at` passes (`expired`). Only a `pending` invite can be withdrawn. To change a pending invitation's email address or role, withdraw it and create a new one.
195A person becomes a member by accepting an invite (or through your organization’s single sign-on, where configured). Creating an invite sends an invitation email; the invite then reads as `pending` until the recipient accepts (`accepted`) or its server-assigned `expires_at` passes (`expired`). Only a `pending` invite can be withdrawn. To change a pending invitation’s email address or role, withdraw it and create a new one.
196196 
197If your organization's plan draws members from a finite pool of purchased seats, a pending invite consumes a seat. The create-invite endpoint does not take a seat or tier parameter: the seat is assigned automatically from the lowest tier that has availability. Creating an invite when no seat is free fails with a 400 error rather than purchasing a seat. Withdrawing the invite, letting it expire, or removing the member later returns the seat to the pool.
197If your organization’s plan draws members from a finite pool of purchased seats, a pending invite consumes a seat. The create-invite endpoint does not take a seat or tier parameter: the seat is assigned automatically from the lowest tier that has availability. Creating an invite when no seat is free fails with a 400 error rather than purchasing a seat. Withdrawing the invite, letting it expire, or removing the member later returns the seat to the pool.
198198 
199199### Groups and roles
200200 
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.
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.
202202 
203203## Versioning
204204 
from line 210
210210 
211211## Pagination
212212 
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`.
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`.
214214 
215215When 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.
216216 
from line 222
222222 
223223### List members
224224 
225`GET /v1/organizations/users` returns the organization's members, most recently added first. Filter by `email` to look up a specific member; the match is case-insensitive and tolerates common variants of the same address (for example, `[email protected]` matches `[email protected]`). Requires the `read:members` scope.
225`GET /v1/organizations/users` returns the organization’s members, most recently added first. Filter by `email` to look up a specific member; the match is case-insensitive and tolerates common variants of the same address (for example, `[email protected]` matches `[email protected]`). Requires the `read:members` scope.
226226 
227227For complete parameter details and response schemas, see [List users](https://platform.claude.com/docs/en/api/organization/users/list) in the API reference.
228228 
from line 415
415415 ```
416416</CodeGroup>
417417 
418### Change a member's role
418### Change a member’s role
419419 
420`POST /v1/organizations/users/{user_id}` sets the member's role to `user` or `managed`. Members holding an administrative role (`owner`, `membership_admin`, or `primary_owner`) cannot be changed through this endpoint, and administrative roles cannot be assigned; both return 400 and are managed in claude.ai organization settings. If your organization's identity provider manages roles (advanced SSO or advanced SCIM provisioning), role updates return 400. Requires the `write:members` scope, plus `write:rbac_groups` when changing the role to `managed`.
420`POST /v1/organizations/users/{user_id}` sets the member’s role to `user` or `managed`. Members holding an administrative role (`owner`, `membership_admin`, or `primary_owner`) cannot be changed through this endpoint, and administrative roles cannot be assigned; both return 400 and are managed in claude.ai organization settings. If your organization’s identity provider manages roles (advanced SSO or advanced SCIM provisioning), role updates return 400. Requires the `write:members` scope, plus `write:rbac_groups` when changing the role to `managed`.
421421 
422422For complete parameter details and response schemas, see [Update user](https://platform.claude.com/docs/en/api/organization/users/update) in the API reference.
423423 
from line 534
534534 
535535### Remove a member
536536 
537`DELETE /v1/organizations/users/{user_id}` removes the member from the organization, returning any purchased seat they occupied to the organization's pool. Members holding an administrative role cannot be removed through this endpoint, and if your identity provider manages membership (SCIM), removals return 400. Requires the `write:members` scope.
537`DELETE /v1/organizations/users/{user_id}` removes the member from the organization, returning any purchased seat they occupied to the organization’s pool. Members holding an administrative role cannot be removed through this endpoint, and if your identity provider manages membership (SCIM), removals return 400. Requires the `write:members` scope.
538538 
539539For complete parameter details and response schemas, see [Remove user](https://platform.claude.com/docs/en/api/organization/users/remove) in the API reference.
540540 
from line 626
626626 
627627`POST /v1/organizations/invites` sends an invitation email and returns the invite with a server-assigned `expires_at`. `role` must be `user` or `managed`. If a pending invite already exists for the email address, or the address already belongs to a member, the request returns 400 naming the existing resource. Organizations whose identity provider provisions users automatically (JIT or SCIM) cannot create invites through the API. Requires the `write:members` scope, plus `write:rbac_groups` when `role` is `managed`.
628628 
629On plans that draw members from a finite seat pool, the invite automatically takes a seat from the lowest tier that has availability. The API does not take a tier parameter. If no seat is free, the request fails with a 400 error rather than purchasing a seat. Add seats through the organization's plan management and retry.
629On plans that draw members from a finite seat pool, the invite automatically takes a seat from the lowest tier that has availability. The API does not take a tier parameter. If no seat is free, the request fails with a 400 error rather than purchasing a seat. Add seats through the organization’s plan management and retry.
630630 
631The optional `rbac_group_ids` field lists groups (by `rbac_group_`-prefixed ID) to assign to the member when they accept. Passing a non-empty `rbac_group_ids` additionally requires the key to carry the `write:rbac_groups` scope, because group assignment can grant the permissions attached to the group's roles.
631The optional `rbac_group_ids` field lists groups (by `rbac_group_`-prefixed ID) to assign to the member when they accept. Passing a non-empty `rbac_group_ids` additionally requires the key to carry the `write:rbac_groups` scope, because group assignment can grant the permissions attached to the group’s roles.
632632 
633633For complete parameter details and response schemas, see [Create invite](https://platform.claude.com/docs/en/api/organization/invites/create) in the API reference.
634634 
from line 789
789789 
790790### List invites
791791 
792`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.
792`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.
793793 
794794For complete parameter details and response schemas, see [List invites](https://platform.claude.com/docs/en/api/organization/invites/list) in the API reference.
795795 
from line 1071
10711071 
10721072### List groups
10731073 
1074`GET /v1/organizations/rbac_groups` returns your enterprise's groups, including identity-provider-managed (`scim`) groups. Requires the `read:rbac_groups` scope.
1074`GET /v1/organizations/rbac_groups` returns your enterprise’s groups, including identity-provider-managed (`scim`) groups. Requires the `read:rbac_groups` scope.
10751075 
10761076For complete parameter details and response schemas, see [List groups](https://platform.claude.com/docs/en/api/beta/organization/rbac_groups/list) in the API reference.
10771077 
from line 1611
16111611}
16121612```
16131613 
1614### List a group's members
1614### List a group’s members
16151615 
1616`GET /v1/organizations/rbac_groups/{rbac_group_id}/members` returns the group's members (each with their `user_id` and email), oldest first. Only current members of your enterprise's organizations are returned, so a page might contain fewer than `limit` entries while `has_more` is `true`. Requires the `read:rbac_groups` scope.
1616`GET /v1/organizations/rbac_groups/{rbac_group_id}/members` returns the group’s members (each with their `user_id` and email), oldest first. Only current members of your enterprise’s organizations are returned, so a page might contain fewer than `limit` entries while `has_more` is `true`. Requires the `read:rbac_groups` scope.
16171617 
16181618For complete parameter details and response schemas, see [List group members](https://platform.claude.com/docs/en/api/beta/organization/rbac_groups/members/list) in the API reference.
16191619 
from line 1750
17501750 
17511751### Add a member to a group
17521752 
1753`POST /v1/organizations/rbac_groups/{rbac_group_id}/members` adds an organization member to the group by `user_id`. The user must already be a member of one of your enterprise's organizations (the request returns 404 otherwise), and adding someone who is already in the group returns 400. For `scim` groups, membership is managed in your identity provider and this request returns 400. To assign groups to a person who has not joined yet, use `rbac_group_ids` on [invite creation](https://platform.claude.com/docs/en/manage-claude/user-management#create-an-invite) instead. Requires the `write:rbac_groups` scope.
1753`POST /v1/organizations/rbac_groups/{rbac_group_id}/members` adds an organization member to the group by `user_id`. The user must already be a member of one of your enterprise’s organizations (the request returns 404 otherwise), and adding someone who is already in the group returns 400. For `scim` groups, membership is managed in your identity provider and this request returns 400. To assign groups to a person who has not joined yet, use `rbac_group_ids` on [invite creation](https://platform.claude.com/docs/en/manage-claude/user-management#create-an-invite) instead. Requires the `write:rbac_groups` scope.
17541754 
17551755For complete parameter details and response schemas, see [Add group member](https://platform.claude.com/docs/en/api/beta/organization/rbac_groups/members/add) in the API reference.
17561756 
from line 1995
19951995 
19961996## Custom roles
19971997 
1998Custom roles are read-only through the API: these endpoints catalog your organization's custom roles (defined in [claude.ai organization settings](https://claude.ai/admin-settings) or provisioned by Anthropic) and the permissions each role grants. Custom-role reads use the `read:members` scope (there is no separate role scope) and work with an organization-level key: unlike the group endpoints, they do not require a key created for all linked organizations, and the catalog returned is your organization's own.
1998Custom roles are read-only through the API: these endpoints catalog your organization’s custom roles (defined in [claude.ai organization settings](https://claude.ai/admin-settings) or provisioned by Anthropic) and the permissions each role grants. Custom-role reads use the `read:members` scope (there is no separate role scope) and work with an organization-level key: unlike the group endpoints, they do not require a key created for all linked organizations, and the catalog returned is your organization’s own.
19991999 
2000Read a role's name from its `display_name` field. For a role provisioned by Anthropic, `display_name` can differ from the label claude.ai shows, and Anthropic might change the name. To keep a lasting reference to a role, store its `id`.
2000Read a role’s name from its `display_name` field. For a role provisioned by Anthropic, `display_name` can differ from the label claude.ai shows, and Anthropic might change the name. To keep a lasting reference to a role, store its `id`.
20012001 
20022002### List roles
20032003 
2004`GET /v1/organizations/rbac_roles` returns your organization's custom roles. Requires the `read:members` scope.
2004`GET /v1/organizations/rbac_roles` returns your organization’s custom roles. Requires the `read:members` scope.
20052005 
20062006For complete parameter details and response schemas, see [List roles](https://platform.claude.com/docs/en/api/beta/organization/rbac_roles/list) in the API reference.
20072007 
from line 2208
22082208 ```
22092209</CodeGroup>
22102210 
2211### List a role's permissions
2211### List a role’s permissions
22122212 
2213`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.
2213`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.
22142214 
22152215Two `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) 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.
22162216 
from line 2463
24632463 
24642464### Audit group membership
24652465 
24661. List groups and record each group's `id`, `name`, and `role_ids`.
24661. List groups and record each group’s `id`, `name`, and `role_ids`.
24672467 
24682. For each group that carries sensitive roles, page through `GET /v1/organizations/rbac_groups/{rbac_group_id}/members` and compare the member emails against your identity provider's roster.
24682. For each group that carries sensitive roles, page through `GET /v1/organizations/rbac_groups/{rbac_group_id}/members` and compare the member emails against your identity provider’s roster.
24692469 
247024703. Remove members who should no longer be in the group with `DELETE /v1/organizations/rbac_groups/{rbac_group_id}/members/{user_id}`. For `scim` groups, make the change in your identity provider instead.
24712471 
2472For a workflow that combines group membership with a temporary spend limit raise, see [Temporarily raise a member's spend limit during an incident](https://platform.claude.com/docs/en/manage-claude/spend-limits-api#temporarily-raise-a-members-spend-limit-during-an-incident) on the Spend Limits API page.
2472For a workflow that combines group membership with a temporary spend limit raise, see [Temporarily raise a member’s spend limit during an incident](https://platform.claude.com/docs/en/manage-claude/spend-limits-api#temporarily-raise-a-members-spend-limit-during-an-incident) on the Spend Limits API page.
24732473 
24742474## Frequently asked questions
24752475 

manage-claude/user-profiles Changed · +59 / -57 lines

from line 4
44description: Attribute API requests to the end customers your platform serves, so a safety enforcement action can apply to one profile instead of your whole organization.
55---
66 
7User profiles ("profiles") tell Anthropic which of your end customers each API request is for. A safety enforcement action, such as a restriction or a ban, can then apply to one end customer instead of your whole organization. When it does, the rest of your traffic is unaffected.
7User profiles (“profiles”) tell Anthropic which of your end customers each API request is for. A safety enforcement action, such as a restriction or a ban, can then apply to one end customer instead of your whole organization. When it does, the rest of your traffic is unaffected.
88 
99If you operate a platform or gateway, or resell API access, the requests you send for your end customers arrive under your organization. Anthropic runs automated safety classifiers over API traffic. Without a profile on the request, one end customer can trigger an enforcement action that applies to your whole organization.
1010 
11You register each end customer once with `POST /v1/user_profiles` and store the `uprof_` ID it returns. Then you send that ID in the `anthropic-user-profile-id` header on every request you make on that end customer's behalf.
11You register each end customer once with `POST /v1/user_profiles` and store the `uprof_` ID it returns. Then you send that ID in the `anthropic-user-profile-id` header on every request you make on that end customer’s behalf.
1212 
13Profiles aren't billable and don't affect pricing.
13Profiles aren’t billable and don’t affect pricing.
1414 
1515## Decide who gets a profile
1616 
17What a profile stands for depends on how you sell Claude: a person who uses your product, or a company you resell API access to. These two cases cover most platforms. The profile's `access_type` field says which one applies.
17What a profile stands for depends on how you sell Claude: a person who uses your product, or a company you resell API access to. These two cases cover most platforms. The profile’s `access_type` field says which one applies.
1818 
1919| Who the traffic is for | Profile | `access_type` |
2020| ------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------- |
from line 25
2525 
2626## What a profile contains and how Anthropic uses it
2727 
28A profile contains only what you send about the end customer, plus any [program status](https://platform.claude.com/docs/en/manage-claude/user-profiles-verification-portal#after-the-end-customer-links-the-profile) or enforcement status that Anthropic sets. It doesn't contain conversation content. Anthropic uses the details you send to attribute requests, to monitor for abuse, for enforcement of the [Usage Policy](https://www.anthropic.com/legal/aup), and to enable application and access to trusted access programs. Anthropic doesn't verify the details.
28A profile contains only what you send about the end customer, plus any [program status](https://platform.claude.com/docs/en/manage-claude/user-profiles-verification-portal#after-the-end-customer-links-the-profile) or enforcement status that Anthropic sets. It doesn’t contain conversation content. Anthropic uses the details you send to attribute requests, to monitor for abuse, for enforcement of the [Usage Policy](https://www.anthropic.com/legal/aup), and to enable application and access to trusted access programs. Anthropic doesn’t verify the details.
2929 
3030Anthropic processes profiles in accordance with the [Privacy Policy](https://www.anthropic.com/legal/privacy).
3131 
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.
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.
39* 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.
3940 
40Amazon Bedrock and Claude Models on Google Cloud (Google managed) 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 Amazon Bedrock and Claude Models on Google Cloud (Google managed)](https://platform.claude.com/docs/en/manage-claude/user-profiles#attribute-requests-on-amazon-bedrock-and-google-cloud).
41Amazon Bedrock and Claude Models on Google Cloud (Google managed) 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 Amazon Bedrock and Claude Models on Google Cloud (Google managed)](https://platform.claude.com/docs/en/manage-claude/user-profiles#attribute-requests-on-amazon-bedrock-and-google-cloud).
4142 
42Keep 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.
43Keep 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.
4344 
44The 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.
45The 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.
4546 
4647## Create a profile for each end customer
4748 
48Create one profile for each end customer whose traffic you send to Claude. Create it once, in your customer-onboarding flow. `POST /v1/user_profiles` isn't idempotent, so every call creates a new profile, even when `reference_id` matches an existing one. If you already have end customers without profiles, see the guidance on registering an existing customer base later in this section.
49Create one profile for each end customer whose traffic you send to Claude. Create it once, in your customer-onboarding flow. `POST /v1/user_profiles` isn’t idempotent, so every call creates a new profile, even when `reference_id` matches an existing one. If you already have end customers without profiles, see the guidance on registering an existing customer base later in this section.
4950 
5051The following example registers a company that buys API access through a gateway, so it sets `access_type` to `passthrough`. For an `application` profile, leave out `access_type`, and describe one end user in `name` and `external_user_details` instead of a company. [Decide who gets a profile](https://platform.claude.com/docs/en/manage-claude/user-profiles#decide-who-gets-a-profile) compares the two access types.
5152 
from line 207
206207}
207208```
208209 
209Store the `id` on your customer record, and have your service instances read it from there instead of creating their own profile. You retrieve, update, and delete a profile by that `id`. The `programs` field is read-only, and attribution doesn't use it. It holds the end customer's status in each program that Anthropic runs. For what its values mean, see [which programs apply to a profile](https://platform.claude.com/docs/en/manage-claude/user-profiles-verification-portal#after-the-end-customer-links-the-profile). [Check whether Anthropic has restricted or banned a profile](https://platform.claude.com/docs/en/manage-claude/user-profiles#check-whether-anthropic-has-restricted-or-banned-a-profile) explains the `enforcement_status` and `enforcement_actions` fields.
210Store the `id` on your customer record, and have your service instances read it from there instead of creating their own profile. You retrieve, update, and delete a profile by that `id`. The `programs` field is read-only, and attribution doesn’t use it. It holds the end customer’s status in each program that Anthropic runs. For what its values mean, see [which programs apply to a profile](https://platform.claude.com/docs/en/manage-claude/user-profiles-verification-portal#after-the-end-customer-links-the-profile). [Check whether Anthropic has restricted or banned a profile](https://platform.claude.com/docs/en/manage-claude/user-profiles#check-whether-anthropic-has-restricted-or-banned-a-profile) explains the `enforcement_status` and `enforcement_actions` fields.
210211 
211There's no cap on the number of profiles in an organization, but profile creation is rate limited. Before you register an existing customer base in bulk, contact your Anthropic account team.
212There’s no cap on the number of profiles in an organization, but profile creation is rate limited. Before you register an existing customer base in bulk, contact your Anthropic account team.
212213 
213214### What to tell Anthropic about an end customer
214215 
from line 217
216217 
217218Follow these rules when you set the fields:
218219 
219* **Unknown values:** If you don't know a value, leave it out instead of sending a placeholder. You can replace a value in `external_user_details` later, but you can't clear it.
220* **Company names:** For a `passthrough` profile, send the company's legal name in `name` if you know it.
221* **Country:** In `country`, send the end customer's country, not yours.
222* **Your own ID:** In `reference_id`, send your own stable identifier for the end customer. It doesn't have to be unique.
223* **Names and email addresses you can't share:** Leave out `name` and send `external_user_details.name_hash` instead. For the email address, send `external_user_details.email_hash`. A profile has no field for the address itself.
220* **Unknown values:** If you don’t know a value, leave it out instead of sending a placeholder. You can replace a value in `external_user_details` later, but you can’t clear it.
221* **Company names:** For a `passthrough` profile, send the company’s legal name in `name` if you know it.
222* **Country:** In `country`, send the end customer’s country, not yours.
223* **Your own ID:** In `reference_id`, send your own stable identifier for the end customer. It doesn’t have to be unique.
224* **Names and email addresses you can’t share:** Leave out `name` and send `external_user_details.name_hash` instead. For the email address, send `external_user_details.email_hash`. A profile has no field for the address itself.
224225* **Hashes:** Compute the hashes yourself, with a function you choose. They show Anthropic which of your profiles share a name or an email address. Use the same function and the same case and whitespace normalization for every profile, because only values computed the same way match.
225226 
226227## Attribute each request
227228 
228Send the profile ID in the `anthropic-user-profile-id` header on every request you make on the end customer's behalf. The SDK and the CLI have an argument that sends the header for you: `user_profile_id` (java: `userProfileId`; php: `userProfileID`; csharp, go: `UserProfileID`; cli: `--user-profile-id`).
229Send the profile ID in the `anthropic-user-profile-id` header on every request you make on the end customer’s behalf. The SDK and the CLI have an argument that sends the header for you: `user_profile_id` (java: `userProfileId`; php: `userProfileID`; csharp, go: `UserProfileID`; cli: `--user-profile-id`).
229230 
230231<CodeGroup>
231232 ```bash cURL
from line 359
358359 
359360The 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.
360361 
361The Claude API, Claude Platform on AWS, 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`.
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`.
362363 
363Message 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`.
364Message 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`.
364365 
365366### Attribute requests on Amazon Bedrock and Claude Models on Google Cloud (Google managed)
366367 
367A profile ID of either access type also works on [Claude in Amazon Bedrock](https://platform.claude.com/docs/en/build-with-claude/claude-in-amazon-bedrock) and on Claude Models on Google Cloud (Google managed). 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.
368A profile ID of either access type also works on [Claude in Amazon Bedrock](https://platform.claude.com/docs/en/build-with-claude/claude-in-amazon-bedrock) and on Claude Models on Google Cloud (Google managed). 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.
368369 
369| Platform | Create profiles | Send the profile ID in |
370| ---------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------ | ------------------------------------------- |
371| Claude API | Yes | `anthropic-user-profile-id` header |
372| [Claude Platform on AWS](https://platform.claude.com/docs/en/build-with-claude/claude-platform-on-aws) | Yes | `anthropic-user-profile-id` header |
373| [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 |
374| [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 |
375| [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 |
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 |
376378 
377379On Claude in Amazon Bedrock, put the ID at the top level of the request body:
378380 
from line 393
3913932. Someone who can manage IAM in the AWS account or Google Cloud project runs a command that the portal provides.
3923943. The admin or owner completes the verification in the portal.
393395 
394Programs that apply to a profile apply to an account's requests only after the account is linked and the portal shows it as **Linked**. Those programs include the ones an end customer's organization is approved for after the end customer [links the profile to that organization](https://platform.claude.com/docs/en/manage-claude/user-profiles-verification-portal) and, for Cyber Verification Program access levels, turns them on for the profile in the portal.
396Programs that apply to a profile apply to an account’s requests only after the account is linked and the portal shows it as **Linked**. Those programs include the ones an end customer’s organization is approved for after the end customer [links the profile to that organization](https://platform.claude.com/docs/en/manage-claude/user-profiles-verification-portal) and, for Cyber Verification Program access levels, turns them on for the profile in the portal.
395397 
396Claude in Amazon Bedrock and Claude Models on Google Cloud (Google managed) check the format of the ID but don't look the profile up. They reject a malformed ID with a `400`. They accept any well-formed ID, so a successful response doesn't confirm that the ID matches a profile. A request with no ID goes through unattributed, and if it triggers an enforcement action, the action applies to your whole organization.
398Claude in Amazon Bedrock and Claude Models on Google Cloud (Google managed) check the format of the ID but don’t look the profile up. They reject a malformed ID with a `400`. They accept any well-formed ID, so a successful response doesn’t confirm that the ID matches a profile. A request with no ID goes through unattributed, and if it triggers an enforcement action, the action applies to your whole organization.
397399 
398400### Identify individual users within a company
399401 
400A `passthrough` profile identifies a company, not the person making the request. If a request comes from one identifiable person, also send an identifier for that person in the [`metadata.user_id`](https://platform.claude.com/docs/en/api/messages/create) field of the Messages request. This is the request's own `metadata` object, not the profile's `metadata` field. The identifier is optional, and it helps Anthropic detect misuse by one person.
402A `passthrough` profile identifies a company, not the person making the request. If a request comes from one identifiable person, also send an identifier for that person in the [`metadata.user_id`](https://platform.claude.com/docs/en/api/messages/create) field of the Messages request. This is the request’s own `metadata` object, not the profile’s `metadata` field. The identifier is optional, and it helps Anthropic detect misuse by one person.
401403 
402404## Check whether Anthropic has restricted or banned a profile
403405 
404A profile's `enforcement_status` and `enforcement_actions` fields report the enforcement actions that Anthropic has open on the end customer. An enforcement action is a restriction or a ban. Every response that returns a profile includes both fields: create, retrieve, update, and each profile in a list. Send these requests with no `user-profiles-` value in the `anthropic-beta` header, because `user-profiles-2026-09-04` and earlier values leave the fields out. The following example shows the fields on a retrieved profile, with the other fields left out:
406A profile’s `enforcement_status` and `enforcement_actions` fields report the enforcement actions that Anthropic has open on the end customer. An enforcement action is a restriction or a ban. Every response that returns a profile includes both fields: create, retrieve, update, and each profile in a list. Send these requests with no `user-profiles-` value in the `anthropic-beta` header, because `user-profiles-2026-09-04` and earlier values leave the fields out. The following example shows the fields on a retrieved profile, with the other fields left out:
405407 
406408```json
407409{
from line 429
427429* `restricted`: At least one action is open and none of them is a ban.
428430* `banned`: A ban is open.
429431 
430While an action is open, Anthropic refuses some or all inference requests that carry the profile's ID.
432While an action is open, Anthropic refuses some or all inference requests that carry the profile’s ID.
431433 
432434`enforcement_actions` lists the open actions and is empty when there are none. An action that ends leaves the list. Each action has these fields:
433435 
434436* `type`: `restriction` or `ban`.
435* `id`: The action's ID, which starts with `enac_`.
436* `reason`: Why Anthropic opened the action. It's one of `unsupported_region`, `fraud_or_abuse`, `high_harm`, `usage_policy_violation`, `account_compromise`, or `unspecified`.
437* `action`: What the end customer can do to clear the action, or `null` when there's nothing they can do.
437* `id`: The action’s ID, which starts with `enac_`.
438* `reason`: Why Anthropic opened the action. It’s one of `unsupported_region`, `fraud_or_abuse`, `high_harm`, `usage_policy_violation`, `account_compromise`, or `unspecified`.
439* `action`: What the end customer can do to clear the action, or `null` when there’s nothing they can do.
438440* `opened_at`: When Anthropic opened the action.
439441* `expires_at`: When the action ends by itself, or `null` when it has no end date.
440442 
441To check a profile, retrieve it with [`GET /v1/user_profiles/{id}`](https://platform.claude.com/docs/en/api/user_profiles/retrieve). To find the profiles that have an open action, [list your profiles](https://platform.claude.com/docs/en/api/user_profiles/list) with `enforcement_status[]=restricted` and `enforcement_status[]=banned`. To get an event when an action opens or ends, see [Organization webhooks](https://platform.claude.com/docs/en/manage-claude/organization-webhooks). Without events, compare both fields with the values you last saw. A change doesn't reliably move `updated_at`.
443To check a profile, retrieve it with [`GET /v1/user_profiles/{id}`](https://platform.claude.com/docs/en/api/user_profiles/retrieve). To find the profiles that have an open action, [list your profiles](https://platform.claude.com/docs/en/api/user_profiles/list) with `enforcement_status[]=restricted` and `enforcement_status[]=banned`. To get an event when an action opens or ends, see [Organization webhooks](https://platform.claude.com/docs/en/manage-claude/organization-webhooks). Without events, compare both fields with the values you last saw. A change doesn’t reliably move `updated_at`.
442444 
443445Anthropic sets both fields. If a create or update request includes either one, the API returns a `400`. `enforcement_status` is separate from `external_user_details.account_status`, which records your own decision about the account.
444446 
445Anthropic can add values. Treat an `enforcement_status` you don't recognize as `restricted`, a `type` you don't recognize as `restriction`, a `reason` you don't recognize as `unspecified`, and an `action` you don't recognize as `null`.
447Anthropic can add values. Treat an `enforcement_status` you don’t recognize as `restricted`, a `type` you don’t recognize as `restriction`, a `reason` you don’t recognize as `unspecified`, and an `action` you don’t recognize as `null`.
446448 
447On Claude Platform on AWS, the two fields don't report enforcement actions: `enforcement_status` is always `unrestricted`, and `enforcement_actions` is always empty. Anthropic doesn't refuse requests there because of an open action.
449On Claude Platform on AWS, the two fields don’t report enforcement actions: `enforcement_status` is always `unrestricted`, and `enforcement_actions` is always empty. Anthropic doesn’t refuse requests there because of an open action.
448450 
449451## Keep profiles current
450452 
451Update a profile when the end customer's details or account status change, and delete it when they close their account or ask you to erase their data.
453Update a profile when the end customer’s details or account status change, and delete it when they close their account or ask you to erase their data.
452454 
453455### Update a profile
454456 
from line 457
455457[`POST /v1/user_profiles/{id}`](https://platform.claude.com/docs/en/api/user_profiles/update) changes only the fields you send. For example, use it when a company rebrands or you suspend an account.
456458 
457459* `name` and `access_type` replace the stored value.
458* Each field you send in `external_user_details` replaces the stored value. You can't clear a value. The API rejects `null` with a `400`.
460* Each field you send in `external_user_details` replaces the stored value. You can’t clear a value. The API rejects `null` with a `400`.
459461* `metadata` merges key by key. A key you send overwrites the stored value, an empty string deletes the key, and keys you leave out stay as they are.
460462 
461463The following example marks the account as suspended and deletes a `trial_cohort` metadata key.
from line 590
588590 
589591### Delete a profile
590592 
591[`DELETE /v1/user_profiles/{id}`](https://platform.claude.com/docs/en/api/user_profiles/delete) permanently deletes a profile and everything you supplied for it, including `name`, `external_user_details`, and `metadata`. It doesn't remove the trust and safety records that Anthropic keeps about that profile ID.
593[`DELETE /v1/user_profiles/{id}`](https://platform.claude.com/docs/en/api/user_profiles/delete) permanently deletes a profile and everything you supplied for it, including `name`, `external_user_details`, and `metadata`. It doesn’t remove the trust and safety records that Anthropic keeps about that profile ID.
592594 
593Delete a profile when an end customer closes their account or asks you to erase their data. Before you delete a profile, stop sending its ID on that end customer's requests. If the end customer stays with you after an erasure request, create a new profile and switch to its ID. Then delete the old one.
595Delete a profile when an end customer closes their account or asks you to erase their data. Before you delete a profile, stop sending its ID on that end customer’s requests. If the end customer stays with you after an erasure request, create a new profile and switch to its ID. Then delete the old one.
594596 
595597<CodeGroup>
596598 ```bash cURL
from line 673
671673 
672674The response repeats the ID with `"type": "user_profile_deleted"`. If a delete returns a server error, retry it. A `404` on the retry means the first delete went through.
673675 
674After a delete, the profile endpoints return a `404` for that ID. For up to about 10 minutes, inference requests that carry the deleted ID can still succeed. After that, the platforms that check the ID on every request reject the request with a `400`. Claude in Amazon Bedrock and Claude Models on Google Cloud (Google managed) don't look profiles up, so they still accept it.
676After a delete, the profile endpoints return a `404` for that ID. For up to about 10 minutes, inference requests that carry the deleted ID can still succeed. After that, the platforms that check the ID on every request reject the request with a `400`. Claude in Amazon Bedrock and Claude Models on Google Cloud (Google managed) don’t look profiles up, so they still accept it.
675677 
676678## Next steps
677679 
678The API reference has each endpoint's fields, types, and limits: [Create a profile](https://platform.claude.com/docs/en/api/user_profiles/create), [Retrieve a profile](https://platform.claude.com/docs/en/api/user_profiles/retrieve), [Update a profile](https://platform.claude.com/docs/en/api/user_profiles/update), [Delete a profile](https://platform.claude.com/docs/en/api/user_profiles/delete), and [List profiles](https://platform.claude.com/docs/en/api/user_profiles/list).
680The API reference has each endpoint’s fields, types, and limits: [Create a profile](https://platform.claude.com/docs/en/api/user_profiles/create), [Retrieve a profile](https://platform.claude.com/docs/en/api/user_profiles/retrieve), [Update a profile](https://platform.claude.com/docs/en/api/user_profiles/update), [Delete a profile](https://platform.claude.com/docs/en/api/user_profiles/delete), and [List profiles](https://platform.claude.com/docs/en/api/user_profiles/list).
679681 
680If an end customer's program approvals should apply when they use Claude through your platform, see [Send an end customer a link to the Verification Portal](https://platform.claude.com/docs/en/manage-claude/user-profiles-verification-portal).
682If an end customer’s program approvals should apply when they use Claude through your platform, see [Send an end customer a link to the Verification Portal](https://platform.claude.com/docs/en/manage-claude/user-profiles-verification-portal).
681683 
682684To get an event when Anthropic restricts or bans one of your end customers, or when the restriction or ban ends, see [Organization webhooks](https://platform.claude.com/docs/en/manage-claude/organization-webhooks).
683685 

manage-claude/user-profiles-verification-portal Changed · +18 / -18 lines

from line 4
44description: Create an enrollment link for a user profile, see what your end customer does in the Verification Portal, and check which programs apply to the profile afterward.
55---
66 
7Anthropic runs programs that an organization can apply to in the Verification Portal. For an end customer's approvals to apply when they use Claude through your platform, the end customer links their user profile to their own Anthropic organization in the portal. You start the process: create an enrollment link for the profile and give it to the end customer.
7Anthropic runs programs that an organization can apply to in the Verification Portal. For an end customer’s approvals to apply when they use Claude through your platform, the end customer links their user profile to their own Anthropic organization in the portal. You start the process: create an enrollment link for the profile and give it to the end customer.
88 
99A user profile tells Anthropic which of your end customers each API request is for. You create one for each end customer and send its `uprof_` ID on every request you make for them. The profile must exist before you can create a link for it. To create one, see [User profiles for end-customer attribution](https://platform.claude.com/docs/en/manage-claude/user-profiles).
1010 
11You can skip this page if you need only attribution, or if creating enrollment links isn't enabled for your organization.
11You can skip this page if you need only attribution, or if creating enrollment links isn’t enabled for your organization.
1212 
1313## Create the link
1414 
15To create an enrollment link for a profile, call [`POST /v1/user_profiles/{id}/action_urls`](https://platform.claude.com/docs/en/api/user_profiles/action_urls/create) with the profile's ID in the path. In the request body, set `action.type` to `enroll_end_user`.
15To create an enrollment link for a profile, call [`POST /v1/user_profiles/{id}/action_urls`](https://platform.claude.com/docs/en/api/user_profiles/action_urls/create) with the profile’s ID in the path. In the request body, set `action.type` to `enroll_end_user`.
1616 
17The call returns a `404` if creating enrollment links isn't enabled for your organization. That's the same status as for a profile ID it can't find, so check the ID first.
17The call returns a `404` if creating enrollment links isn’t enabled for your organization. That’s the same status as for a profile ID it can’t find, so check the ID first.
1818 
1919<CodeGroup>
2020 ```bash cURL
from line 135
135135}
136136```
137137 
138The link works until the time in `expires_at`, about an hour after you create it. Create it when the end customer asks for it, for example when they click a button in your product, not ahead of time in an email they might read later. They can open the link more than once until it expires. If it has expired, create a new one: each call returns a fresh link. Creating a new link doesn't cancel earlier ones.
138The link works until the time in `expires_at`, about an hour after you create it. Create it when the end customer asks for it, for example when they click a button in your product, not ahead of time in an email they might read later. They can open the link more than once until it expires. If it has expired, create a new one: each call returns a fresh link. Creating a new link doesn’t cancel earlier ones.
139139 
140Anyone who has the link can use it until it expires, so give it only to the end customer it's for. Send it to an admin or owner of the end customer's Anthropic organization, because only an admin or owner can link a profile. Don't parse the URL or build one yourself. Its format can change.
140Anyone who has the link can use it until it expires, so give it only to the end customer it’s for. Send it to an admin or owner of the end customer’s Anthropic organization, because only an admin or owner can link a profile. Don’t parse the URL or build one yourself. Its format can change.
141141 
142If you're using Claude Platform on AWS, create the link with `POST /v1/user_profiles/{id}/enrollment_url` instead, and send the `anthropic-beta: user-profiles-2026-08-18` header. That request takes no body, and the response has the same `url` and `expires_at` fields. In the SDK and the CLI, that call is in the beta namespace: `client.beta.user_profiles.create_enrollment_url()` (typescript: `client.beta.userProfiles.createEnrollmentURL()`; csharp: `client.Beta.UserProfiles.CreateEnrollmentUrl()`; go: `client.Beta.UserProfiles.NewEnrollmentURL()`; java: `client.beta().userProfiles().createEnrollmentUrl()`; php: `$client->beta->userProfiles->createEnrollmentURL()`; cli: `ant beta:user-profiles create-enrollment-url`).
142If you’re using Claude Platform on AWS, create the link with `POST /v1/user_profiles/{id}/enrollment_url` instead, and send the `anthropic-beta: user-profiles-2026-08-18` header. That request takes no body, and the response has the same `url` and `expires_at` fields. In the SDK and the CLI, that call is in the beta namespace: `client.beta.user_profiles.create_enrollment_url()` (typescript: `client.beta.userProfiles.createEnrollmentURL()`; csharp: `client.Beta.UserProfiles.CreateEnrollmentUrl()`; go: `client.Beta.UserProfiles.NewEnrollmentURL()`; java: `client.beta().userProfiles().createEnrollmentUrl()`; php: `$client->beta->userProfiles->createEnrollmentURL()`; cli: `ant beta:user-profiles create-enrollment-url`).
143143 
144144`POST /v1/user_profiles/{id}/action_urls` is not available on Microsoft Foundry.
145145 
146146## What the end customer sees
147147 
148The link opens Anthropic's Verification Portal at `portal.anthropic.com`. After the end customer logs in, the portal shows them the name of your Anthropic organization and the profile's ID.
148The link opens Anthropic’s Verification Portal at `portal.anthropic.com`. After the end customer logs in, the portal shows them the name of your Anthropic organization and the profile’s ID.
149149 
150150<Steps>
151151 <Step title="Log in">
from line 157
157157 </Step>
158158 
159159 <Step title="Link the profile">
160 The portal shows a card titled **Link your partner profile**. It names your platform, the profile's ID, the end customer's organization, and when the invitation expires. The end customer selects **Link profile** to accept or **Skip for now** to continue to the portal without linking.
160 The portal shows a card titled **Link your partner profile**. It names your platform, the profile’s ID, the end customer’s organization, and when the invitation expires. The end customer selects **Link profile** to accept or **Skip for now** to continue to the portal without linking.
161161 
162162 <Frame caption="The end customer confirms which organization the profile links to.">
163163 ![Verification Portal card titled Link your partner profile, with the partner, profile ID, organization, and expiry shown.](https://platform.claude.com/docs/images/user-profiles/portal-link-profile.png)
164164 </Frame>
165165 
166 Only an admin or owner of the organization can link a profile. Anyone else sees **Admin access needed** and can't link the profile. They can switch to an organization where they are an admin or owner. Otherwise, tell the end customer that an admin or owner of their Anthropic organization has to open the link.
166 Only an admin or owner of the organization can link a profile. Anyone else sees **Admin access needed** and can’t link the profile. They can switch to an organization where they are an admin or owner. Otherwise, tell the end customer that an admin or owner of their Anthropic organization has to open the link.
167167 </Step>
168168 
169169 <Step title="See the confirmation">
from line 177
177177 
178178If the link has expired by the time an admin or owner opens it and logs in, the portal shows **This invitation has expired** and tells them to ask you for a new one.
179179 
180A profile links to one organization. If it's already linked to a different one, the portal says **This partner profile is already linked to a different organization** and doesn't link it. An admin or owner of the organization it's linked to can unlink it under **Linked accounts** in the portal. After that, create a new link and send it to the end customer.
180A profile links to one organization. If it’s already linked to a different one, the portal says **This partner profile is already linked to a different organization** and doesn’t link it. An admin or owner of the organization it’s linked to can unlink it under **Linked accounts** in the portal. After that, create a new link and send it to the end customer.
181181 
182182## After the end customer links the profile
183183 
184The portal doesn't send the end customer back to your product, and Anthropic doesn't notify you. Tell the end customer in your own interface to return when they have finished.
184The portal doesn’t send the end customer back to your product, and Anthropic doesn’t notify you. Tell the end customer in your own interface to return when they have finished.
185185 
186Linking doesn't approve anything by itself. It connects the profile to the end customer's organization, so that programs the organization is approved for apply to requests that carry the profile's ID, except Cyber Verification Program access levels, which the end customer turns on for each linked profile in the portal. The profile has no field that says it is linked.
186Linking doesn’t approve anything by itself. It connects the profile to the end customer’s organization, so that programs the organization is approved for apply to requests that carry the profile’s ID, except Cyber Verification Program access levels, which the end customer turns on for each linked profile in the portal. The profile has no field that says it is linked.
187187 
188188To see which programs apply to a profile, [retrieve the profile](https://platform.claude.com/docs/en/api/user_profiles/retrieve) and read `programs`. It has a key for each program, such as `cyber` and `efs`, and every profile has every key. Each key is one of the following:
189189 
190* `null`: Anthropic has no status to report for that program. Every key is `null` if Anthropic hasn't enabled programs for your organization.
190* `null`: Anthropic has no status to report for that program. Every key is `null` if Anthropic hasn’t enabled programs for your organization.
191191* An object: Its `status` is `active` when the program applies to the profile, otherwise `pending` or `rejected`.
192192 
193193The end customer can see the linked profile under **Linked accounts** in the portal.
Feedback