API Keys
api_keyAuthorizationBearer <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).
The presented key's metadata (never the token)
application/json- response
What an API-key caller learns about the credential it presented.
created_at?|date-timeexpires_at?|RFC 3339 expiry; null = never expires.
date-timeid*stringuuidkey_prefix?|Leading characters of the plaintext token, for recognizable display.
key_suffix?|Trailing characters of the plaintext token; null for keys minted before the suffix was recorded.
last_used_at?|Best-effort, flushed periodically — may lag the request that reads it.
date-timename*stringorg_id*stringuuidorg_name*stringproject_id*stringuuidproject_name*stringproject_permissions*array<string>The key's explicit project permissions, canonical order.
service_account_id?|The owning service account, when the key was minted for one. Only the
id: service_accounts is management-plane state that workload cells
do not replicate, so a name would be null there and set on home.
uuidcurl -X GET 'https://example.com/api-keys/current'{ "created_at": "2019-08-24T14:15:22Z", "expires_at": "2019-08-24T14:15:22Z", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "key_prefix": "string", "key_suffix": "string", "last_used_at": "2019-08-24T14:15:22Z", "name": "string", "org_id": "a40f5d1f-d889-42e9-94ea-b9b33585fc6b", "org_name": "string", "project_id": "405d8375-3514-403b-8c43-83ae74cfe0e9", "project_name": "string", "project_permissions": [ "string" ], "service_account_id": "81f92c7b-60ae-411e-bc6f-e2dc93db8886"}Read one project API key's metadata (the same shape as a list item, never the token). The caller must be able to enter the key's project and hold read:project_api_keys; an unknown id, or a key in a project the caller cannot enter, is a 404 so nothing is learned about other tenants' keys. Only an OIDC user JWT is admitted on this route; dtno_ organization API keys are not.
user_jwtAuthorizationBearer <token>OIDC access token of a signed-in user (the dashboard/CLI login) used on the management plane: /me, /orgs*, /projects*, /invitations*, /roles, billing, audit, API-key, and service-account routes. Every management operation documents the org/project permission the authenticated member must hold.
id*stringProject API key id
uuidProject API key metadata
application/json- response
created_at?|date-timecreated_by?|The human who minted the key — an id for a read:members holder,
null for everyone else (the projects rule, #942); also null for a
service-account or CLI-minted key.
uuidexpires_at?|date-timeid*stringuuidimported_from?|"v1" when the key was created on Daytona v1 and imported by the
v1 ↔ v2 key sync; null for a key created on this platform.
key_prefix?string|nullkey_suffix?|Last characters of the plaintext token, for a recognizable masked
display; null for keys minted before the suffix was recorded.
last_used_at?|date-timemine*booleanname*stringproject_permissions*array<string>revoked_at?|date-timeservice_account_id?|uuidservice_account_name?string|nullsync_to_v1*booleanWhether the v1 ↔ v2 key sync copies this key to Daytona v1 (for an
organization that is kept in sync with v1). true for a live key a person minted in the organization's
default project unless it was opted out (PATCH /api-keys/{id}),
and always for a live key imported from v1. false for every key
the sync never copies: keys in other projects, service-account keys,
the dashboard's own key named default, and revoked or expired keys.
A v1 copy can read every sandbox, snapshot and registry of the
organization on v1, which has no read permissions.
curl -X GET 'https://example.com/api-keys/497f6eca-6276-4993-bfeb-53cbbbba6f08'{ "created_at": "2019-08-24T14:15:22Z", "created_by": "ee824cad-d7a6-4f48-87dc-e8461a9201c4", "expires_at": "2019-08-24T14:15:22Z", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "imported_from": "string", "key_prefix": "string", "key_suffix": "string", "last_used_at": "2019-08-24T14:15:22Z", "mine": true, "name": "string", "project_permissions": [ "string" ], "revoked_at": "2019-08-24T14:15:22Z", "service_account_id": "81f92c7b-60ae-411e-bc6f-e2dc93db8886", "service_account_name": "string", "sync_to_v1": true}Change whether the v1 ↔ v2 key sync keeps a copy of one project API key on Daytona v1 (sync_to_v1). Turning it off deletes the v1 copy; the key keeps working on this platform. Only a live, unexpired key a person minted in the organization's default project, other than the dashboard's own key named default, is ever copied: turning it on for any other key is a 409 KEY_SYNC_NOT_APPLICABLE, and turning it off for one is a no-op. A live key imported from Daytona v1 is always synced: turning it off is a 409 IMPORTED_KEY_ALWAYS_SYNCED (delete the key to remove it from both platforms); a revoked or expired imported key is answered like any other key that is never copied. Authorized like revoking the key: the caller must be able to enter the key's project and hold write:project_api_keys for a personal key they minted, delete:project_api_keys for anyone else's, or delete:service_accounts for a service account's key. Only an OIDC user JWT is admitted on this route; dtno_ organization API keys are not.
user_jwtAuthorizationBearer <token>OIDC access token of a signed-in user (the dashboard/CLI login) used on the management plane: /me, /orgs*, /projects*, /invitations*, /roles, billing, audit, API-key, and service-account routes. Every management operation documents the org/project permission the authenticated member must hold.
id*stringProject API key id
uuidapplication/json- body
sync_to_v1*booleanWhether the v1 ↔ v2 key sync keeps a copy of this key on Daytona v1.
false deletes the v1 copy (the key keeps working here); true
copies the key to v1 again. A v1 copy can read every sandbox,
snapshot and registry of the organization on v1, which has no read
permissions. Only a key a person minted in the organization's
default project is ever copied; a key imported from v1 always is.
Required: it is the only field.
The key's metadata after the change
application/json- response
created_at?|date-timecreated_by?|The human who minted the key — an id for a read:members holder,
null for everyone else (the projects rule, #942); also null for a
service-account or CLI-minted key.
uuidexpires_at?|date-timeid*stringuuidimported_from?|"v1" when the key was created on Daytona v1 and imported by the
v1 ↔ v2 key sync; null for a key created on this platform.
key_prefix?string|nullkey_suffix?|Last characters of the plaintext token, for a recognizable masked
display; null for keys minted before the suffix was recorded.
last_used_at?|date-timemine*booleanname*stringproject_permissions*array<string>revoked_at?|date-timeservice_account_id?|uuidservice_account_name?string|nullsync_to_v1*booleanWhether the v1 ↔ v2 key sync copies this key to Daytona v1 (for an
organization that is kept in sync with v1). true for a live key a person minted in the organization's
default project unless it was opted out (PATCH /api-keys/{id}),
and always for a live key imported from v1. false for every key
the sync never copies: keys in other projects, service-account keys,
the dashboard's own key named default, and revoked or expired keys.
A v1 copy can read every sandbox, snapshot and registry of the
organization on v1, which has no read permissions.
curl -X PATCH 'https://example.com/api-keys/497f6eca-6276-4993-bfeb-53cbbbba6f08' \ -H 'Content-Type: application/json' \ -d '{ "sync_to_v1": true}'{ "created_at": "2019-08-24T14:15:22Z", "created_by": "ee824cad-d7a6-4f48-87dc-e8461a9201c4", "expires_at": "2019-08-24T14:15:22Z", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "imported_from": "string", "key_prefix": "string", "key_suffix": "string", "last_used_at": "2019-08-24T14:15:22Z", "mine": true, "name": "string", "project_permissions": [ "string" ], "revoked_at": "2019-08-24T14:15:22Z", "service_account_id": "81f92c7b-60ae-411e-bc6f-e2dc93db8886", "service_account_name": "string", "sync_to_v1": true}Revoke one project API key. The caller must be able to enter the key's project and hold delete:project_api_keys, except that revoking a personal key the caller minted (created_by = caller) is also allowed with write:project_api_keys, and revoking a key owned by a service account requires delete:service_accounts instead. Only an OIDC user JWT is admitted on this route; dtno_ organization API keys are not.
user_jwtAuthorizationBearer <token>OIDC access token of a signed-in user (the dashboard/CLI login) used on the management plane: /me, /orgs*, /projects*, /invitations*, /roles, billing, audit, API-key, and service-account routes. Every management operation documents the org/project permission the authenticated member must hold.
id*stringProject API key id
uuidRevoked project API key
application/json- response
revoked*stringuuidcurl -X DELETE 'https://example.com/api-keys/497f6eca-6276-4993-bfeb-53cbbbba6f08'{ "revoked": "139b8438-b6c7-4494-8941-ce249af5d379"}Revoke one organization API key. The caller must be a seated member holding delete:org_api_keys. Only an OIDC user JWT is admitted on this route; dtno_ organization API keys are not.
user_jwtAuthorizationBearer <token>OIDC access token of a signed-in user (the dashboard/CLI login) used on the management plane: /me, /orgs*, /projects*, /invitations*, /roles, billing, audit, API-key, and service-account routes. Every management operation documents the org/project permission the authenticated member must hold.
id*stringOrganization API key id
uuidRevoked organization API key
application/json- response
revoked*stringuuidcurl -X DELETE 'https://example.com/org-api-keys/497f6eca-6276-4993-bfeb-53cbbbba6f08'{ "revoked": "139b8438-b6c7-4494-8941-ce249af5d379"}List the organization API keys of one organization. The caller must be a seated member holding read:org_api_keys. Only an OIDC user JWT is admitted on this route; dtno_ organization API keys are not.
user_jwtAuthorizationBearer <token>OIDC access token of a signed-in user (the dashboard/CLI login) used on the management plane: /me, /orgs*, /projects*, /invitations*, /roles, billing, audit, API-key, and service-account routes. Every management operation documents the org/project permission the authenticated member must hold.
id*stringOrganization id
uuidinclude_revoked?booleanWhen true, return revoked keys as well (same semantics as the project-key list).
Organization API keys
application/json- response
org_api_keys*array<>curl -X GET 'https://example.com/orgs/497f6eca-6276-4993-bfeb-53cbbbba6f08/api-keys'{ "org_api_keys": [ { "created_at": "2019-08-24T14:15:22Z", "created_by": "ee824cad-d7a6-4f48-87dc-e8461a9201c4", "expires_at": "2019-08-24T14:15:22Z", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "key_prefix": "string", "last_used_at": "2019-08-24T14:15:22Z", "name": "string", "org_permissions": [ "string" ], "revoked_at": "2019-08-24T14:15:22Z" } ]}Mint an organization API key (dtno_…). The caller must be a seated member holding write:org_api_keys; the requested org_permissions set must stay within the org-key mint allow-list. Only an OIDC user JWT is admitted on this route; dtno_ organization API keys are not.
user_jwtAuthorizationBearer <token>OIDC access token of a signed-in user (the dashboard/CLI login) used on the management plane: /me, /orgs*, /projects*, /invitations*, /roles, billing, audit, API-key, and service-account routes. Every management operation documents the org/project permission the authenticated member must hold.
id*stringOrganization id
uuidapplication/json- body
expires_at?|Optional expiry (D11); must be in the future. Absent = never expires.
date-timename*stringRequired — org keys have no dashboard auto-mint flow, so there is no
implicit-"default" convenience (or rotation semantics) here. Option
in Rust only for the specific 400; required in the contract.
org_permissions*array<string>Required, validated against the ORG vocabulary (D4/D18/D19): explicit, at least one, project permissions are unknown values here.
1 <= itemsMinted organization API key; plaintext token is returned once
application/json- response
expires_at?|date-timeid*stringuuidkey_prefix*stringname*stringorg_id*stringuuidorg_permissions*array<string>token*stringcurl -X POST 'https://example.com/orgs/497f6eca-6276-4993-bfeb-53cbbbba6f08/api-keys' \ -H 'Content-Type: application/json' \ -d '{ "name": "string", "org_permissions": [ "string" ]}'{ "expires_at": "2019-08-24T14:15:22Z", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "key_prefix": "string", "name": "string", "org_id": "a40f5d1f-d889-42e9-94ea-b9b33585fc6b", "org_permissions": [ "string" ], "token": "string"}List the API keys of one project. The caller must be able to enter the project and hold read:project_api_keys. Only an OIDC user JWT is admitted on this route; dtno_ organization API keys are not.
user_jwtAuthorizationBearer <token>OIDC access token of a signed-in user (the dashboard/CLI login) used on the management plane: /me, /orgs*, /projects*, /invitations*, /roles, billing, audit, API-key, and service-account routes. Every management operation documents the org/project permission the authenticated member must hold.
id*stringProject id, or the literal default for the caller's default project alias
include_revoked?booleanWhen true, return revoked keys as well. Defaults to false so the list only surfaces live keys — revoked keys are noise (and are purged after 7 days by the reaper), shown only on explicit request.
falseProject API keys
application/json- response
project_api_keys*array<>curl -X GET 'https://example.com/projects/string/api-keys'{ "project_api_keys": [ { "created_at": "2019-08-24T14:15:22Z", "created_by": "ee824cad-d7a6-4f48-87dc-e8461a9201c4", "expires_at": "2019-08-24T14:15:22Z", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "imported_from": "string", "key_prefix": "string", "key_suffix": "string", "last_used_at": "2019-08-24T14:15:22Z", "mine": true, "name": "string", "project_permissions": [ "string" ], "revoked_at": "2019-08-24T14:15:22Z", "service_account_id": "81f92c7b-60ae-411e-bc6f-e2dc93db8886", "service_account_name": "string", "sync_to_v1": true } ]}Mint a project API key. The caller must be able to enter the project and hold write:project_api_keys; the requested project_permissions set must stay within the caller's assignable project-permission ceiling. Minting for a service account additionally requires write:service_accounts, and the ceiling is intersected with that account's permissions. Only an OIDC user JWT is admitted on this route; dtno_ organization API keys are not.
user_jwtAuthorizationBearer <token>OIDC access token of a signed-in user (the dashboard/CLI login) used on the management plane: /me, /orgs*, /projects*, /invitations*, /roles, billing, audit, API-key, and service-account routes. Every management operation documents the org/project permission the authenticated member must hold.
id*stringProject id, or the literal default for the caller's default project alias
application/json- body
expires_at?|Optional expiry (D11); must be in the future. Absent = never expires.
date-timename?string|nullproject_permissions*array<string>Required (PLAN-API-KEY-PERMISSIONS.md D4): the key's permissions are ALWAYS
explicit — no defaults, no implied full-power set, and at least one
permission is required (D18); an ABSENT field or empty array is a 400.
Option in Rust only so the handler can answer that specific 400; the
contract marks it required so generated clients cannot omit it.
1 <= itemsservice_account_id?|PLAN-SERVICE-ACCOUNTS.md D6: mint this key for a service account in the
project's org rather than for the calling user; requires
write:service_accounts (issue #926). Absent = the caller owns the
key, exactly as today.
uuidsync_to_v1?|Whether the v1 ↔ v2 key sync may copy this key to Daytona v1. Absent
= true. Only a key a person mints in the organization's default
project is ever copied; elsewhere the field is ignored and the
response says false. A v1 copy can read every sandbox, snapshot and
registry of the organization on v1, which has no read permissions;
false keeps the key on this platform only. Changeable later with
PATCH /api-keys/{id}.
Minted project API key; plaintext token is returned once
application/json- response
expires_at?|date-timeid*stringuuidkey_prefix*stringkey_suffix*stringname*stringproject_id*stringuuidproject_permissions*array<string>service_account_id?|uuidsync_to_v1*booleanWhether the v1 ↔ v2 key sync keeps a copy of this key on Daytona v1;
same meaning as on ProjectApiKeyResponse.
token*stringcurl -X POST 'https://example.com/projects/string/api-keys' \ -H 'Content-Type: application/json' \ -d '{ "project_permissions": [ "string" ]}'{ "expires_at": "2019-08-24T14:15:22Z", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "key_prefix": "string", "key_suffix": "string", "name": "string", "project_id": "405d8375-3514-403b-8c43-83ae74cfe0e9", "project_permissions": [ "string" ], "service_account_id": "81f92c7b-60ae-411e-bc6f-e2dc93db8886", "sync_to_v1": true, "token": "string"}