10xDotIn Developer Docs

JWT Skill Management

Create, update, publish, and delete handle-hosted skills with a signed-in 10x control-plane JWT.

JWT Skill Management

Use this guide when a signed-in creator, operator, or OpenAnalyst package integration needs to manage a handle's hosted 10x skills through the control plane.

JWT skill management is for interactive or user-session-backed control-plane updates. It is separate from PAT-backed automation and from local OpenAnalyst plugin installation.

Auth and access

All routes in this guide use the 10x control-plane JWT from the signed-in user session:

Authorization: Bearer <JWT_TOKEN>

Requirements:

  • The user must have CREATOR access or higher on the target handle.
  • Write routes require the tenant plan feature gate growth_tools.
  • Use the 10x control-plane JWT. Do not use a Smartwork runtime token, provider/billing JWT, or PAT for these hosted skill writes unless a future endpoint explicitly documents PAT write scopes.

Routes

ActionRouteAuthNotes
List handle skillsGET /v2/handles/{handle}/skillsJWT, CREATOR+Returns draft, ready, published, and disabled hosted skills for one handle
Create or update skill metadataPUT /v2/handles/{handle}/skills/{skillKey}JWT, CREATOR+, growth_toolsStores title, description, prompt, tools, and draft/disabled status
Configure runtimePUT /v2/handles/{handle}/skills/{skillKey}/runtimeJWT, CREATOR+, growth_toolsAttaches a verified runtime image and execution limits
Publish skillPOST /v2/handles/{handle}/skills/{skillKey}/publishJWT, CREATOR+, growth_toolsRequires an existing skill and runtime registry row
Delete skillDELETE /v2/handles/{handle}/skills/{skillKey}JWT, CREATOR+Removes the hosted skill record

Skill keys are normalized to lowercase and must use the platform skill-key format. Keep them stable because downstream function bindings, MCP exposure, and OpenAnalyst imports may reference them.

Setup variables

export API_BASE="https://ai.10x.in"
export HANDLE="links"
export SKILL_KEY="crm-lookup"
export JWT_TOKEN="<10x-control-plane-jwt>"

List hosted skills

curl -sS "${API_BASE}/v2/handles/${HANDLE}/skills" \
  -H "Authorization: Bearer ${JWT_TOKEN}"

The response is shaped for hosted catalog and OpenAnalyst import flows:

{
  "skills": [
    {
      "skillKey": "crm-lookup",
      "title": "CRM Lookup",
      "description": "Look up CRM records.",
      "systemPrompt": "Use this skill when CRM context is needed.",
      "tools": [
        {
          "type": "http",
          "name": "lookup",
          "config": {
            "url": "https://api.example.com/lookup"
          }
        }
      ],
      "runtimeStatus": "ready",
      "updatedAt": "2026-05-08T10:30:00.000Z"
    }
  ]
}

runtimeStatus is computed:

  • draft when the skill is stored but no runtime is configured.
  • ready when the skill is draft and a runtime row exists.
  • published after POST /publish.
  • disabled when the stored skill status is disabled.

Create or update skill metadata

curl -sS -X PUT "${API_BASE}/v2/handles/${HANDLE}/skills/${SKILL_KEY}" \
  -H "Authorization: Bearer ${JWT_TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{
    "displayName": "CRM Lookup",
    "description": "Look up CRM records.",
    "systemPrompt": "Use this skill when CRM context is needed.",
    "tools": [
      {
        "type": "http",
        "name": "lookup",
        "config": {
          "url": "https://api.example.com/lookup"
        }
      }
    ],
    "status": "DRAFT"
  }'

Response:

{
  "ok": true,
  "skillKey": "crm-lookup",
  "status": "DRAFT"
}

PUT only accepts user-settable metadata status:

  • Use DRAFT for editable hosted skills.
  • Use DISABLED to hide the skill from import and invocation surfaces.
  • Do not send PUBLISHED; publishing is only set by POST /publish.

Configure the runtime

curl -sS -X PUT "${API_BASE}/v2/handles/${HANDLE}/skills/${SKILL_KEY}/runtime" \
  -H "Authorization: Bearer ${JWT_TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{
    "imageRef": "catalog/node:20",
    "command": ["node", "server.js"],
    "args": [],
    "cpu": 512,
    "memory": 1024,
    "idleTimeoutSec": 900,
    "maxSessionSec": 3600,
    "secretsRefs": [],
    "networkPolicy": {},
    "planGates": {}
  }'

The runtime image must be a verified catalog image (catalog/*) or a private ECR image. Other image references are rejected.

Response:

{
  "ok": true,
  "runtime": {
    "handle": "links",
    "skillKey": "crm-lookup",
    "imageRef": "catalog/node:20",
    "command": ["node", "server.js"],
    "args": [],
    "cpu": 512,
    "memory": 1024,
    "idleTimeoutSec": 900,
    "maxSessionSec": 3600
  }
}

Publish the skill

curl -sS -X POST "${API_BASE}/v2/handles/${HANDLE}/skills/${SKILL_KEY}/publish" \
  -H "Authorization: Bearer ${JWT_TOKEN}"

Response:

{
  "ok": true,
  "skillKey": "crm-lookup",
  "version": "v1770000000000"
}

Publishing requires both the skill metadata row and runtime configuration to exist. After publish, GET /skills returns runtimeStatus: "published" and a newer updatedAt.

Delete a hosted skill

curl -sS -X DELETE "${API_BASE}/v2/handles/${HANDLE}/skills/${SKILL_KEY}" \
  -H "Authorization: Bearer ${JWT_TOKEN}" \
  -i

A successful delete returns 204 No Content. Delete is idempotent for the hosted skill record, but any downstream docs, bindings, or local imports that referenced the skill should be reviewed separately.

OpenAnalyst package workflow

OpenAnalyst package should keep using the existing read/import/sync path for local skills:

  1. Use the 10x control-plane token to call GET /v2/handles/{handle}/skills.
  2. Import hosted skills into the local OpenAnalyst skill catalog.
  3. When hosted editing is needed, use the same 10x token for PUT, PUT /runtime, POST /publish, and optional DELETE.
  4. After a hosted write, refetch GET /skills.
  5. Let the existing OpenAnalyst updatedAt comparison mark the local skill as updateable.
  6. Install or update the local skill through the existing overwrite path.

Do not use the Smartwork runtime token or billing/provider JWT for these writes. Those tokens belong to different trust boundaries.

Common errors

StatusErrorMeaning
401invalid_token, token_expiredThe JWT is missing, invalid, or expired
403insufficient_role or access failureSigned-in user does not have CREATOR+ access to the handle
403feature_lockedThe tenant does not have the growth_tools feature gate required for writes
400invalid_skill_keyThe skillKey path segment is not valid
400invalid_tools, invalid_tool_type, invalid_tool_nameThe tools array is malformed
400invalid_image_refRuntime image is not a verified catalog or ECR image
400runtime_not_configuredPublish was requested before runtime configuration exists
404skill_not_foundRuntime or publish was requested for a missing hosted skill

Updated Jun 19, 2026