Skip to content
ajan.io

Docs menu

On this page

Import Skill

Create or update a Skill from a SKILL.md file or zip archive

Imports a Skill from a SKILL.md file or a zip archive. Use this endpoint to sync repository-managed Skills into ajan.

Base URL

https://api.ajan.io/skills/v1/import

Required Scopes

This endpoint requires the SKILL_API scope.

Request Format

Send the request as multipart/form-data.

FieldTypeRequiredDescription
filefileYesSKILL.md, .zip, or .skill file content.
fileTypestringYesFile parser to use: md or zip. Use zip for .zip and .skill archives.
modestringNoImport mode: create or upsert. Default: create.
integrationIdsstringNoJSON-encoded array of integration UUIDs to attach, for example ["550e8400-e29b-41d4-a716-446655440000"].

SKILL.md Format

The imported Skill must include YAML frontmatter followed by instructions:

mdx
---
name: Support Reply Style
slug: support-reply-style
description: Applies the support team's tone and escalation rules.
---

Write concise replies, include the next best action, and escalate billing issues to the account owner.
Frontmatter FieldRequiredDescription
nameYesSkill name. Maximum: 64 characters.
slugNoStable Skill slug. If omitted, ajan generates one from the name.
descriptionNoDescription used to explain when the Skill should apply. Maximum: 1024 characters.
licenseNoOptional license metadata.

Zip archive rules

Zip archives must contain a SKILL.md file at the root or inside one top-level directory. ajan stores allowed supporting files with the Skill and skips unsupported file types.

LimitValue
Upload size25 MB
Total uncompressed size20 MB
Individual file size5 MB
Files per archive200

Supported supporting file types include Markdown, text, Python, shell, JavaScript, TypeScript, JSON, YAML, TOML, CSV, XML, HTML, CSS, SVG, PDF, Office files, fonts, and common image formats.

Import Modes

ModeBehavior
createCreates a new Skill from the import. The request fails if the slug already exists.
upsertUpdates one editable Skill with the same slug, or creates a new Skill if none exists. The request fails if multiple editable Skills use the same slug.

When an upsert updates an existing Skill, imported files replace the Skill's existing stored files.

Example

javascript
const axios = require("axios");
const FormData = require("form-data");
const fs = require("fs");

async function importSkill() {
  const form = new FormData();
  form.append("file", fs.createReadStream("./support-reply-style.zip"));
  form.append("fileType", "zip");
  form.append("mode", "upsert");
  form.append("integrationIds", JSON.stringify([]));

  const response = await axios.post(
    "https://api.ajan.io/skills/v1/import",
    form,
    {
      headers: {
        Authorization: "Bearer YOUR_API_KEY",
        ...form.getHeaders()
      }
    }
  );

  console.log("Imported Skill:", response.data.skill.id);
}

importSkill();

Response Format

Success Response (200 OK or 201 Created)

typescript
{
  skill: {
    id: string;
    name: string;
    slug: string;
    description: string;
    instructions: string;
    integrationIds: string[];
    createdAt: string;
    updatedAt: string;
  };
  files: Array<{
    path: string;
    sizeBytes: number;
    extension: string;
    hasScript: boolean;
  }>;
}

200 OK means an existing Skill was updated through upsert. 201 Created means a new Skill was created.

Error Handling

Status CodeDescription
400Invalid form data, invalid SKILL.md, invalid zip archive, or inaccessible integrationIds
401Invalid or missing API key
403Missing SKILL_API scope, Skills product access, create permission, or editor access
409Existing slug conflict or ambiguous upsert slug
413Uploaded file is too large
429Rate limit exceeded
500Internal server error

OpenAPI

openapi: 3.0.0
info:
  title: ajan API
  version: 3.0.0
servers:
  - url: https://api.ajan.io
    description: Production
security:
  - bearerAuth: []
paths:
  /skills/v1/import:
    post:
      tags:
        - Skills
      summary: Import a Skill
      description: Creates or updates a Skill from a SKILL.md file or zip archive.
      operationId: importSkill
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/ImportSkillRequest'
      responses:
        '200':
          description: Existing Skill updated successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ImportSkillResponse'
        '201':
          description: Skill created successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ImportSkillResponse'
        '400':
          description: Invalid form data or zip archive
        '401':
          description: Invalid or missing API key
        '403':
          description: Missing required scope or Skill permission
        '409':
          description: Existing slug conflict or ambiguous upsert slug
        '413':
          description: Uploaded file is too large
        '429':
          description: Rate limit exceeded
        '500':
          description: Internal server error
components:
  schemas:
    ImportSkillRequest:
      type: object
      required:
        - file
        - fileType
      properties:
        file:
          type: string
          format: binary
          description: SKILL.md, .zip, or .skill file content.
        fileType:
          type: string
          enum:
            - md
            - zip
          description: File parser to use.
        mode:
          type: string
          enum:
            - create
            - upsert
          default: create
          description: >-
            Whether to create a Skill or update an editable Skill with the same
            slug.
        integrationIds:
          type: string
          description: JSON-encoded array of integration UUIDs.
    ImportSkillResponse:
      type: object
      required:
        - skill
        - files
      properties:
        skill:
          $ref: '#/components/schemas/Skill'
        files:
          type: array
          items:
            $ref: '#/components/schemas/ImportedSkillFile'
    Skill:
      type: object
      required:
        - id
        - name
        - slug
        - description
        - instructions
        - integrationIds
        - createdAt
        - updatedAt
      properties:
        id:
          type: string
          format: uuid
          description: Unique identifier for the Skill.
        name:
          type: string
          maxLength: 64
          description: Skill name.
        slug:
          type: string
          maxLength: 100
          pattern: ^[a-z0-9-]+$
          description: Stable Skill slug.
        description:
          type: string
          maxLength: 1024
          description: Description used to explain when the Skill should apply.
        instructions:
          type: string
          maxLength: 50000
          description: Skill instructions.
        integrationIds:
          type: array
          items:
            type: string
            format: uuid
          description: >-
            Integration IDs attached to the Skill. Each integration must be
            enabled in your workspace.
        createdAt:
          type: string
          format: date-time
          description: ISO 8601 timestamp for Skill creation.
        updatedAt:
          type: string
          format: date-time
          description: ISO 8601 timestamp for the latest Skill update.
    ImportedSkillFile:
      type: object
      required:
        - path
        - sizeBytes
        - extension
        - hasScript
      properties:
        path:
          type: string
          description: File path inside the imported Skill.
        sizeBytes:
          type: integer
          description: File size in bytes.
        extension:
          type: string
          description: File extension.
        hasScript:
          type: boolean
          description: Whether the file is a script file.
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: API Key
      description: API key as Bearer token. Format "Bearer YOUR_API_KEY"