Error
error (string, required) — Human-readable error message.
QuotaExceededError
Per-VM service quota exceeded. The `error` token is a stable
machine-readable code so SDKs can branch on it; `count` is the
configured cap at denial time.
error ("vm_service_quota_exceeded", required)count (integer, required)
DeleteResponse
id (string, required)deleted (boolean, required)
VMStatus
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
Snapshot lifecycle status. Known values: `creating`, `ready`, `error`.
Additional values may be introduced in future server versions.
TTL
Per-VM auto-action timer. The cycle ticks down while the VM is
`running` and freezes on pause. `seconds` is the original cycle
duration; refresh and PATCH-time updates reset to this value.
seconds (integer, required) — Cycle duration. Refresh resets to this value. Capped at 1 year
(31536000s); larger values are rejected with 400.
action ("pause" | "delete", required) — Action taken on expiry. `pause` re-arms the cycle for the
next running session; `delete` is terminal.
QuotaExceeded
429 body returned by `/v1/vms/{id}/resume` when the org's quota
for one of the listed dimensions would be exceeded.
error (string, required)dimension ("vcpu" | "memory_mib" | "disk_gib" | "snapshot_count", required)
MachineType
Machine size identifier (e.g. `c1m2`, `c2m4`). Controls CPU and
memory allocation. Must be supplied on launch unless restoring
from a snapshot.
VM
id (string, required)name (string, required)orgId (string, required)machineName (string)sourceName (string) — Source snapshot or image name (empty on fresh boot).firewall (FirewallPolicy)effectiveFirewall (any) — Read-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.
metadata (Metadata)envVars (EnvVars)publicIpv6 (string)cpu (integer, required)memoryMiB (integer, required)diskGiB (integer, required)status (VMStatus, required)createdAt (string, required)deletedAt (string)ttl (any) — Optional auto-action timer. Null when no TTL is configured.
See `TTL` for semantics.
expiresAtMs (integer) — Absolute timestamp in ms when the TTL fires. Set only while
the VM is `running` (the countdown freezes on pause).
ttlRemainingMs (integer) — Remaining cycle budget in ms. Set only while the VM is
paused; restored to `expiresAtMs` on resume.
pausedAt (string) — When the VM became paused; null otherwise.
Snapshot
id (string, required)name (string, required)orgId (string, required)vmId (string, required)firewall (FirewallPolicy)metadata (Metadata)envVars (EnvVars)services (SnapshotService[]) — Captured service registrations from the source VM at snapshot time.status (SnapshotStatus, required)createdAt (string, required)
PolicyAction
Allow/deny verb. Used both as the per-direction default posture and
as each rule's action.
IngressRuleKind
Ingress rule kind. Only `cidr` is supported — inbound packets don't
carry a domain the worker could match on without TLS interception.
EgressRuleKind
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).
DNSMode
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.
IngressRule
action (PolicyAction, required)kind (IngressRuleKind, required)value (string, required) — CIDR (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", required)ports (string, required) — Single port (`443`), inclusive range (`8080-8090`), or `any`.
When `protocol` is `any`, `ports` MUST be `any`.
description (string)
IngressPolicy
default (PolicyAction, required)rules (IngressRule[])
EgressRule
action (PolicyAction, required)kind (EgressRuleKind, required)value (string, required) — For `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", required)ports (string, required) — Single port (`443`), inclusive range (`8080-8090`), or `any`.
When `protocol` is `any`, `ports` MUST be `any`.
description (string)
EgressPolicy
default (PolicyAction, required)rules (EgressRule[])
DNSPolicy
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`).
mode (DNSMode)domains (string[])blockBypass (boolean) — When 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
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.
ingress (IngressPolicy)egress (EgressPolicy)dns (DNSPolicy)
PatchFirewallRequest
Partial firewall update. Each block (`ingress`, `egress`, `dns`) is
optional; when present, the supplied object replaces that block
wholesale. To change a single rule, send the full block with the
desired rule list. An empty body (`{}`) is a no-op.
ingress (IngressPolicy)egress (EgressPolicy)dns (DNSPolicy)
SnapshotService
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.
name (string, required)port (integer, required)h2c (boolean)
SnapshotRestoreWarnings
Reports best-effort failures during the snapshot-restore
service-replay step. Only present when restoring from a
snapshot AND the post-create bulk service registration failed.
The VM is created successfully and usable; the user can
manually re-register the listed services with one
`POST /v1/vms/{id}/services` per service.
Bulk service registration is atomic at Redis (one Lua call
either writes all-N entries or zero), so partial state
("5 of 8 registered") is impossible — the response is always
either a VM with all services registered or a VM with zero
services and the full list returned here.
servicesRegistrationFailed (boolean, required) — Always `true` when this object is present.unregisteredServices (SnapshotService[]) — Services from the snapshot that did not land on the new
VM. Caller can re-register each via
`POST /v1/vms/{id}/services`.
reason (string) — Operator-facing diagnostic for the failure.
VMCreateResponse
VM object as returned by `POST /v1/vms`. On snapshot restore,
an optional `snapshotRestoreWarnings` field may be present if
the captured services failed to re-register on the new VM.
Existing SDK callers that don't know about the field see the
unchanged VM wire shape (`omitempty` keeps the field absent on
cold boots and on warning-free restores).
CreateVMRequest
Boot behavior depends on which fields are set:
- `snapshotId` set → restore from snapshot (takes precedence over
`machineType` if both are sent).
- Otherwise → fresh boot. `machineType` selects the size; if
omitted or empty, defaults to `c1m2`.
name (string) — User-facing name (trimmed + whitespace-collapsed, max 64 runes
after normalization; longer values are truncated server-side).
Auto-generated as `vm-<8-char-id-prefix>` if empty.
machineType (MachineType)snapshotId (string) — Snapshot ID to restore from.diskGiB (integer) — Override the default disk size (GiB).firewall (FirewallPolicy)metadata (Metadata)envVars (EnvVars)ttl (TTL)
UpdateVMRequest
At least one of `name`, `metadata`, or `ttl` must be provided.
Sending `metadata: {}` clears all metadata; omitting it leaves
existing metadata unchanged. Sending `ttl: null` explicitly
clears the TTL; sending a `TTL` object replaces it; omitting
the field leaves the current TTL unchanged.
name (string)metadata (Metadata)ttl (any)
CreateSnapshotRequest
vmId (string, required)name (string) — Snapshot name (trimmed + whitespace-collapsed, max 64 runes;
longer values are truncated server-side). Auto-generated as
`snapshot-<8-char-vmId-prefix>` if empty.
UpdateSnapshotRequest
Rename a snapshot. `name` is optional; if omitted or empty, the
server regenerates the auto-name (`snapshot-<8-char-vmId-prefix>`).
CreateBuildRequest
At least one of `imageRef` or `dockerfileContent` must be set. If
only `imageRef` is provided, the build VM pulls that image and
rsyncs its rootfs over the VM's `/`. If `dockerfileContent` is
provided, the build VM writes it verbatim to
`/tmp/buildctx/Dockerfile` and runs `buildah bud`.
name (string) — Optional human-readable name for the resulting snapshot. If
omitted, the build ID is used.
imageRef (string) — Docker 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.
dockerfileContent (string) — Raw 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.
machineType (MachineType)diskGiB (integer) — Disk size for the build VM. Defaults to 10 GiB if omitted.
contextDownloadUrl (string) — Presigned 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`.
BuildResponse
Build state snapshot. Returned by `POST /v1/builds` (initial
`pending` state) and `GET /v1/builds/{id}` (current state on
each poll).
id (string, required) — Build ID (UUID). Use this to poll status.name (string)status (string, required) — Current 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.
snapshotId (string) — Set when `status` is `completed`. Fetch the corresponding
Snapshot record via `GET /v1/snapshots/{id}`.
imageRef (string, required)progress (string) — Human-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.
error (string) — Set when `status` is `failed`. Diagnostic from the worker
(truncated to ~4 KiB).
createdAt (string, required)
Metadata
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
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.
ExecVMRequest
command (string[], required) — Argv-style command. First element must be non-empty. For shell
strings, wrap as `["sh", "-c", "<string>"]`.
timeoutSec (integer) — Server-side execution timeout in seconds. Must be positive when
provided; omit to use the server default.
stdin (string) — Optional base64-encoded stdin blob, written to the child's stdin
before the process starts reading much and then closed. Streaming
stdin is not supported — pipe from a file inside the guest if you
need that shape.
ExecEvent
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.
t ("o" | "e" | "x", required) — Event type: `o` = stdout chunk, `e` = stderr chunk, `x` = terminal
exit event.
d (string) — For `o`/`e`: base64-encoded raw bytes of the chunk. For `x`:
optional diagnostic string (e.g. spawn failure) when non-empty.
c (integer) — Exit code. Present on `x` events only.to (boolean) — True if the command was killed by the timeout. `x` events only.ms (integer) — Guest-reported duration in milliseconds. `x` events only.
ExecVMResponse
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.
exitCode (integer, required)stdout (string, required)stderr (string, required)timedOut (boolean, required)stdoutTruncated (boolean, required) — True if the collector dropped stdout bytes past the 4 MiB cap.stderrTruncated (boolean, required) — True if the collector dropped stderr bytes past the 4 MiB cap.durationMs (integer, required)
FilePresignRequest
path (string, required) — Absolute 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.
FilePresignResponse
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.
uploadUrl (string, required) — Presigned 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.
downloadUrl (string, required) — Presigned 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.
expiresInSec (integer, required) — Lifetime of both URLs in seconds.maxUploadBytes (integer, required) — Upper bound on upload size (equals the VM's disk size in bytes).
FileFetchRequest
url (string, required) — Must be the `downloadUrl` previously returned by
`POST /v1/vms/{id}/files/presign` (URLs from other sources are
rejected).
path (string, required) — Absolute destination path inside the guest filesystem.timeoutSec (integer) — Per-fetch timeout in seconds.
ConsoleTokenResponse
token (string, required)expiresInSec (integer, required)websocketPath (string, required) — Relative WebSocket path; combine with your API host as
`wss://<host><websocketPath>?session=<token>`.
SshKey
name (string) — Optional human label.publicKey (string, required) — OpenSSH-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`).
fingerprint (string, required) — OpenSSH 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`.
createdAt (string, required)
SshKeyListResponse
keys (SshKey[], required)
AddSshKeyRequest
name (string) — Optional human label.publicKey (string, required) — OpenSSH-format public key (`ssh-ed25519 AAA...`). Comments are
stripped. Newlines are rejected.
OrgQuotaValues
vcpu (integer, required)memoryMiB (integer, required)diskGiB (integer, required)snapshotCount (integer, required)
OrgQuotaUsage
orgId (string, required)limits (OrgQuotaValues, required)usage (OrgQuotaValues, required)
Service
name (string, required) — Service name (1–29 chars). Embedded in the public URL as
`<name>--<vmIdHexNoHyphens>.proxy.<stack-domain>`.
port (integer, required) — TCP port the service listens on inside the VM. Privileged
ports (<1024) are rejected.
h2c (boolean, required) — When 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.
RegisterServiceRequest
name (string, required)port (integer, required)h2c (boolean) — Optional. When true, the proxy uses HTTP/2 cleartext to the
backend (required for gRPC). Defaults to false (HTTP/1.1).
UpdateServiceRequest
port (integer, required) — New TCP port. Same value as the existing entry is a no-op.h2c (boolean) — Optional. 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.