> ## Documentation Index
> Fetch the complete documentation index at: https://3to1go.docs.thesteau.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Integration secrets

> How destination credentials are stored, replaced, backed up, and recovered.

The entire destination URL is a secret, including its path and query. This matters for Discord because the webhook token is part of the URL. All custom header values are also secret.

## Write-only credentials

You enter secrets when creating a destination. After saving, neither list nor save responses return them, and the editor clears its secret inputs. The UI shows only whether a URL or headers are configured. Editing non-secret fields with blank secret inputs preserves the saved credentials.

Enter a new URL or headers object to replace saved values. **Clear saved headers** removes all headers; an API update with `"headers": {}` does the same. Delete a destination to remove its current stored configuration. Deletion does not revoke its token at the external service or securely erase old copies of the encrypted file.

Only admins can list, save, test, or delete integrations. A scoped automation token needs **manage** permission and an admin account. API responses use `Cache-Control: no-store`. Secrets aren't placed in browser storage, ordinary settings payloads, or the settings database by the new integration feature.

## Encryption on disk

Each app writes an authenticated AES-256-GCM encrypted file at:

```text theme={null}
/config/integrations/destinations.enc
```

By default, it generates its own random encryption key at `/config/integrations/key` on the first save. Integration files use owner-only permissions where supported. Native installs use the `integrations` folder beneath that app's configuration directory; protect it with filesystem permissions or Windows ACLs.

Keeping the default key alongside the ciphertext protects against exposure of the ciphertext alone. Someone who obtains both can decrypt it. Container and host administrators, a compromised app process, and trusted scripts with filesystem access can read the key. This is separate from the **Scout key** used to encrypt backup snapshots.

For stronger separation, supply `INTEGRATIONS_KEY_FILE` pointing to a mounted key. It must contain exactly **64 hexadecimal characters**, with optional surrounding whitespace. The app never creates or overwrites an external key.

## Mount an external key with Compose

Generate a separate key for each app on the deployment host:

```sh theme={null}
mkdir -p secrets
umask 077
openssl rand -hex 32 > secrets/integrations-key
```

Add this to the existing app service and the top level of its Compose file. For Scout use the `scout` service name; for Station use `station`:

```yaml theme={null}
services:
  scout:
    environment:
      INTEGRATIONS_KEY_FILE: /run/secrets/integrations-key
    secrets:
      - integrations-key

secrets:
  integrations-key:
    file: ./secrets/integrations-key
```

Recreate the service after updating Compose. Supply the key before the first integration is saved. To move an existing installation to an external key, securely copy its **existing** `/config/integrations/key` into the mounted file and configure that path. Generating a different key does not rotate existing ciphertext.

Compose mounts file secrets into the service; it doesn't encrypt the source file on the host. Keep the file private, outside source control, and outside selected Scout backup jobs. See [Docker's secret guide](https://docs.docker.com/compose/how-tos/use-secrets/) for deployment details. In Kubernetes, adapt the Scout example to mount your operator-managed Secret and set `INTEGRATIONS_KEY_FILE`; do not put a usable secret in manifests committed to Git.

## Backup and recovery

Preserve `destinations.enc` and the matching key. Losing the key makes the saved destinations unreadable. Startup fails if existing ciphertext cannot be decrypted; it doesn't replace a missing key with a new one. With an external key, back that key up separately under your own secret-management process.

Scout's configuration and Scout key remain included when that folder is part of a backup job. This also includes the default integration key, so protect those encrypted snapshots and the Scout key needed to restore them. Integration secrets are not runtime directories and are not automatically excluded.

To recover, restore the encrypted file and its matching key, then restart the app. If the key is irretrievably lost, stop the app, retain the old integration files privately if needed, remove or move the `integrations` folder out of the config directory, and reconfigure destinations with new external-service credentials. This affects integration settings, not backup snapshots.

## Secrets used by custom scripts

Prefer the built-in HTTP delivery for notifications: it controls credential handling and error output. For a script that needs its own secret, mount a read-only file outside `/hook-scripts`, and have the script read that file. Uploaded scripts and configured commands can be viewed through authenticated APIs, so don't embed tokens there.

The hook runner discards standard output and standard error and logs only timeout or failure outcomes. A script can still write secrets to files or send them over the network, and it inherits the app environment. Run only trusted scripts. Avoid shell tracing and HTTP debug output, and keep any script-managed logs private. With curl, [configuration files](https://curl.se/docs/manpage.html#-K) let it read credential-bearing options without putting their values in command-line arguments.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.