Studios API (CloudSpaces)

Studios are interactive cloud development environments in Lightning AI. In the REST API, Studios are called cloudspaces. Every Studio belongs to a project (teamspace).

Base path: /v1/projects/{projectId}/cloudspaces


Prerequisites

You need a projectId. There is no GET /v1/projects endpoint — use GET /v1/memberships to discover your teamspaces:

AUTH=$(echo -n "${LIGHTNING_USER_ID}:${LIGHTNING_API_KEY}" | base64)

# Step 1: List your memberships to get teamspace (project) IDs
curl -s -H "Authorization: Basic ${AUTH}" \
  "https://lightning.ai/v1/memberships?filterByUserId=true" | jq '.memberships[] | {name, projectId}'

# Step 2: Extract the first project ID (field is camelCase: projectId)
PROJECT_ID=$(curl -s -H "Authorization: Basic ${AUTH}" \
  "https://lightning.ai/v1/memberships?filterByUserId=true" | jq -r '.memberships[0].projectId')

List Studios

GET /v1/projects/{projectId}/cloudspaces

Returns all Studios in a project.

Path parameters:

Parameter Type Required Description
projectId string Yes The project (teamspace) ID

Query parameters:

Parameter Type Required Description
userId string Yes Your user ID (required — without it the response is empty)
name string No Filter by Studio name (exact match)
clusterId string No Filter by cloud account / cluster
pageToken string No Pagination cursor
limit integer No Max results per page
activeOnly boolean No Return only running Studios
isFavorite boolean No Return only favorited Studios

Response:

{
  "cloudspaces": [
    {
      "id": "01abcdef-0000-0000-0000-000000000001",
      "name": "my-studio",
      "displayName": "My Studio",
      "clusterId": "lightning-cloud",
      "codeStatus": {
        "inUse": {
          "phase": "CLOUD_SPACE_INSTANCE_STATE_RUNNING",
          "cloudSpaceInstanceId": "instance-id"
        }
      },
      "createdAt": "2024-01-15T10:00:00Z"
    }
  ]
}

Note: All response fields use camelCase (e.g. displayName, clusterId, codeStatus, createdAt).

Studio status phases:

Phase SDK Status Description
null Stopped No active instance
CLOUD_SPACE_INSTANCE_STATE_UNSPECIFIED Pending Starting
CLOUD_SPACE_INSTANCE_STATE_PENDING Pending Provisioning
CLOUD_SPACE_INSTANCE_STATE_RUNNING Running Active and ready
CLOUD_SPACE_INSTANCE_STATE_STOPPING Stopping Shutting down
CLOUD_SPACE_INSTANCE_STATE_STOPPED Stopped Inactive
CLOUD_SPACE_INSTANCE_STATE_FAILED Failed Error state

Example:

# userId is required — your user ID is available from GET /v1/auth/user
USER_ID="your-user-id"

curl -s -H "Authorization: Basic ${AUTH}" \
  "https://lightning.ai/v1/projects/${PROJECT_ID}/cloudspaces?userId=${USER_ID}" | jq '.cloudspaces[].name'

Get Studio

GET /v1/projects/{projectId}/cloudspaces/{id}

Returns a single Studio by its ID.

Path parameters:

Parameter Type Required Description
projectId string Yes Project ID
id string Yes Studio ID

Example:

curl -s -H "Authorization: Basic ${AUTH}" \
  "https://lightning.ai/v1/projects/${PROJECT_ID}/cloudspaces/${STUDIO_ID}"

Get Studio by Name

GET /v1/users/{userName}/projects/{projectName}/cloudspaces/{cloudspaceName}/getbyname

Returns a Studio by its human-readable name. Useful when you know the names but not the IDs.

Path parameters:

Parameter Type Required Description
userName string Yes Username or org name
projectName string Yes Project (teamspace) name
cloudspaceName string Yes Studio name

Example:

curl -s -H "Authorization: Basic ${AUTH}" \
  "https://lightning.ai/v1/users/johndoe/projects/my-team/cloudspaces/my-studio/getbyname"

Create Studio

POST /v1/projects/{projectId}/cloudspaces

Creates a new Studio in the specified project.

Path parameters:

Parameter Type Required Description
projectId string Yes Project ID

Request body:

{
  "name": "my-new-studio",
  "display_name": "My New Studio",
  "cluster_id": "lightning-cloud",
  "seed_files": [
    {
      "path": "main.py",
      "contents": "print('Hello, Lightning World!')\n"
    }
  ],
  "source": null,
  "disable_secrets": false,
  "cloud_space_environment_template_id": null
}
Field Type Required Description
name string Yes Studio identifier (URL-safe, lowercase)
display_name string No Human-readable name
cluster_id string No Cloud account / cluster ID (defaults to teamspace default)
seed_files array No Initial files to create in the Studio
source string No Source type for creating from template
disable_secrets boolean No Disable automatic secrets injection
cloud_space_environment_template_id string No Environment template ID (base Studio type)

Response: Returns the created V1CloudSpace object.

Note: After creating a Studio, the SDK also creates a Lightning Run via:

POST /v1/projects/{projectId}/cloudspaces/{cloudspaceId}/runs

Example:

curl -s -X POST \
  -H "Authorization: Basic ${AUTH}" \
  -H "Content-Type: application/json" \
  "https://lightning.ai/v1/projects/${PROJECT_ID}/cloudspaces" \
  -d '{
    "name": "my-new-studio",
    "display_name": "My New Studio"
  }'

Start Studio

POST /v1/projects/{projectId}/cloudspaces/{id}/start

Starts (powers on) a stopped Studio on the specified machine.

Path parameters:

Parameter Type Required Description
projectId string Yes Project ID
id string Yes Studio ID

Request body:

{
  "compute_config": {
    "name": "cpu-4",
    "spot": false,
    "requested_run_duration_seconds": "10800"
  }
}
Field Type Required Description
compute_config.name string Yes Machine slug (e.g., cpu-4, lit-t4-1, lit-a100-8)
compute_config.spot boolean No Use interruptible/spot instance (cheaper, but can be preempted)
compute_config.requested_run_duration_seconds string No Max runtime in seconds (required for some high-end machines)

Machine slugs:

Slug Type GPUs/CPUs
cpu-2 CPU 2 vCPUs
cpu-4 CPU 4 vCPUs (default)
cpu-8 CPU 8 vCPUs
cpu-16 CPU 16 vCPUs
data-prep-mid Data Prep 32 vCPUs, large disk
lit-t4-1 GPU 1× T4
lit-t4-2 GPU 2× T4
lit-t4-4 GPU 4× T4
lit-t4-8 GPU 8× T4
lit-l4-1 GPU 1× L4
lit-l4-4 GPU 4× L4
lit-a100-1 GPU 1× A100
lit-a100-8 GPU 8× A100
lit-a100-80gb-8 GPU 8× A100 80GB
lit-h100-1 GPU 1× H100
lit-h100-8 GPU 8× H100
lit-h200x-1 GPU 1× H200
lit-h200x-8 GPU 8× H200
lit-b200x-8 GPU 8× B200

Response:

{}

Example:

# Start on CPU-4 (default)
curl -s -X POST \
  -H "Authorization: Basic ${AUTH}" \
  -H "Content-Type: application/json" \
  "https://lightning.ai/v1/projects/${PROJECT_ID}/cloudspaces/${STUDIO_ID}/start" \
  -d '{"compute_config": {"name": "cpu-4", "spot": false}}'

# Start on A100 GPU
curl -s -X POST \
  -H "Authorization: Basic ${AUTH}" \
  -H "Content-Type: application/json" \
  "https://lightning.ai/v1/projects/${PROJECT_ID}/cloudspaces/${STUDIO_ID}/start" \
  -d '{"compute_config": {"name": "lit-a100-1", "spot": false}}'

Stop Studio

POST /v1/projects/{projectId}/cloudspaces/{id}/stop

Stops a running Studio. The Studio enters a Stopped state and can be restarted later.

Path parameters:

Parameter Type Required Description
projectId string Yes Project ID
id string Yes Studio ID

Request body: None required.

Response:

{}

Example:

curl -s -X POST \
  -H "Authorization: Basic ${AUTH}" \
  "https://lightning.ai/v1/projects/${PROJECT_ID}/cloudspaces/${STUDIO_ID}/stop"

Get Studio Status

GET /v1/projects/{projectId}/cloudspaces/{id}/codestatus

Returns the current runtime status of a Studio instance.

Path parameters:

Parameter Type Required Description
projectId string Yes Project ID
id string Yes Studio ID

Response:

{
  "in_use": {
    "phase": "CLOUD_SPACE_INSTANCE_STATE_RUNNING",
    "cloud_space_instance_id": "inst-abc123",
    "startup_status": {
      "initial_restore_finished": true,
      "top_up_restore_finished": true
    }
  },
  "requested": null
}

Example:

curl -s -H "Authorization: Basic ${AUTH}" \
  "https://lightning.ai/v1/projects/${PROJECT_ID}/cloudspaces/${STUDIO_ID}/codestatus" \
  | jq '.in_use.phase'

Switch Machine

PUT /v1/projects/{projectId}/cloudspaces/{id}/codeconfig

Switches a running Studio to a different machine type.

Path parameters:

Parameter Type Required Description
projectId string Yes Project ID
id string Yes Studio ID

Request body:

{
  "compute_config": {
    "name": "lit-a100-1",
    "spot": false
  }
}

Confirm the switch (required after the machine is ready):

POST /v1/projects/{projectId}/cloudspaces/{id}/switch-confirm

Cancel a pending switch:

POST /v1/projects/{projectId}/cloudspaces/{id}/switch-cancel


Execute Command

POST /v1/projects/{projectId}/cloudspaces/{id}/execute

Runs a command inside a running Studio and returns the output.

Path parameters:

Parameter Type Required Description
projectId string Yes Project ID
id string Yes Studio ID

Request body:

{
  "command": "echo hello && ls -la",
  "session": "optional-session-id"
}
Field Type Required Description
command string Yes Shell command(s) to execute
session string No Session ID for tracking long-running commands

Response:

{
  "output": "hello\ntotal 8\n...",
  "exit_code": 0,
  "session": "session-id-abc123"
}

Example:

curl -s -X POST \
  -H "Authorization: Basic ${AUTH}" \
  -H "Content-Type: application/json" \
  "https://lightning.ai/v1/projects/${PROJECT_ID}/cloudspaces/${STUDIO_ID}/execute" \
  -d '{"command": "python --version"}'

Get Long-Running Command Output

GET /v1/projects/{projectId}/cloudspaces/{id}/execute/{session}

Poll for the output of a long-running command identified by a session ID.

Path parameters:

Parameter Type Required Description
projectId string Yes Project ID
id string Yes Studio ID
session string Yes Session ID returned from the execute endpoint

Stream Command Output

GET /v1/projects/{projectId}/cloudspaces/{id}/execute/{session}/stream

Stream the output of a long-running command (server-sent events).


Delete Studio

DELETE /v1/projects/{projectId}/cloudspaces/{id}

Permanently deletes a Studio and all its data.

Path parameters:

Parameter Type Required Description
projectId string Yes Project ID
id string Yes Studio ID

Example:

curl -s -X DELETE \
  -H "Authorization: Basic ${AUTH}" \
  "https://lightning.ai/v1/projects/${PROJECT_ID}/cloudspaces/${STUDIO_ID}"

Update Studio

PUT /v1/projects/{projectId}/cloudspaces/{id}

Updates Studio properties such as display name, auto-sleep configuration, and environment variables.

Request body:

{
  "display_name": "New Studio Name",
  "code_config": {
    "disable_auto_shutdown": false,
    "idle_shutdown_seconds": 3600,
    "env_vars": [
      {"name": "MY_VAR", "value": "my-value"}
    ]
  }
}

Auto-Sleep Configuration

PUT /v1/projects/{projectId}/cloudspaces/{id}/sleepconfig

Configure auto-sleep settings for a Studio.

Request body:

{
  "code_config": {
    "disable_auto_shutdown": false,
    "idle_shutdown_seconds": 3600
  }
}
Field Description
disable_auto_shutdown Set to true to disable auto-sleep (requires paid plan)
idle_shutdown_seconds Seconds of inactivity before auto-sleep triggers

Duplicate (Fork) Studio

PUT /v1/projects/{projectId}/cloudspaces/{id}/fork

Duplicates a Studio (optionally to a different project).

Request body:

{
  "project_id": "target-project-id",
  "compute_config": {
    "name": "cpu-4"
  },
  "new_name": "my-studio-copy"
}

Restart Studio

POST /v1/projects/{projectId}/cloudspaces/{id}/restart

Restarts a running Studio instance without changing machine type.


Keep Alive

POST /v1/projects/{projectId}/cloudspaces/{id}/keep-alive

Sends a keepalive heartbeat to prevent the Studio from auto-sleeping. The lightning-sdk sends this automatically every 30 seconds while a Studio is running.


Plugins

List Available Plugins

GET /v1/cloudspaces/plugins

Returns all plugins that can be installed in Studios.

List Installed Plugins

GET /v1/projects/{projectId}/cloudspaces/{id}/plugins

Returns plugins installed in a specific Studio.

Install Plugin

POST /v1/projects/{projectId}/cloudspaces/{id}/plugins/{pluginId}

Installs a plugin in the Studio.

Path parameters:

Parameter Type Required Description
projectId string Yes Project ID
id string Yes Studio ID
pluginId string Yes Plugin name (e.g., jobs, inference-server, custom-port)

Built-in plugins:

Plugin ID Description
jobs Run async Jobs from the Studio
multi-machine-training Multi-machine distributed training
inference-server Deploy inference servers
custom-port Expose custom ports

Uninstall Plugin

DELETE /v1/projects/{projectId}/cloudspaces/{id}/plugins/{pluginId}

Execute Plugin

POST /v1/projects/{projectId}/cloudspaces/{id}/plugins/{pluginId}/execute

Runs a plugin command in the Studio.


Endpoints (Ports)

Add Port

POST /v1/projects/{projectId}/endpoints

Exposes a port on the Studio as a public HTTPS endpoint.

Request body:

{
  "port": 8080,
  "name": "my-app",
  "cloudspace_id": "studio-id",
  "endpoint_type": "V1_ENDPOINT_TYPE_PRIVATE"
}
Field Description
port Port number to expose
name Optional label for the endpoint
endpoint_type V1_ENDPOINT_TYPE_PRIVATE or V1_ENDPOINT_TYPE_PUBLIC

List Ports

GET /v1/projects/{projectId}/endpoints

Returns all exposed ports for the project.

Get Open Ports

GET /v1/projects/{projectId}/cloudspaces/{cloudspaceId}/open-ports

Returns currently open ports on the Studio instance.

Remove Port

DELETE /v1/projects/{projectId}/endpoints/{id}


Complete Python SDK Example

import base64
import requests

BASE_URL = "https://lightning.ai"
USER_ID = "your-user-id"
API_KEY = "your-api-key"

def get_headers():
    token = base64.b64encode(f"{USER_ID}:{API_KEY}".encode()).decode()
    return {
        "Authorization": f"Basic {token}",
        "Content-Type": "application/json",
    }

def list_projects():
    # No GET /v1/projects — use memberships endpoint instead
    r = requests.get(
        f"{BASE_URL}/v1/memberships?filterByUserId=true",
        headers=get_headers()
    )
    return r.json()["memberships"]

def list_studios(project_id, user_id):
    # userId query param is required
    r = requests.get(
        f"{BASE_URL}/v1/projects/{project_id}/cloudspaces",
        params={"userId": user_id},
        headers=get_headers(),
    )
    return r.json()["cloudspaces"]

def start_studio(project_id, studio_id, machine="cpu-4"):
    r = requests.post(
        f"{BASE_URL}/v1/projects/{project_id}/cloudspaces/{studio_id}/start",
        headers=get_headers(),
        json={"compute_config": {"name": machine, "spot": False}},
    )
    return r.json()

def stop_studio(project_id, studio_id):
    r = requests.post(
        f"{BASE_URL}/v1/projects/{project_id}/cloudspaces/{studio_id}/stop",
        headers=get_headers(),
    )
    return r.json()

def run_command(project_id, studio_id, command):
    r = requests.post(
        f"{BASE_URL}/v1/projects/{project_id}/cloudspaces/{studio_id}/execute",
        headers=get_headers(),
        json={"command": command},
    )
    return r.json()

# Usage
memberships = list_projects()
project_id = memberships[0]["projectId"]  # note: response fields are camelCase

studios = list_studios(project_id, USER_ID)
studio_id = studios[0]["id"]

start_studio(project_id, studio_id, "cpu-4")
result = run_command(project_id, studio_id, "echo hello world")
print(result["output"])
stop_studio(project_id, studio_id)