Workspaces
Core CRUD operations for managing workspaces. A workspace is an isolated micro-VM with its own filesystem, network, and resources.
Create workspace
Create a new workspace from an image.
const workspace = await ws.create({
name: 'my-app',
image: 'node-20',
namespace: 'production',
mode: 'permanent',
config: {
cpus: 2,
memory_mb: 2048,
writable_size_mb: 1024,
ttl: '1h',
ttl_action: 'stop',
remove_on_exit: false,
restart_policy: 'always',
max_restarts: 5,
keep_logs: true,
static_network: true,
network_config: {
allow_internet: true,
public_ingress: false,
},
ssh_access: true,
env: [
{ key: 'NODE_ENV', value: 'production' },
{ key: 'PORT', value: '3000' },
],
cmd: ['node', 'server.js'],
workloads: [],
wait_for_init: true,
proxy_assignment_id: 42,
},
});POST /workspace{
"name": "my-app",
"image": "node-20",
"namespace": "production",
"mode": "permanent",
"config": {
"cpus": 2,
"memory_mb": 2048,
"writable_size_mb": 1024,
"ttl": "1h",
"ttl_action": "stop",
"remove_on_exit": false,
"restart_policy": "always",
"max_restarts": 5,
"keep_logs": true,
"static_network": true,
"network_config": {
"allow_internet": true,
"public_ingress": false
},
"ssh_access": true,
"env": [
{ "key": "NODE_ENV", "value": "production" },
{ "key": "PORT", "value": "3000" }
],
"cmd": ["node", "server.js"],
"workloads": [],
"wait_for_init": true,
"proxy_assignment_id": 42
}
}curl -X POST https://api.oblien.com/workspace \
-H "X-Client-ID: $OBLIEN_CLIENT_ID" \
-H "X-Client-Secret: $OBLIEN_CLIENT_SECRET" \
-H "Content-Type: application/json" \
-d '{
"name": "my-app",
"image": "node-20",
"config": { "cpus": 2, "memory_mb": 2048 }
}'Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
name | string | No | Display name (max 255 characters) |
image | string | Yes | Base image ID. See Images |
namespace | string | No | Namespace for organization (alphanumeric + hyphens) |
mode | string | No | "permanent" or "temporary". Default: "temporary" |
config | object | No | Configuration object (see below) |
type | string | No | Workspace type identifier |
Config object
| Field | Type | Default | Description |
|---|---|---|---|
cpus | number | 1 | CPU cores (1–32, subject to plan limits) |
memory_mb | number | 512 | Memory in MB (128–65536, subject to plan limits) |
writable_size_mb | number | 512 | Writable disk in MB (64–204800, subject to plan limits) |
ttl | string | - | Time to live (e.g., "30m", "1h", "24h"). Only for temporary mode |
ttl_action | string | "stop" | Action when TTL expires: "stop" or "remove" |
remove_on_exit | boolean | false | Auto-delete workspace when VM exits |
restart_policy | string | "no" | "no", "always", "on-failure" |
max_restarts | number | 0 | Max restart attempts (0 = unlimited when policy is set) |
keep_logs | boolean | true | Persist logs across restarts |
static_network | boolean | false | Assign a static internal IP |
network_config | object | - | Network policy (see below) |
ssh_access | boolean | false | Enable SSH on creation |
env | array | [] | Environment variables: [{ key, value }] |
cmd | array | - | Override startup command: ["node", "server.js"] |
workloads | array | [] | Workloads to start on boot |
wait_for_init | boolean | false | Wait for VM to be fully initialized before returning |
proxy_assignment_id | number | - | Outbound IP proxy assignment ID |
Network config
| Field | Type | Default | Description |
|---|---|---|---|
allow_internet | boolean | true | Allow outbound internet access |
public_ingress | boolean | false | Allow inbound from public internet |
Response 201
{
"success": true,
"workspace": {
"id": "ws_a1b2c3d4",
"name": "my-app",
"namespace": "production",
"mode": "permanent",
"image": "node-20",
"ip": "10.0.0.15",
"uptime": 0,
"start_time": "2026-02-24T10:30:00Z",
"info": {
"status": "running",
"is_running": true,
"user_requested_stop": false
},
"access": {
"ssh_enabled": false
},
"network": {
"allow_internet": true,
"ingress_ports": [],
"egress_ports": [],
"egress": [],
"public_access": false,
"ingress": []
},
"public_ports": [],
"resources": {
"cpus": 2,
"memory_mb": 2048,
"disk_size_mb": 1024
},
"created_at": "2026-02-24T10:30:00Z",
"updated_at": "2026-02-24T10:30:00Z"
}
}Errors
| Code | Status | Cause |
|---|---|---|
MISSING_USER_ID | 401 | Authentication failed |
INVALID_NAMESPACE | 400 | Namespace contains invalid characters |
INVALID_NAME_LENGTH | 400 | Name exceeds 255 characters |
INVALID_IMAGE | 400 | Image ID is not a string or is empty |
INVALID_CONFIG | 400 | Config is not an object |
SANDBOX_LIMIT_REACHED | 402 | Maximum workspace count for your plan |
RESOURCE_NOT_ALLOWED | 403 | Requested resources exceed plan limits |
POOL_LIMIT_REACHED | 402 | Owned resource pool is full |
RUNNING_POOL_REACHED | 402 | Running resource pool is full |
VM_UNAVAILABLE | 503 | VM backend is unreachable |
CREATE_FAILED | 500 | Workspace creation failed |
List workspaces
Retrieve a paginated list of your workspaces.
const result = await ws.list({
page: 1,
limit: 20,
mode: 'permanent',
});
console.log(result.workspaces); // WorkspaceResponse[]
console.log(result.total); // Total countGET /workspace?page=1&limit=20&mode=permanentcurl "https://api.oblien.com/workspace?page=1&limit=20" \
-H "X-Client-ID: $OBLIEN_CLIENT_ID" \
-H "X-Client-Secret: $OBLIEN_CLIENT_SECRET"Query parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
page | number | 1 | Page number |
limit | number | 20 | Results per page (max 100) |
mode | string | - | Filter by mode: "permanent" or "temporary" |
Response
{
"success": true,
"workspaces": [ /* WorkspaceResponse[] */ ],
"total": 42,
"page": 1,
"limit": 20
}Get workspace
Get a single workspace by ID.
const workspace = await ws.get('ws_a1b2c3d4');GET /workspace/:workspaceIdcurl "https://api.oblien.com/workspace/ws_a1b2c3d4" \
-H "X-Client-ID: $OBLIEN_CLIENT_ID" \
-H "X-Client-Secret: $OBLIEN_CLIENT_SECRET"Response
{
"success": true,
"workspace": { /* WorkspaceResponse */ }
}Get details
Aggregated workspace details - combines workspace info, live stats, SSH status, API access status, and lifecycle config in a single call.
const details = await ws.details('ws_a1b2c3d4');
// details.workspace includes: token, stats, ssh, api_access, lifecycle, configGET /workspace/:workspaceId/detailscurl "https://api.oblien.com/workspace/ws_a1b2c3d4/details" \
-H "X-Client-ID: $OBLIEN_CLIENT_ID" \
-H "X-Client-Secret: $OBLIEN_CLIENT_SECRET"Response
Returns the standard workspace object plus:
{
"success": true,
"workspace": {
"...standard fields...",
"token": "eyJhbG...",
"stats": {
"cpuUsage": 12.5,
"memoryUsage": 45.2,
"memoryUsedMB": 230,
"memoryTotalMB": 512,
"networkIn": "1.2 MB",
"networkOut": "0.5 MB"
},
"ssh": {
"ssh_enabled": true,
"ssh_id": "abc123",
"connection": { "command": "ssh root@abc123 -J root@ssh.oblien.com" }
},
"api_access": { "terminal": true, "preview": false },
"lifecycle": {
"mode": "permanent",
"restart_policy": "always",
"uptime": 3600
},
"config": { /* raw VM config */ }
}
}Update workspace
Update workspace name or config.
const updated = await ws.update('ws_a1b2c3d4', {
name: 'renamed-workspace',
});PUT /workspace/:workspaceId{
"name": "renamed-workspace"
}curl -X PUT "https://api.oblien.com/workspace/ws_a1b2c3d4" \
-H "X-Client-ID: $OBLIEN_CLIENT_ID" \
-H "X-Client-Secret: $OBLIEN_CLIENT_SECRET" \
-H "Content-Type: application/json" \
-d '{ "name": "renamed-workspace" }'Parameters
| Parameter | Type | Description |
|---|---|---|
name | string | New display name |
config | object | Updated config fields |
Only name and config are updatable. Unknown fields are rejected.
Delete workspace
Permanently delete a workspace. The VM is destroyed and all data is removed.
await ws.delete('ws_a1b2c3d4');DELETE /workspace/:workspaceIdcurl -X DELETE "https://api.oblien.com/workspace/ws_a1b2c3d4" \
-H "X-Client-ID: $OBLIEN_CLIENT_ID" \
-H "X-Client-Secret: $OBLIEN_CLIENT_SECRET"Response
{
"success": true,
"message": "Workspace deleted"
}This action is irreversible. All workspace data, snapshots, and logs are permanently deleted.
Get quota
Check your current resource quota based on your plan.
const quota = await ws.quota();GET /workspace/quotacurl "https://api.oblien.com/workspace/quota" \
-H "X-Client-ID: $OBLIEN_CLIENT_ID" \
-H "X-Client-Secret: $OBLIEN_CLIENT_SECRET"Response
{
"success": true,
"plan": "pro",
"planLabel": "Pro",
"limits": {
"cpus": { "min": 1, "max": 8, "default": 1 },
"memory_mb": { "min": 128, "max": 4096, "default": 512 },
"writable_size_mb": { "min": 64, "max": 51200, "default": 512 }
},
"pool": { "cpus": 16, "memory_mb": 16384, "disk_mb": 51200 },
"pool_usage": { "cpus": 4, "memory_mb": 4096, "disk_mb": 2048 },
"running_pool": { "cpus": 8, "memory_mb": 8192, "disk_mb": 25600 },
"running_pool_usage": { "cpus": 2, "memory_mb": 2048, "disk_mb": 1024 },
"maxSandboxes": 10,
"currentSandboxes": 3,
"canCreate": true,
"reason": null
}See Resource Pools for how pool quotas work.
Workspace object
All workspace endpoints return this shape:
interface WorkspaceResponse {
id: string;
name: string;
namespace: string;
mode: 'permanent' | 'temporary';
image: string;
ip: string;
uptime: number;
start_time: string;
info: {
status: string; // 'running' | 'stopped' | 'paused' | 'creating' | ...
is_running: boolean;
user_requested_stop: boolean;
};
access: {
ssh_enabled: boolean;
};
network: {
allow_internet: boolean;
ingress_ports: number[];
egress_ports: number[];
egress: string[];
public_access: boolean;
ingress: string[];
};
public_ports: Array<{
port: number;
hash: string;
label: string;
url: string;
}>;
resources: {
cpus: number;
memory_mb: number;
disk_size_mb: number;
};
created_at: string;
updated_at: string;
}