Skip to main content
Skills

Create a Skill

Forward API reference.

Description

Uploads a Skill package and creates a new Skill record. Submit the request as multipart/form-data. A successful request also creates the initial version and points latest_version to it.

Path

POST /api/v1/forward/skills

Request headers

HeaderRequiredDescription
AuthorizationYesBearer <PAT or SAT>
Content-TypeYesmultipart/form-data
Idempotency-KeyNoRecommended. Requests with the same key and the same normalized files fingerprint can be retried safely.

Query parameters

ParameterTypeRequiredDescription
identity_idstringNoUse only when operating on Identity-owned resources. A PAT can explicitly supply this query parameter; omitting it uses administrator scope. SAT ownership is determined by the credential. Explicitly supplying this parameter with any SAT (including an empty value) returns HTTP 400. Idempotency scopes are isolated between Identities. See Identity ownership.

Form fields

FieldTypeRequiredDescription
filesfileYes*Recommended upload field; it can appear multiple times. Supports two forms:
① A single .zip archive;
② A bare file tree, with one file per part and a relative path in filename (for example, code-review/SKILL.md or code-review/scripts/run.sh).
Both the compressed archive and its extracted contents must be no larger than 50 MB.
metadataJSON stringNoCaller metadata object with up to 15 keys. created_by is reserved and must not be supplied (supplying it returns 400).
icon_idstringNoPublic Forward Resource icon ID.
filefileYes*⚠️ Deprecated: A single .zip archive using the relaxed package rules. Matching requests return Deprecation: true in the response headers. Migrate to files.
namestringNo⚠️ Deprecated: The final name is always parsed from name in the uploaded package's SKILL.md frontmatter. This field is retained only for compatibility and is ignored when supplied.
descriptionstringNo⚠️ Deprecated: The final description is always parsed from SKILL.md.
typestringNo⚠️ Deprecated: Skill creation type, either custom or prebuilt; defaults to custom. With prebuilt, the response source is qoder; otherwise it is custom.
*Provide either files or file. If both are supplied, files takes precedence.
See Skill package for package structure rules. A package must contain SKILL.md, have exactly one top-level directory, and use the name from SKILL.md as the directory name.

Example request

Single zip archive:
curl -X POST "https://api.qoder.com.cn/api/v1/forward/skills" \
  -H "Authorization: Bearer $QODER_ACCESS_TOKEN" \
  -H "Idempotency-Key: create-skill-001" \
  -F "files=@skill.zip;type=application/zip" \
  -F "type=custom" \
  -F 'metadata={"source":"console"}' \
  -F "icon_id=pic_skill_default"
Bare file tree (repeat the files field):
curl -X POST "https://api.qoder.com.cn/api/v1/forward/skills" \
  -H "Authorization: Bearer $QODER_ACCESS_TOKEN" \
  -H "Idempotency-Key: create-skill-002" \
  -F "files=@code-review/SKILL.md;filename=code-review/SKILL.md" \
  -F "files=@code-review/scripts/run.sh;filename=code-review/scripts/run.sh"

Example response

HTTP 201 Created
{
  "id": "skill_xxx",
  "type": "skill",
  "display_title": "code-review",
  "description": "Code review skill",
  "source": "custom",
  "latest_version": "1759178010641129",
  "metadata": {
    "source": "console"
  },
  "created_at": "2026-07-23T10:00:00Z",
  "updated_at": "2026-07-23T10:00:00Z",
  "identity_id": null,
  "icon_url": null,
  "binding_info": {
    "agent_template_count": 0
  }
}

Response fields

The response is a Skill object. The request also creates an initial Skill version object, available through List Skill Versions. latest_version points to the version's 16-digit Unix microsecond timestamp.

Errors

HTTPTypeTrigger
400invalid_request_errorMultipart parsing failed; the package structure is invalid (for example, missing SKILL.md, multiple top-level directories, or a directory name that differs from name); type is invalid; metadata is invalid or contains a reserved key; or any SAT explicitly supplies the query parameter identity_id (including an empty value).
400invalid_request_errorIf the reserved key created_by is supplied, message is metadata key "created_by" is reserved, identifying the invalid field.
400skill_content_too_largeThe compressed archive or its extracted contents exceed 50 MB.
401authentication_errorThe authentication token is missing or invalid.
403permission_errorAn Owner mismatch occurs in administrator scope, or a downstream service denies access.
404not_found_errorThe Identity specified by the PAT does not exist, is disabled or deleted, or does not belong to the caller.
409conflict_errorThe Idempotency-Key maps to a different request fingerprint.
413invalid_request_errorThe request body exceeds the service limit.
429rate_limit_errorThe caller exceeded the API rate limit.
500/502/503api_errorForward or a dependent service failed.
Best Practices
API reference