---
title: "Secrets - Workflow Suite"
description: "Store API keys, tokens, passwords and webhook URLs once, encrypted, and use them in any step or function without ever showing them in the run history."
canonical: "https://docs.workflow-suite.app/secrets"
---

# Secrets

A secret is a value you store once and use by name: an API key, a token, an SFTP password, a Slack webhook URL. The value is encrypted, never shown again after you save it, and kept out of the run history.

## Create a secret

1. Open **Secrets** in the app menu and select **Create secret**.
2. Enter a **Name**: letters, numbers and underscores, for example `ORDER_API_TOKEN`. The name cannot be changed after creation.
3. Enter the **Value**.
4. Optional: a **Description**, so your colleagues know what it is for.
5. Save.

To replace a value, open the secret and enter a new one. The stored value is hidden and cannot be read back, not in the app and not over the API.

## Use it in a step

In any field:

```liquid
Bearer {{ secrets.ORDER_API_TOKEN }}
```

Typical places: the **Webhook URL** of a Slack message, an **Authorization** header of an HTTP request or a Download file step, **Username**, **Password** and **Private key** of a File transfer step.

## Use it in code

In a function or in code written in a step, read it as `secrets.NAME`:

```js
export default async function (input, ctx) {
  const res = await ctx.fetch("https://api.example.com/orders", {
    method: "POST",
    headers: { authorization: `Bearer ${secrets.ORDER_API_TOKEN}` },
    body: JSON.stringify(input.event.payload),
  })
  return { status: res.status }
}
```

## How secrets are protected

- Values are encrypted with a dedicated key management service, on top of the encrypted database.
- A secret is only loaded for a step that mentions it.
- The filled-in input of a step is never stored. In the run history, in test results and in the debugger, secret values are masked in a step's output and in error messages.
- A workflow variable may hold a secret: variables are worked out again for each step and are not stored with the run.
- The Developer API lists secrets by name with `hasValue`. A value is never returned at any access level.

## Where secrets must not go

Some fields are stored with the run on purpose, so the editor refuses a secret there:

- **Input (JSON)** of a Run function step. The code reads `secrets.NAME` itself.
- **Payload (JSON)** of a Start another workflow step. The started workflow reads its own secrets.

And two habits to avoid:

- Do not write a secret into a **Log** message or return it from code. Masking catches the exact value, but not a value your code has changed, for example encoded or cut.
- Do not type a password into a step as plain text. For the File transfer step the editor enforces this: a workflow with a plain-text login cannot be turned on.

> [!WARNING]
> **Never send us a secret**
> We never need a secret's value to help you. In a bug report or a support chat, refer to a secret by its name.

## Who can see and use secrets

Everyone with access to the app in your Shopify admin can use every secret in a workflow and can replace or delete it. Nobody can read a stored value.

## Deleting a secret

A step that reads a deleted secret gets an empty value, and usually fails at the other system with an authentication error. Before you delete a secret, search your workflows for its name. Over the Developer API, a workflow's requirements list the secrets it names. See [Developer API and MCP](https://docs.workflow-suite.app/developer-api-and-mcp.md).

## Related

- [Variables and the variable picker](https://docs.workflow-suite.app/variables.md)
- [HTTP request](https://docs.workflow-suite.app/http-request.md)
- [Files, SFTP and downloads](https://docs.workflow-suite.app/files-sftp-and-downloads.md)
