Follow Discord
Sweep 22 Oct 2026 · 04:32Z Build v2.1.308 527 read Stable v2.1.308 Latest v2.1.308 Next v2.1.308 Feeds RSS JSON llms.txt llms-full.txt Unofficial
One change · api

plugins-api changedmanage-claude/plugins-api

Nearest release: v2.1.307, published an hour after this site recorded the change. Shown because the two are within 24 hours of each other. Nothing here says the release caused the edit.

Recorded here
Lines+69added
Lines−69removed
From line 17 where the diff opens
First seen 1 Oct 2026 this site's first read of the page
Recorded edits9to this page, all time

The whole hunk

from line 17, old and new numbered
/
lines
from line 17
1717<Note>
1818 The Plugins API is in **beta** and is available to Claude Enterprise organizations only. It is not available to Claude Platform (Claude Console) organizations, or to organizations with HIPAA readiness enabled.
1919 
20 Every request must include the [beta header](https://platform.claude.com/docs/en/api/beta-headers) `anthropic-beta: ce-plugins-2026-09-01` (the SDKs and the `ant` CLI send it for you). A request without it returns `404`, exactly as if the endpoint did not exist.
20 Every request must include the [beta header](https://platform.claude.com/docs/en/api/beta-headers) `anthropic-beta: ce-plugins-2026-09-01` (the SDK and the `ant` CLI send it for you). A request without it returns `404`, exactly as if the endpoint did not exist.
2121</Note>
2222 
2323## Endpoints
from line 40
4040* Your primary owner creates an Admin API key with the `read:plugins` scope, the `write:plugins` scope, or both in [claude.ai > Organization settings > API](https://claude.ai/admin-settings/api-access). See [Create an Admin API key](https://platform.claude.com/docs/en/manage-claude/admin-api-keys#create-a-key-for-a-claude-enterprise-organization).
4141* Every request carries three headers: `x-api-key`, `anthropic-version: 2023-06-01`, and `anthropic-beta: ce-plugins-2026-09-01`.
4242 
43The Python, TypeScript, C#, Go, Java, PHP, and Ruby SDKs expose these endpoints under `client.beta.organization` (csharp, go: `client.Beta.Organization`; java: `client.beta().organization()`; php: `$client->beta->organization`), and the [`ant` CLI](https://platform.claude.com/docs/en/cli-sdks-libraries/cli/quickstart) under `ant beta:organization`; they send the `anthropic-version` and `anthropic-beta` headers for you. The examples on this page use each SDK's default client, which, like the CLI, reads the Admin API key from the `ANTHROPIC_API_KEY` environment variable; the curl examples read the key from the same variable and pass it in the `x-api-key` header. Where an SDK or the CLI fetches more pages for you, `limit` sets the page size, not the total (see [Pagination](https://platform.claude.com/docs/en/manage-claude/plugins-api#pagination)).
43The SDK exposes these endpoints under `client.beta.organization` (csharp, go: `client.Beta.Organization`; java: `client.beta().organization()`; php: `$client->beta->organization`), and the [`ant` CLI](https://platform.claude.com/docs/en/cli-sdks-libraries/cli/quickstart) under `ant beta:organization`; they send the `anthropic-version` and `anthropic-beta` headers for you. The examples on this page use the SDK's default client, which, like the CLI, reads the Admin API key from the `ANTHROPIC_API_KEY` environment variable; the curl examples read the key from the same variable and pass it in the `x-api-key` header. Where an SDK or the CLI fetches more pages for you, `limit` sets the page size, not the total (see [Pagination](https://platform.claude.com/docs/en/manage-claude/plugins-api#pagination)).
4444 
4545API keys belong to the organization and keep working after the person who created them leaves. Do not share them or check them into source control.
4646 
from line 224
224224 
225225A **plugin** is a package that extends Claude for your organization's members. It contains any combination of these components:
226226 
227| Component | What it is |
228| ---------- | -------------------------------------------------------------------------------------------------------- |
229| Skill | Instructions and files that Claude loads when a task calls for it. |
230| Command | A saved prompt a member runs by typing `/` followed by the command's name. |
231| Agent | A helper assistant with its own instructions, to which Claude can hand part of a task. |
232| Hook | A command that runs automatically when an event happens in a session, such as before Claude uses a tool. |
233| MCP server | A connection from Claude to tools and data in another system (Model Context Protocol). |
234| CLI | A command-line program that the plugin lets Claude run. |
227| Component | What it is |
228| ---------- | ------------------------------------------------------------------------------------------------------- |
229| Skill | Instructions and files that Claude loads when a task calls for it. |
230| Command | A saved prompt a member runs by typing `/` followed by the command's name. |
231| Agent | A helper assistant with its own instructions, to which Claude can hand part of a task. |
232| Hook | A command that runs automatically when an event occurs in a session, such as before Claude uses a tool. |
233| MCP server | A connection from Claude to tools and data in another system (Model Context Protocol). |
234| CLI | A command-line program that the plugin lets Claude run. |
235235 
236236Every 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.
237237 
from line 257
257257 
258258Every upload creates a new, immutable **version**, whether it comes from this API, from claude.ai, or from a Git synchronization. A plugin has two pointers to its versions:
259259 
260* `latest_version_id`: the newest version.
261* `served_version_id`: the version members are served.
260* `latest_version_id`: the newest version
261* `served_version_id`: the version members are served
262262 
263263By 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 after its scan completes 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.
264264 
265265Choosing 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.
266266 
267This lets a release pipeline upload each build, test it, and then promote it. To have your pipeline decide 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` until the current version's scan completes, and `400 scan_failed` if the scan completed with `fail` or `unknown`, or errored (`warn` is accepted). A pinned plugin cannot currently be unpinned, here or in claude.ai.
267This 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` until the current version's scan completes, and `400 scan_failed` if the scan completed with `fail` or `unknown`, or errored (`warn` is accepted). A pinned plugin cannot currently be unpinned, here or in claude.ai.
268268 
269269To roll back, set `served_version_id` to an earlier version. Roll forward the same way.
270270 
from line 272
272272 
273273### Installation settings
274274 
275**Installation settings** decide who can use an organization-owned plugin. Each setting has one of four values, carried in the fields named `installation_preference` (and, on the plugin and marketplace objects, `organization_installation_preference` and `default_installation_preference`):
275**Installation settings** determine who can use an organization-owned plugin. Each setting has one of four values, carried in the fields named `installation_preference` (and, on the plugin and marketplace objects, `organization_installation_preference` and `default_installation_preference`):
276276 
277277| Value | Members see |
278278| --------------- | ---------------------------------------------- |
from line 281
281281| `available` | The plugin can be installed on request. |
282282| `not_available` | The plugin is hidden. |
283283 
284A plugin can hold an organization-wide setting and one setting per 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:
284A 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:
285285 
2862861. 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.
2872872. A member who belongs to no group holding a setting for the plugin gets the organization-wide value.
from line 293
293293 
294294### Shares
295295 
296**Shares** decide who can use a member-owned plugin. The owner shares it in claude.ai with every member, with a group, or with named members. This API lists shares but cannot change them.
296**Shares** determine who can use a member-owned plugin. The owner shares it in claude.ai with every member, with a group, or with named members. This API lists shares but cannot change them.
297297 
298298If your organization has turned off a kind of sharing in its claude.ai settings, shares of that kind still appear in the list but give no one access while that setting is off; the list itself does not show whether it is.
299299 
from line 334
334334* No file may be under a top-level `bin/` directory.
335335* No nested `.zip` files. Packaged MCP servers (`.mcpb`, `.dxt`) are allowed.
336336* File paths must be relative, contain no `..`, and use only letters, digits, spaces, and `_ . - / ( ) ,`.
337* The request body and the uncompressed archive are each at most 200 MB; a request body over the limit returns `413` (`request_too_large`) rather than `400`. An upload has at most 5,000 files, a path depth of 12, paths of 472 characters, and file or folder names of 255 characters.
337* The request body and the uncompressed archive are each at most 200 MB; a request body over the limit returns `413` (`request_too_large`) rather than `400`. An upload has at most 5,000 files, a path depth of 12, paths of 472 characters, and file or folder names of 255 characters.
338338* ZIP archives must use DEFLATE or STORE compression, and cannot be encrypted or contain symbolic links.
339339* A marketplace holds at most 500 items, counting its plugins and any standalone skills members keep in it. This limit and the 5,000-file limit are current values that may be raised.
340340 
from line 342
342342 
343343### Publish each build from a release pipeline
344344 
345Upload every tagged build from CI, and let the pipeline decide when a build is served.
345Upload every tagged build from CI, and let the pipeline determine when a build is served.
346346 
3473471. Find the marketplace to upload into with `GET /v1/organizations/plugin_marketplaces?owner_type=organization`, or omit `marketplace_id` to use the library marketplace.
3483482. 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)).
from line 504
504504 
505505The 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.
506506 
507| Field | Description |
508| ---------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
509| `id` | Prefixed `plugin_`. |
510| `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. |
511| `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 began recording this field in August 2026. An upload is never refused because of its `version`, and `manifest_version` is not unique. |
512| `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). |
513| `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. |
514| `owner` | `{"type": "organization"}`, or `{"type": "user", "user_id": "user_..."}` for a member's personal marketplace. |
515| `marketplace_id` | Prefixed `marketplace_`. |
516| `created_by` | Who created the plugin: `{"type": "user_actor", "user_id": "user_...", "email_address": "..."}` for a person in claude.ai (`email_address` may 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. |
517| `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`. |
518| `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. |
519| `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. |
520| `reach` | `contained`, `privileged`, or `remote`. See [Reach](https://platform.claude.com/docs/en/manage-claude/plugins-api#reach). |
521| `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 new scan results. |
507| Field | Description |
508| ---------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
509| `id` | Prefixed `plugin_`. |
510| `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. |
511| `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. |
512| `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). |
513| `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. |
514| `owner` | `{"type": "organization"}`, or `{"type": "user", "user_id": "user_..."}` for a member's personal marketplace. |
515| `marketplace_id` | Prefixed `marketplace_`. |
516| `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. |
517| `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`. |
518| `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. |
519| `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. |
520| `reach` | `contained`, `privileged`, or `remote`. See [Reach](https://platform.claude.com/docs/en/manage-claude/plugins-api#reach). |
521| `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 new scan results. |
522522 
523523The `content_scan` object:
524524 
from line 536
536536 | `remote-code-instruction-loader` | Tells Claude to download and run, or follow instructions from, outside content that can change after the plugin is installed. |
537537 | `credential-exposure` | Contains live credentials, or collects credentials or tokens from the member's environment. |
538538 | `guardrail-tampering` | Weakens the member's safeguards, for example by pre-approving every permission prompt. |
539 | `system-prompt-spoofing` | Imitates or tries to replace Claude's system instructions. |
539 | `system-prompt-spoofing` | Imitates or attempts to replace Claude's system instructions. |
540540 | `covert-record-tampering` | Quietly changes, hides, or deletes information the member would otherwise see. |
541541 | `covert-behavior-override` | Changes Claude's behavior beyond the plugin's purpose and hides the change from the member. |
542542 | `hidden-code-execution` | Runs bundled code while telling Claude not to reveal what it does. |
from line 551
551551 
552552### List plugins
553553 
554`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` (prefixed `user_`; 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.
554`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.
555555 
556556<CodeGroup>
557557 ```bash cURL
from line 668
668668 
669669### Create a plugin
670670 
671`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 per file, where each part's filename is the file's path within the plugin (for example `.claude-plugin/plugin.json`). Optional fields are `marketplace_id` (an organization-owned `manual` marketplace; defaults to 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.
671`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.
672672 
673673Upload an archive:
674674 
from line 836
836836}
837837```
838838 
839Upload individual files into a named marketplace. Attach each file under its path within the plugin (the `;filename=` suffix in the cURL example, the filename arguments in the SDK examples); a file sent under its base name alone means the manifest is not found. The TypeScript and Java SDKs and the `ant` CLI cannot yet attach files under a path, so those examples upload the plugin as one archive into the marketplace instead:
839Upload individual files into a named marketplace. Attach each file under its path within the plugin (the `;filename=` suffix in the cURL example, the file name arguments in the SDK examples); a file sent under its base name alone means the manifest is not found. The TypeScript and Java SDKs and the `ant` CLI cannot yet attach files under a path, so those examples upload the plugin as one archive into the marketplace instead:
840840 
841841<CodeGroup>
842842 ```bash cURL
from line 1030
10301030 ```
10311031</CodeGroup>
10321032 
1033Besides 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:
1033Besides 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:
10341034 
10351035| Status | Cause | What to do |
10361036| -------------------------- | -------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
from line 1395
13951395 
13961396## Plugin versions
13971397 
1398A 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; shown in claude.ai's version history) and `created_by` (who uploaded it).
1398A 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).
13991399 
14001400A `{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`.
14011401 
from line 1700
17001700}
17011701```
17021702 
1703Besides 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` for a member-owned plugin; see [Error responses](https://platform.claude.com/docs/en/manage-claude/plugins-api#error-responses)), the request can fail with:
1703Besides 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` for a member-owned plugin; see [Error responses](https://platform.claude.com/docs/en/manage-claude/plugins-api#error-responses)), the request can fail with:
17041704 
17051705| Status | Cause | What to do |
17061706| -------------------------- | -------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
from line 1822
18221822 
18231823### Download a version's files
18241824 
1825`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` filename is derived from the plugin's name and is not unique; name saved files by plugin and version ID. Requires the `read:plugins` scope.
1825`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.
18261826 
18271827Downloading 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.
18281828 
from line 2483
24832483}
24842484```
24852485 
2486| Field | Description |
2487| --------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
2488| `name` | The marketplace's name. Fixed for its lifetime. |
2489| `owner` | Same shape as on the plugin. |
2490| `source` | `manual`, `github`, `gitlab`, or `public_git`. See [Marketplaces](https://platform.claude.com/docs/en/manage-claude/plugins-api#marketplaces). |
2491| `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 happens for a marketplace whose source is `manual`. |
2492| `last_sync_ended_at` | When the most recent synchronization attempt finished, whatever its outcome; for a connected repository that has not synchronized yet, when the marketplace was created. `null` for a marketplace that is not synchronized. |
2493| `last_sync_read_sha` | The commit the last synchronization read from the repository. Not necessarily the commit the served versions came from. `null` for a marketplace that is not synchronized. |
2494| `default_installation_preference` | Organization marketplaces: the organization-wide value for every plugin in it without its own setting (`not_available` if never set). Personal marketplaces: `null`. |
2486| Field | Description |
2487| --------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
2488| `name` | The marketplace's name. Fixed for its lifetime. |
2489| `owner` | Same shape as on the plugin. |
2490| `source` | `manual`, `github`, `gitlab`, or `public_git`. See [Marketplaces](https://platform.claude.com/docs/en/manage-claude/plugins-api#marketplaces). |
2491| `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`. |
2492| `last_sync_ended_at` | When the most recent synchronization attempt finished, whatever its outcome; for a connected repository that has not synchronized yet, when the marketplace was created. `null` for a marketplace that is not synchronized. |
2493| `last_sync_read_sha` | The commit the last synchronization read from the repository. Not necessarily the commit the served versions came from. `null` for a marketplace that is not synchronized. |
2494| `default_installation_preference` | Organization marketplaces: the organization-wide value for every plugin in it without its own setting (`not_available` if never set). Personal marketplaces: `null`. |
24952495 
24962496A `marketplace_id` that lacks the `marketplace_` prefix returns `400`. One that carries the prefix but does not resolve, or belongs to another organization, returns `404`.
24972497 
from line 2838
28382838 
28392839### Validate marketplace content
28402840 
2841Two 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 per 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).
2841Two 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).
28422842 
28432843The repository, and any plugin source outside it on GitHub, are read anonymously, so a private repository or private plugin source is reported as not found. Plugin sources on hosts other than GitHub are not fetched; such a plugin normally gets a `marketplace_validate_source_not_checked` warning and is checked when the marketplace actually synchronizes. If the repository is, or the archive names, a marketplace that Anthropic synchronizes into every organization, stricter rules apply: every plugin source outside the marketplace must be pinned to a full commit SHA, unpinned or unsupported-host sources are reported as plugin errors, and the branch read defaults to the one that marketplace synchronizes from.
28442844 
2845`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 it is omitted or `null`, 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 filename: a `.zip` of the marketplace directory, at most 32 MB, with its contents at the root or wrapped in one folder (as a Git host's download produces), DEFLATE or STORE compression only. No other form field is accepted.
2845`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 it is omitted or `null`, 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: a `.zip` of the marketplace directory, at most 32 MB, with its contents at the root or wrapped in one folder (as a Git host's download produces), DEFLATE or STORE compression only. No other form field is accepted.
28462846 
28472847Validate a public repository at a branch:
28482848 
from line 2991
29912991}
29922992```
29932993 
2994| Field | Description |
2995| --------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
2996| `valid` | `true` when `marketplace.json` is well-formed and no plugin would be skipped. Warnings do not make it `false`. |
2997| `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. |
2998| `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). |
2999| `total_plugin_count` | How many plugins `marketplace.json` declares; `0` when it could not be read. |
3000| `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 finish within 120 seconds reports `manifest_error_code: "marketplace_validate_deadline_exceeded"`. |
3001| `plugin_errors` | One `{name, error, error_code}` per plugin a synchronization would skip. |
3002| `plugin_warnings` | One `{name, warnings: [{message, error_code}]}` per plugin that would synchronize with some contents left out. |
2994| Field | Description |
2995| --------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
2996| `valid` | `true` when `marketplace.json` is well-formed and no plugin would be skipped. Warnings do not make it `false`. |
2997| `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. |
2998| `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). |
2999| `total_plugin_count` | How many plugins `marketplace.json` declares; `0` when it could not be read. |
3000| `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"`. |
3001| `plugin_errors` | One `{name, error, error_code}` per plugin a synchronization would skip. |
3002| `plugin_warnings` | One `{name, warnings: [{message, error_code}]}` per plugin that would synchronize with some contents left out. |
30033003 
30043004Validate a local copy of the marketplace directory instead, as a `.zip`; the response is the same report:
30053005 
from line 3120
31203120 
31213121Problems with the content never fail the request. Apart from the responses every endpoint shares (a `403` for a key that has only `read:org_audit` or `read:compliance_org_data`; see [Error responses](https://platform.claude.com/docs/en/manage-claude/plugins-api#error-responses) and [Rate limiting](https://platform.claude.com/docs/en/manage-claude/plugins-api#rate-limiting)), the request itself can fail with:
31223122 
3123| Status | Cause | What to do |
3124| ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------ |
3125| 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 filename, or another form field is present. | Fix the request and resend. |
3126| 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. |
3123| Status | Cause | What to do |
3124| ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------ |
3125| 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. |
3126| 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. |
31273127 
31283128#### Report codes
31293129 
3130Each 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 may 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`.
3130Each 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`.
31313131 
31323132## Unrecognized values
31333133 
from line 3135
31353135 
31363136## Rate limiting
31373137 
3138Read requests (every `GET` endpoint on this page) share a limit of **300 requests per minute** per organization, and 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** per organization. A marketplace validation (either endpoint) counts as a read, and validations are additionally limited to 10 a minute per 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).
3138Read requests (every `GET` endpoint on this page) share a limit of **300 requests per minute** for each organization, and 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).
31393139 
31403140An 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)).
31413141 
from line 3147
31473147 
31483148## Error responses
31493149 
3150Error responses follow the standard shape documented in [Errors](https://platform.claude.com/docs/en/api/errors). Quote the `request_id` from the response body when contacting support.
3150Error responses follow the standard shape documented in [Claude API errors](https://platform.claude.com/docs/en/api/errors). Quote the `request_id` from the response body when contacting support.
31513151 
31523152| Status | Meaning |
31533153| ------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
from line 3216
32163216| `marketplace_updated` | A marketplace's default installation setting changes, or an administrator or owner starts a synchronization in claude.ai. |
32173217| `marketplace_deleted` | A marketplace is deleted in claude.ai together with its plugins (no per-plugin events). |
32183218| `claude_plugin_archive_accessed` | A member-owned plugin's archive is downloaded. |
3219| `claude_plugin_security_scan_completed` | A content scan finishes. |
3219| `claude_plugin_security_scan_completed` | A content scan completes. |
32203220 
32213221The 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`.
32223222 
Feedback