Images
- "is precached?" ?ref=ubuntu:22.04 → the image + per-layer hit/miss
- "what's cached?" (no ref) → a paginated list of cached ref-manifests
The API has no NFS mount (control-plane / runner split), so the scan runs on
a runner over NATS request/reply (runner.<id>.cache.images). The cache is
shared across all runners' NFS, so ANY live runner yields the same answer; we
try live runners in turn until one replies. This is deliberately NOT scoped
to the caller's project: the CAS is global infrastructure keyed by layer
diff-id. Per-project image ownership lives in GET /images, a separate plane.
AuthorizationBearer <token>Project API key (dtn_…) as a Bearer token. Mint via the management API (POST /projects/:id/api-keys) or this deployment's key-mint CLI. Every key carries an explicit set of verb:resource project permissions chosen at mint time (PLAN-API-KEY-PERMISSIONS.md); each operation lists the project permission it requires in its security requirement, and a key lacking it is answered 403 missing required project permission: <project-permission>. Some operations require an additional permission depending on the request body, stated in the operation's description. Holding a mutating verb (write:/delete:/invoke:) implies the resource's read: permission. Operations whose api_key project-permission list is empty need no specific project permission — any live project key works (the global catalogs and the artifact-cache read).
ref?stringWhen set, a single-ref precache lookup with per-layer detail (e.g. ?ref=ubuntu:22.04). Otherwise a paginated list.
limit?integerPage size for the list (clamped runner-side to [1, 500]); ignored for ref.
int64cursor?stringOpaque continuation token from a previous page's next_cursor.
Runner cache scan result (proxied runner reply, shape is runner-defined): with ref, the image + per-layer hit/miss; without, a paginated { images, next_cursor } list
response?unknownapplication/jsoncurl -X GET 'https://example.com/cache/images'nullAuthorizationBearer <token>Project API key (dtn_…) as a Bearer token. Mint via the management API (POST /projects/:id/api-keys) or this deployment's key-mint CLI. Every key carries an explicit set of verb:resource project permissions chosen at mint time (PLAN-API-KEY-PERMISSIONS.md); each operation lists the project permission it requires in its security requirement, and a key lacking it is answered 403 missing required project permission: <project-permission>. Some operations require an additional permission depending on the request body, stated in the operation's description. Holding a mutating verb (write:/delete:/invoke:) implies the resource's read: permission. Operations whose api_key project-permission list is empty need no specific project permission — any live project key works (the global catalogs and the artifact-cache read).
Scope: read:images
limit?integerint64cursor?stringname?stringsandbox_id?stringanonymous?stringplatform?stringWhich images to list: false (default) the project's own, true
the platform images (deprecated ones excluded), any both.
Images in the project and, with platform=true|any, the platform images (keyset-paginated, newest first). The anonymous backup image a v1 sandbox import registers (imported_from, no name) is never listed — it only serves the sandbox it was imported for and stays reachable by id
application/json- response
Page of images (GET /images).
images*array<>next_cursor?|Opaque keyset token for the next page; null on the last page.
curl -X GET 'https://example.com/images'{ "images": [ { "anonymous": true, "available_in": [ "string" ], "bytes": 0, "class": "string", "default": true, "deprecated": true, "error": "string", "expires_at": "2019-08-24T14:15:22Z", "format_outdated": true, "format_version": 0, "id": "string", "imported_from": { "id": "string", "platform": "string" }, "layer_count": 0, "manifest_name": "string", "name": "string", "origin": "string", "platform": true, "region": "string", "retention": "string", "source": null, "status": "string", "created_at": "2019-08-24T14:15:22Z", "cursor": "string" } ], "next_cursor": "string"}AuthorizationBearer <token>Project API key (dtn_…) as a Bearer token. Mint via the management API (POST /projects/:id/api-keys) or this deployment's key-mint CLI. Every key carries an explicit set of verb:resource project permissions chosen at mint time (PLAN-API-KEY-PERMISSIONS.md); each operation lists the project permission it requires in its security requirement, and a key lacking it is answered 403 missing required project permission: <project-permission>. Some operations require an additional permission depending on the request body, stated in the operation's description. Holding a mutating verb (write:/delete:/invoke:) implies the resource's read: permission. Operations whose api_key project-permission list is empty need no specific project permission — any live project key works (the global catalogs and the artifact-cache read).
Scope: write:images
JSON build request (registry/named source). Alternatively send multipart/form-data with fields name, optional dockerfile (path within the context), region, cpu_arch, and the file field context (a build-context tar).
- body
cpu_arch?|CPU architecture to build for — amd64 or arm64. Absent => the
region's default (PLAN-ARM64.md §2.2).
The same Dockerfile produces a different image per architecture, so this is part of the build's content key: an amd64 and an arm64 build of one Dockerfile are two builds that never adopt each other (PLAN-BUILD-DEDUPE.md). It also pins which runners may serve the build.
dockerfile?|An inline, self-contained Dockerfile body to build (no COPY/ADD of
local files — use the multipart/form-data variant to upload a real
build context). The API synthesizes the trivial single-file context for
you. Mutually exclusive with source.
idle?|Idle-retention window in seconds for an ANONYMOUS image: the image is
deleted once this long has passed without a sandbox being created from
it (every create from the image restarts the clock). Only without
name (a named image is permanent; idle with name is 400).
Accepted: omitted or -1 ⇒ the server maximum
(DAYTONA_ANON_IMAGE_MAX_IDLE, 7 days by default); 1 … max ⇒ that
window. 0, values below -1, and values above the maximum ⇒
400 IDLE_OUT_OF_RANGE (the body carries max).
int64name?string|nullregion?|Target region for the build (PLAN-REGIONS.md). Absent => resolved default. The image is homed in this region; other regions replicate it on first use.
source?null||||Build enqueued
application/json- response
Response for POST /images: the enqueued build. Field order is
alphabetical to keep the wire bytes identical to the former
serde_json::json! construction (BTreeMap key order).
image_id*stringjob_id?|The build's CURRENT attempt. For an adopted image this is the job that
already produced it, not a job this call enqueued — so it is not
evidence that a build was started. null when the image was reused
and no build job is on record for it (an anonymous registry import
whose pull job has been pruned): poll GET /images/{id} for status
instead — the image id, not a job id, is the handle to wait on.
uuidname?string|nullregion*stringHome region the image is built in (PLAN-REGIONS.md).
status*stringThe build's status. pending for a build this call enqueued, and
building when it joined one already in flight — but ready when the
image was ADOPTED from an identical build that had already finished
(PLAN-BUILD-DEDUPE.md), in which case no build runs and the image is
usable immediately. Poll GET /images (or the job) for progress.
curl -X POST 'https://example.com/images' \ -H 'Content-Type: application/json' \ -d '{}'{ "image_id": "string", "job_id": "453bd7d7-5355-4d6d-a38e-d9e7eb218c3f", "name": "string", "region": "string", "status": "string"}Mirrors GET /snapshots/{id}: a build is asynchronous, so a client that
just POSTed needs somewhere to wait. (Before
PLAN-ARTIFACT-UNIFICATION.md DP-7 the only such surface was the Daytona
alias facade, which polled the same row through a second table.)
AuthorizationBearer <token>Project API key (dtn_…) as a Bearer token. Mint via the management API (POST /projects/:id/api-keys) or this deployment's key-mint CLI. Every key carries an explicit set of verb:resource project permissions chosen at mint time (PLAN-API-KEY-PERMISSIONS.md); each operation lists the project permission it requires in its security requirement, and a key lacking it is answered 403 missing required project permission: <project-permission>. Some operations require an additional permission depending on the request body, stated in the operation's description. Holding a mutating verb (write:/delete:/invoke:) implies the resource's read: permission. Operations whose api_key project-permission list is empty need no specific project permission — any live project key works (the global catalogs and the artifact-cache read).
Scope: read:images
id*stringimage id (img_…; bare UUID also accepted during the transition)
wait?stringBlock until the image reaches this status (ready) or a terminal state
(ready/failed). Absent => return immediately.
timeout_ms?integerint640 <= valueThe image
application/json- response
anonymous*booleanavailable_in*array<string>Every region that holds a copy of this image's current manifest right now (PLAN-ARTIFACT-RESIDENCY.md "The copy record"); the home region is listed only while its own copy is there. Empty until the build finishes, and after every copy has been evicted. A create in a region not listed here waits while that region fetches the image from the global artifact store. A registry import whose export is not yet durable, or a create of one that carries volumes, is pulled from the registry again instead; any other create that carries volumes is refused there.
Not a column: filled in by one batched query per page.
bytes?|Captured erofs layer size in bytes; null until the build completes.
int64class*stringcreated_at*stringdate-timedefault*booleanThe platform default image: what POST /sandboxes without image
boots. Only ever true on a platform image.
deprecated*booleanA deprecated platform image: no new creates by name, not listed by
GET /images?platform=…; its img_… id still resolves.
error?|Build failure reason; null unless status is failed.
expires_at?|date-timeformat_outdated*booleanformat_version is below the current format. Such an image converts
on its first Linux sandbox create (which waits queued meanwhile) or
ahead of time with POST /images/{id}/convert; every other door
(GPU, Windows, functions, a POST /images named source) refuses it
with 409 IMAGE_FORMAT_OUTDATED until then. Derived, never stored.
format_version*integerThe image's format generation — how its artifact is stored
(images::format): 1 = stored by Daytona v1 (the v1 → v2
migration registers these; nothing pulled yet), 2 = the platform's
current artifact. status is the pipeline state of the artifact at
this format.
int32id*stringimported_from?Where the image was imported from (an archived Daytona v1 sandbox's
backup, #3035): {platform: "v1", id: <v1 sandbox id>}. Absent (never null) when
the image was not imported, so the item and the page row share one
optional, non-nullable shape.
layer_count?|int32manifest_name?|Resolved erofs manifest name; null until the build completes.
name?string|nullorigin*stringplatform*booleanA platform image: published by the platform operator, owned by no project, and bootable by every project (PLAN-PLATFORM-IMAGES.md). A project's own image of the same name takes precedence for that project. Platform images cannot be renamed, converted or deleted through this API.
region*stringHome region the image was built in (PLAN-REGIONS.md).
retention*stringsource?unknownThe build source as stored (ImageSource JSON).
status*stringcurl -X GET 'https://example.com/images/string'{ "anonymous": true, "available_in": [ "string" ], "bytes": 0, "class": "string", "created_at": "2019-08-24T14:15:22Z", "default": true, "deprecated": true, "error": "string", "expires_at": "2019-08-24T14:15:22Z", "format_outdated": true, "format_version": 0, "id": "string", "imported_from": { "id": "string", "platform": "string" }, "layer_count": 0, "manifest_name": "string", "name": "string", "origin": "string", "platform": true, "region": "string", "retention": "string", "source": null, "status": "string"}Promotion only: an image that already has a name answers 409. Renaming a named image is deliberately not offered yet — sandboxes reference images by id, so a rename would silently relabel every sandbox created from it, and nothing would record the name the caller created them with.
AuthorizationBearer <token>Project API key (dtn_…) as a Bearer token. Mint via the management API (POST /projects/:id/api-keys) or this deployment's key-mint CLI. Every key carries an explicit set of verb:resource project permissions chosen at mint time (PLAN-API-KEY-PERMISSIONS.md); each operation lists the project permission it requires in its security requirement, and a key lacking it is answered 403 missing required project permission: <project-permission>. Some operations require an additional permission depending on the request body, stated in the operation's description. Holding a mutating verb (write:/delete:/invoke:) implies the resource's read: permission. Operations whose api_key project-permission list is empty need no specific project permission — any live project key works (the global catalogs and the artifact-cache read).
Scope: write:images
id*stringimage id (img_…; bare UUID also accepted during the transition)
application/json- body
name*stringThe now-named, permanent image
application/json- response
anonymous*booleanavailable_in*array<string>Every region that holds a copy of this image's current manifest right now (PLAN-ARTIFACT-RESIDENCY.md "The copy record"); the home region is listed only while its own copy is there. Empty until the build finishes, and after every copy has been evicted. A create in a region not listed here waits while that region fetches the image from the global artifact store. A registry import whose export is not yet durable, or a create of one that carries volumes, is pulled from the registry again instead; any other create that carries volumes is refused there.
Not a column: filled in by one batched query per page.
bytes?|Captured erofs layer size in bytes; null until the build completes.
int64class*stringcreated_at*stringdate-timedefault*booleanThe platform default image: what POST /sandboxes without image
boots. Only ever true on a platform image.
deprecated*booleanA deprecated platform image: no new creates by name, not listed by
GET /images?platform=…; its img_… id still resolves.
error?|Build failure reason; null unless status is failed.
expires_at?|date-timeformat_outdated*booleanformat_version is below the current format. Such an image converts
on its first Linux sandbox create (which waits queued meanwhile) or
ahead of time with POST /images/{id}/convert; every other door
(GPU, Windows, functions, a POST /images named source) refuses it
with 409 IMAGE_FORMAT_OUTDATED until then. Derived, never stored.
format_version*integerThe image's format generation — how its artifact is stored
(images::format): 1 = stored by Daytona v1 (the v1 → v2
migration registers these; nothing pulled yet), 2 = the platform's
current artifact. status is the pipeline state of the artifact at
this format.
int32id*stringimported_from?Where the image was imported from (an archived Daytona v1 sandbox's
backup, #3035): {platform: "v1", id: <v1 sandbox id>}. Absent (never null) when
the image was not imported, so the item and the page row share one
optional, non-nullable shape.
layer_count?|int32manifest_name?|Resolved erofs manifest name; null until the build completes.
name?string|nullorigin*stringplatform*booleanA platform image: published by the platform operator, owned by no project, and bootable by every project (PLAN-PLATFORM-IMAGES.md). A project's own image of the same name takes precedence for that project. Platform images cannot be renamed, converted or deleted through this API.
region*stringHome region the image was built in (PLAN-REGIONS.md).
retention*stringsource?unknownThe build source as stored (ImageSource JSON).
status*stringcurl -X PATCH 'https://example.com/images/string' \ -H 'Content-Type: application/json' \ -d '{ "name": "string"}'{ "anonymous": true, "available_in": [ "string" ], "bytes": 0, "class": "string", "created_at": "2019-08-24T14:15:22Z", "default": true, "deprecated": true, "error": "string", "expires_at": "2019-08-24T14:15:22Z", "format_outdated": true, "format_version": 0, "id": "string", "imported_from": { "id": "string", "platform": "string" }, "layer_count": 0, "manifest_name": "string", "name": "string", "origin": "string", "platform": true, "region": "string", "retention": "string", "source": null, "status": "string"}New in PLAN-ARTIFACT-UNIFICATION.md phase 2. Before it, image deletion
existed ONLY inside the Daytona alias facade, running a shorter guard set
than the snapshot route — so which endpoint you happened to use decided
whether a paused sandbox kept its layers. Both routes are the same code now
(snapshots::delete_artifact), and neither can reach across the
image/snapshot partition.
AuthorizationBearer <token>Project API key (dtn_…) as a Bearer token. Mint via the management API (POST /projects/:id/api-keys) or this deployment's key-mint CLI. Every key carries an explicit set of verb:resource project permissions chosen at mint time (PLAN-API-KEY-PERMISSIONS.md); each operation lists the project permission it requires in its security requirement, and a key lacking it is answered 403 missing required project permission: <project-permission>. Some operations require an additional permission depending on the request body, stated in the operation's description. Holding a mutating verb (write:/delete:/invoke:) implies the resource's read: permission. Operations whose api_key project-permission list is empty need no specific project permission — any live project key works (the global catalogs and the artifact-cache read).
Scope: delete:images
id*stringimage id (img_…; bare UUID also accepted during the transition)
Image deleted
application/json- response
DELETE /images/:id response.
image_id*stringstatus*stringAlways deleted.
curl -X DELETE 'https://example.com/images/string'{ "image_id": "string", "status": "string"}AuthorizationBearer <token>Project API key (dtn_…) as a Bearer token. Mint via the management API (POST /projects/:id/api-keys) or this deployment's key-mint CLI. Every key carries an explicit set of verb:resource project permissions chosen at mint time (PLAN-API-KEY-PERMISSIONS.md); each operation lists the project permission it requires in its security requirement, and a key lacking it is answered 403 missing required project permission: <project-permission>. Some operations require an additional permission depending on the request body, stated in the operation's description. Holding a mutating verb (write:/delete:/invoke:) implies the resource's read: permission. Operations whose api_key project-permission list is empty need no specific project permission — any live project key works (the global catalogs and the artifact-cache read).
Scope: read:images
id*stringimage id (img_…; bare UUID also accepted during the transition)
Absolute regional proxy URL
application/json- response
Absolute canonical regional proxy URL for once, text-follow and SSE reads.
url*stringcurl -X GET 'https://example.com/images/string/build-logs-url'{ "url": "string"}The same conversion the first create runs (images::format::convert): an
image below the current format (format_outdated) flips to pending and
its conversion job — for a format-1 image, the registry import of its v1
ref — is enqueued in the image's region. Idempotent and safe to repeat: a
conversion already in flight is joined (nothing enqueued), a failed one is
retried, and an image already at the current format answers
converted: false with its own status, whatever that is — its build is
POST /images' business.
AuthorizationBearer <token>Project API key (dtn_…) as a Bearer token. Mint via the management API (POST /projects/:id/api-keys) or this deployment's key-mint CLI. Every key carries an explicit set of verb:resource project permissions chosen at mint time (PLAN-API-KEY-PERMISSIONS.md); each operation lists the project permission it requires in its security requirement, and a key lacking it is answered 403 missing required project permission: <project-permission>. Some operations require an additional permission depending on the request body, stated in the operation's description. Holding a mutating verb (write:/delete:/invoke:) implies the resource's read: permission. Operations whose api_key project-permission list is empty need no specific project permission — any live project key works (the global catalogs and the artifact-cache read).
Scope: write:images
id*stringimage id (img_…; bare UUID also accepted during the transition)
The conversion started or joined (converted: true), or nothing to convert (converted: false)
application/json- response
POST /images/{id}/convert (#3032): the result.
converted*booleantrue when this call started or joined a conversion; false when the
image was already at the current format and nothing was enqueued.
from_format*integerThe image's format before the call (ImageListItem.format_version).
int32image_id*stringstatus*stringThe image's status after the call: pending/building while it
converts, or its own status when it was already at the current format.
to_format*integerThe format the conversion targets: the current one.
int32curl -X POST 'https://example.com/images/string/convert'{ "converted": true, "from_format": 0, "image_id": "string", "status": "string", "to_format": 0}AuthorizationBearer <token>Project API key (dtn_…) as a Bearer token. Mint via the management API (POST /projects/:id/api-keys) or this deployment's key-mint CLI. Every key carries an explicit set of verb:resource project permissions chosen at mint time (PLAN-API-KEY-PERMISSIONS.md); each operation lists the project permission it requires in its security requirement, and a key lacking it is answered 403 missing required project permission: <project-permission>. Some operations require an additional permission depending on the request body, stated in the operation's description. Holding a mutating verb (write:/delete:/invoke:) implies the resource's read: permission. Operations whose api_key project-permission list is empty need no specific project permission — any live project key works (the global catalogs and the artifact-cache read).
Scope: write:images
id*stringexternal sandbox id (base58 body with optional region tag, or a bare UUID)
application/json- body
idle?|Idle-retention window in seconds for an ANONYMOUS image: the image is
deleted once this long has passed without a sandbox being created from
it (every create from the image restarts the clock). Only without
name (a named image is permanent; idle with name is 400). The
same rule as POST /images: omitted or -1 ⇒ the server maximum
(DAYTONA_ANON_IMAGE_MAX_IDLE, 7 days by default); 1 … max ⇒ that
window; 0, < -1 or > max ⇒ 400 IDLE_OUT_OF_RANGE (the body
carries max). Promote the image (PATCH /images/{id}) to keep it.
int64name?string|nullFilesystem capture accepted; image row queued on the sandbox's runner
application/json- response
anonymous*booleanavailable_in*array<string>Every region that holds a copy of this image's current manifest right now (PLAN-ARTIFACT-RESIDENCY.md "The copy record"); the home region is listed only while its own copy is there. Empty until the build finishes, and after every copy has been evicted. A create in a region not listed here waits while that region fetches the image from the global artifact store. A registry import whose export is not yet durable, or a create of one that carries volumes, is pulled from the registry again instead; any other create that carries volumes is refused there.
Not a column: filled in by one batched query per page.
bytes?|Captured erofs layer size in bytes; null until the build completes.
int64class*stringcreated_at*stringdate-timedefault*booleanThe platform default image: what POST /sandboxes without image
boots. Only ever true on a platform image.
deprecated*booleanA deprecated platform image: no new creates by name, not listed by
GET /images?platform=…; its img_… id still resolves.
error?|Build failure reason; null unless status is failed.
expires_at?|date-timeformat_outdated*booleanformat_version is below the current format. Such an image converts
on its first Linux sandbox create (which waits queued meanwhile) or
ahead of time with POST /images/{id}/convert; every other door
(GPU, Windows, functions, a POST /images named source) refuses it
with 409 IMAGE_FORMAT_OUTDATED until then. Derived, never stored.
format_version*integerThe image's format generation — how its artifact is stored
(images::format): 1 = stored by Daytona v1 (the v1 → v2
migration registers these; nothing pulled yet), 2 = the platform's
current artifact. status is the pipeline state of the artifact at
this format.
int32id*stringimported_from?Where the image was imported from (an archived Daytona v1 sandbox's
backup, #3035): {platform: "v1", id: <v1 sandbox id>}. Absent (never null) when
the image was not imported, so the item and the page row share one
optional, non-nullable shape.
layer_count?|int32manifest_name?|Resolved erofs manifest name; null until the build completes.
name?string|nullorigin*stringplatform*booleanA platform image: published by the platform operator, owned by no project, and bootable by every project (PLAN-PLATFORM-IMAGES.md). A project's own image of the same name takes precedence for that project. Platform images cannot be renamed, converted or deleted through this API.
region*stringHome region the image was built in (PLAN-REGIONS.md).
retention*stringsource?unknownThe build source as stored (ImageSource JSON).
status*stringcurl -X POST 'https://example.com/sandboxes/string/images' \ -H 'Content-Type: application/json' \ -d '{}'{ "anonymous": true, "available_in": [ "string" ], "bytes": 0, "class": "string", "created_at": "2019-08-24T14:15:22Z", "default": true, "deprecated": true, "error": "string", "expires_at": "2019-08-24T14:15:22Z", "format_outdated": true, "format_version": 0, "id": "string", "imported_from": { "id": "string", "platform": "string" }, "layer_count": 0, "manifest_name": "string", "name": "string", "origin": "string", "platform": true, "region": "string", "retention": "string", "source": null, "status": "string"}