Secrets
Use secrets for passwords, tokens, and connection credentials that should not appear in flow source or ordinary runtime variables. Secrets belong to a workspace and can be associated with an environment. Values are encrypted at rest; list and metadata operations do not include plaintext.
On this page
Create a secretList, inspect, and updateUse secrets in an integrationCopy and rotate secretsCommon problemsSecret management requires secrets.write (owner/admin). Reading metadata and decrypted values requires secrets.read (owner/admin/developer). The permission is not limited to viewing names. Full models are in the OpenAPI reference.
Create a secret
curl --fail-with-body -X POST "$DAGY_API_URL/secrets" \
-H "Authorization: Bearer $DAGY_TOKEN" \
-H "Content-Type: application/json" \
--data-binary @secret-request.jsonCreate secret-request.json locally with restrictive permissions and a value supplied by your secret manager:
{
"secret_name":"warehouse_password",
"value":"YOUR_SECRET_VALUE",
"environment":"develop",
"description":"Development warehouse access"
}Remove this temporary plaintext file after use. Do not commit it. POST returns 201 with metadata including secret_name, logical_name, environment, description, enabled, and timestamps. The plaintext value is absent.
Use logical_name to identify the same credential concept across environments. Save the returned secret_name as the API resource identifier and percent-encode it when placing it in a URL. It can differ from the requested logical name when an environment is provided. Do not construct its encoding yourself. The requested secret name must not contain ::.
Creating the same name/environment can replace an existing value. Choose names carefully and use update when intentionally rotating a credential.
List, inspect, and update
| Operation | Request/query | Result |
|---|---|---|
GET /secrets | Optional environment, limit default 100 | items of metadata; no cursor. |
GET /secrets/{secret_name} | Returned identifier | Metadata only. |
GET /secrets/{secret_name}/value | Returned identifier | Metadata plus decrypted_value; treat the response as a secret. |
PUT /secrets/{secret_name} | {"value":"REPLACEMENT_VALUE"} | Replaces the value; returns metadata. |
PATCH /secrets/{secret_name} | {"description":"...","enabled":false} | Updates supplied metadata without changing the value. |
DELETE /secrets/{secret_name} | Returned identifier | {"deleted":true}. |
Read a value only in a trusted process that needs it. Do not log the response. Missing resources return 404. Secret value reads and management actions create audit events; avoid assuming audit delivery is a complete compliance record.
Use secrets in an integration
Some workflow nodes accept fields such as password_ref or api_key_ref. A value such as secret:warehouse_password names a secret in the node's execution context. Supply the actual value in that context when running the node directly:
import os
from dagy.nodes import ExecutionContext
from dagy.nodes.execution import SecretStr
# Your secret manager supplies this environment value to the trusted process.
context = ExecutionContext(secrets={
"warehouse_password": SecretStr(os.environ["WAREHOUSE_PASSWORD"])
})
# A node configured with password_ref="secret:warehouse_password" uses context.You can also retrieve a workspace secret with an authenticated GET /secrets/{secret_name}/value and pass its decrypted_value to that context. Creating a workspace secret alone does not hydrate every node execution context, and saving it does not automatically place it in os.environ. Verify the credential-supply path for the runtime you use. Never put secret values in flow parameters retained in run history.
Saved connectors have a separate credential configuration. Their designated fields accept actual credential values, which are stored encrypted; they do not automatically resolve workspace secret references. Updating a workspace secret does not rotate a saved connector's credential. Configure and test those records separately.
Environment association helps choose credentials; it is not a separate permission boundary. A user with workspace secrets.read can retrieve accessible environment-associated values. Disabling a secret records enabled state for consumers that honor it; it does not revoke the upstream password/token or prevent direct authorized value reads. Rotate or revoke the credential with the upstream service when ending access.
Copy and rotate secrets
To intentionally use the same credential in another environment:
POST /secrets/copy{
"logical_name":"warehouse_password",
"source_environment":"develop",
"target_environment":"staging"
}This returns target metadata with 201, without returning plaintext. A missing source returns 404. Copying can replace the target's same-named secret. The operation copies the current value; it does not create a live link that follows future source rotations. Deployment promotion does not copy secrets automatically.
For rotation:
- Obtain a replacement credential from the upstream service.
- Update the appropriate environment's secret value.
- Test each consuming node or a small flow run. Rotate separate saved-connector credentials independently when required.
- Revoke the previous credential upstream after all consumers work with the replacement.
Use separate credentials for production when the upstream platform supports them. Keep secret-reading permissions separate from ordinary run monitoring.
Common problems
| Problem | Resolution |
|---|---|
403 reading a value | The caller needs secrets.read; viewer cannot read secrets. |
404 after creation | Use the returned secret_name, URL-encoded, and the correct workspace. |
422 on secret name | Remove the reserved :: sequence from the requested name. |
| Consumer still uses old credentials | Verify context/reference and environment. Copied secrets and separate saved-connector credentials do not follow later rotations. |
| Disabled credential still works elsewhere | Disabling metadata does not revoke the upstream credential. |
Secret operations return persistent 500 | Contact the workspace owner/support channel; do not copy credentials into ordinary variables as a workaround. |