Create a skill version
POST /v1/skills/{skill_id}/versions
Saves a new version of a skill from its complete set of files.
Send every file of the skill, the same way as for
Create a skill. A version is a whole snapshot: any file you
leave out is not in the new version. The name in SKILL.md must be the skill’s name. The key’s owner must be
able to edit the skill.
The upload becomes the skill’s newest version at once, so agents that have the skill use this version from their next session. An upload identical to the newest version saves nothing and returns that version.
The key must be a personal key with the skills:write capability. For what each capability allows, see Keys.
Path parameters
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
skill_id | string | Yes | The ID of the skill. |
Body (multipart/form-data)
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
files | array<binary> | Yes | The skill’s files. On the wire each file is one files[] part, with the file’s path in the skill as the filename. The SDKs send the files parameter this way. You can instead send one zip archive that contains all the files. |
Response
Returns 200 with the skill version. For every field, see Skills.
{ "id": "b1c2d3e4-f5a6-4b7c-8d9e-0f1a2b3c4d5e", "type": "skill_version", "created_at": "2026-10-27T15:02:11.388Z", "description": "Summarize a pull request for reviewers.", "name": "pr-summary", "skill_id": "8b3f6c1e-2a4d-4f7b-9c1e-5d6a7b8c9d0e"}Errors
This endpoint can return these errors as well as the common errors.
| Status | error.type | Cause and fix |
|---|---|---|
| 400 | invalid_request_error | The upload breaks a rule, such as SKILL.md missing or the files totaling over 30 MiB (31,457,280 bytes) uncompressed. The message names the rule. Fix the files and upload again. |
| 400 | invalid_request_error | The name in SKILL.md is not the skill’s name. Keep the skill’s name, or create a separate skill. |
| 400 | invalid_request_error | The skill is a built-in skill, which is read-only. Create your own skill instead. |
| 400 | invalid_request_error | The form has a field other than files[]. Remove it. |
| 403 | permission_error | The key lacks skills:write, is not a personal key, or its owner can’t edit this skill. Use a personal key with skills:write whose owner can edit the skill. |
| 404 | not_found_error | No skill with this ID exists, or the key’s owner can’t read it. Check the ID, and check that the key’s owner can read the skill. |
| 413 | request_too_large | The request is over 32 MiB (33,554,432 bytes). Remove files until the request is under 32 MiB. |
| 429 | rate_limit_error | This key already has 2 skill uploads in progress, or the server is processing too many uploads. Wait for the time in Retry-After, then retry. The SDKs retry it for you. |
Example
curl -sS -X POST "$CONTEXT_BASE_URL/v1/skills/8b3f6c1e-2a4d-4f7b-9c1e-5d6a7b8c9d0e/versions" \ -H "x-api-key: $CONTEXT_API_KEY" -F "files[]=@pr-summary.zip;type=application/zip"version = client.beta.skills.versions.create( "8b3f6c1e-2a4d-4f7b-9c1e-5d6a7b8c9d0e", files=[("pr-summary.zip", open("pr-summary.zip", "rb"), "application/zip")],)import { readFile } from "node:fs/promises"import { toFile } from "@anthropic-ai/sdk"
const version = await client.beta.skills.versions.create("8b3f6c1e-2a4d-4f7b-9c1e-5d6a7b8c9d0e", { files: [await toFile(await readFile("pr-summary.zip"), "pr-summary.zip", { type: "application/zip" })],})