ScaleBox Docs

Projects API

Complete API reference for managing projects. Projects organize sandboxes into logical groups and support default-project workflows for each user.

Authentication Required: All project APIs require the X-API-Key header.

Project Concepts

Projects help you group related sandboxes and control the default destination for new sandboxes.

  • Default project: the first project for a user is forced to is_default: true.
  • Access scope: regular users only see their own projects; account root users can see projects for the whole account.
  • Move rules: add/evict operations only work for running sandboxes and still enforce account ownership checks.
  • Status field: list and get responses may include status for forward compatibility; it is not updated via PUT /v1/projects/{project_id}. Responses do not include per-project spend or total_spent.

Standard Response Format

Projects use the standard API envelope:

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

Mutating actions now return both structured data and a top-level message.

API Endpoints

Create Project

POST /v1/projects

Create a new project.

Request body

NameTypeRequiredDescription
namestringYesProject name
descriptionstringNoProject description
is_defaultbooleanNoWhether to make this the default project

Example

curl -X POST https://api.scalebox.dev/v1/projects \
  -H "X-API-Key: sk-1234567890abcdef1234567890abcdef12345678" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "frontend-development",
    "description": "Project for all frontend development sandboxes",
    "is_default": false
  }'

Response

{
  "success": true,
  "data": {
    "project_id": "prj-abc123def456789",
    "name": "frontend-development",
    "description": "Project for all frontend development sandboxes",
    "owner_user_id": "usr-xyz789abc123456",
    "status": "active",
    "is_default": false,
    "sandbox_count": 0,
    "created_at": "2026-04-17T12:00:00Z",
    "updated_at": "2026-04-17T12:00:00Z"
  },
  "timestamp": "2026-04-17T12:00:00Z"
}

List Projects

GET /v1/projects

List all visible projects.

Query parameters

NameTypeRequiredDescription
pageintegerNoPage number, default 1
limitintegerNoPage size, default 50 (alias: page_size)
offsetintegerNoOffset, default 0 (alias: skip)
owner_user_idstringNoRoot users only: filter projects by owner user id

Response

{
  "success": true,
  "data": {
    "projects": [
      {
        "project_id": "prj-abc123def456789",
        "name": "frontend-development",
        "description": "Project for all frontend development sandboxes",
        "owner_user_id": "usr-xyz789abc123456",
        "status": "active",
        "is_default": false,
        "sandbox_count": 5,
        "created_at": "2026-04-10T10:00:00Z",
        "updated_at": "2026-04-17T11:30:00Z",
        "owner": {
          "user_id": "usr-xyz789abc123456",
          "username": "developer",
          "display_name": "John Developer",
          "email": "john@example.com"
        }
      }
    ],
    "pagination": {
      "page": 1,
      "limit": 50,
      "total": 1,
      "total_pages": 1
    }
  },
  "timestamp": "2026-04-17T12:00:00Z"
}

owner appears for account root users. Admin-only list responses may also include account_owner.

Get Project

GET /v1/projects/{project_id}

Get one project.

Response

{
  "success": true,
  "data": {
    "project_id": "prj-abc123def456789",
    "name": "frontend-development",
    "description": "Project for all frontend development sandboxes",
    "owner_user_id": "usr-xyz789abc123456",
    "status": "active",
    "is_default": false,
    "sandbox_count": 5,
    "created_at": "2026-04-10T10:00:00Z",
    "updated_at": "2026-04-17T11:30:00Z"
  },
  "timestamp": "2026-04-17T12:00:00Z"
}

Update Project

PUT /v1/projects/{project_id}

Update project name, description, and default flag. Project status is reserved for future use and is not changed through this endpoint.

Request body

NameTypeRequiredDescription
namestringNoNew project name
descriptionstringNoNew project description
is_defaultbooleanNoSet or unset default project

Response

{
  "success": true,
  "data": {
    "project_id": "prj-abc123def456789",
    "name": "full-stack-development",
    "description": "Updated project for full-stack development work",
    "owner_user_id": "usr-xyz789abc123456",
    "status": "active",
    "is_default": true,
    "sandbox_count": 5,
    "created_at": "2026-04-10T10:00:00Z",
    "updated_at": "2026-04-17T12:05:00Z",
    "owner": {
      "user_id": "usr-xyz789abc123456",
      "username": "developer",
      "display_name": "John Developer",
      "email": "john@example.com"
    }
  },
  "message": "Project updated successfully",
  "timestamp": "2026-04-17T12:05:00Z"
}

This response now uses the same projected shape as list/get responses, plus the top-level success message.

Delete Project

DELETE /v1/projects/{project_id}

Delete an empty project.

Response

{
  "success": true,
  "data": {
    "project_id": "prj-abc123def456789",
    "deleted": true
  },
  "message": "Project deleted successfully",
  "timestamp": "2026-04-17T12:10:00Z"
}

Get Project Sandboxes

GET /v1/projects/{project_id}/sandboxes

List sandboxes in a project.

Query parameters

NameTypeRequiredDescription
statusstringNoFilter by sandbox status
pageintegerNoPage number, default 1
skipintegerNoOffset, default 0
limitintegerNoLimit, default 50 (alias: page_size)

Response

{
  "success": true,
  "data": {
    "sandboxes": [
      {
        "id": "sbx-abc123def456789",
        "name": "react-frontend-dev",
        "description": "Frontend sandbox",
        "template_id": "tpl-react-dev",
        "owner_user_id": "usr-xyz789abc123456",
        "project_id": "prj-abc123def456789",
        "cpu_count": 2,
        "memory_mb": 4096,
        "storage_gb": 20,
        "status": "running",
        "started_at": "2026-04-17T11:00:00Z",
        "stopped_at": null,
        "created_at": "2026-04-17T10:55:00Z",
        "updated_at": "2026-04-17T11:00:00Z"
      }
    ],
    "pagination": {
      "page": 1,
      "limit": 50,
      "total": 1,
      "total_pages": 1,
      "offset": 0
    }
  },
  "timestamp": "2026-04-17T12:12:00Z"
}

This endpoint returns data.sandboxes plus data.pagination.

Add Sandbox to Project

POST /v1/projects/{project_id}/sandboxes/{sandbox_id}/add

Move a running sandbox into the target project.

Response

{
  "success": true,
  "data": {
    "sandbox_id": "sbx-abc123def456789",
    "project_id": "prj-abc123def456789",
    "previous_project": "prj-default123456789",
    "action": "added_to_project"
  },
  "message": "Sandbox added to project successfully",
  "timestamp": "2026-04-17T12:15:00Z"
}

Evict Sandbox from Project

POST /v1/projects/{project_id}/sandboxes/{sandbox_id}/evict

Move a running sandbox back to the caller's default project.

Response

{
  "success": true,
  "data": {
    "sandbox_id": "sbx-abc123def456789",
    "project_id": "prj-default123456789",
    "previous_project": "prj-abc123def456789",
    "action": "evicted_to_default_project"
  },
  "message": "Sandbox evicted from project successfully",
  "timestamp": "2026-04-17T12:16:00Z"
}

Common Errors

{
  "success": false,
  "error": "Project not found",
  "timestamp": "2026-04-17T12:20:00Z"
}

Common project errors:

  • 400: invalid project name, duplicate name, deleting a project that still has sandboxes, or unsetting the only default project
  • 403: insufficient account scope
  • 404: project or sandbox not found in your scope
  • 500: database or cleanup failure

On this page