Types
All types in this file mirror the createos-sandbox control-plane JSON HTTP API. Fields use the
server's snake_case names so JSON parses without translation. When the server uses omitempty on
a field, the TypeScript field is marked optional (?) — the key is absent from the wire payload
rather than sent as null. List endpoints return a doubly-nested pagination envelope
{ data: { data: [...], pagination: { total, limit, offset, count } } }; rootfs is the lone
exception (a plain view). The server clamps limit to 500 — drive paging from the reported
total, not the requested page size. Every type here is re-exported via export * from "./types.js"
in index.ts, making the entire surface public.
See also: Client · Sandbox · Sub-APIs
At a glance
- Package:
@nodeops-createos/sandbox(npm) - Import:
import { createClient } from "@nodeops-createos/sandbox" - Base URL:
https://api.sb.createos.sh— override withCREATEOS_SANDBOX_BASE_URL - Auth: API key via the
apiKeyoption orCREATEOS_SANDBOX_API_KEY
JSend envelope
The control plane wraps every response in one of three JSend shapes. The SDK
unwraps these transparently; consumers only see them when using the raw
CreateosSandboxHttp transport directly.
TypeScript1export interface SuccessEnvelope<T> {2 status: "success";3 data: T;4}56export interface FailEnvelope {7 status: "fail";8 /** Field-keyed object or plain string depending on the endpoint. */9 data: Record<string, unknown> | string;10}1112export interface ErrorEnvelope {13 status: "error";14 message: string;15 code: number;16}1718export type JSendEnvelope<T> = SuccessEnvelope<T> | FailEnvelope | ErrorEnvelope;
Client & request options
RetryOptions
Exponential-backoff retry policy. Omit a field to keep its default.
TypeScript1export interface RetryOptions {2 maxRetries?: number; // Extra attempts after the first. Default 2 (3 total).3 baseDelayMs?: number; // Base backoff delay in ms. Default 500.4 maxDelayMs?: number; // Backoff ceiling in ms. Default 30000.5}
RetryReason
TypeScript1export type RetryReason = "network" | "status" | "rate-limit";
RequestHookContext
Delivered to ClientHooks.onRequest. All credentials are pre-redacted.
| Field | Type | Notes |
|---|---|---|
url | string | URL with userinfo stripped and sensitive query params redacted |
method | string | Uppercase HTTP method |
headers | Record<string, string> | Credentials replaced by "redacted" |
attempt | number | 1 for first try, 2+ for retries |
ResponseHookContext
Extends RequestHookContext.
| Field | Type | Notes |
|---|---|---|
status | number | HTTP status code |
durationMs | number | Elapsed time for the fetch call, in ms |
requestId | string | undefined | Server-supplied request id, when present |
RetryHookContext
Extends Omit<ResponseHookContext, "status">.
| Field | Type | Notes |
|---|---|---|
status | number | undefined | HTTP status, or undefined for network errors |
reason | RetryReason | Why the SDK is retrying |
delayMs | number | Sleep time before next attempt |
ClientHooks
Optional lifecycle hooks for zero-dep observability. Every payload is pre-redacted. Throws inside a hook are swallowed. Hooks are awaited in the request path — keep hook work cheap or dispatch slow work without returning the promise.
TypeScript1export interface ClientHooks {2 onRequest?: (ctx: RequestHookContext) => void | Promise<void>;3 onResponse?: (ctx: ResponseHookContext) => void | Promise<void>;4 onRetry?: (ctx: RetryHookContext) => void | Promise<void>;5}
CreateosSandboxClientOptions
Construction options for CreateosSandboxClient. All fields are optional.
| Field | Type | Notes |
|---|---|---|
apiKey | string? | Sent as X-Api-Key. Falls back to CREATEOS_SANDBOX_API_KEY env var |
authHeaders | HeadersInit? | Auth headers used instead of an API key |
baseUrl | string? | Control-plane base URL. Falls back to CREATEOS_SANDBOX_BASE_URL, then https://api.sb.createos.sh |
fetch | typeof fetch? | Custom fetch implementation (useful in tests) |
timeoutMs | number? | Per-request timeout in ms. Default 60000. 0 disables |
retry | RetryOptions | false? | Retry policy, or false to disable retries entirely |
userAgent | string? | Overrides the User-Agent header |
hooks | ClientHooks? | Lifecycle hooks for observability |
RequestOptions
Per-call overrides accepted by every SDK method.
| Field | Type | Notes |
|---|---|---|
signal | AbortSignal? | Cancel the request and any in-flight retry backoff |
headers | HeadersInit? | Merged into this request, overriding client defaults |
timeoutMs | number? | Per-request timeout in ms, overrides client default |
retry | RetryOptions | false? | Retry policy for this request, overrides client default |
ExecOptions
TypeScript1export type ExecOptions = RequestOptions;
Alias for RequestOptions; passed to Sandbox.runCommand and Sandbox.streamCommand.
Catalog & identity
Shape
A sandbox sizing preset. Returned by listShapes().
| Field | Type | Notes |
|---|---|---|
id | string | Shape id passed as CreateSandboxRequest.shape, e.g. s-1vcpu-256mb |
vcpu | number | Virtual CPU count |
mem_mib | number | Memory in MiB |
default_disk_mib | number | Default overlay disk size when the create request omits disk_mib |
cpu_quota_pct | number? | cgroup v2 cpu.max quota as a percent of one CPU; absent = unlimited |
RootfsEntry
Metadata for one built-in rootfs image in the catalog.
| Field | Type | Notes |
|---|---|---|
name | string | Catalog name |
description | string? | Human-readable description |
deprecated | boolean? | True when this image is being retired |
successor | string? | Recommended replacement when this image is deprecated |
RootfsData
TypeScript1export interface RootfsData {2 /** Available rootfs catalog names usable as `CreateSandboxRequest.rootfs`. */3 rootfs: string[];4 /** Name used when a create request omits `rootfs`. */5 default: string;6 /** Rich per-rootfs metadata; absent when the catalog is empty. */7 entries?: RootfsEntry[];8}
Response from listRootfs(). entries is absent when the catalog is empty. This endpoint returns
a plain view, not the paginated envelope used by all other list routes.
HostStatus
TypeScript1export type HostStatus = "active" | "draining" | "dead";
Scheduling state of a worker host.
HostPublic
A worker host visible to the caller. Returned by listHosts().
| Field | Type | Notes |
|---|---|---|
id | string | |
status | HostStatus | |
free_mib | number | Schedulable memory currently free, in MiB |
vm_count | number | Sandboxes currently placed on the host |
rootfses | string[]? | Rootfs images cached on the host; absent (omitempty) when none |
WhoAmIStatsView
Per-state sandbox counts for the calling identity.
| Field | Type | Notes |
|---|---|---|
running | number | Sandboxes currently running |
paused | number | Sandboxes currently paused |
other | number | Sandboxes in any other state |
total | number | Total non-destroyed sandboxes |
WhoAmIView
Identity behind the configured API key. Returned by whoami().
| Field | Type | Notes |
|---|---|---|
user_id | string | Stable id of the authenticated user |
stats | WhoAmIStatsView | Sandbox counts grouped by lifecycle state |
Sandbox
NetworkEntry
References an overlay network by id in CreateSandboxRequest.networks.
TypeScript1export interface NetworkEntry {2 id: string;3}
CreateSandboxRequest
Body of POST /v1/sandboxes. Only shape is required.
Note:
bandwidth_quota_bytesis not settable at create time — the server returns400for any non-zero value. Grow the quota post-create withSandbox.rechargeBandwidth().
node_selectorandingress_*fields are not described in the published OpenAPI spec; verify against the live API.
| Field | Type | Notes |
|---|---|---|
shape | string | Required. A shape id from listShapes() |
rootfs | string? | Rootfs catalog name or template id/name; empty = host default |
name | string? | User-facing VM name, unique per user; empty = auto-generated |
networks | NetworkEntry[]? | Overlay networks to join at create time |
disk_mib | number? | Overlay disk size in MiB; 0 = shape default |
egress | string[]? | Egress allowlist; empty / ["*"] = allow all |
envs | Record<string, string>? | Env vars injected into every command inside the VM |
ssh_pubkeys | string[]? | OpenSSH public keys authorized for the SSH gateway |
host_id | string? | Pin placement to a specific host id; empty = scheduler picks |
node_selector | Record<string, string>? | Scheduler placement labels (k8s NodeSelector semantics) |
ingress_enabled | boolean? | Opt the sandbox into HTTP ingress at create time |
disks | DiskAttachment[]? | Disks to mount into the VM at boot |
region | string? | Pin to a region; must equal the server's region (no cross-region routing) |
auto_pause_after_seconds | number? | Idle auto-pause timeout in seconds (60–86400) |
start_paused | boolean? | If true, the sandbox boots into paused state |
CreateSandboxResponse
Result of POST /v1/sandboxes, returned before the SDK fetches the full SandboxView.
Records the resolved placement and boot timing.
| Field | Type | Notes |
|---|---|---|
id | string | |
name | string | |
ip | string | The VM's private IP |
shape | string | |
rootfs | string | |
vcpu | number | |
mem_mib | number | Memory in MiB |
disk_mib | number | Overlay disk size in MiB |
spawn_ms | number | Wall-clock time to boot the VM, in ms |
egress | string[] | Resolved egress allowlist |
bandwidth_quota_bytes | number | Transferable byte quota; -1 = unmetered |
ingress_url_template | string? | Ingress URL template with literal <port> placeholder; set when ingress is on |
SandboxStatus
Lifecycle state of a sandbox. Transitional states (pausing, resuming, forking, creating,
destroying) settle into a steady or terminal one.
TypeScript1export type SandboxStatus =2 | "creating"3 | "running"4 | "pausing"5 | "paused"6 | "resuming"7 | "forking"8 | "error"9 | "destroying"10 | "destroyed"11 | "failed";
SandboxView
Full server-side projection of a sandbox. Backs the Sandbox handle and is returned by get/list
endpoints. Optional fields are omitted by the server (omitempty) rather than sent as null.
Wire drift:
node_selector,ingress_enabled,ingress_url_template, andingress_bytesare absent from the published OpenAPI spec. Verify against the live API.
| Field | Type | Notes |
|---|---|---|
id | string | |
status | SandboxStatus | |
ip | string? | Absent until the VM is assigned an address (omitted while creating) |
vcpu | number | |
mem_mib | number | Memory in MiB |
disk_mib | number | Overlay disk size in MiB |
created_at | string | RFC 3339 timestamp |
ingress_enabled | boolean | |
ingress_url_template | string? | Ingress URL template with <port> placeholder; set when ingress is on |
name | string? | |
running_at | string? | RFC 3339 timestamp of when the VM last reached running |
destroyed_at | string? | RFC 3339 timestamp of when the VM was destroyed |
spawn_ms | number? | Wall-clock boot time in ms |
shape | string? | |
rootfs | string? | |
region | string? | |
egress | string[]? | |
envs | string[]? | Names of env vars stored on the sandbox; values are never returned |
ssh_pubkeys | string[]? | |
created_by | string? | Identity that created the sandbox |
bandwidth_quota_bytes | number? | Transferable byte quota |
ingress_bytes | number? | Inbound bytes observed (never enforced) |
node_selector | Record<string, string>? | Scheduler placement labels |
host_id | string? | Host the sandbox is placed on |
paused_at | string? | RFC 3339 timestamp of the last pause |
last_resumed_at | string? | RFC 3339 timestamp of the last resume |
forked_from | string? | Source sandbox id when created via fork |
auto_pause_after_seconds | number? | Idle auto-pause timeout in seconds; absent when auto-pause is disabled |
ListSandboxesOptions
Extends RequestOptions.
| Field | Type | Notes |
|---|---|---|
limit | number? | Cap the number of handles returned; omit to fetch every page |
status | "running" | "creating" | "destroyed" | "failed"? | Filter to one lifecycle state |
ForkSandboxRequest
Optional overrides applied to a fork. Omitted fields inherit from the source.
| Field | Type | Notes |
|---|---|---|
start_paused | boolean? | Keep the fork in paused instead of auto-resuming |
ssh_pubkeys | string[]? | |
egress | string[]? | |
ingress_enabled | boolean? | |
envs | Record<string, string>? | |
bandwidth_quota_bytes | number? |
PatchSandboxRequest
Body of the sandbox PATCH endpoint, used by Sandbox.setIngress and Sandbox.setAutoPause.
Omitted fields are left unchanged.
| Field | Type | Notes |
|---|---|---|
ingress_enabled | boolean? | |
auto_pause_after_seconds | number? | Idle auto-pause timeout in seconds (60–86400) |
disable_auto_pause | boolean? | When true, clears the auto-pause timeout; required because omitting auto_pause_after_seconds means "leave unchanged" |
AddSSHPubkeysRequest
Body of Sandbox.addSSHPubkeys — keys to add to a live sandbox.
TypeScript1export interface AddSSHPubkeysRequest {2 /** OpenSSH-formatted public keys. Keys already present are de-duplicated. */3 keys: string[];4}
AddSSHPubkeysResponse
TypeScript1export interface AddSSHPubkeysResponse {2 /** Total `ssh_pubkeys` on the sandbox after the add. */3 count: number;4}
DestroyedResponse
TypeScript1export interface DestroyedResponse {2 /** True when the sandbox was already terminal or was reclaimed inline. */3 status: Extract<SandboxStatus, "destroying" | "destroyed" | "paused" | "error">;4}
SetEgressRequest
TypeScript1export interface SetEgressRequest {2 /** `host:port` allow rules. `null`, omitted, or `[]` means allow all. */3 egress?: string[] | null;4}
EgressView
The sandbox's current egress allowlist. Returned by getEgress / setEgress.
TypeScript1export interface EgressView {2 id: string;3 /** Active `host:port` allow rules. Empty = allow all. */4 egress: string[];5}
BandwidthView
Bandwidth quota and usage counters. Returned by getBandwidth / rechargeBandwidth.
| Field | Type | Notes |
|---|---|---|
id | string | |
quota_bytes | number | Total transferable byte quota; -1 = unmetered |
used_bytes | number | Egress bytes — billed against the quota |
ingress_bytes | number | Inbound bytes — observed, never enforced |
remaining_bytes | number | Bytes left before the VM is network-capped |
capped | boolean | true once the quota is exhausted and egress is blocked |
RechargeBandwidthRequest
TypeScript1export interface RechargeBandwidthRequest {2 /** Bytes to add to the quota. */3 add_bytes: number;4}
ResizeSandboxRequest
TypeScript1export interface ResizeSandboxRequest {2 /** New overlay disk size in MiB. Must be larger than the current size. */3 disk_mib: number;4}
ResizeSandboxResponse
TypeScript1export interface ResizeSandboxResponse {2 /** Disk size in MiB after the grow. */3 disk_mib: number;4}
Command execution
ExecRequest
Wire request body for POST /v1/sandboxes/:id/exec.
| Field | Type | Notes |
|---|---|---|
cmd | string | Executable to run inside the guest. Not run through a shell — wrap in ["bash", "-c", "…"] for pipes, globbing, or redirection |
args | string[]? | Arguments passed to cmd |
stream | boolean? | Stream output as NDJSON frames instead of buffering. Set by streamCommand |
ExecResult
Buffered output of a completed command. Returned by runCommand.
| Field | Type | Notes |
|---|---|---|
stdout | string | Captured standard output |
stderr | string | Captured standard error |
exit_code | number | Process exit code; 0 = success |
error | string? | Agent-level failure (the command could not be started) |
ExecResponse
Result of runCommand: the buffered output plus timing.
TypeScript1export interface ExecResponse {2 result: ExecResult;3 /** Wall-clock time the command ran, in milliseconds. */4 exec_ms: number;5}
ExecStreamEvent
Discriminated union yielded by Sandbox.streamCommand. Switch on type to handle each kind of
event — TypeScript narrows the payload.
TypeScript1export type ExecStreamEvent =2 | { type: "stdout"; data: string }3 | { type: "stderr"; data: string }4 | { type: "exit"; exitCode: number }5 | { type: "error"; message: string }6 | { type: "heartbeat" };
ExecStreamFrame
Raw NDJSON frame as emitted by the server. Exposed for advanced users who want to bypass the
ExecStreamEvent projection (e.g. log forwarders that need the snake_case shape).
| Field | Type | Notes |
|---|---|---|
stdout | string? | |
stderr | string? | |
exit_code | number? | |
error | string? | |
hb | boolean? | Heartbeat marker emitted every 5 s |
Handle option types
CreateSandboxOptions
Extends RequestOptions. Passed to CreateosSandboxClient.createSandbox.
| Field | Type | Notes |
|---|---|---|
wait | boolean? | Wait until the sandbox reaches running before resolving; default true |
waitTimeoutMs | number? | Budget for the wait in ms; default 120000 |
WaitOptions
Options for the Sandbox.waitUntil* pollers.
| Field | Type | Notes |
|---|---|---|
timeoutMs | number? | Wait budget in ms; default 120000 |
signal | AbortSignal? | Cancel the wait |
request | RequestOptions? | Per-request options applied to each poll refresh; note that timeoutMs here is the per-request transport timeout, not the overall wait budget |
Templates
TemplateStatus
TypeScript1export type TemplateStatus = "pending" | "building" | "ready" | "failed";
ready once the rootfs image is usable as a sandbox rootfs.
TemplateCreateRequest
Body of templates.create — a Dockerfile to build into a sandbox rootfs.
| Field | Type | Notes |
|---|---|---|
name | string | |
dockerfile | string | Dockerfile source built into the rootfs image |
base | string? | Base rootfs catalog name to build on top of; empty = host default |
TemplateView
A custom rootfs template. Returned by the templates endpoints.
| Field | Type | Notes |
|---|---|---|
id | string | |
name | string | |
base | string | Base rootfs the template was built on |
status | TemplateStatus | |
ext4_size_bytes | number | Size of the built ext4 rootfs image, in bytes |
created_at | string | RFC 3339 |
built_at | string? | RFC 3339; absent until ready |
dockerfile | string? | Present only on detail GET with include: "dockerfile" |
GetTemplateOptions
Extends RequestOptions.
TypeScript1export interface GetTemplateOptions extends RequestOptions {2 /** Set to `"dockerfile"` to include the original build source in the response. */3 include?: "dockerfile";4}
TemplateLogEvent
One NDJSON line from a template build log stream.
| Field | Type | Notes |
|---|---|---|
ts | string? | Timestamp |
level | string? | Log level |
line | string? | Log line text |
attempt | number? | Build attempt number |
final | boolean? | Terminal frame when true |
status | string? | "ready" or "failed" in the terminal frame |
[key] | unknown | Additional arbitrary fields (index signature) |
TemplateLogsOptions
Options for templates.logs / templates.followLogs. Extends RequestOptions.
TypeScript1export interface TemplateLogsOptions extends RequestOptions {2 /** Filter to one build attempt. Default = all attempts. */3 attempt?: number;4}
Disks
DiskKind
TypeScript1export type DiskKind = "s3";
Storage backend for a registered disk. Only "s3" today (covers AWS S3, Cloudflare R2, MinIO,
and any S3-compatible endpoint).
DiskConfig
Non-secret S3 disk configuration. Persisted server-side as JSON.
| Field | Type | Notes |
|---|---|---|
bucket | string | |
endpoint | string | S3-compatible endpoint URL |
region | string? | |
use_path_style | boolean? | Force path-style addressing (endpoint/bucket/key) instead of virtual-hosted; needed for MinIO / R2 with custom domains |
DiskCredentials
Bucket credentials. Sent only on create; AES-GCM-encrypted at rest and never returned by any read endpoint.
TypeScript1export interface DiskCredentials {2 access_key: string;3 secret_key: string;4}
DiskCreateRequest
Body of POST /v1/disks.
| Field | Type | Notes |
|---|---|---|
name | string | User-scoped name; must match ^[a-z0-9][a-z0-9-]{0,62}$ |
kind | DiskKind | |
config | DiskConfig | |
credentials | DiskCredentials |
DiskView
User-facing projection of a registered disk. Credentials never appear here.
| Field | Type | Notes |
|---|---|---|
id | string | |
name | string | |
kind | DiskKind | |
config | DiskConfig | Server returns this as a JSON blob; the SDK exposes it as parsed JSON |
created_at | string | RFC 3339 |
DiskMountStatus
TypeScript1export type DiskMountStatus = "pending" | "mounted" | "error" | "unmounting";
DiskAttachment
One element of CreateSandboxRequest.disks or the body of the attach endpoint.
| Field | Type | Notes |
|---|---|---|
disk_id | string | A disk_<ulid> id or the user-scoped disk name |
mount_path | string | Absolute path inside the guest, e.g. /mnt/data |
sub_path | string? | Bucket sub-folder to expose at mount_path |
SandboxDiskView
Per-attachment projection. Returned from GET /v1/sandboxes/:id/disks.
| Field | Type | Notes |
|---|---|---|
disk_id | string | The disk_<ulid> id of the registered disk |
name | string | |
kind | DiskKind | |
config | DiskConfig | |
mount_path | string | Absolute path inside the guest where the disk is mounted |
sub_path | string? | Bucket sub-folder exposed at mount_path, when set |
mount_status | DiskMountStatus | |
mount_error | string? | Failure detail when mount_status is "error" |
AttachDiskOptions
Options for Sandbox.attachDisk.
| Field | Type | Notes |
|---|---|---|
diskId | string | A disk_<ulid> id or the user-scoped disk name |
mountPath | string | Absolute path inside the guest, e.g. /mnt/data |
subPath | string? | Optional bucket sub-folder to expose at mountPath |
Note:
detachDiskrequires thedisk_<ulid>id, not the name. See fc-sdk issue #70.
DetachDiskOptions
Options for Sandbox.detachDisk.
| Field | Type | Notes |
|---|---|---|
diskId | string | A disk_<ulid> id or the user-scoped disk name |
mountPath | string | Absolute path inside the guest where the disk is currently mounted; required because the same disk may be attached at multiple paths and the composite key is (sandbox, disk, mountPath) |
DiskDeletedResponse
TypeScript1export interface DiskDeletedResponse {2 deleted: boolean;3}
DiskDetachedResponse
TypeScript1export interface DiskDetachedResponse {2 detached: boolean;3}
Networks
NetworkCreateRequest
TypeScript1export interface NetworkCreateRequest {2 name: string;3}
NetworkMember
A sandbox attached to an overlay network, with its address on that network.
| Field | Type | Notes |
|---|---|---|
sandbox_id | string | |
status | string | |
ip | string? | The member's IP on this overlay network; absent until the membership is programmed |
name | string? | The member sandbox's user-facing name, when set |
Network
An overlay network. Returned by the networks endpoints.
| Field | Type | Notes |
|---|---|---|
id | string | |
name | string | |
created_at | string | RFC 3339 |
member_count | number? | Number of attached sandboxes; present on list responses |
members | NetworkMember[]? | Attached sandboxes with per-network addresses; present on detail GET |
Misc / probe responses
OKResponse
Generic acknowledgement returned by endpoints with no richer payload.
TypeScript1export interface OKResponse {2 ok: boolean;3}
HealthzResponse
Liveness probe result. Returned by healthz().
TypeScript1export interface HealthzResponse {2 /** True once the control plane process is up. */3 up: boolean;4}
ReadyzResponse
Readiness probe result. Returned by readyz().
TypeScript1export interface ReadyzResponse {2 /** True once the control plane is ready to serve traffic. */3 ready: boolean;4 /** Why the control plane is not ready, when `ready` is false. */5 reason?: string;6 /** Milliseconds since the scheduler last completed a healthy pass. */7 scheduler_last_ok_ms_ago?: number;8}