Python SDK

Reference for fastvm. Auto-generated from the OpenAPI spec.

Install

shell
pip install fastvm

Import

python
from fastvm import FastvmClient

client = FastvmClient()  # reads FASTVM_API_KEY / FASTVM_BASE_URL

Top-level helpers

client.*

client.health

GET/healthz
client.health() -> HealthResponse

Description

Health check

Returns

client.uploadhelper

client.upload(
    vm_id: str,
    local_path: str,
    remote_path: str,
    *,
    fetch_timeout_sec: int = 600,
    exec_timeout_sec: int = 600,
) -> None

Description

Copy a local file or directory into the VM. Uses vms.files.presign and vms.files.fetch under the hood. Directories are tarred on the fly before upload and extracted VM-side after fetch.

Streams end-to-end with no intermediate copy to /tmp on the client, so multi-GB transfers are bounded by VM disk, not RAM. Directory mode needs the tar binary on the client's PATH (standard on macOS and Linux; available on modern Windows via bsdtar).

Parameters

ParamTypeDefaultDescription
vm_idstrrequiredTarget VM id.
local_pathstrrequiredLocal file or directory path.
remote_pathstrrequiredDestination path inside the VM.
fetch_timeout_secint600Timeout on the VM-side /files/fetch call.
exec_timeout_secint600Timeout on VM-side tar extraction (dir mode only).

Returns

None

Example

python
client.upload(vm.id, "./config.toml", "/etc/app.toml")   # file
client.upload(vm.id, "./src", "/root/src")               # directory (tar-streamed)

client.downloadhelper

client.download(
    vm_id: str,
    remote_path: str,
    local_path: str,
    *,
    exec_timeout_sec: int = 600,
) -> None

Description

Copy a file or directory from the VM to the client. Uses vms.files.presign plus a VM-side exec to classify the path and stream its contents out. Directories are tarred VM-side and un-tarred on the client, rooted at ./ so upload and download are symmetric.

Streams end-to-end with no intermediate copy. Missing paths raise FileNotFoundError (Python) or FileTransferError with code: 'ENOENT' (TypeScript).

Parameters

ParamTypeDefaultDescription
vm_idstrrequiredTarget VM id.
remote_pathstrrequiredSource path inside the VM.
local_pathstrrequiredDestination path on the client.
exec_timeout_secint600Timeout on VM-side exec (classify + stream).

Returns

None

Example

python
client.download(vm.id, "/root/out.log", "./out.log")   # file
client.download(vm.id, "/var/log", "./log-backup")     # directory

client.wait_for_vm_readyhelper

client.wait_for_vm_ready(
    vm_id: str,
    *,
    poll_interval: float = 2.0,
    timeout: float = 300.0,
) -> VM

Description

Poll GET /v1/vms/{id} until the VM reaches status == "running" or a terminal failure status. Same polling logic as vms.launch; use this when you already have a VM id from vms.list() or another flow.

Parameters

ParamTypeDefaultDescription
vm_idstrrequiredTarget VM id.
poll_intervalfloat2.0Seconds between polls.
timeoutfloat300.0Total wait deadline in seconds.

Returns

Example

python
vm = client.vms.retrieve(some_id)
vm = client.wait_for_vm_ready(vm.id, timeout=120)

VMs

client.vms.*

client.vms.list

GET/v1/vms
client.vms.list(
    status: VMStatus,
) -> VM[]

Description

List VMs

Parameters

ParamTypeDefaultDescription
statusVMStatusRestrict to VMs with this status. Accepts any value of VMStatus; unknown values return an empty list.

Returns

[]

client.vms.launchoverride

POST/v1/vms
client.vms.launch(
    *,
    machine_type: MachineType | None = None,
    snapshot_id: str | None = None,
    name: str | None = None,
    metadata: dict[str, str] | None = None,
    firewall: FirewallPolicy | None = None,
    wait: bool = True,
    poll_interval: float = 2.0,
    wait_timeout: float = 300.0,
    timeout: float | httpx.Timeout | None = None,
    max_retries: int = 0,
) -> VM

Description

Launch a VM and (by default) block until it reaches status == "running". POST /v1/vms returns 201 for immediately-running VMs and 202 for queued VMs; the override handles both paths transparently by polling GET /v1/vms/{id}.

Pass wait=false (TS) / wait=False (Python) to skip polling and return the raw 201/202 body. Pass snapshot_id / snapshotId to restore from a snapshot instead of cold-booting.

Terminal failure statuses (error, stopped, deleting) raise VMLaunchError. Polling-deadline exceeded raises VMNotReadyError.

Parameters

ParamTypeDefaultDescription
machine_typeMachineType | NoneNoneVM flavor (c1m2, c2m4, ...). Required unless snapshot_id is set.
snapshot_idstr | NoneNoneRestore from snapshot instead of cold-booting.
namestr | NoneNoneHuman-readable VM name.
metadatadict[str, str] | NoneNoneFree-form key/value labels.
firewallFirewallPolicy | NoneNoneInitial firewall policy.
waitboolTrueBlock until RUNNING. Set False for raw 201/202 behavior.
poll_intervalfloat2.0Seconds between polls when wait=True.
wait_timeoutfloat300.0Max seconds to wait for RUNNING. Raises VMNotReadyError on exceed.
timeoutfloat | httpx.Timeout | NoneNonePer-request HTTP timeout (forwarded to generated launch verbatim).
max_retriesint0Auto-retry on 5xx/connect errors. POST is non-idempotent, default 0.

Returns

Example

python
from fastvm import FastvmClient

client = FastvmClient()
vm = client.vms.launch(machine_type="c1m2", name="dev")
print(vm.id, vm.status)  # "running"

# Restore from snapshot
vm = client.vms.launch(snapshot_id="snp_...")

# Skip polling — get the raw 201/202 body
vm = client.vms.launch(machine_type="c1m2", wait=False)

client.vms.retrieve

GET/v1/vms/{id}
client.vms.retrieve(
    id: str,
) -> VM

Description

Get a VM

Parameters

ParamTypeDefaultDescription
idstrrequiredVM ID (UUID).

Returns

client.vms.update

PATCH/v1/vms/{id}
client.vms.update(
    id: str,
    name: str,
    metadata: Metadata,
    ttl: unknown,
) -> VM

Description

Update a VM

Parameters

ParamTypeDefaultDescription
idstrrequiredVM ID (UUID).
namestr
metadataMetadata
ttlunknown

Returns

client.vms.delete

DELETE/v1/vms/{id}
client.vms.delete(
    id: str,
) -> DeleteResponse

Description

Delete a VM

Parameters

ParamTypeDefaultDescription
idstrrequiredVM ID (UUID).

Returns

client.vms.pause

POST/v1/vms/{id}/pause
client.vms.pause(
    id: str,
) -> VM

Description

Pause a VM

Parameters

ParamTypeDefaultDescription
idstrrequiredVM ID (UUID).

Returns

client.vms.resume

POST/v1/vms/{id}/resume
client.vms.resume(
    id: str,
) -> VM

Description

Resume a paused VM

Parameters

ParamTypeDefaultDescription
idstrrequiredVM ID (UUID).

Returns

client.vms.refresh_ttl

POST/v1/vms/{id}/ttl/refresh
client.vms.refresh_ttl(
    id: str,
) -> VM

Description

Reset the VM's TTL cycle

Parameters

ParamTypeDefaultDescription
idstrrequiredVM ID (UUID).

Returns

client.vms.set_firewall

PUT/v1/vms/{id}/firewall
client.vms.set_firewall(
    id: str,
    ingress: IngressPolicy,
    egress: EgressPolicy,
    dns: DNSPolicy,
) -> VM

Description

Replace firewall policy

Parameters

ParamTypeDefaultDescription
idstrrequiredVM ID (UUID).
ingressIngressPolicy
egressEgressPolicy
dnsDNSPolicy

Returns

client.vms.patch_firewall

PATCH/v1/vms/{id}/firewall
client.vms.patch_firewall(
    id: str,
    ingress: IngressPolicy,
    egress: EgressPolicy,
    dns: DNSPolicy,
) -> VM

Description

Patch firewall policy

Parameters

ParamTypeDefaultDescription
idstrrequiredVM ID (UUID).
ingressIngressPolicy
egressEgressPolicy
dnsDNSPolicy

Returns

client.vms.console_token

POST/v1/vms/{id}/console-token
client.vms.console_token(
    id: str,
) -> ConsoleTokenResponse

Description

Mint a console token

Parameters

ParamTypeDefaultDescription
idstrrequiredVM ID (UUID).

Returns

client.vms.runoverride

POST/v1/vms/{id}/exec
client.vms.run(
    id: str,
    *,
    command: str | Sequence[str],
    timeout_sec: int | None = None,
    max_retries: int = 0,
) -> ExecVMResponse

Description

Execute a command inside a VM. The override accepts str in addition to Sequence[str]: plain shell strings are auto-wrapped into ["sh", "-c", "<cmd>"] before hitting the API. Argv-style calls pass through unchanged.

The wrap guards against Python's silent string-to-chars iteration when a Sequence[str] parameter is passed a bare string, which would otherwise produce a nonsensical argv like ["l","s"," ","-","l","a"].

Parameters

ParamTypeDefaultDescription
idstrrequiredTarget VM id.
commandstr | Sequence[str]requiredShell string (auto-wrapped) or argv.
timeout_secint | NoneNoneServer-side execution timeout.
max_retriesint0Auto-retry on 5xx. Non-idempotent, default 0.

Returns

Example

python
# Shell strings work — auto-wrapped into ["sh", "-c", ...]
result = client.vms.run(vm.id, command="ls -la /root")

# Argv lists pass through unchanged
result = client.vms.run(vm.id, command=["python3", "main.py", "--flag"])

print(result.exit_code, result.stdout)

client.vms.streamhelper

client.vms.stream(
    id: str,
    *,
    command: str | Sequence[str],
    timeout_sec: int | None = None,
) -> Iterator[ExecEvent]

Description

Stream exec output as typed events via Accept: application/x-ndjson.

Same endpoint as vms.run (POST /v1/vms/{id}/exec), but the server emits a newline-delimited stream of ExecEvent objects instead of a single buffered JSON response. Events are:

  • "o" — stdout chunk (decoded bytes in data)
  • "e" — stderr chunk (decoded bytes in data)
  • "x" — terminal exit event (exit_code, timed_out, duration_ms)

There is no 4 MiB per-stream cap on output. The HTTP connection stays open until the command exits or timeout_sec fires server-side. Use this for long-running processes (builds, test runners, live logs) where you need incremental output without buffering the entire result.

Shell strings (Python only) are auto-wrapped into ["sh", "-c", ...] exactly like vms.run.

Parameters

ParamTypeDefaultDescription
idstrrequiredTarget VM id.
commandstr | Sequence[str]requiredShell string (auto-wrapped) or argv list.
timeout_secint | NoneNoneServer-side execution timeout in seconds.

Returns

Iterator[]

Example

python
from fastvm import FastvmClient, ExecEvent

client = FastvmClient()
for event in client.vms.stream(vm.id, command="make -j8"):
    if event.type == "o":
        sys.stdout.buffer.write(event.data)
    elif event.type == "e":
        sys.stderr.buffer.write(event.data)
    elif event.type == "x":
        print(f"exit {event.exit_code} in {event.duration_ms} ms")

VMs.Services

client.vms.services.*

client.vms.services.list

GET/v1/vms/{id}/services
client.vms.services.list(
    id: str,
) -> Service[]

Description

List service registrations

Parameters

ParamTypeDefaultDescription
idstrrequiredVM ID (UUID).

Returns

[]

client.vms.services.register

POST/v1/vms/{id}/services
client.vms.services.register(
    id: str,
    name: str,
    port: int,
    h2c: bool,
) -> Service

Description

Register a service on a VM

Parameters

ParamTypeDefaultDescription
idstrrequiredVM ID (UUID).
namestrrequired
portintrequired
h2cboolfalseOptional. When true, the proxy uses HTTP/2 cleartext to the backend (required for gRPC). Defaults to false (HTTP/1.1).

Returns

client.vms.services.update

PUT/v1/vms/{id}/services/{serviceName}
client.vms.services.update(
    id: str,
    service_name: str,
    port: int,
    h2c: bool,
) -> Service

Description

Register or update a service on a VM

Parameters

ParamTypeDefaultDescription
idstrrequiredVM ID (UUID).
service_namestrrequiredService registration name. 1–29 chars, lowercase letters and digits with optional single internal hyphens (no leading, trailing, or consecutive hyphens). Embedded in the public URL as the leftmost label.
portintrequiredNew TCP port. Same value as the existing entry is a no-op.
h2cboolfalseOptional. When true, the proxy uses HTTP/2 cleartext to the backend. Same value as the existing entry is a no-op; a different value updates the registered transport.

Returns

client.vms.services.delete(
    id: str,
    service_name: str,
)

Description

Deregister a service from a VM

Parameters

ParamTypeDefaultDescription
idstrrequiredVM ID (UUID).
service_namestrrequiredService registration name. 1–29 chars, lowercase letters and digits with optional single internal hyphens (no leading, trailing, or consecutive hyphens). Embedded in the public URL as the leftmost label.

VMs.Ssh_keys

client.vms.ssh_keys.*

client.vms.ssh_keys.list

GET/v1/vms/{id}/ssh-keys
client.vms.ssh_keys.list(
    id: str,
) -> SshKeyListResponse

Description

List authorized SSH keys for a VM

Parameters

ParamTypeDefaultDescription
idstrrequiredVM ID (UUID).

Returns

client.vms.ssh_keys.add

POST/v1/vms/{id}/ssh-keys
client.vms.ssh_keys.add(
    id: str,
    name: str,
    public_key: str,
) -> SshKey

Description

Register an SSH public key

Parameters

ParamTypeDefaultDescription
idstrrequiredVM ID (UUID).
namestrOptional human label.
public_keystrrequiredOpenSSH-format public key (ssh-ed25519 AAA...). Comments are stripped. Newlines are rejected.

Returns

Example

python
with open(os.path.expanduser("~/.ssh/id_ed25519.pub")) as f:
    client.vms.ssh_keys.add(vm.id, public_key=f.read(), name="laptop")
# then: ssh root@<vm.publicIpv6>
client.vms.ssh_keys.delete(
    id: str,
    fingerprint: str,
) -> DeleteResponse

Description

Remove an authorized SSH key

Parameters

ParamTypeDefaultDescription
idstrrequiredVM ID (UUID).
fingerprintstrrequiredOpenSSH SHA256 fingerprint of the key to delete (e.g. SHA256:abc...). The base64 hash includes + and / and the prefix has :, so callers MUST URL-encode the value into the path segment. SDKs do this automatically.

Returns

VMs.Files

client.vms.files.*

client.vms.files.presign

POST/v1/vms/{id}/files/presign
client.vms.files.presign(
    id: str,
    path: str,
) -> FilePresignResponse

Description

Mint signed URLs for uploading a file to a VM

Parameters

ParamTypeDefaultDescription
idstrrequiredVM ID (UUID).
pathstrrequiredAbsolute destination path inside the guest filesystem (where the file will land after fetchFileToVm). Used only to scope the staging object key; any value server-side is accepted here.

Returns

Example

python
# High-level helpers — handle presign + PUT/GET + fetch + (for dirs) tar
# for both file and directory transfers automatically.
client.upload(vm.id, "./local/file.txt", "/root/file.txt")
client.upload(vm.id, "./local-dir", "/root/remote-dir")

client.download(vm.id, "/root/out.log", "./out.log")
client.download(vm.id, "/var/log", "./log-backup")

# Raw call if you need manual control over the signed-URL flow:
presign = client.vms.files.presign(vm.id, path="/root/file.txt")

client.vms.files.fetch

POST/v1/vms/{id}/files/fetch
client.vms.files.fetch(
    id: str,
    url: str,
    path: str,
    timeout_sec: int,
) -> ExecVMResponse

Description

Fetch a file into a VM from a presigned URL

Parameters

ParamTypeDefaultDescription
idstrrequiredVM ID (UUID).
urlstrrequiredMust be the downloadUrl previously returned by POST /v1/vms/{id}/files/presign (URLs from other sources are rejected).
pathstrrequiredAbsolute destination path inside the guest filesystem.
timeout_secintPer-fetch timeout in seconds.

Returns

Example

python
# You usually don't call this directly — client.upload() composes
# presign + PUT + fetch in a single call. Use it when you need to
# pipe an already-hosted URL (still from /files/presign) into the VM.
client.vms.files.fetch(vm.id, url=presign.download_url, path="/root/file.txt")

Snapshots

client.snapshots.*

client.snapshots.list

GET/v1/snapshots
client.snapshots.list() -> Snapshot[]

Description

List snapshots

Returns

[]

client.snapshots.create

POST/v1/snapshots
client.snapshots.create(
    vm_id: str,
    name: str,
) -> Snapshot

Description

Create a snapshot from a VM

Parameters

ParamTypeDefaultDescription
vm_idstrrequired
namestrSnapshot name (trimmed + whitespace-collapsed, max 64 runes; longer values are truncated server-side). Auto-generated as snapshot-<8-char-vmId-prefix> if empty.

Returns

client.snapshots.retrieve

GET/v1/snapshots/{id}
client.snapshots.retrieve(
    id: str,
) -> Snapshot

Description

Get a snapshot

Parameters

ParamTypeDefaultDescription
idstrrequiredSnapshot ID (UUID).

Returns

client.snapshots.update

PATCH/v1/snapshots/{id}
client.snapshots.update(
    id: str,
    name: str,
) -> Snapshot

Description

Rename a snapshot

Parameters

ParamTypeDefaultDescription
idstrrequiredSnapshot ID (UUID).
namestr

Returns

client.snapshots.delete

DELETE/v1/snapshots/{id}
client.snapshots.delete(
    id: str,
) -> DeleteResponse

Description

Delete a snapshot

Parameters

ParamTypeDefaultDescription
idstrrequiredSnapshot ID (UUID).

Returns

Builds

client.builds.*

client.builds.create

POST/v1/builds
client.builds.create(
    name: str,
    image_ref: str,
    dockerfile_content: str,
    machine_type: MachineType,
    disk_gi_b: int,
    context_download_url: str,
) -> BuildResponse

Description

Build a snapshot from an image ref or Dockerfile

Parameters

ParamTypeDefaultDescription
namestrOptional human-readable name for the resulting snapshot. If omitted, the build ID is used.
image_refstrDocker image reference (e.g. python:3.13-slim, ghcr.io/user/repo:tag). Used directly on the no-Dockerfile path, and as a fallback FROM source otherwise.
dockerfile_contentstrRaw Dockerfile content to feed to buildah bud inside the build VM. Multi-stage, SHELL, RUN --mount, and every standard Dockerfile feature is supported (handled natively by buildah). Container-runtime metadata (CMD, ENTRYPOINT, EXPOSE, LABEL, HEALTHCHECK) is consumed by buildah but does not surface on the resulting FastVM snapshot — when the snapshot boots, systemd takes over, not the container's CMD.
machine_typeMachineType
disk_gi_bintDisk size for the build VM. Defaults to 10 GiB if omitted.
context_download_urlstrPresigned GET URL for a tar.gz of the build context. The worker downloads and extracts this into /tmp/buildctx before invoking buildah, so COPY instructions resolve against the user's files. Obtain via POST /v1/build-contexts/presign.

Returns

Example

python
# High-level: builds, polls, returns the completed Snapshot.
snapshot = await client.build(
    image_ref="python:3.13-slim",
    dockerfile="FROM python:3.13-slim\nRUN pip install flask\n",
)

# With a build context for COPY instructions:
snapshot = await client.build(
    image_ref="ubuntu:24.04",
    dockerfile=Path("./Dockerfile").read_text(),
    context_dir="./my-app",
)

client.builds.retrieve

GET/v1/builds/{id}
client.builds.retrieve(
    id: str,
) -> BuildResponse

Description

Get build status

Parameters

ParamTypeDefaultDescription
idstrrequiredBuild ID (UUID).

Returns

Build_contexts

client.build_contexts.*

client.build_contexts.presign

POST/v1/build-contexts/presign
client.build_contexts.presign() -> FilePresignResponse

Description

Mint signed URLs for uploading a build context tarball

Returns

Quotas

client.quotas.*

client.quotas.retrieve

GET/v1/org/quotas
client.quotas.retrieve() -> OrgQuotaUsage

Description

Get org quotas and usage

Returns

Types

Shared schemas referenced in parameters and return values.

DeleteResponse

object
FieldTypeDescription
idstr
deletedbool

VMStatus

primitive
Lifecycle status. Known values: provisioning, running, stopped, pausing, paused, resuming, deleting, error. Terminal failure statuses are error and stopped; transitional values (provisioning, pausing, resuming, deleting) indicate the VM is in flight. Additional values may be introduced in future server versions; clients should treat unknown values as "in transition" rather than as hard errors.

SnapshotStatus

primitive
Snapshot lifecycle status. Known values: creating, ready, error. Additional values may be introduced in future server versions.

MachineType

primitive
Machine size identifier (e.g. c1m2, c2m4). Controls CPU and memory allocation. Must be supplied on launch unless restoring from a snapshot.

VM

object
FieldTypeDescription
idstr
namestr
org_idstr
machine_namestr
source_namestrSource snapshot or image name (empty on fresh boot).
firewallFirewallPolicy
effective_firewallunknownRead-only composed view: firewall (the user policy) unioned with per-service auto-rules from this VM's registered services. Each auto-rule has source CIDR ::/0 and a description of the form auto: proxy service <name>. The same policy is what the worker firewall actually enforces. Set firewall to mutate; this field is computed per-response from firewall and the current service registry, never persisted.
metadataMetadata
env_varsEnvVars
public_ipv6str
cpuint
memory_mi_bint
disk_gi_bint
statusVMStatus
created_atstr
deleted_atunknown
ttlunknownOptional auto-action timer. Null when no TTL is configured. See TTL for semantics.
expires_at_msintAbsolute timestamp in ms when the TTL fires. Set only while the VM is running (the countdown freezes on pause).
ttl_remaining_msintRemaining cycle budget in ms. Set only while the VM is paused; restored to expiresAtMs on resume.
paused_atunknownWhen the VM became paused; null otherwise.

Snapshot

object
FieldTypeDescription
idstr
namestr
org_idstr
vm_idstr
firewallFirewallPolicy
metadataMetadata
env_varsEnvVars
servicesSnapshotService[]Captured service registrations from the source VM at snapshot time.
statusSnapshotStatus
created_atstr

PolicyAction

enum
Allow/deny verb. Used both as the per-direction default posture and as each rule's action.
allowdeny

IngressRuleKind

enum
Ingress rule kind. Only cidr is supported — inbound packets don't carry a domain the worker could match on without TLS interception.
cidr

EgressRuleKind

enum
Egress rule kind. - cidr: match by destination IP/CIDR + port/proto. - fqdn: match by destination domain (resolved through the in-process DNS resolver) + port/proto. Resolved IPs land in a per-rule dynamic nft set; the chain emits one rule per fqdn rule keyed on (set, proto, port). Port/proto enforcement on fqdn rules is honest — the prior kind: domain shape with a shared allow-set silently ignored them. Fqdn values accept an optional leading *. wildcard (e.g. *.example.com). Bare wildcards and non-leading wildcards are rejected. Wildcards match one-or-more labels left of the suffix and do not match the apex (matches DNS wildcard semantics).
cidrfqdn

DNSMode

enum
Toggles the meaning of dns.domains. - allow: allowlist — only listed domains can resolve; any other query returns NXDOMAIN. - deny: blocklist — listed domains return NXDOMAIN; all other queries resolve through the upstream resolver. Default is deny with an empty list, which means "resolve everything" — the safe default that preserves existing behavior when callers omit the dns block.
allowdeny

IngressRule

object
FieldTypeDescription
actionPolicyAction
kindIngressRuleKind
valuestrCIDR (e.g. ::/0, 10.0.0.0/8). IPv4 and IPv6 CIDRs are both accepted in the schema; L3 enforcement coverage per family is a worker-side concern.
protocol"tcp" | "udp" | "any"
portsstrSingle port (443), inclusive range (8080-8090), or any. When protocol is any, ports MUST be any.
descriptionstr

IngressPolicy

object
FieldTypeDescription
defaultPolicyAction
rulesIngressRule[]

EgressRule

object
FieldTypeDescription
actionPolicyAction
kindEgressRuleKind
valuestrFor kind: cidr, an IPv4 or IPv6 CIDR. For kind: fqdn, a domain name with optional leading *. wildcard. Must be reachable through the dns gate — a fqdn value blocked by dns.mode/dns.domains is rejected at PUT time as a dead rule.
protocol"tcp" | "udp" | "any"
portsstrSingle port (443), inclusive range (8080-8090), or any. When protocol is any, ports MUST be any.
descriptionstr

EgressPolicy

object
FieldTypeDescription
defaultPolicyAction
rulesEgressRule[]

DNSPolicy

object
DNS-layer filtering, independent of egress L4 rules. The resolver applies the DNS gate BEFORE L4 enforcement; a domain blocked here returns NXDOMAIN regardless of what egress.rules says about its IPs. All fields are optional — the server defaults mode to deny when missing, domains to [], and blockBypass to false (see normalizeDNSPolicy in scheduler/internal/httpapi/firewall.go).
FieldTypeDescription
modeDNSMode
domainslist[str]
block_bypassboolWhen true, the worker denies DoT (TCP 853) and the known public DoH endpoint IPs at the nft layer so guests cannot sidestep the in-process resolver. Default false — turning this on breaks workloads that legitimately reach 1.1.1.1 / 8.8.8.8 / etc. on TCP/443 for non-DoH reasons (e.g. services whose data plane lives on a Cloudflare anycast IP). Operators who enable DNS allowlist mode typically also flip this on explicitly.

FirewallPolicy

object
Top-level firewall policy with three independent axes. All sub-blocks are optional — the server substitutes the safe default (ingress deny / egress allow / dns mode=deny + empty) for missing blocks. Sending firewall: null on VM create is also valid.
FieldTypeDescription
ingressIngressPolicy
egressEgressPolicy
dnsDNSPolicy

SnapshotService

object
Captured (name, port, h2c) tuple for a single service registration on a snapshotted VM. Carried across snapshot/ restore by POST /v1/vms (snapshot-restore branch) so the new VM gets the same service registrations the source VM had at snapshot time.
FieldTypeDescription
namestr
portint
h2cbool

BuildResponse

object
Build state snapshot. Returned by POST /v1/builds (initial pending state) and GET /v1/builds/{id} (current state on each poll).
FieldTypeDescription
idstrBuild ID (UUID). Use this to poll status.
namestr
statusstrCurrent state. Known values: pending (accepted, not yet started), running (worker is executing), completed (snapshot is ready), failed (build did not produce a snapshot). Additional values may be introduced in future server versions; clients should treat unknown values as "in progress" rather than as hard errors.
snapshot_idstrSet when status is completed. Fetch the corresponding Snapshot record via GET /v1/snapshots/{id}.
image_refstr
progressstrHuman-readable phase string while the build runs (e.g. creating build VM, buildah pull, buildah bud, applying image, settling VM, creating snapshot). Not present after a terminal status.
errorstrSet when status is failed. Diagnostic from the worker (truncated to ~4 KiB).
created_atstr

Metadata

object
Free-form string→string map. Server-enforced limits: up to 256 keys, key length 1–256 bytes, value length ≤4096 bytes, total JSON encoding ≤65536 bytes.

EnvVars

object
Environment variable string→string map injected into the VM at boot. Keys must be 1–256 bytes and match shell-variable name ([A-Za-z_][A-Za-z0-9_]*); values may not contain newline, carriage return, or null bytes. Total JSON encoding ≤65536 bytes.

ExecEvent

object
One event in the NDJSON exec stream returned by POST /v1/vms/{id}/exec under Accept: application/x-ndjson. Short field names (t, d, c, to, ms) keep per-chunk overhead small since high-output commands can produce thousands of events per exec.
FieldTypeDescription
t"o" | "e" | "x"Event type: o = stdout chunk, e = stderr chunk, x = terminal exit event.
dstrFor o/e: base64-encoded raw bytes of the chunk. For x: optional diagnostic string (e.g. spawn failure) when non-empty.
cintExit code. Present on x events only.
toboolTrue if the command was killed by the timeout. x events only.
msintGuest-reported duration in milliseconds. x events only.

ExecVMResponse

object
Buffered response shape for POST /v1/vms/{id}/exec under Accept: application/json. The server collects the streamed events and returns this aggregate once the command exits. Per-stream output is capped at 4 MiB; overflow bytes are dropped and signalled via stdoutTruncated / stderrTruncated. Streaming clients (Accept: application/x-ndjson) receive every byte without a cap.
FieldTypeDescription
exit_codeint
stdoutstr
stderrstr
timed_outbool
stdout_truncatedboolTrue if the collector dropped stdout bytes past the 4 MiB cap.
stderr_truncatedboolTrue if the collector dropped stderr bytes past the 4 MiB cap.
duration_msint

FilePresignResponse

object
Pair of signed URLs scoped to the same per-VM staging object. Usable in either direction: either side (client or VM) PUTs bytes to uploadUrl, and either side GETs them back via downloadUrl. URLs expire after expiresInSec seconds and the staging object is auto-deleted after about a day.
FieldTypeDescription
upload_urlstrPresigned PUT URL for the staging object. Accepts Content-Type: application/octet-stream. Used by the client on upload, or by the VM (via an exec'd curl -T -) on download.
download_urlstrPresigned GET URL for the same staging object. Used by the VM (via POST /v1/vms/{id}/files/fetch) on upload, or by the client (via httpx.stream / curl) on download.
expires_in_secintLifetime of both URLs in seconds.
max_upload_bytesintUpper bound on upload size (equals the VM's disk size in bytes).

ConsoleTokenResponse

object
FieldTypeDescription
tokenstr
expires_in_secint
websocket_pathstrRelative WebSocket path; combine with your API host as wss://<host><websocketPath>?session=<token>.

SshKey

object
FieldTypeDescription
namestrOptional human label.
public_keystrOpenSSH-format public key, of the form <type> <base64-blob> — the optional comment is stripped server-side. Supported types: ssh-ed25519, ssh-rsa, ecdsa-sha2-nistp{256,384,521}, plus FIDO2 hardware-backed variants (sk-...@openssh.com).
fingerprintstrOpenSSH SHA256 fingerprint, e.g. SHA256:abc.... This is the identifier — matches what ssh-keygen -lf prints and what your ssh client shows on first connect; pass it back as the {fingerprint} path segment to deleteSshKey.
created_atstr

SshKeyListResponse

object
FieldTypeDescription
keysSshKey[]

OrgQuotaValues

object
FieldTypeDescription
vcpuint
memory_mi_bint
disk_gi_bint
snapshot_countint

OrgQuotaUsage

object
FieldTypeDescription
org_idstr
limitsOrgQuotaValues
usageOrgQuotaValues

Service

object
FieldTypeDescription
namestrService name (1–29 chars). Embedded in the public URL as <name>--<vmIdHexNoHyphens>.proxy.<stack-domain>.
portintTCP port the service listens on inside the VM. Privileged ports (<1024) are rejected.
h2cboolWhen true, the proxy speaks HTTP/2 cleartext (h2c) to the backend. Required for gRPC and h2c-only apps. When false (default), the proxy uses HTTP/1.1 — covers HTTP/1.1 apps, Server-Sent Events, and WebSocket pass-through.

HealthResponse

object
Health check
FieldTypeDescription
statusstr