ATOM Documentation

← Back to App

Marketplace API Documentation

Complete API reference for all marketplace endpoints in the ATOM SaaS platform.

Table of Contents

---

Overview

The marketplace system provides multiple marketplaces for different types of assets:

  • **Skill Marketplace**: Share and discover agent skills
  • **Agent Marketplace**: Publish and install agent templates
  • **Domain Marketplace**: Share specialist domains
  • **Canvas Component Marketplace**: UI components and canvases
  • **Workflow Marketplace**: Workflow templates and blueprints
  • **Private Marketplace**: Tenant-specific skill management

All marketplace endpoints support:

  • Search and filtering
  • Rating and reviews
  • Version management
  • Approval workflows
  • Installation tracking

---

Authentication

Most marketplace endpoints require authentication. The platform supports multiple authentication methods:

API Key Authentication

X-API-Key: your-api-key-here

OAuth Bearer Token

Authorization: Bearer your-access-token

Session Authentication

For web-based requests, session cookies are automatically handled.

---

Skill Marketplace

Base URL: /api/skills

Browse Marketplace

GET /api/skills/marketplace

Browse and search for skills in the marketplace.

**Query Parameters:**

ParameterTypeRequiredDefaultDescription
querystringNo-Search term
categorystringNo-Filter by category
tagsstringNo-Comma-separated tags
skill_typestringNo-Filter by type (api, function, script, docker, container)
sort_bystringNopopularitySort field
limitintegerNo50Max results
offsetintegerNo0Pagination offset

**Response:**

{
  "success": true,
  "skills": [
    {
      "id": "skill-uuid-123",
      "name": "Data Analysis Skill",
      "description": "Advanced data analysis with Python",
      "category": "productivity",
      "skill_type": "script",
      "price": 0.0,
      "rating": 4.5,
      "rating_count": 42,
      "installs": 156,
      "tags": ["python", "data", "analysis"],
      "is_approved": true,
      "created_at": "2026-04-01T12:00:00Z"
    }
  ]
}

**Authentication:** Required (SKILL_VIEW permission)

---

Publish Skill

POST /api/skills/publish

Publish a private skill to the marketplace.

**Request Body:**

{
  "skill_id": "skill-uuid-123",
  "price": 0.0,
  "category": "productivity",
  "tags": ["python", "data"],
  "long_description": "Full description here...",
  "documentation_url": "https://docs.example.com/skill"
}

**Response:**

{
  "success": true,
  "marketplace_id": "marketplace-uuid-456",
  "status": "pending_approval",
  "message": "Skill submitted for marketplace review"
}

**Authentication:** Required (SKILL_MANAGE permission)

---

Approve Skill (Admin)

POST /api/skills/approve/{marketplace_id}

Approve a skill for marketplace availability.

**Path Parameters:**

  • marketplace_id (string): Marketplace listing ID

**Response:**

{
  "success": true,
  "marketplace_id": "marketplace-uuid-456",
  "status": "approved",
  "approved_at": "2026-04-05T12:00:00Z"
}

**Authentication:** Required (GOVERNANCE_APPROVE permission)

---

Reject Skill (Admin)

POST /api/skills/reject/{marketplace_id}

Reject a marketplace submission.

**Path Parameters:**

  • marketplace_id (string): Marketplace listing ID

**Query Parameters:**

  • reason (string): Rejection reason

**Response:**

{
  "success": true,
  "marketplace_id": "marketplace-uuid-456",
  "status": "rejected",
  "reason": "Does not meet quality standards"
}

**Authentication:** Required (GOVERNANCE_APPROVE permission)

---

Install Skill

POST /api/skills/install

Install a marketplace skill into your tenant.

**Request Body:**

{
  "skill_id": "marketplace-uuid-456",
  "agent_id": "agent-uuid-789",
  "config_overrides": {
    "timeout": 30
  }
}

**Response:**

{
  "success": true,
  "skill_id": "installed-skill-uuid-999",
  "status": "installed",
  "message": "Skill installed successfully"
}

**Authentication:** Required (SKILL_MANAGE permission)

---

Rate Skill

POST /api/skills/rate/{marketplace_id}

Rate and review a marketplace skill.

**Path Parameters:**

  • marketplace_id (string): Marketplace listing ID

**Request Body:**

{
  "rating": 5,
  "review": "Excellent skill, saved me hours of work!"
}

**Response:**

{
  "success": true,
  "rating": 5,
  "new_average": 4.7,
  "total_ratings": 43
}

**Authentication:** Required (SKILL_VIEW permission)

---

Create Skill Version

POST /api/skills/version

Create a frozen version of a skill.

**Query Parameters:**

  • skill_id (string): Skill ID
  • version_name (string): Version name (e.g., "v1.0.0")
  • description (string): Optional description

**Response:**

{
  "success": true,
  "version_id": "version-uuid-123",
  "version_name": "v1.0.0"
}

**Authentication:** Required (SKILL_MANAGE permission)

---

Get Version History

GET /api/skills/history/{skill_id}

Get the version history for a skill.

**Path Parameters:**

  • skill_id (string): Skill ID

**Response:**

{
  "success": true,
  "history": [
    {
      "version_id": "version-uuid-123",
      "version_name": "v1.0.0",
      "description": "Initial release",
      "created_at": "2026-04-01T12:00:00Z"
    }
  ]
}

**Authentication:** Required (SKILL_VIEW permission)

---

Rollback Skill

POST /api/skills/rollback/{skill_id}

Rollback a skill to a previous version.

**Path Parameters:**

  • skill_id (string): Skill ID

**Query Parameters:**

  • version_id (string): Target version ID

**Response:**

{
  "success": true,
  "message": "Skill skill-uuid-123 rolled back to version version-uuid-456"
}

**Authentication:** Required (SKILL_MANAGE permission)

---

Agent Marketplace

Base URL: /api/agent-marketplace

Browse Agents

GET /api/agent-marketplace/browse

Browse available agent templates.

**Query Parameters:**

ParameterTypeRequiredDefaultDescription
limitintegerNo50Max results
offsetintegerNo0Pagination offset

**Response:**

{
  "agents": [
    {
      "id": "agent-template-uuid-123",
      "name": "Sales Assistant",
      "description": "Automated sales follow-up agent",
      "category": "sales",
      "price": 19.99,
      "rating": 4.8,
      "installs": 234,
      "version": "1.2.0"
    }
  ],
  "total": 150,
  "limit": 50,
  "offset": 0
}

**Authentication:** Required (Session auth)

---

Publish Agent

POST /api/agent-marketplace/publish/{agent_id}

Publish an agent to the marketplace.

**Path Parameters:**

  • agent_id (string): Agent ID to publish

**Query Parameters:**

ParameterTypeRequiredDescription
namestringYesAgent name
descriptionstringYesAgent description
pricefloatNoPrice (default: 0.0)
categorystringNoCategory

**Response:**

{
  "success": true,
  "template_id": "agent-template-uuid-456",
  "status": "pending_approval",
  "message": "Agent submitted for marketplace review"
}

**Authentication:** Required (Session auth)

---

Install Agent

POST /api/agent-marketplace/install/{template_id}

Install an agent template from the marketplace.

**Path Parameters:**

  • template_id (string): Template ID to install

**Response:**

{
  "success": true,
  "agent_id": "installed-agent-uuid-789",
  "status": "installed",
  "message": "Agent installed successfully"
}

**Authentication:** Required (Session auth)

---

Domain Marketplace

Base URL: /api/v1/domains/marketplace

Submit Domain

POST /api/v1/domains/marketplace/submit

Submit a domain to the marketplace.

**Request Body:**

{
  "domain_id": "domain-uuid-123",
  "price_usd": 29.99,
  "license_type": "MIT",
  "tags": ["sales", "crm", "automation"]
}

**Response:**

{
  "success": true,
  "domain_id": "domain-uuid-123",
  "status": "pending_approval",
  "price_usd": 29.99,
  "license_type": "MIT"
}

**Authentication:** Required (Tenant context)

---

List My Submissions

GET /api/v1/domains/marketplace/my-submissions

List domains submitted by current tenant.

**Response:**

[
  {
    "domain_id": "domain-uuid-123",
    "domain_name": "Sales Automation",
    "status": "approved",
    "price_usd": 29.99,
    "install_count": 45,
    "rating_average": 4.7
  }
]

**Authentication:** Required (Tenant context)

---

Approve Domain (Admin)

POST /api/v1/domains/marketplace/{domain_id}/approve

Approve a domain for marketplace.

**Path Parameters:**

  • domain_id (string): Domain ID

**Response:**

{
  "success": true,
  "domain_id": "domain-uuid-123",
  "status": "approved"
}

**Authentication:** Required (Tenant context, TODO: Admin check)

---

Reject Domain (Admin)

POST /api/v1/domains/marketplace/{domain_id}/reject

Reject a domain submission.

**Path Parameters:**

  • domain_id (string): Domain ID

**Query Parameters:**

  • reason (string): Rejection reason

**Response:**

{
  "success": true,
  "domain_id": "domain-uuid-123",
  "status": "rejected",
  "reason": "Does not meet quality standards"
}

**Authentication:** Required (Tenant context, TODO: Admin check)

---

Search Marketplace

GET /api/v1/domains/marketplace/search

Search marketplace for domains.

**Query Parameters:**

ParameterTypeRequiredDefaultDescription
qstringNo-Search query
categorystringNo-Filter by category
tagsstringNo-Comma-separated tags
max_pricefloatNo-Maximum price
limitintegerNo20Max results (1-100)

**Response:**

[
  {
    "id": "domain-uuid-123",
    "domain_name": "Sales Automation",
    "domain_slug": "sales-automation",
    "description": "Advanced sales workflows",
    "category": "sales",
    "price_usd": 29.99,
    "license_type": "MIT",
    "tags": ["sales", "crm", "automation"],
    "install_count": 45,
    "rating_average": 4.7,
    "rating_count": 12,
    "publisher_tenant_id": "tenant-uuid-789"
  }
]

**Authentication:** None required

---

GET /api/v1/domains/marketplace/trending

Get trending domains by install count.

**Query Parameters:**

  • limit (integer): Max results (1-50, default: 10)

**Response:**

[
  {
    "id": "domain-uuid-123",
    "domain_name": "Sales Automation",
    "install_count": 156,
    "rating_average": 4.7
  }
]

**Authentication:** None required

---

Get Marketplace Stats

GET /api/v1/domains/marketplace/stats

Get marketplace statistics.

**Response:**

{
  "total_domains": 234,
  "approved_domains": 189,
  "pending_domains": 45,
  "total_installs": 5678
}

**Authentication:** None required

---

Install Domain

POST /api/v1/domains/marketplace/install

Install a domain template from marketplace.

**Request Body:**

{
  "template_domain_id": "domain-uuid-123",
  "custom_name": "My Sales Domain"
}

**Response:**

{
  "success": true,
  "domain_id": "installed-domain-uuid-456",
  "domain_name": "My Sales Domain",
  "template_id": "domain-uuid-123"
}

**Authentication:** Required (Tenant context)

---

Rate Domain

POST /api/v1/domains/marketplace/{domain_id}/rate

Rate a domain in the marketplace.

**Path Parameters:**

  • domain_id (string): Domain ID

**Request Body:**

{
  "rating": 4.5
}

**Response:**

{
  "success": true,
  "domain_id": "domain-uuid-123",
  "rating": 4.5,
  "new_average": 4.6,
  "total_ratings": 13
}

**Authentication:** Required (Tenant context)

---

Get Domain Details

GET /api/v1/domains/marketplace/{domain_id}

Get detailed information about a marketplace domain.

**Path Parameters:**

  • domain_id (string): Domain ID

**Response:**

{
  "id": "domain-uuid-123",
  "domain_name": "Sales Automation",
  "domain_slug": "sales-automation",
  "description": "Advanced sales workflows",
  "category": "sales",
  "price_usd": 29.99,
  "license_type": "MIT",
  "tags": ["sales", "crm", "automation"],
  "install_count": 45,
  "rating_average": 4.7,
  "rating_count": 12,
  "publisher_tenant_id": "tenant-uuid-789"
}

**Authentication:** None required

---

Canvas Component Marketplace

Base URL: /api/components (legacy) or /api/canvas-marketplace (preferred)

Browse Components

GET /api/canvas-marketplace/components

Browse marketplace components.

**Query Parameters:**

ParameterTypeRequiredDefaultDescription
querystringNo-Search query
categorystringNo-Filter by category
tagsstringNo-Comma-separated tags
component_typestringNo-Filter by type
min_pricefloatNo-Minimum price
max_pricefloatNo-Maximum price
is_freebooleanNofalseFree only
is_featuredbooleanNofalseFeatured only
sort_bystringNocreated_atSort field
sort_orderstringNodescSort order (asc/desc)
limitintegerNo50Max results (max 100)
offsetintegerNo0Pagination offset

**Response:**

{
  "components": [
    {
      "id": "component-uuid-123",
      "name": "Data Table",
      "description": "Interactive data table component",
      "category": "ui",
      "component_type": "component",
      "tags": ["table", "data", "ui"],
      "version": "1.0.0",
      "thumbnail_url": "https://cdn.example.com/thumb.png",
      "price": 0.0,
      "is_free": true,
      "is_featured": true,
      "license": "MIT",
      "installs": 234,
      "rating": 4.7,
      "rating_count": 45,
      "created_at": "2026-04-01T12:00:00Z",
      "updated_at": "2026-04-05T12:00:00Z"
    }
  ],
  "total": 150,
  "limit": 50,
  "offset": 0,
  "has_more": true
}

**Authentication:** None required (optional for rate limits)

---

Get Component Details

GET /api/canvas-marketplace/components/{component_id}

Get detailed component information including code and config.

**Path Parameters:**

  • component_id (string): Component ID

**Response:**

{
  "id": "component-uuid-123",
  "name": "Data Table",
  "description": "Interactive data table component",
  "category": "ui",
  "component_type": "component",
  "tags": ["table", "data", "ui"],
  "version": "1.0.0",
  "code": "export function DataTable({ data }) { ... }",
  "config_schema": {
    "type": "object",
    "properties": {
      "data": { "type": "array" }
    }
  },
  "dependencies": ["react", "lodash"],
  "css_dependencies": ["bootstrap"],
  "thumbnail_url": "https://cdn.example.com/thumb.png",
  "preview_url": "https://cdn.example.com/preview.png",
  "demo_url": "https://demo.example.com",
  "price": 0.0,
  "is_free": true,
  "is_featured": true,
  "license": "MIT",
  "installs": 234,
  "rating": 4.7,
  "rating_count": 45,
  "recent_ratings": [
    {
      "id": "rating-uuid-456",
      "rating": 5,
      "review": "Great component!",
      "helpful_count": 12,
      "created_at": "2026-04-05T12:00:00Z"
    }
  ],
  "created_at": "2026-04-01T12:00:00Z",
  "updated_at": "2026-04-05T12:00:00Z"
}

**Authentication:** None required

---

Publish Component

POST /api/canvas-marketplace/components/publish

Submit a component for marketplace review.

**Request Body:**

{
  "component_id": "component-uuid-123",
  "price": 0.0,
  "license": "MIT",
  "tags": ["table", "data", "ui"]
}

**Response:**

{
  "status": "submitted_for_approval",
  "component_id": "component-uuid-123",
  "message": "Component submitted for marketplace review. You will be notified once approved."
}

**Authentication:** Required (Session auth)

---

Approve Component (Admin)

POST /api/canvas-marketplace/components/{component_id}/approve

Approve a component for the marketplace.

**Path Parameters:**

  • component_id (string): Component ID

**Response:**

{
  "status": "approved",
  "component_id": "component-uuid-123"
}

**Authentication:** Required (SUPER_ADMIN, ADMIN, or OWNER role)

---

Reject Component (Admin)

POST /api/canvas-marketplace/components/{component_id}/reject

Reject a component from the marketplace.

**Path Parameters:**

  • component_id (string): Component ID

**Query Parameters:**

  • reason (string): Rejection reason

**Response:**

{
  "status": "rejected",
  "component_id": "component-uuid-123",
  "reason": "Does not meet quality standards"
}

**Authentication:** Required (SUPER_ADMIN, ADMIN, or OWNER role)

---

Install Component

POST /api/canvas-marketplace/components/install

Install a marketplace component to tenant's canvas.

**Request Body:**

{
  "component_id": "component-uuid-123",
  "canvas_id": "canvas-uuid-456"
}

**Response:**

{
  "status": "installed",
  "component_id": "component-uuid-123",
  "canvas_id": "canvas-uuid-456",
  "message": "Component installed successfully"
}

**Authentication:** Required (Session auth)

---

Rate Component

POST /api/canvas-marketplace/components/{component_id}/rate

Rate and review a marketplace component.

**Path Parameters:**

  • component_id (string): Component ID

**Request Body:**

{
  "rating": 5,
  "review": "Excellent component!"
}

**Response:**

{
  "status": "rated",
  "component_id": "component-uuid-123",
  "rating": 5,
  "aggregate_rating": 4.7
}

**Authentication:** Required (Session auth)

---

Get Component Ratings

GET /api/canvas-marketplace/components/{component_id}/ratings

Get ratings and reviews for a component.

**Path Parameters:**

  • component_id (string): Component ID

**Query Parameters:**

ParameterTypeRequiredDefaultDescription
limitintegerNo20Max ratings (max 100)
offsetintegerNo0Pagination offset

**Response:**

{
  "ratings": [
    {
      "id": "rating-uuid-456",
      "rating": 5,
      "review": "Great component!",
      "helpful_count": 12,
      "not_helpful_count": 0,
      "author_response": "Thank you!",
      "author_response_at": "2026-04-06T12:00:00Z",
      "created_at": "2026-04-05T12:00:00Z"
    }
  ],
  "total": 45,
  "limit": 20,
  "offset": 0
}

**Authentication:** None required

---

List Categories

GET /api/canvas-marketplace/categories

List all component categories with counts.

**Response:**

{
  "categories": [
    {
      "name": "ui",
      "count": 45
    },
    {
      "name": "charts",
      "count": 23
    }
  ]
}

**Authentication:** None required

---

List Tags

GET /api/canvas-marketplace/tags

List all popular tags.

**Response:**

{
  "tags": [
    {
      "name": "table",
      "count": 42
    },
    {
      "name": "data",
      "count": 35
    }
  ]
}

**Authentication:** None required

---

Workflow Marketplace

Base URL: /api/marketplace

Get Templates

GET /api/marketplace/templates

Get workflow templates with filtering.

**Query Parameters:**

ParameterTypeRequiredDefaultDescription
categorystringNo-Filter by category
template_typestringNo-Filter by type (legacy, advanced, industry)
industrystringNo-Filter by industry
tagslistNo-Filter by tags

**Response:**

[
  {
    "id": "tmpl_email_summarizer",
    "name": "Daily Email Summarizer",
    "description": "Summarize unread emails from Gmail and send digest to Slack",
    "category": "Productivity",
    "author": "ATOM Team",
    "version": "1.0.0",
    "integrations": ["gmail", "slack", "openai"],
    "complexity": "Beginner",
    "tags": ["email", "automation"],
    "estimated_duration": 300,
    "multi_step_support": true,
    "pause_resume_support": false,
    "downloads": 156,
    "rating": 4.5,
    "template_type": "legacy",
    "created_at": "2026-04-01T12:00:00Z"
  }
]

**Authentication:** None required

---

Get Template Types

GET /api/marketplace/templates/types

Get available template types.

**Response:**

{
  "template_types": [
    {
      "value": "legacy",
      "label": "Legacy",
      "description": "Legacy workflow templates"
    },
    {
      "value": "advanced",
      "label": "Advanced",
      "description": "Advanced workflow templates"
    },
    {
      "value": "industry",
      "label": "Industry",
      "description": "Industry workflow templates"
    }
  ]
}

**Authentication:** None required

---

GET /api/marketplace/templates/featured

Get featured templates.

**Query Parameters:**

  • limit (integer): Max results (1-50, default: 10)

**Response:**

[
  {
    "id": "tmpl_email_summarizer",
    "name": "Daily Email Summarizer",
    "rating": 4.5,
    "downloads": 156,
    "is_featured": true
  }
]

**Authentication:** None required

---

Get Template Details

GET /api/marketplace/templates/{template_id}

Get a specific template by ID.

**Path Parameters:**

  • template_id (string): Template ID

**Response:**

{
  "id": "tmpl_email_summarizer",
  "name": "Daily Email Summarizer",
  "description": "Summarize unread emails from Gmail",
  "category": "Productivity",
  "author": "ATOM Team",
  "version": "1.0.0",
  "integrations": ["gmail", "slack", "openai"],
  "complexity": "Beginner",
  "workflow_data": {
    "nodes": [
      {
        "id": "1",
        "type": "trigger",
        "label": "Every Morning",
        "config": {"cron": "0 9 * * *"}
      }
    ],
    "edges": [
      {"source": "1", "target": "2"}
    ]
  },
  "downloads": 156,
  "rating": 4.5,
  "tags": ["email", "automation"]
}

**Authentication:** None required

---

Import Template

POST /api/marketplace/templates/{template_id}/import

Import a template into your workspace.

**Path Parameters:**

  • template_id (string): Template ID

**Response:**

{
  "id": "workflow-uuid-789",
  "name": "Imported: Daily Email Summarizer",
  "nodes": [...],
  "edges": [...],
  "imported_at": "2026-04-05T12:00:00Z"
}

**Authentication:** None required

---

Create Advanced Template

POST /api/marketplace/templates/advanced

Create a new advanced workflow template.

**Request Body:**

{
  "id": "advanced_custom_workflow",
  "name": "Custom Advanced Workflow",
  "description": "My custom workflow",
  "category": "Custom",
  "author": "Your Name",
  "version": "1.0.0",
  "integrations": ["slack", "email"],
  "complexity": "Intermediate",
  "tags": ["custom", "automation"],
  "input_schema": [
    {
      "name": "data_source",
      "type": "select",
      "label": "Data Source",
      "required": true
    }
  ],
  "steps": [
    {
      "step_id": "validate",
      "name": "Validate Inputs",
      "step_type": "validation",
      "estimated_duration": 30
    }
  ],
  "estimated_duration": 300,
  "prerequisites": ["api_access"],
  "use_cases": ["Data processing"],
  "benefits": ["Automation", "Efficiency"]
}

**Response:**

{
  "id": "advanced_custom_workflow",
  "name": "Custom Advanced Workflow",
  "input_schema": [...],
  "steps": [...],
  "estimated_duration": 300,
  "created_at": "2026-04-05T12:00:00Z"
}

**Authentication:** None required

---

Create Workflow from Template

POST /api/marketplace/templates/{template_id}/create-workflow

Create a workflow from an advanced template.

**Path Parameters:**

  • template_id (string): Template ID

**Query Parameters:**

  • workflow_name (string): Workflow name
  • parameters (object): User inputs (JSON)

**Response:**

{
  "status": "success",
  "workflow_definition": {
    "workflow_id": "workflow-uuid-789",
    "name": "My Workflow",
    "category": "Data Processing",
    "input_schema": [...],
    "steps": [...],
    "user_inputs": {...}
  },
  "message": "Workflow 'My Workflow' created successfully from template tmpl_email_summarizer"
}

**Authentication:** None required

---

Import Workflow (File)

POST /api/marketplace/import

Import a workflow from a JSON file.

**Request Body (multipart/form-data):**

  • file: Workflow JSON file

**Response:**

{
  "id": "workflow-uuid-789",
  "name": "Imported: My Workflow",
  "nodes": [...],
  "edges": [...],
  "imported_at": "2026-04-05T12:00:00Z"
}

**Authentication:** None required

---

Export Workflow

POST /api/marketplace/export

Export a workflow to JSON format.

**Request Body:**

{
  "name": "My Workflow",
  "description": "My custom workflow",
  "nodes": [...],
  "edges": [...]
}

**Response:**

{
  "name": "My Workflow",
  "description": "My custom workflow",
  "nodes": [...],
  "edges": [...],
  "metadata": {
    "exported_at": "2026-04-05T12:00:00Z",
    "version": "1.0.0"
  }
}

**Authentication:** None required

---

Get Template Statistics

GET /api/marketplace/templates/statistics

Get marketplace statistics.

**Response:**

{
  "total_templates": 50,
  "total_downloads": 1234,
  "average_rating": 4.5,
  "categories": {
    "Productivity": {"count": 20, "downloads": 500},
    "Sales": {"count": 15, "downloads": 400}
  },
  "template_types": {
    "legacy": {"count": 30, "downloads": 600},
    "advanced": {"count": 15, "downloads": 500},
    "industry": {"count": 5, "downloads": 134}
  },
  "complexity_levels": {
    "Beginner": {"count": 20, "downloads": 400},
    "Intermediate": {"count": 20, "downloads": 500},
    "Advanced": {"count": 10, "downloads": 334}
  }
}

**Authentication:** None required

---

Private Marketplace

Base URL: /api/v1/skills

List Private Skills

GET /api/v1/skills/private

List tenant's private skills (created + installed).

**Query Parameters:**

ParameterTypeRequiredDefaultDescription
querystringNo-Search term
categorystringNo-Filter by category
skill_typestringNo-Filter by type
is_installedbooleanNo-Filter by installation status
sort_bystringNonameSort field
sort_orderstringNoascSort order (asc/desc)
limitintegerNo50Max results
offsetintegerNo0Pagination offset

**Response:**

{
  "success": true,
  "skills": [
    {
      "id": "skill-uuid-123",
      "name": "My Custom Skill",
      "description": "Custom skill for my workflow",
      "skill_type": "function",
      "category": "productivity",
      "is_own": true,
      "is_installed": false,
      "rating": 4.5,
      "created_at": "2026-04-01T12:00:00Z"
    }
  ],
  "total": 25,
  "limit": 50,
  "offset": 0
}

**Authentication:** Required (SKILL_VIEW permission)

---

Install from Marketplace

POST /api/v1/skills/private/install

Install a marketplace skill to private marketplace.

**Request Body:**

{
  "marketplace_skill_id": "marketplace-skill-uuid-123",
  "agent_id": "agent-uuid-456",
  "config_overrides": {
    "timeout": 60
  }
}

**Response:**

{
  "success": true,
  "skill_id": "installed-skill-uuid-789",
  "status": "installed",
  "message": "Skill installed successfully",
  "packages_installed": [
    {
      "package_name": "requests",
      "package_type": "python",
      "status": "installed"
    }
  ]
}

**Authentication:** Required (SKILL_MANAGE permission)

---

Customize Skill

PUT /api/v1/skills/private/{skill_id}

Customize an installed private skill.

**Path Parameters:**

  • skill_id (string): Skill ID

**Request Body:**

{
  "name": "My Custom Name",
  "description": "My custom description",
  "config_overrides": {
    "timeout": 60
  },
  "environment_vars": {
    "API_KEY": "custom-key"
  }
}

**Response:**

{
  "success": true,
  "skill_id": "skill-uuid-123",
  "name": "My Custom Name",
  "description": "My custom description",
  "config_overrides_applied": true
}

**Authentication:** Required (SKILL_MANAGE permission)

---

Uninstall Skill

DELETE /api/v1/skills/private/{skill_id}

Uninstall a marketplace skill from private marketplace.

**Path Parameters:**

  • skill_id (string): Skill ID

**Response:**

{
  "success": true,
  "skill_id": "skill-uuid-123",
  "status": "uninstalled",
  "message": "Skill uninstalled successfully"
}

**Authentication:** Required (SKILL_MANAGE permission)

---

Create Private Skill

POST /api/v1/skills/private

Create a completely private skill (not shared to marketplace).

**Request Body:**

{
  "name": "My Private Skill",
  "description": "Internal skill only",
  "skill_type": "function",
  "input_schema": {
    "type": "object",
    "properties": {
      "data": {"type": "string"}
    }
  },
  "output_schema": {
    "type": "object",
    "properties": {
      "result": {"type": "string"}
    }
  },
  "config": {
    "timeout": 30
  },
  "code": "def execute(data): return {'result': data}",
  "category": "productivity",
  "tags": ["internal", "custom"]
}

**Response:**

{
  "success": true,
  "skill_id": "skill-uuid-123",
  "name": "My Private Skill",
  "status": "created",
  "is_public": false
}

**Authentication:** Required (SKILL_MANAGE permission)

---

Public Marketplace API

Base URL: /api/public/v1/marketplace

Browse Public Skills

GET /api/public/v1/marketplace/skills

Browse the public skill marketplace (read-only API).

**Query Parameters:**

ParameterTypeRequiredDefaultDescription
querystringNo-Search term
categorystringNo-Filter by category
tagsstringNo-Comma-separated tags
skill_typestringNo-Filter by type
is_freebooleanNofalseFree only
is_featuredbooleanNofalseFeatured only
sort_bystringNocreated_atSort field
sort_orderstringNodescSort order (asc/desc)
limitintegerNo50Max results (max 100)
offsetintegerNo0Pagination offset

**Response:**

{
  "skills": [
    {
      "id": "skill-uuid-123",
      "name": "Data Analysis",
      "description": "Advanced data analysis",
      "category": "productivity",
      "skill_type": "script",
      "price": 0.0,
      "is_free": true,
      "rating": 4.5,
      "rating_count": 42,
      "installs": 156,
      "tags": ["python", "data"],
      "created_at": "2026-04-01T12:00:00Z"
    }
  ],
  "total": 150,
  "limit": 50,
  "offset": 0,
  "has_more": true
}

**Authentication:** Optional (higher rate limits with auth)

---

Get Public Skill Details

GET /api/public/v1/marketplace/skills/{skill_id}

Get detailed information about a specific marketplace skill.

**Path Parameters:**

  • skill_id (string): Skill ID

**Response:**

{
  "id": "skill-uuid-123",
  "name": "Data Analysis",
  "description": "Advanced data analysis with Python",
  "long_description": "Full documentation...",
  "category": "productivity",
  "skill_type": "script",
  "input_schema": {...},
  "output_schema": {...},
  "config": {...},
  "price": 0.0,
  "is_free": true,
  "rating": 4.5,
  "rating_count": 42,
  "installs": 156,
  "tags": ["python", "data"],
  "license": "MIT",
  "documentation_url": "https://docs.example.com",
  "repository_url": "https://github.com/example/skill",
  "python_packages": [{"name": "pandas", "version": "2.0.0"}],
  "npm_packages": [],
  "recent_reviews": [
    {
      "rating": 5,
      "review": "Excellent!",
      "created_at": "2026-04-05T12:00:00Z"
    }
  ],
  "created_at": "2026-04-01T12:00:00Z"
}

**Authentication:** Optional

---

Get Categories

GET /api/public/v1/marketplace/categories

Get all skill categories.

**Response:**

{
  "categories": ["productivity", "sales", "finance", "communication"]
}

**Authentication:** Optional

---

Get Tags

GET /api/public/v1/marketplace/tags

Get all skill tags with usage counts.

**Response:**

{
  "tags": [
    {"name": "python", "count": 42},
    {"name": "api", "count": 35},
    {"name": "data", "count": 28}
  ]
}

**Authentication:** Optional

---

Submit Skill (Public API)

POST /api/public/v1/marketplace/submit

Submit a skill for the marketplace (requires authentication).

**Request Body:**

{
  "name": "My Skill",
  "description": "Skill description",
  "skill_type": "function",
  "input_schema": {...},
  "output_schema": {...},
  "config": {...},
  "code": "...",
  "long_description": "Full documentation...",
  "category": "productivity",
  "tags": ["python", "data"],
  "price": 0.0,
  "license": "MIT",
  "documentation_url": "https://docs.example.com",
  "repository_url": "https://github.com/example/skill",
  "python_packages": [{"name": "requests", "version": "2.28.0"}],
  "npm_packages": []
}

**Response:**

{
  "success": true,
  "skill_id": "skill-uuid-123",
  "status": "pending_approval",
  "message": "Skill submitted for marketplace review"
}

**Authentication:** Required (API key or OAuth token)

---

Rate Skill (Public API)

POST /api/public/v1/marketplace/skills/{skill_id}/rate

Rate a marketplace skill (requires authentication).

**Path Parameters:**

  • skill_id (string): Skill ID

**Request Body:**

{
  "rating": 5,
  "review": "Excellent skill!"
}

**Response:**

{
  "success": true,
  "rating": 5,
  "new_average": 4.7,
  "total_ratings": 43
}

**Authentication:** Required (API key or OAuth token)

---

Get Reviews

GET /api/public/v1/marketplace/skills/{skill_id}/reviews

Get reviews for a skill (no authentication required).

**Path Parameters:**

  • skill_id (string): Skill ID

**Query Parameters:**

ParameterTypeRequiredDefaultDescription
limitintegerNo20Max reviews (1-100)
offsetintegerNo0Pagination offset

**Response:**

{
  "reviews": [
    {
      "id": "review-uuid-456",
      "rating": 5,
      "review": "Excellent skill!",
      "created_at": "2026-04-05T12:00:00Z",
      "helpful_count": 12
    }
  ],
  "total": 42,
  "limit": 20,
  "offset": 0
}

**Authentication:** None required

---

Flag Review

POST /api/public/v1/marketplace/reviews/{review_id}/flag

Flag a review for moderation (requires authentication).

**Path Parameters:**

  • review_id (string): Review ID

**Query Parameters:**

  • reason (string): Flag reason (1-500 chars)

**Response:**

{
  "success": true,
  "review_id": "review-uuid-456",
  "status": "flagged"
}

**Authentication:** Required (API key or OAuth token)

---

Error Codes

HTTP Status Codes

StatusDescription
200Success
201Created
400Bad Request
401Unauthorized
403Forbidden
404Not Found
429Rate Limit Exceeded
500Internal Server Error

Error Response Format

All error responses follow this format:

{
  "error": "Error type",
  "message": "Detailed error message",
  "code": "ERROR_CODE",
  "details": {
    "field": "Additional context"
  }
}

Common Error Scenarios

Authentication Errors

**401 Unauthorized**

{
  "error": "Unauthorized",
  "message": "Authentication required. Use X-API-Key or Authorization: Bearer header.",
  "code": "AUTH_REQUIRED"
}

**401 Invalid API Key**

{
  "error": "Unauthorized",
  "message": "Invalid or inactive API key",
  "code": "INVALID_API_KEY"
}

**401 Expired Token**

{
  "error": "Unauthorized",
  "message": "Invalid or expired OAuth token",
  "code": "EXPIRED_TOKEN"
}

Permission Errors

**403 Forbidden**

{
  "error": "Forbidden",
  "message": "Read-only key cannot perform write operations",
  "code": "INSUFFICIENT_SCOPE"
}

**403 Governance Denied**

{
  "error": "Forbidden",
  "message": "Agent maturity level insufficient for this action",
  "code": "GOVERNANCE_DENIED"
}

Validation Errors

**400 Bad Request**

{
  "error": "Bad Request",
  "message": "Validation failed",
  "code": "VALIDATION_ERROR",
  "details": {
    "field": "skill_type",
    "message": "Invalid skill type. Must be one of: api, function, script, docker, container"
  }
}

**400 Invalid Input**

{
  "error": "Bad Request",
  "message": "Maximum limit is 100",
  "code": "INVALID_LIMIT"
}

Not Found Errors

**404 Not Found**

{
  "error": "Not Found",
  "message": "Skill not found or not approved",
  "code": "SKILL_NOT_FOUND"
}

**404 Component Not Found**

{
  "error": "Not Found",
  "message": "Component not found",
  "code": "COMPONENT_NOT_FOUND"
}

Rate Limiting

**429 Rate Limit Exceeded**

{
  "error": "Rate Limit Exceeded",
  "message": "Rate limit exceeded. Please try again later.",
  "code": "RATE_LIMIT_EXCEEDED",
  "retry_after": 60
}

Headers:

Retry-After: 60

Server Errors

**500 Internal Server Error**

{
  "error": "Internal Server Error",
  "message": "An unexpected error occurred",
  "code": "INTERNAL_ERROR"
}

Marketplace-Specific Error Codes

CodeHTTP StatusDescription
SKILL_NOT_FOUND404Skill not found or not approved
COMPONENT_NOT_FOUND404Component not found
TEMPLATE_NOT_FOUND404Template not found
DOMAIN_NOT_FOUND404Domain not found
AGENT_NOT_FOUND404Agent template not found
ALREADY_PUBLISHED409Item already published
PENDING_APPROVAL403Item is pending approval
APPROVAL_REQUIRED403Item requires admin approval
NOT_OWNER403User does not own this item
INSTALL_FAILED422Installation failed
PACKAGE_INSTALL_FAILED422Package installation failed
INVALID_VERSION400Invalid version format
RATING_EXISTS409User has already rated this item
TENANT_NOT_FOUND404Tenant context not found
TENANT_LIMIT_EXCEEDED429Tenant quota limit exceeded
AGENT_LIMIT_EXCEEDED429Agent count limit exceeded
SKILL_LIMIT_EXCEEDED429Skill count limit exceeded
PACKAGE_NOT_WHITELISTED403Package not in whitelist
PACKAGE_VULNERABILITY403Package has security vulnerabilities
DEPENDENCY_MISSING422Required dependency missing
CONFIG_SCHEMA_INVALID400Configuration schema invalid
INPUT_VALIDATION_FAILED400Input validation failed
MISSING_REQUIRED_FIELD400Required field missing
INVALID_ENUM_VALUE400Invalid enum value provided
DUPLICATE_ENTRY409Duplicate entry detected
CONFLICTING_OPERATION409Conflicting operation in progress
SERVICE_UNAVAILABLE503Service temporarily unavailable
MAINTENANCE_MODE503System under maintenance
MARKETPLACE_DISABLED503Marketplace feature disabled

---

Advanced Error Scenarios

Tenant Quota Errors

**429 Too Many Requests - Tenant Agent Limit**

{
  "error": "Quota Exceeded",
  "message": "Tenant has reached maximum agent limit (10). Upgrade to Team plan for 25 agents.",
  "code": "AGENT_LIMIT_EXCEEDED",
  "details": {
    "current": 10,
    "limit": 10,
    "plan": "Free",
    "upgrade_url": "https://atom-saas.fly.dev/settings/billing"
  }
}

**Solution:** Upgrade plan or delete unused agents

---

**429 Too Many Requests - Daily Skill Execution Limit**

{
  "error": "Quota Exceeded",
  "message": "Daily skill execution limit reached (50/50). Resets at midnight UTC.",
  "code": "SKILL_LIMIT_EXCEEDED",
  "details": {
    "current": 50,
    "limit": 50,
    "resets_at": "2026-04-06T00:00:00Z"
  }
}

**Solution:** Wait for daily reset or upgrade plan

---

Package Installation Errors

**403 Forbidden - Package Not Whitelisted**

{
  "error": "Forbidden",
  "message": "Package 'malicious-package' is not whitelisted. Contact administrator to request approval.",
  "code": "PACKAGE_NOT_WHITELISTED",
  "details": {
    "package_name": "malicious-package",
    "package_type": "python",
    "request_url": "https://atom-saas.fly.dev/admin/packages/request"
  }
}

**Solution:** Request package whitelisting from admin

---

**403 Forbidden - Package Vulnerability Detected**

{
  "error": "Forbidden",
  "message": "Package 'old-package' has 2 known security vulnerabilities. Update to version 2.0.0 or later.",
  "code": "PACKAGE_VULNERABILITY",
  "details": {
    "package_name": "old-package",
    "current_version": "1.5.0",
    "safe_version": "2.0.0",
    "vulnerabilities": [
      {
        "severity": "HIGH",
        "cve": "CVE-2024-12345",
        "description": "Remote code execution vulnerability"
      }
    ]
  }
}

**Solution:** Update package to safe version

---

**422 Unprocessable Entity - Dependency Missing**

{
  "error": "Installation Failed",
  "message": "Required dependency 'pandas' is not installed. Install it first.",
  "code": "DEPENDENCY_MISSING",
  "details": {
    "missing_package": "pandas",
    "required_by": "data-analysis-skill",
    "install_command": "pip install pandas>=2.0.0"
  }
}

**Solution:** Install missing dependency

---

Governance Errors

**403 Forbidden - Agent Maturity Insufficient**

{
  "error": "Governance Denied",
  "message": "Agent maturity 'student' cannot perform action 'send_email'. Required maturity: 'supervised'.",
  "code": "GOVERNANCE_DENIED",
  "details": {
    "agent_id": "agent-uuid-123",
    "current_maturity": "student",
    "required_maturity": "supervised",
    "action": "send_email",
    "reason": "Student agents are read-only. Graduate agent to intern for proposal permissions."
  }
}

**Solution:** Graduate agent to higher maturity level

---

**403 Forbidden - Skill Requires Approval**

{
  "error": "Approval Required",
  "message": "Skill 'exec-shell-commands' requires explicit approval due to security risk.",
  "code": "APPROVAL_REQUIRED",
  "details": {
    "skill_id": "skill-uuid-456",
    "risk_level": "HIGH",
    "reason": "Can execute arbitrary shell commands",
    "approval_url": "https://atom-saas.fly.dev/admin/skills/approve"
  }
}

**Solution:** Request admin approval for high-risk skills

---

Validation Errors

**400 Bad Request - Invalid Configuration Schema**

{
  "error": "Validation Failed",
  "message": "Configuration schema does not match skill requirements.",
  "code": "CONFIG_SCHEMA_INVALID",
  "details": {
    "expected_schema": {
      "type": "object",
      "properties": {
        "api_key": {"type": "string"},
        "timeout": {"type": "number"}
      },
      "required": ["api_key"]
    },
    "provided_config": {
      "api_key": "sk-123",
      "invalid_field": "value"
    },
    "errors": [
      "Additional property 'invalid_field' not allowed",
      "Missing required property 'timeout'"
    ]
  }
}

**Solution:** Fix configuration to match schema

---

**400 Bad Request - Invalid Enum Value**

{
  "error": "Validation Failed",
  "message": "Invalid value for field 'skill_type'.",
  "code": "INVALID_ENUM_VALUE",
  "details": {
    "field": "skill_type",
    "provided_value": "webhook",
    "allowed_values": ["api", "function", "script", "docker", "container"]
  }
}

**Solution:** Use valid enum value

---

**409 Conflict - Duplicate Entry**

{
  "error": "Duplicate Entry",
  "message": "A skill with this name already exists in your private marketplace.",
  "code": "DUPLICATE_ENTRY",
  "details": {
    "field": "name",
    "value": "Data Analysis",
    "existing_skill_id": "skill-uuid-789",
    "suggestion": "Use a different name or update the existing skill"
  }
}

**Solution:** Use unique name or update existing entry

---

Service Errors

**503 Service Unavailable - Maintenance Mode**

{
  "error": "Service Unavailable",
  "message": "Marketplace is under maintenance. Expected downtime: 30 minutes.",
  "code": "MAINTENANCE_MODE",
  "details": {
    "started_at": "2026-04-05T12:00:00Z",
    "expected_end": "2026-04-05T12:30:00Z",
    "status_page": "https://status.atomagentos.com"
  }
}

**Solution:** Wait for maintenance to complete

---

**503 Service Unavailable - Marketplace Disabled**

{
  "error": "Service Unavailable",
  "message": "Marketplace feature is disabled for this tenant.",
  "code": "MARKETPLACE_DISABLED",
  "details": {
    "feature": "public_marketplace",
    "reason": "Enterprise plan required",
    "upgrade_url": "https://atom-saas.fly.dev/settings/billing"
  }
}

**Solution:** Upgrade to enable marketplace

---

Troubleshooting Guide

Authentication Issues

Problem: 401 Unauthorized - No API Key Provided

**Symptoms:**

{
  "error": "Unauthorized",
  "message": "Authentication required. Use X-API-Key or Authorization: Bearer header.",
  "code": "AUTH_REQUIRED"
}

**Diagnosis:**

  • Missing X-API-Key header
  • Missing Authorization: Bearer header
  • Session cookie expired

**Solutions:**

  1. **Add API Key Header:**
curl -X GET "https://atom-saas.fly.dev/api/skills/marketplace" \
  -H "X-API-Key: sk-your-api-key"
  1. **Add Bearer Token:**
curl -X GET "https://atom-saas.fly.dev/api/skills/marketplace" \
  -H "Authorization: Bearer your-access-token"
  1. **Check API Key Format:**
  • Must start with sk-
  • Only alphanumeric characters after prefix
  • Example: sk-abc123def456

---

Problem: 401 Unauthorized - Invalid API Key

**Symptoms:**

{
  "error": "Unauthorized",
  "message": "Invalid or inactive API key",
  "code": "INVALID_API_KEY"
}

**Diagnosis:**

  • API key doesn't exist in database
  • API key is inactive (is_active=False)
  • API key has been revoked

**Solutions:**

  1. **Verify Key in Dashboard:**
  • Go to Settings → API Keys
  • Check key status is "Active"
  • Copy key again (ensure no extra spaces)
  1. **Generate New Key:**
  • Delete old key
  • Create new key
  • Update application with new key
  1. **Check Key Scope:**
# Verify key has correct scope
key = db.query(APIKey).filter(key_value="sk-your-key").first()
print(f"Scope: {key.scope}")  # Should be "read_write" for operations

---

Problem: 401 Unauthorized - Expired OAuth Token

**Symptoms:**

{
  "error": "Unauthorized",
  "message": "Invalid or expired OAuth token",
  "code": "EXPIRED_TOKEN"
}

**Diagnosis:**

  • Access token expired (typically 1 hour lifetime)
  • Refresh token also expired
  • Token revoked by user

**Solutions:**

  1. **Refresh Access Token:**
# Use refresh token to get new access token
response = requests.post("https://atom-saas.fly.dev/oauth/token", data={
    "grant_type": "refresh_token",
    "refresh_token": refresh_token
})

new_access_token = response.json()["access_token"]
  1. **Re-authenticate User:**
# Redirect user to OAuth flow
auth_url = f"https://atom-saas.fly.dev/oauth/authorize?response_type=code&client_id={client_id}&redirect_uri={redirect_uri}"
# Redirect user to auth_url

---

Permission Issues

Problem: 403 Forbidden - Insufficient Scope

**Symptoms:**

{
  "error": "Forbidden",
  "message": "Read-only key cannot perform write operations",
  "code": "INSUFFICIENT_SCOPE"
}

**Diagnosis:**

  • API key has read scope
  • Attempting write operation (POST, PUT, DELETE)

**Solutions:**

  1. **Check Key Scope:**
key = db.query(APIKey).filter(key_value="sk-your-key").first()
if key.scope == "read":
    print("Key is read-only. Need read_write scope.")
  1. **Create Read-Write Key:**
  • Delete read-only key
  • Create new key with scope="read_write"
  1. **Use Correct Key:**
# Use read_write key for write operations
curl -X POST "https://atom-saas.fly.dev/api/skills/publish" \
  -H "X-API-Key: sk-read-write-key" \
  -H "Content-Type: application/json" \
  -d '{"skill_id": "..."}'

---

Problem: 403 Forbidden - Governance Denied

**Symptoms:**

{
  "error": "Forbidden",
  "message": "Agent maturity level insufficient for this action",
  "code": "GOVERNANCE_DENIED"
}

**Diagnosis:**

  • Agent maturity too low for action
  • Action requires higher maturity level

**Maturity Levels:**

  • student: Read-only (browse, search)
  • intern: Proposals (requires approval)
  • supervised: Live monitoring (can act with supervision)
  • autonomous: Full access (can supervise others)

**Solutions:**

  1. **Graduate Agent:**
# Check graduation readiness
from core.agent_graduation_service import AgentGraduationService

grad_service = AgentGraduationService(db)
result = grad_service.check_unified_graduation(
    agent_id="agent-uuid-123",
    tenant_id=tenant_id,
    target_maturity="SUPERVISED"
)

if result["ready"]:
    # Graduate agent
    grad_service graduate_agent(agent_id, "SUPERVISED")
  1. **Use Higher Maturity Agent:**
# Find supervised agent
agent = db.query(Agent).filter(
    Agent.maturity == "supervised",
    Agent.tenant_id == tenant_id
).first()

# Use this agent for the action

---

Rate Limiting Issues

Problem: 429 Too Many Requests

**Symptoms:**

HTTP/1.1 429 Too Many Requests
Retry-After: 60

{
  "error": "Rate Limit Exceeded",
  "message": "Rate limit exceeded. Please try again later.",
  "code": "RATE_LIMIT_EXCEEDED"
}

**Diagnosis:**

  • Exceeded request limit (60-100 req/min depending on auth)
  • Too many requests from same IP/API key

**Solutions:**

  1. **Implement Exponential Backoff:**
import time
import random

def make_request_with_backoff(url, headers, max_retries=3):
    for attempt in range(max_retries):
        response = requests.get(url, headers=headers)

        if response.status_code != 429:
            return response

        # Exponential backoff: 2^attempt + random jitter
        wait_time = (2 ** attempt) + random.uniform(0, 1)
        retry_after = int(response.headers.get("Retry-After", wait_time))

        print(f"Rate limited. Waiting {retry_after} seconds...")
        time.sleep(retry_after)

    return response  # Last attempt
  1. **Cache Responses:**
from functools import lru_cache
import time

@lru_cache(maxsize=100)
def get_marketplace_skills(cache_buster=None):
    """Cache marketplace skills for 5 minutes"""
    response = requests.get(
        "https://atom-saas.fly.dev/api/skills/marketplace",
        headers={"X-API-Key": "sk-your-key"}
    )
    return response.json()

# Use cache buster to invalidate
cache_key = int(time.time() // 300)  # New key every 5 minutes
skills = get_marketplace_skills(cache_buster=cache_key)
  1. **Batch Operations:**
# Instead of multiple requests
for skill_id in skill_ids:
    response = requests.get(f"/api/skills/{skill_id}")  # Bad: N requests

# Use single request with IDs
response = requests.get("/api/skills", params={"ids": ",".join(skill_ids)})  # Good: 1 request
  1. **Monitor Rate Limit Headers:**
response = requests.get(url, headers=headers)

# Check rate limit status
remaining = int(response.headers.get("X-RateLimit-Remaining", 0))
limit = int(response.headers.get("X-RateLimit-Limit", 60))

if remaining < 10:
    print(f"Warning: Only {remaining} requests remaining (limit: {limit})")
    # Slow down requests

---

Installation Failures

Problem: 422 Unprocessable Entity - Package Not Whitelisted

**Symptoms:**

{
  "error": "Installation Failed",
  "message": "Package 'malicious-package' is not whitelisted.",
  "code": "PACKAGE_NOT_WHITELISTED"
}

**Diagnosis:**

  • Skill requires package not in whitelist
  • Security policy blocks unknown packages

**Solutions:**

  1. **Request Package Whitelist:**
# Submit package for approval
curl -X POST "https://atom-saas.fly.dev/api/packages/request" \
  -H "X-API-Key: sk-your-key" \
  -H "Content-Type: application/json" \
  -d '{
    "package_name": "data-package",
    "package_type": "python",
    "version": "1.0.0",
    "reason": "Required for data analysis skill"
  }'
  1. **Use Alternative Package:**
# Find whitelisted alternative
from core.package_whitelist_service import PackageWhitelistService

service = PackageWhitelistService(db)
alternatives = service.search_packages(
    query="data processing",
    package_type="python"
)

print(f"Alternatives: {alternatives}")
  1. **Contact Admin:**
  • Email: support@atomagentos.com
  • Include: package name, version, use case

---

Problem: 403 Forbidden - Package Vulnerability

**Symptoms:**

{
  "error": "Forbidden",
  "message": "Package 'old-package' has 2 known security vulnerabilities.",
  "code": "PACKAGE_VULNERABILITY"
}

**Diagnosis:**

  • Package has known CVEs
  • Automated security scan detected issues

**Solutions:**

  1. **Update Package:**
# Check for safe version
from core.package_installation_service import PackageInstallationService

service = PackageInstallationService(db)
safe_version = service.get_safe_version("old-package")

print(f"Update to version: {safe_version}")  # e.g., "2.0.0"
  1. **Modify Skill Requirements:**
{
  "python_packages": [
    {
      "name": "old-package",
      "version": "2.0.0",  // Updated to safe version
      "type": "python"
    }
  ]
}
  1. **Review CVE Details:**
# Check vulnerability details
curl "https://atom-saas.fly.dev/api/packages/old-package/vulnerabilities" \
  -H "X-API-Key: sk-your-key"

---

Problem: 422 Unprocessable Entity - Dependency Missing

**Symptoms:**

{
  "error": "Installation Failed",
  "message": "Required dependency 'pandas' is not installed.",
  "code": "DEPENDENCY_MISSING"
}

**Diagnosis:**

  • Skill requires package that isn't installed
  • Dependency chain incomplete

**Solutions:**

  1. **Install Missing Dependency:**
from core.package_installation_service import PackageInstallationService

service = PackageInstallationService(db)

# Install dependency
result = await service.install_package(
    tenant_id=tenant_id,
    package_name="pandas",
    package_type="python",
    version=">=2.0.0"
)

print(f"Installation: {result['status']}")
  1. **Install Skill with Dependencies:**
# Skill installation should auto-install dependencies
curl -X POST "https://atom-saas.fly.dev/api/skills/install" \
  -H "X-API-Key: sk-your-key" \
  -H "Content-Type: application/json" \
  -d '{
    "skill_id": "skill-uuid-123",
    "install_dependencies": true
  }'
  1. **Verify Dependencies:**
# Check installed packages
service = PackageInstallationService(db)
installed = service.list_installed_packages(tenant_id)

print("Installed packages:")
for pkg in installed:
    print(f"  - {pkg['name']}: {pkg['version']}")

---

Validation Errors

Problem: 400 Bad Request - Invalid Configuration

**Symptoms:**

{
  "error": "Validation Failed",
  "message": "Configuration schema does not match skill requirements.",
  "code": "CONFIG_SCHEMA_INVALID"
}

**Diagnosis:**

  • Config doesn't match skill schema
  • Missing required fields
  • Invalid data types

**Solutions:**

  1. **Get Skill Schema:**
# Retrieve skill schema first
curl -X GET "https://atom-saas.fly.dev/api/skills/skill-uuid-123" \
  -H "X-API-Key: sk-your-key"

# Response includes config_schema
{
  "config_schema": {
    "type": "object",
    "properties": {
      "api_key": {"type": "string"},
      "timeout": {"type": "number", "default": 30}
    },
    "required": ["api_key"]
  }
}
  1. **Match Configuration to Schema:**
# Build config matching schema
config = {
    "api_key": "sk-123",  # Required
    "timeout": 60  # Optional, with default
}

# Validate config before sending
from jsonschema import validate

validate(instance=config, schema=skill["config_schema"])
  1. **Use Schema Builder:**
# Auto-generate config form from schema
def build_config_form(schema):
    form = {}
    for field_name, field_def in schema["properties"].items():
        required = field_name in schema.get("required", [])
        form[field_name] = {
            "type": field_def["type"],
            "required": required,
            "default": field_def.get("default")
        }
    return form

form = build_config_form(skill["config_schema"])

---

Common Mistakes

Mistake 1: Missing Content-Type Header

**Wrong:**

curl -X POST "https://atom-saas.fly.dev/api/skills/publish" \
  -H "X-API-Key: sk-your-key" \
  -d '{"skill_id": "..."}'

**Correct:**

curl -X POST "https://atom-saas.fly.dev/api/skills/publish" \
  -H "X-API-Key: sk-your-key" \
  -H "Content-Type: application/json" \
  -d '{"skill_id": "..."}'

---

Mistake 2: Wrong API Key for Environment

**Problem:** Using production key in development

**Solution:**

import os

# Use environment-specific keys
if os.environ.get("ENV") == "production":
    API_KEY = os.environ["PRODUCTION_API_KEY"]
    BASE_URL = "https://atom-saas.fly.dev"
else:
    API_KEY = os.environ["DEV_API_KEY"]
    BASE_URL = "https://atom-saas-dev.fly.dev"

---

Mistake 3: Ignoring Rate Limit Headers

**Wrong:**

# Doesn't check rate limits
while True:
    response = requests.get(url, headers=headers)

**Correct:**

# Checks rate limits
while True:
    response = requests.get(url, headers=headers)

    remaining = int(response.headers.get("X-RateLimit-Remaining", 0))
    if remaining == 0:
        reset_time = int(response.headers.get("X-RateLimit-Reset", 0))
        wait_seconds = reset_time - int(time.time())
        time.sleep(wait_seconds)

---

Mistake 4: Not Handling Pagination

**Wrong:**

# Only gets first page
response = requests.get(f"{url}?limit=50")
skills = response.json()["skills"]

**Correct:**

# Gets all pages
all_skills = []
offset = 0
limit = 50

while True:
    response = requests.get(f"{url}?limit={limit}&offset={offset}")
    data = response.json()

    all_skills.extend(data["skills"])

    if not data["has_more"]:
        break

    offset += limit

---

Mistake 5: Hardcoding IDs

**Wrong:**

# Hardcoded ID breaks when skill changes
skill_id = "skill-uuid-123"

**Correct:**

# Search for skill by name
response = requests.get(f"{url}?query=data%20analysis")
skills = response.json()["skills"]

if skills:
    skill_id = skills[0]["id"]  # Use actual ID

---

Debugging Tools

API Test Console

Built-in API explorer for testing endpoints:

# Open API test console
open "https://atom-saas.fly.dev/api/test-console"

Features:

  • Interactive API testing
  • Request/response inspection
  • Authentication handling
  • Error explanation

---

Logging

Enable debug logging:

import logging

# Enable request logging
logging.basicConfig(level=logging.DEBUG)
requests_log = logging.getLogger("requests.packages.urllib3")
requests_log.setLevel(logging.DEBUG)
requests_log.propagate = True

# Make request
response = requests.get(url, headers=headers)

# Logs show:
# DEBUG:urllib3.connectionpool:Starting new HTTPS connection
# DEBUG:urllib3.connectionpool:https://atom-saas.fly.dev:443 "GET /api/skills/marketplace HTTP/1.1" 200 1234

---

Response Inspection

Inspect full response details:

def inspect_response(response):
    """Print detailed response information."""
    print(f"Status: {response.status_code}")
    print(f"Headers: {dict(response.headers)}")
    print(f"Body: {response.text}")

    # Check rate limits
    if "X-RateLimit-Remaining" in response.headers:
        remaining = response.headers["X-RateLimit-Remaining"]
        limit = response.headers["X-RateLimit-Limit"]
        print(f"Rate Limit: {remaining}/{limit} remaining")

    # Check for errors
    try:
        data = response.json()
        if "error" in data:
            print(f"Error Code: {data.get('code')}")
            print(f"Error Message: {data.get('message')}")
            if "details" in data:
                print(f"Details: {data['details']}")
    except:
        pass

# Use it
response = requests.get(url, headers=headers)
inspect_response(response)

---

Monitoring and Alerting

Health Checks

Monitor API health:

# Check API status
curl -X GET "https://atom-saas.fly.dev/api/health"

**Response:**

{
  "status": "healthy",
  "version": "1.0.0",
  "timestamp": "2026-04-05T12:00:00Z",
  "services": {
    "database": "healthy",
    "redis": "healthy",
    "marketplace": "healthy"
  }
}

---

Error Tracking

Track errors over time:

from collections import defaultdict

class ErrorTracker:
    def __init__(self):
        self.errors = defaultdict(int)

    def log_error(self, response):
        if response.status_code >= 400:
            try:
                data = response.json()
                error_code = data.get("code", "UNKNOWN")
                self.errors[error_code] += 1
            except:
                self.errors["UNKNOWN"] += 1

    def get_summary(self):
        return dict(self.errors)

# Use it
tracker = ErrorTracker()

for i in range(100):
    response = requests.get(url, headers=headers)
    tracker.log_error(response)

print("Error Summary:")
print(tracker.get_summary())
# Output: {"RATE_LIMIT_EXCEEDED": 5, "SKILL_NOT_FOUND": 2}

Troubleshooting Guide

Authentication Issues

  1. **Check API key format**: Should be sk- followed by alphanumeric characters
  2. **Verify key is active**: Check in admin dashboard
  3. **Check key scope**: Read-only keys cannot write
  4. **OAuth token expired**: Obtain new token

Permission Issues

  1. **Verify user permissions**: Check RBAC settings
  2. **Check agent maturity**: Higher maturity required for some actions
  3. **Tenant context required**: Some endpoints need tenant context

Rate Limiting

  1. **Default limits**: 60-100 requests per minute depending on auth
  2. **Backoff strategy**: Implement exponential backoff
  3. **Retry-After header**: Use provided retry delay

Installation Failures

  1. **Check dependencies**: Verify packages are whitelisted
  2. **Agent maturity**: Some skills require minimum maturity
  3. **Config validation**: Verify config schema matches

---

Rate Limiting

Default Limits

  • **Unauthenticated**: 20 requests/minute
  • **API Key (read)**: 60 requests/minute
  • **API Key (read_write)**: 60 requests/minute
  • **OAuth Token**: 100 requests/minute
  • **Federation**: 100 requests/minute per IP

Rate Limit Headers

All responses include rate limit headers:

X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 1775411393

Best Practices

  1. **Check rate limit headers**: Monitor remaining quota
  2. **Implement backoff**: Exponential backoff on 429
  3. **Use caching**: Cache marketplace data locally
  4. **Batch requests**: Combine multiple operations when possible

---

SDK Examples

Python SDK

from atom_saas import MarketplaceClient

# Initialize client
client = MarketplaceClient(api_key="sk-your-key")

# Browse skills
skills = client.skills.browse(category="productivity", limit=10)

# Install skill
result = client.skills.install(
    skill_id="skill-uuid-123",
    agent_id="agent-uuid-456"
)

# Rate skill
client.skills.rate(
    skill_id="skill-uuid-123",
    rating=5,
    review="Excellent!"
)

JavaScript SDK

import { MarketplaceClient } from '@atom-saas/sdk';

// Initialize client
const client = new MarketplaceClient({ apiKey: 'sk-your-key' });

// Browse skills
const skills = await client.skills.browse({
  category: 'productivity',
  limit: 10
});

// Install skill
const result = await client.skills.install({
  skillId: 'skill-uuid-123',
  agentId: 'agent-uuid-456'
});

// Rate skill
await client.skills.rate({
  skillId: 'skill-uuid-123',
  rating: 5,
  review: 'Excellent!'
});

cURL Examples

# Browse skills
curl -X GET "https://atom-saas.fly.dev/api/skills/marketplace?category=productivity&limit=10" \
  -H "X-API-Key: sk-your-key"

# Install skill
curl -X POST "https://atom-saas.fly.dev/api/skills/install" \
  -H "X-API-Key: sk-your-key" \
  -H "Content-Type: application/json" \
  -d '{
    "skill_id": "skill-uuid-123",
    "agent_id": "agent-uuid-456"
  }'

# Rate skill
curl -X POST "https://atom-saas.fly.dev/api/skills/rate/skill-uuid-123" \
  -H "X-API-Key: sk-your-key" \
  -H "Content-Type: application/json" \
  -d '{
    "rating": 5,
    "review": "Excellent!"
  }'

---

Changelog

v1.0.0 (2026-04-05)

  • Initial marketplace API documentation
  • Skill, Agent, Domain, Canvas, Workflow marketplaces
  • Public marketplace API
  • Private marketplace endpoints
  • Federation protocol
  • Comprehensive error codes and troubleshooting

---

Support

For issues, questions, or feature requests:

  • **Documentation**: https://docs.atomagentos.com
  • **GitHub Issues**: https://github.com/rush86999/atom-saas/issues
  • **Email**: support@atomagentos.com