Skip to content
Fuse
Esc
↑↓navigate↵open⌘Jpreview

Snapshot a running VM

Checkpoints a running VM into a new snapshot. Creation is synchronous; the 201 body is the persisted record, already in state ready, with parent_snapshot_id pointing at the VM’s previous ready snapshot. mode defaults to manual.

live: false (the default, and the value of an omitted body) copies the rootfs and nothing else, so restoring cold-boots the guest. live: true additionally captures the guest’s memory and vCPU state inside a single pause window, so restoring resumes the guest where it stopped. It costs the environment’s full configured memory in bytes on every create, pauses the guest for the length of the capture, and produces an artifact pinned to the host that took it.

The response’s kind is what was actually written, not what was requested. A host running an agent too old to know about live snapshots answers live: true with a disk snapshot and the record says disk, so a caller that depends on the memory being present must read kind rather than assume the request was honoured.

Preconditions are reported as 4xx, not 5xx:

  • 404 not_found — unknown VM.
  • 409 conflict — the VM is not running (e.g. draining), the per-tenant snapshot quota (count or bytes) is exhausted, or the VM holds a GPU passthrough device. A vfio device cannot be checkpointed, so GPU environments can never be snapshotted; this is permanent and must not be retried. A GPU VM asking for live: true gets this same 409 and the same GPU-specific message, not the 501 below: the device is what cannot be checkpointed, so dropping live will not help.
  • 501 unimplemented — the provider has no snapshot support (e.g. the in-memory stub), or live: true was requested against a provider that supports disk snapshots but not live ones. The latter is not a conflict: nothing about the VM’s state is wrong and retrying it unchanged can never succeed, but the same call without live will, and the message says so. Only Firecracker hosts running an agent new enough to capture memory implement it.

Byte quotas were calibrated against rootfs-only snapshots, so a workload that switches to live: true reaches the 409 quota case far sooner than its snapshot count suggests.

A lifecycle hitl gate matching snapshot can hold the create (202) or deny it (403 hitl_denied). A held create runs on approval and the intervention’s result.snapshot_id names the snapshot.

POST/v1/environments/{vmId}/snapshots
Authorization
AuthorizationBearer token · headerrequired
`Authorization: Bearer <token>` — either the static master token (`ORCH_AUTH_TOKEN`) or a revocable API key issued via /v1/api-keys (API keys require Postgres; without a database only the master token is accepted). Master-only surfaces (exec, attach, API key management) refuse API keys with 403. An expired key is refused with 401 like an unknown one. A key minted with `scopes` reaches only the hitl routes (`/v1/interventions`, `/v1/hitl/*`, and POST /v1/api-keys to mint a narrower key). Any other route is 403 code `forbidden`, reason `env_scope`, except an `/v1/environments/{vmId}` route for an environment the key does not cover, which is 404 so the key cannot probe which environments exist. **Authentication can be disabled entirely.** When neither `ORCH_AUTH_TOKEN` nor an API key store (`DATABASE_URL`) is configured — the default local-development posture — the bearer middleware becomes a pass-through: every operation this document marks as secured is reachable with no credentials, requests carry no principal, and master-only surfaces therefore admit everyone. Never run that configuration on a reachable network; set `ORCH_REQUIRE_AUTH=true` to make the orchestrator refuse to start without a master token.
or
fuse_sessionAPI key · cookierequired
HttpOnly session cookie set by POST /login for browser callers. Consulted only when no Authorization header is present.
Path parameters
vmIdstringrequired
VM identifier assigned by the orchestrator.
Request body
application/json
commentstring
Free-form note attached to the snapshot.
modestring
Defaults to "manual" when omitted. Values outside this set are not rejected by the server.
Allowed:manualauto
retention_secondsinteger<int64>
Seconds from now until the snapshot is eligible for garbage collection. Omitted or 0 falls back to the server's default retention if configured; otherwise the snapshot is kept until deleted.
metadataobject
layer_keystring
Labels this snapshot as the artifact of one cacheable setup step, so a later build can find it by recipe instead of by id. Set by `fuse build`; every other caller omits it. A layer is still an ordinary build-mode snapshot; the key is the only thing that distinguishes it.
liveboolean
Capture the guest's memory and vCPU state alongside the rootfs, so restoring resumes the guest instead of cold-booting it. Omitted or false takes a disk-only snapshot, which is the default everywhere. A live snapshot costs the environment's full configured memory in bytes on top of the rootfs, on every create, and pauses the guest for the length of the capture. The resulting artifact is pinned to the host that took it: a memory image depends on that host's CPU model and Firecracker version. Fork reads only a snapshot's rootfs, so forking a live snapshot silently yields a cold-booting environment. Asking for it on a provider without live-snapshot support is a 501, not a 409. Check the response's `kind` rather than assuming this flag was honoured.
default: false
export_refstring
export_statusstring
Defaults to "pending" when omitted. Values outside this set are not rejected by the server.
Allowed:pendingreadyerror
Responses
201Snapshot created (already in state `ready`).
idstringrequired
vm_idstringrequired
task_idstring
tenant_idstring
parent_snapshot_idstring
modestring
Normally "manual" or "auto". Not an enum: the server stores the caller-supplied `mode` verbatim (only an empty value is defaulted to "manual"), so an arbitrary string can appear here. Treat unknown values as opaque rather than rejecting the response.
statestring
Allowed:creatingreadyrestoringdeletingerror
commentstring
layer_keystring
Derived cache key of the setup step this artifact materializes. Absent on any snapshot that is not a build layer.
archstring
Architecture of the host that built the artifact, not of whoever asked for it. An ext4 rootfs does not travel across architectures, so this is what says whether these bytes are bootable for you.
Allowed:amd64arm64
digeststring
Hex sha256 of the artifact rootfs, for verifying a transfer of these exact bytes. It is not an identity two artifacts can share: rebuilding the same recipe produces different bytes, so nothing is looked up by digest. Absent when the host agent does not hash. The exception is the live snapshot a migrate takes in its final pause on an xfs or btrfs host: its rootfs is never read whole there, so its digest is a sha256 of its per-block hash table instead.
kindstring
What this artifact actually contains. "disk" is the rootfs and nothing else, so restoring it cold-boots the guest; "live" additionally carries the vCPU state and the whole guest memory, so restoring it resumes the guest where it stopped. This is what the host agent reports it wrote, never what the caller requested: a `live: true` create served by an agent that could only take a disk snapshot reads back as "disk". Branch on this rather than on your own request. Always present, on every read path. Records written before live snapshots existed read back as "disk".
default: "disk"
Allowed:disklive
size_bytesinteger<int64>
created_atstring<date-time>required
updated_atstring<date-time>
retention_untilstring<date-time> | null
When the snapshot becomes eligible for garbage collection; null/absent when it is kept until deleted.
last_errorstring
export_refstring
exportsSnapshotExport[]
Show properties
Array of SnapshotExport
destinationstringrequired
statusstring
Normally "pending", "ready", or "error". Not an enum: the create handler stores the caller-supplied `export_status` verbatim (only an empty value is defaulted to "pending"), so an arbitrary string can appear here. Treat unknown values as opaque rather than rejecting the response.
requested_atstring<date-time>
updated_atstring<date-time>
last_errorstring
202A hitl gate holds the action. Nothing ran yet. The body is a HeldResponse naming the pending intervention, and `Location` points at it. Wait on it with GET /v1/interventions/{interventionId}?wait=; once approved the orchestrator performs the action and stores the outcome in the intervention's `result`.
intervention_idstringrequired
interventionInterventionrequired
Show properties
idstringrequired
env_idstringrequired
kindstringrequired
Allowed:asksecrettakeoverreviewexeclifecyclecomputerstallexpiry
gatestring
The gate that raised it. Empty for a request.
modestring
The gate's mode. Notify and deny records are born terminal.
Allowed:asknotifydeny
statestringrequired
Allowed:pendingapprovedrejectedexpiredcancelled
payloadobjectrequired
What was asked or attempted: `question` for an ask, `secret`, `takeover` or `review` for those requests, `exec`, `lifecycle` or `computer` for a gate, `signal` for a stall or expiry. `decider` is set when a gate's decider sent the action on to a human.
Show properties
questionstring
choicesstring[]
execExecPayload
A held exec.
Show properties
argvstring[]required
shellstring
The script when the caller sent `shell`; argv is then the sh -lc that runs it.
timeout_msinteger<int64>
lifecycleLifecyclePayload
A held environment action.
Show properties
actionstringrequired
Allowed:destroyforkmigratedrainsnapshotrotate-token
secretInterventionSecret
A secret request. It never holds the value.
Show properties
targetstringrequired
The declared target's `env` name or `file` path.
labelstringrequired
The target's label from the policy. Show it first: the agent writes `message`, so `message` alone could claim to be anything.
messagestring
The agent's own text.
takeoverInterventionTakeover
A takeover. `holder` and `started_at` are set while a human holds the environment, which is also when the agent's exec and computer calls get 423. The intervention stays `pending` until release.
Show properties
viastringrequired
Allowed:terminaldesktop
reasonstring
holderActor
Show properties
idstringrequired
A pinned or asserted actor id, `key:<key_id>`, `master`, `system` for fuse itself, or `decider:<gate>`.
namestring
sourcestringrequired
`pinned`: fixed on the key at mint time. `asserted`: named in `Fuse-Actor` by a `hitl:act-as` key or the master token, and only as true as that caller's own auth. `key`: derived from the credential. `system`: expiry and cancellation. `decider`: a gate's decider allowed or denied the action; the id is `decider:<gate>`.
Allowed:pinnedassertedkeysystemdecider
key_idstring
The key that authenticated the request, including the key that asserted an actor. Omitted for the master token.
started_atstring<date-time>
signalInterventionSignal
What fuse saw when it raised a stall or expiry. A stall carries `failures` and `last_exit_code`, or `quiet_seconds`. An expiry carries `reaper` and `reap_at`, and once approved `extended_until`.
Show properties
failuresinteger
The run of consecutive non-zero exec exits.
last_exit_codeinteger
The exit code that completed the run.
quiet_secondsinteger<int64>
How long the agent had made no exec or computer call.
reaperstring
What will tear the environment down.
Allowed:idle_timeoutmax_runtime
reap_atstring<date-time>
When. The expiry's own deadline is capped at this, with a 10s floor.
extended_untilstring<date-time>
Set on approval. The reapers leave the environment alone until then.
computerComputerPayload
A held computer action. On approval the orchestrator replays `input` to the guest, with the approver's `edited_text` in place of `text` when there is one.
Show properties
actionstringrequired
The computer action name.
textstring
The text of a `type` (or the keys of a `key`), as sent.
inputobjectrequired
The whole action body as the caller sent it (a ComputerActionRequest).
reviewInterventionReview
A review request. When `path` is set, `content` is that file as fuse read it at request time, so the human reviews what the agent submitted even if the file changed afterwards.
Show properties
pathstring
contentstringrequired
formatstringrequired
Allowed:textdiff
messagestring
The agent's note to the reviewer.
truncatedboolean
Set when the file was longer than 1 MiB and was cut off.
deciderInterventionDecider
What a gate's decider said about an action it sent on to a human: `verdict` `ask` with its `reason`, or the `error` that made fuse fall through to a human.
Show properties
verdictstringrequired
Allowed:ask
reasonstring
errorstring
Set when the decider call failed.
triggered_byActorrequired
Show properties
idstringrequired
A pinned or asserted actor id, `key:<key_id>`, `master`, `system` for fuse itself, or `decider:<gate>`.
namestring
sourcestringrequired
`pinned`: fixed on the key at mint time. `asserted`: named in `Fuse-Actor` by a `hitl:act-as` key or the master token, and only as true as that caller's own auth. `key`: derived from the credential. `system`: expiry and cancellation. `decider`: a gate's decider allowed or denied the action; the id is `decider:<gate>`.
Allowed:pinnedassertedkeysystemdecider
key_idstring
The key that authenticated the request, including the key that asserted an actor. Omitted for the master token.
deadlinestring<date-time>required
on_timeoutstringrequired
Allowed:rejectallow
decisionobject
Present once terminal. An expired intervention carries the on_timeout outcome and a cancelled one a reject, both decided by "system".
Show properties
outcomestringrequired
Allowed:approvereject
answerstring
reasonstring
decided_byActorrequired
Show properties
idstringrequired
A pinned or asserted actor id, `key:<key_id>`, `master`, `system` for fuse itself, or `decider:<gate>`.
namestring
sourcestringrequired
`pinned`: fixed on the key at mint time. `asserted`: named in `Fuse-Actor` by a `hitl:act-as` key or the master token, and only as true as that caller's own auth. `key`: derived from the credential. `system`: expiry and cancellation. `decider`: a gate's decider allowed or denied the action; the id is `decider:<gate>`.
Allowed:pinnedassertedkeysystemdecider
key_idstring
The key that authenticated the request, including the key that asserted an actor. Omitted for the master token.
decided_atstring<date-time>required
edited_argvstring[]
The argv the approver replaced a held exec's with.
edited_textstring
The text the approver replaced a held `type` action's with.
grantstring
How far an approval of a gated action reaches.
resultInterventionResult
What performing an approved gated action produced.
Show properties
execExecEnvironmentResponse
The outcome of a guest command. A non-zero `exit_code` arrives with **HTTP 200**: the command ran and failed, which is a successful answer to the question the caller asked. It is not an error and must not be raised by an SDK. HTTP errors mean the command could not be run at all. `stdout` and `stderr` are kept apart, and are plain strings rather than base64 — exec output is overwhelmingly text, and encoding it would make every caller pay a decoding tax for the rare binary case.
Show properties
exit_codeintegerrequired
The guest command's own exit status. Non-zero is a normal result, delivered with HTTP 200.
stdoutstringrequired
stderrstringrequired
computerComputerActionResponse
The guest's answer to one action.
Show properties
outputstring
Textual output, e.g. the pointer location for `cursor_position`.
screenshotstring
Base64 PNG of the display after the action settled. Present on every action that implies one; for `zoom` it is the cropped region at full resolution.
env_idstring
The environment a fork or migrate produced.
snapshot_idstring
The snapshot a snapshot action produced.
errorstring
Set when the approved action could not be performed. A non-zero exec exit code is a result in `exec`, not an error.
finished_atstring<date-time>required
created_atstring<date-time>required
updated_atstring<date-time>required
400Malformed request.
errorobjectrequired
Show properties
codestringrequired
Stable machine-readable code. `route_not_found` (404) means the URL matches no route this server exposes — usually a wrong host, port, or path prefix — as opposed to `not_found`, where the route exists but the resource does not. `forbidden` is emitted by CIDR-allowlist rejections and by hitl access checks, which set `details.reason` (see the Forbidden response); master-only refusals (exec, attach, listing and revoking API keys) return 403 with code `unauthorized`.
Allowed:not_foundroute_not_foundconflictinvalid_argumentunauthorizedforbiddenunavailableinternalunimplementedlocked
messagestringrequired
Human-readable description.
detailsobject
Optional stable, non-sensitive metadata (e.g. ids, counts). Omitted when empty. A 403 `forbidden` from a hitl access check carries `reason` (`missing_scope`, `env_scope`, `self_approval`, `actor_required`, `actor_mismatch`, `actor_not_allowed`, `mint_escalation`, `hitl_denied`), plus `scope` for `missing_scope`, and `gate` and `intervention_id` for `hitl_denied`. A 423 `locked` carries `intervention_id` and `kind` (`takeover` or `stall`).
403A hitl gate in `deny` mode refused the action (code `forbidden`, `details.reason` `hitl_denied`, `details.gate` the gate's name, `details.intervention_id` the terminal record; the message is the gate's `reason`), or the caller may not use the route.
errorobjectrequired
Show properties
codestringrequired
Stable machine-readable code. `route_not_found` (404) means the URL matches no route this server exposes — usually a wrong host, port, or path prefix — as opposed to `not_found`, where the route exists but the resource does not. `forbidden` is emitted by CIDR-allowlist rejections and by hitl access checks, which set `details.reason` (see the Forbidden response); master-only refusals (exec, attach, listing and revoking API keys) return 403 with code `unauthorized`.
Allowed:not_foundroute_not_foundconflictinvalid_argumentunauthorizedforbiddenunavailableinternalunimplementedlocked
messagestringrequired
Human-readable description.
detailsobject
Optional stable, non-sensitive metadata (e.g. ids, counts). Omitted when empty. A 403 `forbidden` from a hitl access check carries `reason` (`missing_scope`, `env_scope`, `self_approval`, `actor_required`, `actor_mismatch`, `actor_not_allowed`, `mint_escalation`, `hitl_denied`), plus `scope` for `missing_scope`, and `gate` and `intervention_id` for `hitl_denied`. A 423 `locked` carries `intervention_id` and `kind` (`takeover` or `stall`).
404Resource does not exist. Note the distinct code `route_not_found`, returned when the URL matches no registered route at all (wrong host, port, or path prefix) rather than a known route with a missing resource.
errorobjectrequired
Show properties
codestringrequired
Stable machine-readable code. `route_not_found` (404) means the URL matches no route this server exposes — usually a wrong host, port, or path prefix — as opposed to `not_found`, where the route exists but the resource does not. `forbidden` is emitted by CIDR-allowlist rejections and by hitl access checks, which set `details.reason` (see the Forbidden response); master-only refusals (exec, attach, listing and revoking API keys) return 403 with code `unauthorized`.
Allowed:not_foundroute_not_foundconflictinvalid_argumentunauthorizedforbiddenunavailableinternalunimplementedlocked
messagestringrequired
Human-readable description.
detailsobject
Optional stable, non-sensitive metadata (e.g. ids, counts). Omitted when empty. A 403 `forbidden` from a hitl access check carries `reason` (`missing_scope`, `env_scope`, `self_approval`, `actor_required`, `actor_mismatch`, `actor_not_allowed`, `mint_escalation`, `hitl_denied`), plus `scope` for `missing_scope`, and `gate` and `intervention_id` for `hitl_denied`. A 423 `locked` carries `intervention_id` and `kind` (`takeover` or `stall`).
409The VM is not running, the per-tenant snapshot quota (count or bytes) is exhausted, or the VM holds a GPU passthrough device. The GPU case is reported here for `live: true` as well as for a plain disk snapshot.
errorobjectrequired
Show properties
codestringrequired
Stable machine-readable code. `route_not_found` (404) means the URL matches no route this server exposes — usually a wrong host, port, or path prefix — as opposed to `not_found`, where the route exists but the resource does not. `forbidden` is emitted by CIDR-allowlist rejections and by hitl access checks, which set `details.reason` (see the Forbidden response); master-only refusals (exec, attach, listing and revoking API keys) return 403 with code `unauthorized`.
Allowed:not_foundroute_not_foundconflictinvalid_argumentunauthorizedforbiddenunavailableinternalunimplementedlocked
messagestringrequired
Human-readable description.
detailsobject
Optional stable, non-sensitive metadata (e.g. ids, counts). Omitted when empty. A 403 `forbidden` from a hitl access check carries `reason` (`missing_scope`, `env_scope`, `self_approval`, `actor_required`, `actor_mismatch`, `actor_not_allowed`, `mint_escalation`, `hitl_denied`), plus `scope` for `missing_scope`, and `gate` and `intervention_id` for `hitl_denied`. A 423 `locked` carries `intervention_id` and `kind` (`takeover` or `stall`).
500Unexpected server error.
errorobjectrequired
Show properties
codestringrequired
Stable machine-readable code. `route_not_found` (404) means the URL matches no route this server exposes — usually a wrong host, port, or path prefix — as opposed to `not_found`, where the route exists but the resource does not. `forbidden` is emitted by CIDR-allowlist rejections and by hitl access checks, which set `details.reason` (see the Forbidden response); master-only refusals (exec, attach, listing and revoking API keys) return 403 with code `unauthorized`.
Allowed:not_foundroute_not_foundconflictinvalid_argumentunauthorizedforbiddenunavailableinternalunimplementedlocked
messagestringrequired
Human-readable description.
detailsobject
Optional stable, non-sensitive metadata (e.g. ids, counts). Omitted when empty. A 403 `forbidden` from a hitl access check carries `reason` (`missing_scope`, `env_scope`, `self_approval`, `actor_required`, `actor_mismatch`, `actor_not_allowed`, `mint_escalation`, `hitl_denied`), plus `scope` for `missing_scope`, and `gate` and `intervention_id` for `hitl_denied`. A 423 `locked` carries `intervention_id` and `kind` (`takeover` or `stall`).
501The provider has no snapshot support at all, or `live: true` was asked of a provider that can take disk snapshots but not live ones. In the second case the message says to retry without `live` for a disk snapshot.
errorobjectrequired
Show properties
codestringrequired
Stable machine-readable code. `route_not_found` (404) means the URL matches no route this server exposes — usually a wrong host, port, or path prefix — as opposed to `not_found`, where the route exists but the resource does not. `forbidden` is emitted by CIDR-allowlist rejections and by hitl access checks, which set `details.reason` (see the Forbidden response); master-only refusals (exec, attach, listing and revoking API keys) return 403 with code `unauthorized`.
Allowed:not_foundroute_not_foundconflictinvalid_argumentunauthorizedforbiddenunavailableinternalunimplementedlocked
messagestringrequired
Human-readable description.
detailsobject
Optional stable, non-sensitive metadata (e.g. ids, counts). Omitted when empty. A 403 `forbidden` from a hitl access check carries `reason` (`missing_scope`, `env_scope`, `self_approval`, `actor_required`, `actor_mismatch`, `actor_not_allowed`, `mint_escalation`, `hitl_denied`), plus `scope` for `missing_scope`, and `gate` and `intervention_id` for `hitl_denied`. A 423 `locked` carries `intervention_id` and `kind` (`takeover` or `stall`).
Request
curl -X POST "http://localhost:8080/v1/environments/string/snapshots" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "comment": "string",
  "mode": "manual",
  "retention_seconds": 0,
  "metadata": {},
  "layer_key": "string",
  "live": false,
  "export_ref": "string",
  "export_status": "pending"
}'
Response
{
  "id": "string",
  "vm_id": "string",
  "task_id": "string",
  "tenant_id": "string",
  "parent_snapshot_id": "string",
  "mode": "manual",
  "state": "creating",
  "comment": "string",
  "layer_key": "string",
  "arch": "amd64",
  "digest": "string",
  "kind": "disk",
  "size_bytes": 0,
  "created_at": "2024-01-01T00:00:00Z",
  "updated_at": "2024-01-01T00:00:00Z",
  "retention_until": "2024-01-01T00:00:00Z",
  "last_error": "string",
  "export_ref": "string",
  "exports": [
    {
      "destination": "string",
      "status": "pending",
      "requested_at": "2024-01-01T00:00:00Z",
      "updated_at": "2024-01-01T00:00:00Z",
      "last_error": "string"
    }
  ]
}