# Snapshots and tiers

> Push a stopped machine to the snapshot store as a warm or cold snapshot, follow it to ready, list and delete snapshots one at a time or in bulk, and how long stops move down the tiers.

A **snapshot** stores a stopped machine in the deployment's snapshot store, so it can later be [restored as a new machine](/docs/guides/fork-and-restore) on any host. Taking a snapshot never changes the machine: it stays stopped, with the same ID, and you can start it as usual.

> [!NOTE]
> Use the **Snapshots** tab of a machine in the console, `vy snapshot` and `vy snapshots`, the SDKs, or the HTTP API below. Owners, Admins, and Operators take, restore, and delete snapshots; every member can list them.

## Tiers

| Tier | What is kept | A restore… |
| --- | --- | --- |
| `warm` (default) | Memory, device state, and disk | resumes the processes that were running when the machine stopped |
| `cold` | The disk | boots fresh from the disk |

Cold snapshots are smaller to keep. They need a KVM machine; Cloud Hypervisor hosts support warm snapshots only. Docker development hosts pause a stopped machine in place and cannot push it at all, and networked VMs cannot be pushed.

## Take a snapshot

The machine must be requested **and** observed stopped. Stop it and wait for the stop to succeed first; otherwise the push answers `409 machine_not_stopped`.

```sh
curl -X POST "$VMYARD_API_URL/v1/machines/$MACHINE_ID/snapshots" \
  -H "Authorization: Bearer $VMYARD_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"tier": "warm"}'
```

The answer is `202` with `snapshot_id`, `operation_id`, `machine_id`, `operation_url`, and `snapshot_url`. A push is a durable [operation](/docs/concepts/operations): retry with the same `Idempotency-Key` and body to replay it, never to push twice.

The snapshot is `pending` until its operation settles it:

- `ready`, with `manifest`, `generation` (counting up per machine), `parent_manifest`, `size_bytes`, `uploaded_bytes`, `disk_synced`, and `completed_at`; or
- `failed`, with `error_code`. A push whose outcome stays uncertain through five attempts fails with `snapshot_outcome_unknown`; the machine is unchanged, so take a new snapshot.

```sh
curl "$VMYARD_API_URL/v1/snapshots/$SNAPSHOT_ID" \
  -H "Authorization: Bearer $VMYARD_API_KEY"
```

A successful push emits the [`snapshot.ready` webhook](/docs/guides/webhooks); a failed one emits `operation.failed`.

A machine keeps at most **20** snapshots you took (`409 snapshot_limit_reached`); delete one to take another.

## List and delete

`GET /v1/machines/{machine_id}/snapshots` lists a machine's snapshots, newest first, in cursor pages. [Templates](/docs/guides/templates) are not included. Each snapshot has a `source`: `api` (one you took), `tier_policy` (a long stop, below), or `automatic` (a capture of the running machine, see [Automatic snapshots](/docs/guides/automatic-snapshots)). The console's **Snapshots** tab filters by source.

```sh
curl -X DELETE "$VMYARD_API_URL/v1/snapshots/$SNAPSHOT_ID" \
  -H "Authorization: Bearer $VMYARD_API_KEY"
```

Deleting answers `204`. The snapshot disappears from VMYard and can no longer be restored; machines already restored from it are not affected. A push that hasn't settled can't be deleted yet (`409 snapshot_pending`).

## Delete several snapshots

Delete up to **100** snapshots by ID in one request (`422` for none or more than 100; duplicates are reported once):

```sh
curl -X POST "$VMYARD_API_URL/v1/snapshots/bulk-delete" \
  -H "Authorization: Bearer $VMYARD_API_KEY" \
  -H "Content-Type: application/json" \
  -d "{\"snapshot_ids\": [\"$SNAPSHOT_A\", \"$SNAPSHOT_B\"]}"
```

Or delete all of a machine's snapshots, or only one source's with `?source=api`, `tier_policy`, or `automatic`:

```sh
curl -X DELETE "$VMYARD_API_URL/v1/machines/$MACHINE_ID/snapshots" \
  -H "Authorization: Bearer $VMYARD_API_KEY"
```

Both answer `200` with a result for every snapshot, in request order (a machine's snapshots oldest first), even when some were not deleted:

```json
{
  "deleted": 2,
  "results": [
    { "snapshot_id": "…", "result": "deleted" },
    { "snapshot_id": "…", "result": "pending" },
    { "snapshot_id": "…", "result": "template" }
  ]
}
```

| `result` | Meaning |
| --- | --- |
| `deleted` | Deleted. |
| `not_found` | Unknown, already deleted, or another organization's. |
| `pending` | Kept: its push is still running. Delete it once it settles. |
| `template` | Kept: templates are deleted only through `DELETE /v1/templates/{template}`, so deleting all of a machine's snapshots reports its templates as kept. |

In the console, select snapshots on the **Snapshots** tab and choose **Delete selected**, or use **Delete automatic** and **Delete all**; each asks for confirmation and then lists every result. Owners, Admins, and Operators can delete.

## Stopped machines move down the tiers

Stopping a machine on a KVM host keeps a **hot** copy on that host: memory, device state, and disk, so `start` wakes it with its processes intact. On top of that, a background policy in the control plane pushes long stops to the snapshot store:

| Stopped for | VMYard pushes | Kept in the store |
| --- | --- | --- |
| 6 hours | a `warm` snapshot | memory, device state, disk |
| 7 days | a `cold` snapshot | the disk |

These are the defaults; operators of a deployment can change either threshold or turn the policy off. Policy snapshots have `source: "tier_policy"`, are requested at most once per stop and only while the machine is still in that stop, don't count toward the 20-snapshot limit, and replace the machine's earlier policy snapshots once ready. Only KVM machines qualify.

A policy push makes a stopped machine restorable on any host and protects it if its host is lost. It does not free the host: `start` still wakes the hot copy. [Idle sleep](/docs/concepts/idle-sleep), when you turn it on, stops a running machine that does nothing; VMYard does not yet wake a machine when a request arrives. See [Sleep and wake](/docs/concepts/sleep-and-wake).
