# Secrets

Secrets are encrypted values, such as API tokens or passwords, that you store once per workspace and reference from job configs as `{{secret.NAME}}`. The value is filled in only at the moment a request is sent or a command runs. It is never returned by the API, never shown in the dashboard, and never written to run history or logs.

## Why use them

Without secrets, a token would sit in plain text inside every job that uses it. It would be visible to anyone who can read jobs, copied into exports, and painful to rotate. With secrets you store it once, reference it everywhere, and rotate it with a single update.

## Create or update a secret

```sh
curl -X PUT "$CRONPAD_URL/api/v1/secrets/REPORTS_TOKEN" \
  -H "Authorization: Bearer $CRONPAD_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"value": "sk_live_…"}'
```

Names are `UPPER_SNAKE_CASE`, up to 64 characters. Values are up to 8 KiB.

## Use it

```json
"headers": {"Authorization": "Bearer {{secret.REPORTS_TOKEN}}"}
```

Secrets work anywhere [templates](../sinks/index.md#templates) do: webhook URL, headers and body; command arguments and environment. Saving a job that references a secret that doesn't exist fails with a validation error.

## List and delete

- `GET /api/v1/secrets` lists names and timestamps, never values.
- `DELETE /api/v1/secrets/{name}` deletes a secret. Jobs that still reference it fail their next run with a fatal error, `secret REPORTS_TOKEN not found`.

## How they're protected

- Encrypted with AES-256-GCM using the server's `secrets.encryption_key`.
- Write-only through the API and dashboard.
- Redacted from attempts, logs and traces.
- Self-hosted: set the key from an environment variable (`CRONPAD_SECRETS__ENCRYPTION_KEY`), and keep a copy somewhere safe. Without it, stored secrets can't be decrypted, including from backups. Rotate with `cronpad secrets rekey --new-key <base64>` while the server is stopped; restart with the new key. Rekeying also covers webhook signing secrets and idempotency responses. Existing plaintext signing-secret and idempotency rows are encrypted atomically on startup when the key is configured.