Skip to main content
POST /api/v1/cloud/skills Uploads and creates a new Skill resource. Skill content must be uploaded as a .zip archive using multipart/form-data encoding.

Headers

HeaderRequiredDescription
AuthorizationYesBearer $QODER_PAT
Content-TypeNoSet automatically by curl -F to multipart/form-data; do not specify manually

Request body (multipart/form-data)

FieldTypeRequiredDescription
filefileYes.zip archive of skill content, maximum 5 MB
namestringNoAccepted for compatibility, but the API uses the name from SKILL.md frontmatter
typestringNoSkill type. One of: custom, prebuilt (default custom)
descriptionstringNoAccepted for compatibility, but the API uses the description from SKILL.md frontmatter
metadataJSON stringNoCustom metadata as a JSON object

Zip file structure

The archive must contain SKILL.md at the archive root or one directory below the root. SKILL.md must start with YAML frontmatter in this format:
---
name: my-skill
description: Skill description
version: 1.0.0
---

# Skill title

## Steps
1. Step one
2. Step two
Zip entry paths may use either / or Windows-style \ separators; the service normalizes them when locating SKILL.md.

Example request

# Prepare skill content
mkdir my-skill && cat > my-skill/SKILL.md << 'EOF'
---
name: my-custom-skill
description: Custom skill example
version: 1.0.0
---

# My Custom Skill

## Steps
1. Perform action A
2. Perform action B

## Verification
Confirm the operation completed.
EOF

# Pack as zip
cd my-skill && zip ../my-skill.zip SKILL.md && cd ..

# Upload to create
curl -X POST https://api.qoder.com/api/v1/cloud/skills \
  -H "Authorization: Bearer $QODER_PAT" \
  -F "name=my-custom-skill" \
  -F "type=custom" \
  -F 'metadata={"team":"docs"}' \
  -F "description=Custom skill example" \
  -F "file=@my-skill.zip"

Example response

HTTP 201 Created
{
  "id": "skill_019e3bba474b73cfaf19eae9b5f5e66d",
  "type": "skill",
  "display_title": "my-custom-skill",
  "description": "Custom skill example",
  "source": "custom",
  "latest_version": "1",
  "metadata": {
    "team": "docs"
  },
  "created_at": "2026-05-18T15:35:24.248164Z",
  "updated_at": "2026-05-18T15:35:24.248164Z"
}

Response fields

FieldTypeDescription
idstringSkill unique identifier with the skill_ prefix
typestringAlways "skill"
display_titlestringDisplay title derived from the stored skill name
descriptionstringSkill description
sourcestringSkill source: custom or qoder
latest_versionstringLatest version number as a string
metadataobjectCustom metadata object stored with the Skill; defaults to {}
created_atstringCreation time (ISO 8601)
updated_atstringLast update time (ISO 8601)

Errors

HTTPTypeTrigger
400invalid_request_errorNon-multipart request: “Invalid multipart form or request too large.”
400invalid_request_errorMissing file field: “Field ‘file’ is required.”
400invalid_request_errorNot a zip file: “Only .zip files are accepted.”
401TOKEN_INVALIDMissing or invalid authentication token

Notes

  • Duplicate skill names are allowed (uniqueness is not enforced).
  • name and description are always read from the SKILL.md frontmatter. Form values do not override the archive content.
  • Skill names must be at most 64 characters and contain only lowercase letters, digits, hyphens (-), or underscores (_), starting with a letter or digit.
  • Zip archives created on Windows are supported; backslash path separators are normalized.
  • Initial version number is 1.
  • JSON Content-Type is not supported; multipart/form-data is required.
See Errors for the full error envelope.

Agent Skills

Attach domain expertise to your agent.