Store API keys and tokens as secrets
Store API keys and tokens encrypted in your project, then use them by name in workflow steps with {{ $anythink.secrets.NAME }} instead of pasting them in.
Last updated
A workflow that calls another service needs a credential: an API key, a bearer token or a shared secret. Don't paste it into the step. Store it once as a secret, then refer to it by name. The value is encrypted at rest, never shown again after you save it, and only available to workflows in the same project.
| Property | What it means |
|---|---|
| Encrypted at rest | The value is encrypted before it's stored. |
| Write-only | You can set a value and replace it, but you can never read it back through the Anythink dashboard, the CLI or an API response. Lists show names, assigned users and dates. Keep your own copy in your password manager. |
| Project-scoped | A secret belongs to one project. A workflow in another project can't use it, even with the same name. |
| Used by name | A step refers to {{ $anythink.secrets.NAME }}. Anythink swaps in the value when the step runs. |
How secrets differ from connections and API keys
| Secret | How integrations work | API keys | |
|---|---|---|---|
| Direction | Your project sends it to another service | Your project acts on a connected service | Someone sends it to your project |
| Who creates the credential | You, in the other service | Anythink, through sign-in with the provider | Anythink, when you create the key |
| What you store | Any text value | A connection to Google, Slack and similar | A key with a set of permissions and an expiry |
| Used in | Any step field that accepts template expressions | Integration steps | The x-api-key header on requests to your project |
If the service you need is in the integrations catalogue, connect it there instead. Use a secret for everything else: a partner's REST API, a payment gateway key, a webhook shared secret.
Create a secret
A secret has a key (its name) and a value.
Naming rules
- Use letters, numbers, underscores and hyphens, for example
PARTNER_API_KEYorpartner-api-key. The dashboard enforces this. Stick to it everywhere, because the name goes straight into the template expression. - Names are case-sensitive:
Partner_KeyandPARTNER_KEYare different secrets, and a step that uses the wrong case fails. - Each name is unique within a project. Creating a name that already exists is rejected; rotate the existing secret instead.
- The value can't be empty.
Name each secret after the service and purpose, such as STRIPE_SECRET_KEY, not KEY1. One secret per credential makes rotating and deleting safe.
In the Anythink dashboard
- Open Settings and select Secrets under Platform Settings.
- Select Add Secret.
- Enter the Key and the Value.
- Select Create Secret.
With the CLI
anythink secrets create PARTNER_API_KEY
The CLI asks for the value with a hidden prompt, so it stays out of your terminal output. For scripts, pass --value:
anythink secrets create PARTNER_API_KEY --value "<the partner's key>"
On success the CLI prints the expression to use in a workflow.
With an AI assistant (MCP)
Create a secret called PARTNER_API_KEY.
The assistant runs secrets create through the cli tool. The assistant can't show you a hidden prompt, so anything you type as the value is part of the conversation. Create secrets in the dashboard or at your own terminal, and ask the assistant only to use them by name.
List secrets
Lists show the key, who it's assigned to, and when it was created and last updated. They never include values.
In the Anythink dashboard
Open Settings › Secrets. The table shows Key, Users, Created At and Updated At.
With the CLI
anythink secrets list
With an AI assistant (MCP)
List the secrets in this project.
The assistant runs secrets list and reports the keys.
Update a secret to rotate it
When you issue a new key in the other service, overwrite the stored value. Workflows that use the name pick up the new value the next time a step runs, with no edits to the workflow.
You always supply the new value. You can't change a secret's name; to rename one, create the new name, point your steps at it, then delete the old one.
In the Anythink dashboard
- Open Settings › Secrets.
- Open the actions menu on the secret's row and select Edit.
- Enter the new value.
- Select Update Secret.
With the CLI
anythink secrets update PARTNER_API_KEY
Enter the new value at the hidden prompt, or pass --value. A name that doesn't exist returns 404.
With an AI assistant (MCP)
Rotate the secret PARTNER_API_KEY.
The assistant runs secrets update. As with creating, rotate in the dashboard or at your terminal if you don't want the new value in the conversation.
Delete a secret
Delete a secret once nothing uses it. A step that still refers to a deleted name fails when it runs.
In the Anythink dashboard
- Open Settings › Secrets.
- Open the actions menu on the secret's row and select Delete.
- Confirm the deletion. It can't be undone.
With the CLI
anythink secrets delete PARTNER_API_KEY
The CLI asks you to confirm. Add --yes to skip the prompt in scripts.
With an AI assistant (MCP)
Delete the secret PARTNER_API_KEY.
The assistant runs secrets delete. Check no workflow still uses the name first.
Use a secret in a workflow step
Write the expression wherever a step field accepts Template syntax:
{{ $anythink.secrets.PARTNER_API_KEY }}
The name after secrets. must match the stored key exactly. Anythink looks the value up when the step runs, so a rotated value is used straight away.
Secret expressions work in any templated step field, including Call An API (URL, headers and body), integration inputs and conditions. The most common use is a Call An API header:
{
"url": "https://partner.example.com/v1/orders",
"method": "POST",
"headers": {
"Authorization": "Bearer {{ $anythink.secrets.PARTNER_API_KEY }}",
"X-Source": "anythink"
},
"body": "{\"order_id\": \"{{ $anythink.trigger.data.order_id }}\"}"
}
A header can combine text and a secret, as Bearer … does above. To send a key that the other service expects in the body, put the expression in the body in the same way. See Webhooks for the whole Call An API step, and Step types for the other steps.
If a name doesn't exist, the step fails and the job's error names the key it couldn't find. Check the spelling and case, and that the secret exists in this project.
Note: Put credentials in headers or the request body, not in the URL or query string. Request URLs are written to the step log.
Where to use a secret
Use a secret for a credential that a step sends to another service. Anything a step writes to a record, an email or a command is stored or delivered as plain text, and each step's output is kept in the job history. Don't write a secret into those, and don't echo one back into a response or a field a later step stores.
Add a secret to a step
In the Anythink dashboard
- Create the secret first, as above.
- Open the workflow and select Add Step, then choose Call An API.
- In Headers, add a header such as
Authorizationand enterBearer {{ $anythink.secrets.PARTNER_API_KEY }}as its value. - Save the step, then save the workflow.
In a field's variable menu, Secret Value… asks for the key name and inserts the expression for you.
With the CLI
anythink workflows step-add 42 send_to_partner \
--action CallAnApi \
--start --enabled \
--params '{"url":"https://partner.example.com/v1/orders","method":"POST","headers":{"Authorization":"Bearer {{ $anythink.secrets.PARTNER_API_KEY }}"}}'
Replace 42 with your workflow's id.
With an AI assistant (MCP)
In workflow 42, add a Call An API step that POSTs to https://partner.example.com/v1/orders with an Authorization header of "Bearer" followed by the PARTNER_API_KEY secret.
The assistant runs workflows step-add and writes the expression into the header. It only needs the secret's name.
What shows in job history and logs
Open a workflow's View Job History, or run anythink workflows jobs <workflow_id>, to see each step's log and output.
- A step's parameters are shown as you wrote them, with
{{ $anythink.secrets.PARTNER_API_KEY }}and not the value. - Call An API logs the names of the headers it adds, not their values.
- Request URLs are written to the step log, so keep credentials out of the URL.
- A step's output is stored with the job. If a service echoes your credential back in its response, or you put one into a field a step outputs, it's kept there.
Who can manage secrets
Secrets use four permissions on the anythink_secrets resource: read, create, update and delete. They're part of the project's roles, so you grant or remove them in Roles and permissions.
| Who | What they see and can change |
|---|---|
| Administrators | Every secret in the project. |
| Other roles with the permissions | Only secrets that have been assigned to them. They need the matching permission for each action. |
The default Standard User role includes the secrets permissions. If only administrators should manage secrets in your project, remove them from the roles that shouldn't have them.
Limits
- A secret's key is unique within a project, and key and value are both required.
- A secret is available only in the project that owns it.
- Values are write-only: set and replace them, but they're never returned by the dashboard, CLI or API responses. Store your own copy where it belongs.
Next steps
- Webhooks: call another system from a workflow and send a secret in a header
- How integrations work: connect Google, Slack and other services without managing keys yourself
- API keys: let your own apps and scripts call your project
- Step types: what each workflow step can do
- Template syntax: every
{{ }}expression a step accepts