Snapshots

The golden-snapshot catalog: registering immutable versions, sharing, and deleting golden lineages. See Goldens and imports for the deeper mechanics and the exact 409 wording this page documents from the code.

Registering a version directly (POST /v1/snapshots/versions) is a lower-level primitive than adj import run — the import pipeline (see Sources & imports) calls it internally after a successful dump. Most admins never call it directly.

POST /v1/snapshots/versions — register a snapshot version

Auth: admin.

Request body

Field Type Required Notes
name string yes The golden lineage name (created on first use).
substrate string yes e.g. "postgres". Must match the substrate of any existing version of the same name.
source_ref string no Free-form provenance note.
vsc_handle string yes The volume-snapshot-controller handle the data-plane operator clones from.
size_bytes integer no Reported size, for adj org usage / adj catalog ls display.
$ curl -s https://api.stagdb.com/v1/snapshots/versions -X POST -H "Authorization: Bearer $TOKEN" \
    -H 'Content-Type: application/json' \
    -d '{"name":"prod-pg16","substrate":"postgres","vsc_handle":"vsc-prod-pg16-v3","size_bytes":45097156608}'

Response 201 Created

{"snapshot_id": "5f2a9c11-3d7e-4b8a-9c1d-2e3f4a5b6c7d", "version": 3}

version is the next sequential integer for this lineage (1 on first registration). Versions are immutable — nothing in this API ever mutates an existing version's data.

Status When
400 name empty or substrate invalid — wire body is the generic {"error": "invalid input"}.
403 Caller is not an admin.
409 substrate doesn't match the existing lineage's substrate — wire body is the generic {"error": "conflict"}.

GET /v1/snapshots — list visible goldens

Auth: bearer.

$ curl -s https://api.stagdb.com/v1/snapshots -H "Authorization: Bearer $TOKEN"

Response 200 OK

{
  "snapshots": [
    {
      "id": "5f2a9c11-3d7e-4b8a-9c1d-2e3f4a5b6c7d",
      "name": "prod-pg16",
      "substrate": "postgres",
      "share_scope": "org",
      "latest_version": 3,
      "created_at": "2026-06-10T08:00:00Z"
    }
  ]
}

share_scope is "admin" (visible only to admins) or "org" (shared, visible to everyone). Non-admin callers only ever see "org"-scoped goldens — admin-private ones are filtered out of this response entirely for them, not just hidden in the UI. latest_version is the newest ready version (0 if none yet).

Status When
401 Missing/invalid/expired bearer token.

POST /v1/snapshots/{id}/share — set sharing

Auth: admin.

Request body

Field Type Required
shared boolean yes
$ curl -s https://api.stagdb.com/v1/snapshots/5f2a9c11-3d7e-4b8a-9c1d-2e3f4a5b6c7d/share -X POST \
    -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' -d '{"shared":true}'

shared: true moves the golden to share_scope: "org" (visible to developers); shared: false reverts it to "admin". Existing clones are unaffected either way — sharing only changes future visibility.

Response: 204 No Content.

Status When
400 {id} not a valid UUID.
403 Caller is not an admin.
404 No snapshot with that id in this org.

DELETE /v1/snapshots/{id} — delete a golden

Auth: admin.

Query parameter

Param Notes
force ?force=true cascades the delete through live child instances. Omit (or any other value) for the safe, blocked-by-default behavior.

Without ?force=true — blocked if clones exist

$ curl -s https://api.stagdb.com/v1/snapshots/5f2a9c11-3d7e-4b8a-9c1d-2e3f4a5b6c7d -X DELETE \
    -H "Authorization: Bearer $TOKEN"

If live instances were cloned from this golden, the delete is refused:

{
  "error": "golden has live child instances; re-run with --force",
  "children": [
    {"id": "7a1e9c3d-5b2f-4c8a-9d0e-2f3a4b5c6d7e", "owner": "3e6f0a2b-7c8d-4e1f-9a2b-3c4d5e6f7a8b", "phase": "Ready"}
  ]
}

children lists every live clone as {id, owner, phase} so the caller (the CLI prints this as a table) knows exactly what --force would destroy. Nothing is deleted in this response — the golden and its clones are untouched. 409 Conflict.

With ?force=true — cascades clones, never import history

$ curl -s "https://api.stagdb.com/v1/snapshots/5f2a9c11-3d7e-4b8a-9c1d-2e3f4a5b6c7d?force=true" -X DELETE \
    -H "Authorization: Bearer $TOKEN" -o /dev/null -w '%{http_code}\n'
202

force=true destroys the golden and every live clone of it, asynchronously. One thing it never cascades: import history. If the golden lineage was built by adj import run (or has a clone pool pinning it), the delete is refused outright — --force does not bypass this, because it's a foreign-key restrict, not a live-children check:

{"error": "golden is still referenced by an import record or clone pool"}

409 Conflict. This is a different 409 from the live-children one above — same status code, different body, different meaning. Remove the pool first (DELETE /v1/pools/{id}) if that's what's blocking it; an import record blocking it means the lineage is meant to stay, and per-version delete isn't exposed by this API.

Response on success: 202 Accepted, empty body — the CR delete and clone teardown proceed asynchronously on the data plane.

Status When
400 {id} not a valid UUID.
403 Caller is not an admin.
404 No snapshot with that id in this org.
409 Live child instances exist and force was not true (body includes children); or force=true was passed but an import record or clone pool still references the golden ("golden is still referenced by an import record or clone pool" — never bypassed by force).

Next