API Keys
Daytona API keys authenticate requests from the SDKs, the CLI, and the API to the resources in a project. To pass a key, see authentication.
Organization API keys cover organization-level operations that are not tied to a project.
Every project API key belongs to exactly one project and carries an explicit list of permissions; its requests are confined to both. Keys can carry an expiry. Revocation applies to new requests; a regional proxy can accept a revoked key for up to 30 seconds.
Create an API key
Section titled “Create an API key”Create an API key to authenticate Daytona SDK and API requests.
- Go to Daytona Dashboard ↗
- Select the project in the header switcher
- Click
- Enter a , optionally set an expiry, and select permissions
- Click
- Copy the API key to your clipboard and use it to authenticate requests
daytona key mint --project PROJECT_ID \ --name my-api-key \ --permission write:sandboxes,delete:sandboxes \ --expires 2027-01-01T00:00:00Z| Flag | Type | Description |
|---|---|---|
--permission | string | A comma-separated list of permissions. |
--expires | string | An RFC 3339 timestamp or a Go duration such as 720h, counted from now. |
daytona key mintprints the plaintext token once, when the key is created.
curl 'https://api.daytona.com/projects/PROJECT_ID/api-keys' \ --request POST \ --header 'Authorization: Bearer YOUR_OIDC_TOKEN' \ --header 'Content-Type: application/json' \ --data '{ "name": "my-api-key", "project_permissions": ["write:sandboxes", "delete:sandboxes"], "expires_at": "2027-01-01T00:00:00Z"}'{ "id": "KEY_ID", "name": "my-api-key", "project_id": "PROJECT_ID", "key_prefix": "dtn_...", "token": "YOUR_API_KEY", "project_permissions": ["read:sandboxes", "write:sandboxes", "delete:sandboxes"], "expires_at": "2027-01-01T00:00:00Z", "service_account_id": null}- The create response is the only response that returns
token. - Store the
tokenvalue when you create the key. - Write and delete permissions add their read counterpart, such as
read:sandboxes. - A key can hold only permissions you hold.
- Daytona refuses a request for more permissions than you hold and does not narrow the request.
- Live key names are unique per project.
- A new
defaultor unnamed key revokesdefaultkeys older than two minutes. - A project holds at most 100,000 live keys.
| Field | Description |
|---|---|
name | Display name for the key. Optional; defaults to default. |
project_permissions | Required, non-empty list of permissions. Unknown values are rejected with 400 error status code. |
expires_at | Optional RFC 3339 timestamp in the future. Omit for a key that never expires. |
service_account_id | Optional. Mint the key for a service account instead of yourself. Service account keys must be named. |
Credentials
Section titled “Credentials”Daytona accepts two bearer credentials, named differently in this page’s API examples:
| Credential | Description |
|---|---|
| API KEY | A project API key created as described above. It authenticates SDK, toolbox, and sandbox requests, and the few management routes that accept it, such as getting the current key. This is the credential the SDKs and the DAYTONA_API_KEY variable carry. See authentication for how to pass it to the SDKs, the CLI, and API requests. |
| OIDC TOKEN | The session token of a signed-in user (an OIDC bearer JWT, the credential the dashboard uses). Management routes that act on behalf of a person require it and reject API keys with 401: creating, listing, and revoking keys, service accounts, organizations, projects, and billing. Obtain it by signing in with the dashboard or daytona login; the CLI commands in those sections use the saved session for you. |
Organization API keys (dtno_...) are a third kind, scoped to an organization rather than a project; that section lists the scopes they can hold.
Permissions & Scopes
Section titled “Permissions & Scopes”| Resource | Scope | Description |
|---|---|---|
| Sandboxes | read:sandboxes | View sandboxes and use the toolbox |
write:sandboxes | Create/modify sandboxes | |
delete:sandboxes | Delete sandboxes | |
| Snapshots | read:snapshots | View snapshots |
write:snapshots | Create/modify snapshots | |
delete:snapshots | Delete snapshots | |
| Images | read:images | View images |
write:images | Create/modify images | |
delete:images | Delete images | |
| Registries | read:registries | View registries |
write:registries | Create/modify registries | |
delete:registries | Delete registries | |
| Secrets | read:secrets | View secrets |
write:secrets | Create/modify secrets | |
delete:secrets | Delete secrets | |
| Spending | read:spending | View project spending |
| Limits | read:limits | View project limits (reserved) |
| Runners | read:runners | View runners (reserved) |
Operations
Section titled “Operations”List API keys
Section titled “List API keys”List the API keys of a project. The list never contains tokens and contains only live keys. Daytona deletes revoked and expired keys 7 days after they stop working.
daytona key list --project PROJECT_IDcurl 'https://api.daytona.com/projects/PROJECT_ID/api-keys' \ --header 'Authorization: Bearer YOUR_OIDC_TOKEN'{ "project_api_keys": [ { "id": "KEY_ID", "name": "my-api-key", "key_prefix": "dtn_...", "created_at": "2026-09-10T12:00:00Z", "revoked_at": null, "last_used_at": "2026-09-11T08:30:00Z", "project_permissions": ["read:sandboxes", "write:sandboxes", "delete:sandboxes"], "expires_at": "2027-01-01T00:00:00Z", "service_account_id": null, "service_account_name": null } ], "next_cursor": null}- You can revoke a key you minted with
write:project_api_keysalone.
Get by ID
Section titled “Get by ID”curl 'https://api.daytona.com/projects/PROJECT_ID/api-keys/KEY_ID' \ --header 'Authorization: Bearer YOUR_OIDC_TOKEN'Get the current API key
Section titled “Get the current API key”Get the API key that authenticates the request, including the project and organization it acts in and the permissions it carries. The response never contains the token.
from daytona import Daytona
daytona = Daytona()key = daytona.v2.current_api_key()print(key.name, key.context.project_name, key.context.org_name)print(key.project_permissions)import { Daytona } from '@daytona/sdk'
const daytona = new Daytona()const key = await daytona.v2.currentApiKey()console.log(key.name, key.context.project_name, key.context.org_name)console.log(key.project_permissions)curl 'https://api.daytona.com/api-keys/current' \ --header 'Authorization: Bearer YOUR_API_KEY'/api-keys/currenttakes a project API key, not a token from exchange a token.- Daytona updates
last_used_atperiodically, solast_used_atcan lag the request that reads it.
Exchange a token
Section titled “Exchange a token”Exchange a signed-in user’s session token for a short-lived access token scoped to one project. The access token carries the user’s own permissions in that project and authenticates workload requests in place of a project API key. Organization API keys cannot be exchanged.
curl 'https://api.daytona.com/auth/token' \ --request POST \ --header 'Authorization: Bearer YOUR_OIDC_TOKEN' \ --header 'Content-Type: application/json' \ --data '{ "grant_type": "urn:ietf:params:oauth:grant-type:token-exchange", "subject_token": "YOUR_OIDC_TOKEN", "subject_token_type": "urn:ietf:params:oauth:token-type:access_token", "project_id": "PROJECT_ID"}'{ "access_token": "eyJ...", "issued_token_type": "urn:ietf:params:oauth:token-type:access_token", "token_type": "Bearer", "expires_in": 300}| Field | Type | Description |
|---|---|---|
grant_type | string | Required. urn:ietf:params:oauth:grant-type:token-exchange. |
subject_token | string | Required. Must be the same token as the bearer in the Authorization header; otherwise the request returns 400. |
subject_token_type | string | Required. urn:ietf:params:oauth:token-type:access_token or urn:ietf:params:oauth:token-type:jwt. |
project_id | string | Required. The project the access token is scoped to. An unknown project, or one you are not a member of, returns 404. |
- The request also accepts the fields form-encoded.
expires_inis the access token lifetime in seconds.- Exchange again for a new access token when the current access token expires.
- The request must omit
scopeandresource. - The access token cannot be narrowed below your permissions.
Revoke an API key
Section titled “Revoke an API key”Revoke an API key. Revocation cannot be undone. New requests made with the key fail, except at a regional proxy, which can accept the key for up to 30 seconds after revocation. Daytona deletes the revoked key 7 days later.
- Go to Daytona Dashboard ↗
- Click next to the API key you want to revoke
- Confirm the revocation
daytona key revoke KEY_IDcurl 'https://api.daytona.com/projects/PROJECT_ID/api-keys/KEY_ID' \ --request DELETE \ --header 'Authorization: Bearer YOUR_OIDC_TOKEN'- Revoking a key requires
delete:project_api_keys. - Revoking a key you minted requires only
write:project_api_keys. - Revoking a key owned by a service account requires
delete:service_accountsinstead.
Service accounts
Section titled “Service accounts”Service accounts are non-human identities in your organization. Use them to own API keys for automation so that the keys are not tied to a person’s membership.
Create a service account
Section titled “Create a service account”daytona service-account create my-service-account --role developer --org ORG_ID| Flag | Type | Description |
|---|---|---|
--role | string | A comma-separated list of role slugs. |
curl 'https://api.daytona.com/orgs/ORG_ID/service-accounts' \ --request POST \ --header 'Authorization: Bearer YOUR_OIDC_TOKEN' \ --header 'Content-Type: application/json' \ --data '{ "name": "my-service-account", "roles": ["developer"]}'| Field | Type | Description |
|---|---|---|
name | string | Required. At most 64 letters, digits, -, or _, unique in the organization. |
description | string | Optional, up to 512 characters. |
roles | string[] | Required. Must hold at least one role. The admin role is refused, and every permission the roles grant must be one you hold yourself. |
- Personal organizations cannot have service accounts.
- An organization holds at most 500 live service accounts.
Create a service account key
Section titled “Create a service account key”Create an API key owned by a service account. The key keeps working when its creator leaves the organization. Outside the default project, the service account must first be added to the project, and the key can carry only permissions you and the service account both hold.
- Go to Daytona Dashboard ↗
- Click
- Under , select the service account
- Enter a , select permissions, and click
daytona key mint --project PROJECT_ID \ --name my-service-account-key \ --permission write:sandboxes \ --service-account SERVICE_ACCOUNT_ID \ --org ORG_IDcurl 'https://api.daytona.com/projects/PROJECT_ID/api-keys' \ --request POST \ --header 'Authorization: Bearer YOUR_OIDC_TOKEN' \ --header 'Content-Type: application/json' \ --data '{ "name": "my-service-account-key", "project_permissions": ["write:sandboxes"], "service_account_id": "SERVICE_ACCOUNT_ID"}'- Creating a service account key requires
write:service_accountsin addition towrite:project_api_keys.
List service accounts
Section titled “List service accounts”daytona service-account list --org ORG_IDcurl 'https://api.daytona.com/orgs/ORG_ID/service-accounts' \ --header 'Authorization: Bearer YOUR_OIDC_TOKEN'Get a service account
Section titled “Get a service account”daytona service-account get SERVICE_ACCOUNT_IDcurl 'https://api.daytona.com/orgs/ORG_ID/service-accounts/SERVICE_ACCOUNT_ID' \ --header 'Authorization: Bearer YOUR_OIDC_TOKEN'Update a service account
Section titled “Update a service account”Update a service account’s name, description, or roles. Fields you leave out stay unchanged, and new roles replace the whole role set. When the new roles are narrower, Daytona revokes the account’s project API keys that exceed them.
# The CLI updates the name (--name) and roles (--role); it cannot set the descriptiondaytona service-account update SERVICE_ACCOUNT_ID --role maintainercurl 'https://api.daytona.com/orgs/ORG_ID/service-accounts/SERVICE_ACCOUNT_ID' \ --request PATCH \ --header 'Authorization: Bearer YOUR_OIDC_TOKEN' \ --header 'Content-Type: application/json' \ --data '{ "description": "CI runner", "roles": ["maintainer"]}'
# Preview the change without applying it: { "revoked_api_keys": ..., "revoked_preview_grants": ... }curl 'https://api.daytona.com/orgs/ORG_ID/service-accounts/SERVICE_ACCOUNT_ID/update-preview' \ --request POST \ --header 'Authorization: Bearer YOUR_OIDC_TOKEN' \ --header 'Content-Type: application/json' \ --data '{ "roles": ["maintainer"]}'- The request requires at least one of
name,description, orroles.
Archive a service account
Section titled “Archive a service account”Archive a service account. This revokes every project API key it owns. An archived account cannot be updated, added to projects, or given new keys, and lists do not contain it.
daytona service-account delete SERVICE_ACCOUNT_IDcurl 'https://api.daytona.com/orgs/ORG_ID/service-accounts/SERVICE_ACCOUNT_ID' \ --request DELETE \ --header 'Authorization: Bearer YOUR_OIDC_TOKEN'Organization API keys
Section titled “Organization API keys”Organization API keys authenticate organization-level operations that are not tied to a project.
| Resource | Scope | Description |
|---|---|---|
| Audit logs | read:audit | View audit logs |
| Billing | read:billing, write:billing | View and manage billing |
| SSO | read:sso, write:sso | View and manage SSO |
| BYOC infrastructure | read:regions, write:regions, delete:regions | View and manage regions |
write:runners, delete:runners | Register and remove runners |
# Createdaytona org-key mint --org ORG_ID --name my-org-key --permission read:audit
# Listdaytona org-key list --org ORG_ID
# Revokedaytona org-key revoke KEY_ID| Flag | Type | Description |
|---|---|---|
--name | string | Required. |
daytona org-key mintprints the plaintext token once, at creation.daytona org-key revokeasks for confirmation before it revokes the key.
# Createcurl 'https://api.daytona.com/orgs/ORG_ID/api-keys' \ --request POST \ --header 'Authorization: Bearer YOUR_OIDC_TOKEN' \ --header 'Content-Type: application/json' \ --data '{ "name": "my-org-key", "org_permissions": ["read:audit"]}'
# Listcurl 'https://api.daytona.com/orgs/ORG_ID/api-keys' \ --header 'Authorization: Bearer YOUR_OIDC_TOKEN'
# Revokecurl 'https://api.daytona.com/orgs/ORG_ID/api-keys/KEY_ID' \ --request DELETE \ --header 'Authorization: Bearer YOUR_OIDC_TOKEN'| Field | Type | Description |
|---|---|---|
name | string | Required. |
org_permissions | string[] | Required. A non-empty list of scopes from the table above. |
expires_at | string | Optional. Must be in the future. |
- The create response contains the plaintext
dtno_token. - Daytona returns the
dtno_token only once. - Creating an organization API key requires
write:org_api_keys. - Listing organization API keys requires
read:org_api_keys. - Revoking an organization API key requires
delete:org_api_keys. - An organization caps live organization API keys at 100,000.