ScaleBox Docs

Template API

Complete API reference for managing environment templates. Templates define the base images and configurations used to create sandbox environments in ScaleBox.

Authentication Required: All API requests require authentication using the X-API-Key header with your API key.

Template Concepts

Templates in ScaleBox are pre-configured environment definitions that serve as the foundation for creating sandbox environments. They define the base image, default resource allocations, and metadata that will be used when users create new sandboxes.

Template Components

  • Base Image - Harbor registry image with pre-installed software and configurations
  • Resource Defaults - Default CPU, memory, and storage allocations for sandboxes
  • Metadata - JSON metadata describing template capabilities and use cases
  • Access Control - Public/private visibility and ownership permissions

Template Name Validation

Template names are validated strictly so they work as identifiers (e.g. in sandbox creation and image paths). The same rules apply when creating or updating a template and when providing new_name for share.

  • Length: 4–32 characters
  • Characters: Only lowercase letters (a–z), numbers (0–9), hyphens (-), and underscores (_)
  • Start and end: Must start and end with an alphanumeric character (letter or digit)
  • Cannot start with a number
  • No consecutive separators: No --, __, -_, or _-
  • Cannot start with tpl- (reserved for system template IDs)
  • Reserved words (exact match, case-insensitive): admin, root, system, scalebox, harbor, docker, k8s, kubernetes, api, www, mail, ftp, ssh, public, private, test, dev, prod, staging, local, localhost, example, sample

Invalid examples: My Nginx (uppercase and space), nginx (too short), tpl-my-app (reserved prefix), my--app (consecutive hyphens)

Valid examples: my-nginx, python-data-science, node_web_app

Template Statuses

Templates progress through different statuses during their lifecycle:

StatusDescription
pendingTemplate has been created but build process has not started
buildingTemplate image is being built from source
pushingTemplate image is being pushed to Harbor registry
availableTemplate is ready for use in sandbox creation
failedTemplate build or push process failed

Template Access Control

Template access is controlled by ownership and visibility settings:

TypeDescription
Public TemplatesAccessible to all authenticated users, typically created by admin users
Private TemplatesAccessible only to the owner and root users in the same account
Account TemplatesAccessible to all users in the same account (root user templates)

Response Conventions

Most JSON endpoints on this page return the standard envelope:

{
  "success": true,
  "data": {},
  "timestamp": "2026-04-17T12:34:56Z"
}

Some legacy handlers also place a message field inside data; that is part of the current backend contract.

Special cases:

  • GET /v1/templates/{template_id}/document?download=... returns a raw Markdown file, not the JSON envelope.
  • POST /v1/templates/import and POST /v1/templates/{template_id}/import return 202 Accepted immediately; the import continues asynchronously.

API Endpoints

List Templates

GET /v1/templates

List all accessible templates for the authenticated user.

Request Parameters

NameTypeRequiredDescription
pageintegerNoPage number, default 1
limitintegerNoPage size, default 20 (alias: page_size)
offsetintegerNoOffset, default 0 (alias: skip)
statusstringNoFilter templates by status (pending, building, pushing, available, failed)
visibilitystringNoFilter templates by visibility (private, account_shared, public)
namestringNoExact template name match (e.g. for resolving by name)
usablestringNoSet to 'true' to return only templates usable for sandbox creation

Each template object includes has_template_document (boolean): whether non-empty Markdown is stored. The template_document body itself is omitted from list responses to keep payloads small; use Get template or Get template document for full text.

Success response

200 OK in the standard envelope:

  • data.templates: array of template list objects. Each object includes template_id, name, description, default_cpu_count, default_memory_mb, visibility, template_source, custom_image_source, external_image_url, external_registry_username, status, owner_user_id, owner_account_id, harbor_image_url, harbor_project, harbor_repository, harbor_tag, image_size_bytes, metadata, ports, custom_command, ready_command, build_started_at, push_started_at, push_completed_at, build_error_message, last_storage_sync_at, created_at, updated_at, and has_template_document.
  • data.templates[].owner: optional object with user_id, username, and display_name when owner information is exposed.
  • data.pagination: object with page, limit, total, total_pages, and optional offset.

Example

curl -X GET https://api.scalebox.dev/v1/templates \
  -H "X-API-Key: sk-1234567890abcdef1234567890abcdef12345678"

Get Template

GET /v1/templates/{template_id}

Get detailed information about a specific template.

Example

curl -X GET https://api.scalebox.dev/v1/templates/tpl-abc123def456789 \
  -H "X-API-Key: sk-1234567890abcdef1234567890abcdef12345678"

template_document field: The full template response may include template_document (string or null) — long-form Markdown user documentation (getting started, ports, examples). It is separate from the short description. List templates responses omit this field to keep payloads small; use GET /v1/templates/{template_id} or the dedicated document endpoint below.

Success response

200 OK in the standard envelope with data set to one template object. It contains the same fields as List Templates, plus parent_template_id, root_template_id, and template_document.

Template documentation (Markdown)

Templates can store an optional Markdown document (max 65,535 bytes, MySQL TEXT). Any user who can access the template can read the document; create, update, and delete require the same permissions as editing the template (owner, account root for account members, or admin for public templates).

Get template document (JSON)

GET /v1/templates/{template_id}/document

Returns 200 OK in the standard envelope:

{
  "success": true,
  "data": {
    "template_id": "tpl-abc123def456789",
    "template_document": "# Getting started\n\n..."
  },
  "timestamp": "2026-04-17T12:34:56Z"
}

template_document is omitted or null when no document is stored.

curl -X GET https://api.scalebox.dev/v1/templates/tpl-abc123def456789/document \
  -H "X-API-Key: sk-1234567890abcdef1234567890abcdef12345678"

Download template document (raw Markdown)

GET /v1/templates/{template_id}/document?download=1

Same access rules as the JSON endpoint. On success it returns 200 OK with a raw Markdown body, Content-Type: text/markdown; charset=utf-8, and Content-Disposition: attachment for a .md file. Returns 400 if there is no document or the stored content is empty/whitespace-only (avoids useless downloads).

Accepted query values include download=true, download=1, or download=yes.

curl -L -o guide.md "https://api.scalebox.dev/v1/templates/tpl-abc123def456789/document?download=1" \
  -H "X-API-Key: sk-1234567890abcdef1234567890abcdef12345678"

Set template document

PUT /v1/templates/{template_id}/document

Request body (JSON):

NameTypeRequiredDescription
template_documentstringYesMarkdown body. Empty or whitespace-only clears the document

Success response

200 OK in the standard envelope with:

  • data.template_id
  • data.template_document - stored Markdown string, or null if the submitted content was empty or whitespace-only
curl -X PUT https://api.scalebox.dev/v1/templates/tpl-abc123def456789/document \
  -H "X-API-Key: sk-1234567890abcdef1234567890abcdef12345678" \
  -H "Content-Type: application/json" \
  -d '{"template_document": "# Guide\n\nHello."}'

Delete template document

DELETE /v1/templates/{template_id}/document

Clears stored Markdown. Same edit permissions as PUT.

Success response

200 OK in the standard envelope with top-level message: "Template document removed" and:

  • data.template_id
  • data.template_document - always null
curl -X DELETE https://api.scalebox.dev/v1/templates/tpl-abc123def456789/document \
  -H "X-API-Key: sk-1234567890abcdef1234567890abcdef12345678"

Create Template

POST /v1/templates

Create a new template (ScaleBox-family or custom). Full validation applies: name uniqueness, budget, subscription limits, and for custom external images pre-validation.

Request Parameters

NameTypeRequiredDefaultDescription
namestringYes-Template name. Must follow Template Name Validation rules
descriptionstringNo-Detailed description of the template
default_cpu_countintegerNo2Default CPU cores for sandboxes using this template
default_memory_mbintegerNo512Default memory in MB for sandboxes using this template
visibilitystringNoprivateTemplate visibility: 'private', 'account_shared', or 'public' (admin only)
template_sourcestringNoscalebox_family'scalebox_family' (default) or 'custom'
custom_image_sourcestringNo-Required if template_source is 'custom': 'external' or 'imported'
external_image_urlstringNo-Required for custom external templates. Full image URL
external_registry_usernamestringNo-Optional registry username for private external images
external_registry_passwordstringNo-Optional registry password for private external images
harbor_image_urlstringNo-Full Harbor image URL
harbor_projectstringNoAuto-generatedHarbor project name
harbor_repositorystringNo-Harbor repository name
harbor_tagstringNolatestHarbor image tag
metadatastringNoJSON metadata for the template
base_template_idstringNo-Template ID to inherit from (same template_source only)
portsstringNo[]JSON array of port configurations
reset_portsbooleanNofalseIf true, remove unprotected ports inherited from base
custom_commandstringNo-Custom startup command for the container
ready_commandstringNo-Readiness probe: JSON with type (exec/httpGet/tcpSocket)

Success response

201 Created in the standard envelope. data includes:

  • template_id, name, description, default_cpu_count, default_memory_mb, visibility
  • template_source, custom_image_source, external_image_url, external_registry_username
  • status, harbor_image_url, harbor_project, harbor_repository, harbor_tag, image_size_bytes
  • metadata, ports, build_started_at, push_started_at, push_completed_at, build_error_message, last_storage_sync_at
  • owner_id, created_at, updated_at

Note the create response uses owner_id as the field name here.

Example

curl -X POST https://api.scalebox.dev/v1/templates \
  -H "X-API-Key: sk-1234567890abcdef1234567890abcdef12345678" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "python-data-science",
    "description": "Python environment with data science libraries",
    "default_cpu_count": 2,
    "default_memory_mb": 4096,
    "harbor_project": "scalebox-public",
    "harbor_repository": "python-data-science",
    "harbor_tag": "latest",
    "metadata": {
      "category": "data-science",
      "languages": ["python"],
      "frameworks": ["pandas", "numpy", "scikit-learn"]
    }
  }'

Update Template

PUT /v1/templates/{template_id}

Update template configuration and Harbor information.

Success response

200 OK with top-level message: "Template updated successfully". data.template includes:

  • template_id, name, description, template_document
  • default_cpu_count, default_memory_mb, visibility, status
  • harbor_image_url, harbor_project, harbor_repository, harbor_tag, image_size_bytes
  • metadata, ports, build_started_at, push_started_at, push_completed_at, build_error_message, last_storage_sync_at
  • owner_id, created_at, updated_at

Example

curl -X PUT https://api.scalebox.dev/v1/templates/tpl-abc123def456789 \
  -H "X-API-Key: sk-1234567890abcdef1234567890abcdef12345678" \
  -H "Content-Type: application/json" \
  -d '{
    "description": "Updated Python environment with latest libraries",
    "default_memory_mb": 8192
  }'

Delete Template

DELETE /v1/templates/{template_id}

Delete a template and its Harbor image.

Success response

200 OK with top-level message: "Template deleted successfully". No data object is returned on success.

Example

curl -X DELETE https://api.scalebox.dev/v1/templates/tpl-abc123def456789 \
  -H "X-API-Key: sk-1234567890abcdef1234567890abcdef12345678"

Legacy POST /v1/templates/register removed: That endpoint is not in the API anymore. If an image already exists in Harbor, create the template with POST /v1/templates and set Harbor fields (harbor_image_url, harbor_project, harbor_repository, harbor_tag, etc.) per Create Template. To copy an image from an external registry into Harbor, use POST /v1/templates/import (direct import) or POST /v1/templates/{template_id}/import (existing external template), documented below.

Direct import template (external → Harbor)

POST /v1/templates/import

Creates a custom template from an external OCI/Docker image reference and queues a Skopeo copy into ScaleBox Harbor in one step. Responds with 202 Accepted and data containing template_id, optional job_id, status, and image URLs when the import job is created.

Harbor project / repository / tag are derived by the server (repository aligns with the template name, tag latest); clients do not send Harbor destination fields for this path.

Request body (JSON)

NameTypeRequiredDescription
namestringYesTemplate name (same validation as Create Template)
external_image_urlstringYesFull upstream image reference (e.g. ghcr.io/org/image:tag)
descriptionstringNoTemplate description
external_registry_usernamestringNoRegistry username for private sources
external_registry_passwordstringNoRegistry password or token
default_cpu_countintegerNoSandbox defaults
default_memory_mbintegerNoSandbox defaults
visibilitystringNoprivate (default for most users), account_shared (account root only), or public (admin only)
portsstringNoJSON port list (same shape as Create Template)
custom_commandstringNoOptional startup command
ready_commandstringNoOptional readiness probe JSON

Success response

202 Accepted. The import continues asynchronously; poll GET /v1/templates/{template_id}/import.

  • data.template_id
  • data.name
  • data.visibility
  • data.job_id, data.status, data.external_image_url, data.harbor_image_url, data.created_at when the job is created
  • data.message - either Template created and import started or Template created but import failed to start. Retry via POST /v1/templates/:template_id/import

Example

curl -X POST https://api.scalebox.dev/v1/templates/import \
  -H "X-API-Key: sk-1234567890abcdef1234567890abcdef12345678" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "my-upstream-tool",
    "description": "Copied from upstream registry",
    "external_image_url": "docker.io/library/alpine:latest",
    "default_cpu_count": 2,
    "default_memory_mb": 1024,
    "visibility": "private"
  }'

Start import for existing external template

POST /v1/templates/{template_id}/import

Starts Harbor import for a template row that already exists with custom_image_source: external. Returns 202 Accepted with job_id and status. Typical errors: template not external, already imported, import already running (409), permission denied, or no healthy cluster / Harbor (503).

No JSON body is required.

Success response

202 Accepted with:

  • data.job_id
  • data.template_id
  • data.status
  • data.external_image_url
  • data.harbor_image_url
  • data.created_at
  • data.message - Import started
curl -X POST https://api.scalebox.dev/v1/templates/tpl-abc123def456789/import \
  -H "X-API-Key: sk-1234567890abcdef1234567890abcdef12345678"

Get template import status

GET /v1/templates/{template_id}/import

Returns the active import job for the template, or the most recent completed / failed / cancelled job. Template owner only (same user as owner_user_id).

Response includes: job_id, template_id, status, progress_percentage, external_image_url, harbor_image_url, timestamps, last_log_message, error_message, skopeo_logs.

Success response

200 OK in the standard envelope with data containing:

  • job_id, template_id, status, progress_percentage
  • external_image_url, harbor_image_url
  • created_at, started_at, completed_at
  • last_log_message, error_message, skopeo_logs

Cancel template import (by template)

DELETE /v1/templates/{template_id}/import

Cancels the active import job for this template. Owner only. 404 if there is no active job.

Success response

200 OK in the standard envelope with:

  • data.job_id
  • data.status - always cancelled
  • data.message - Import job cancelled
curl -X DELETE https://api.scalebox.dev/v1/templates/tpl-abc123def456789/import \
  -H "X-API-Key: sk-1234567890abcdef1234567890abcdef12345678"

Update Template Status

PUT /v1/templates/{template_id}/status

Update template build status and tracking information.

Request Parameters

NameTypeRequiredDescription
statusstringYesTemplate status (pending, building, pushing, available, failed)
error_messagestringNoError message if status is failed
push_logsstringNoBuild and push logs
harbor_image_urlstringNoUpdated Harbor image URL

Success response

200 OK in the standard envelope with:

  • data.message - Template status updated successfully
  • data.template_id
  • data.build_status

Validate Template

POST /v1/templates/{template_id}/validate

Validate and activate a template with Harbor image.

Request Parameters

NameTypeRequiredDescription
harbor_image_urlstringYesHarbor image URL to validate

Success response

200 OK in the standard envelope with:

  • data.message - Template validated successfully
  • data.template_id
  • data.build_status
  • data.harbor_image_url

Get Storage Usage

GET /v1/templates/storage-usage

Get private template storage usage statistics.

Success response

200 OK in the standard envelope with:

  • data.used_gb
  • data.limit_gb
  • data.percentage

Example

curl -X GET https://api.scalebox.dev/v1/templates/storage-usage \
  -H "X-API-Key: sk-1234567890abcdef1234567890abcdef12345678"

Data example

{
  "success": true,
  "data": {
    "used_gb": 2.5,
    "limit_gb": 5.0,
    "percentage": 50.0
  },
  "timestamp": "2026-04-17T12:34:56Z"
}

List Import Jobs

GET /v1/import-jobs

List template import jobs for the current user.

Request Parameters

NameTypeRequiredDescription
statusstringNoFilter: ongoing (default), pending, running, completed, failed, cancelled
template_idstringNoFilter jobs for this template ID
pageintegerNoPage number, default 1
limitintegerNoMax jobs to return (1-100). Alias: page_size
offsetintegerNoPagination offset (alias: skip)

Success response

200 OK in the standard envelope with:

  • data.jobs: array of import job summaries with job_id, template_id, status, progress_percentage, external_image_url, harbor_image_url, created_at, started_at, completed_at, and error_message
  • data.pagination: object with page, limit, total, total_pages, and optional offset

Get Import Job

GET /v1/import-jobs/{job_id}

Get a single import job by job ID.

Success response

200 OK in the standard envelope with:

  • data.job_id, data.template_id, data.status, data.progress_percentage
  • data.external_image_url, data.harbor_image_url
  • data.created_at, data.started_at, data.completed_at, data.updated_at
  • data.last_log_message, data.error_message, data.skopeo_logs
  • data.retry_count, data.max_retries

Cancel Import Job

DELETE /v1/import-jobs/{job_id}

Cancel an import job by job ID (same ownership rules as listing jobs).

Success response

200 OK in the standard envelope with:

  • data.job_id
  • data.status - always cancelled
  • data.message - Import job cancelled
curl -X DELETE https://api.scalebox.dev/v1/import-jobs/job-xyz789 \
  -H "X-API-Key: sk-1234567890abcdef1234567890abcdef12345678"

You can also cancel via DELETE /v1/templates/{template_id}/import when you only know the template ID.

Share Template

POST /v1/templates/{template_id}/share

Share a private template with your account (visibility → account_shared). Only template owner or admin.

Request Parameters

NameTypeRequiredDescription
new_namestringNoOptional new name when sharing

Success response

200 OK in the standard envelope with:

  • data.template_id
  • data.visibility - account_shared
  • data.harbor_project
  • data.harbor_image_url
  • data.message - Template successfully shared with account

Example

curl -X POST https://api.scalebox.dev/v1/templates/tpl-abc123def456789/share \
  -H "X-API-Key: sk-1234567890abcdef1234567890abcdef12345678" \
  -H "Content-Type: application/json" \
  -d '{}'

Unshare Template

POST /v1/templates/{template_id}/unshare

Make an account-shared template private again. Only template owner or admin.

Success response

200 OK in the standard envelope with:

  • data.template_id
  • data.visibility - private
  • data.harbor_project
  • data.harbor_image_url
  • data.message - Template successfully unshared (now private)

Example

curl -X POST https://api.scalebox.dev/v1/templates/tpl-abc123def456789/unshare \
  -H "X-API-Key: sk-1234567890abcdef1234567890abcdef12345678" \
  -H "Content-Type: application/json" \
  -d '{}'

Create vs direct import

AspectPOST /v1/templatesPOST /v1/templates/import
PurposeCreate or derive a template (base_template_id), or create with Harbor / custom fields per API rulesCreate template and queue external → Harbor copy
ImageYou supply Harbor and/or external fields according to template typeRequires external_image_url; Harbor destination is server-derived
Response201 (typical create)202 (async import job)
When to useNormal lifecycle, derivatives, images already addressable in Harbor in the create payloadOnboarding an upstream registry image in one API call

Harbor Integration

Templates are tightly integrated with Harbor container registry for image storage and management:

Harbor Project Structure

  • Public Templates: Stored in scalebox-public project
  • Private Templates: Stored in user-specific projects like scalebox-{user_id}
  • Admin Templates: Can be stored in any project, including scalebox-public

Image Management

  • Automatic Size Detection: Template image sizes are automatically retrieved from Harbor
  • Storage Tracking: Private template storage usage is tracked and limited
  • Cleanup: Deleting templates automatically removes Harbor images and repositories

Error Handling

ScenarioDescription
Template Name ValidationTemplate names must follow the Template Name Validation rules
Access ControlUsers can only access public templates and their own private templates
Template UsageTemplates cannot be deleted if they are being used by active sandboxes

Best Practices

PracticeDescription
Template NamingUse names that pass validation: lowercase, 4–32 characters
Resource DefaultsSet appropriate default CPU and memory based on typical usage patterns
Metadata UsageInclude rich metadata to help users discover and understand template capabilities

HTTP Status Codes

CodeDescription
200Success
201Created
400Bad Request
401Unauthorized
403Forbidden
404Not Found
429Too Many Requests
500Internal Server Error

On this page