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

# Credentials

> Store an API token once, use it in every workflow, and let a workflow keep it fresh.

A credential is a named secret your whole organization can use in workflows — an API key, an OAuth access token, a signed service-account token.

Without one, auth material ends up pasted into an HTTP step's headers, where it is stored in the workflow definition, copied into every execution record, and shown in run views. When it expires, someone edits the workflow.

A credential fixes both halves of that: the value is encrypted, never shown again, and redacted from run records — and if it expires, a workflow of your own renews it on a schedule.

```
Authorization: {{ 'Bearer ' & $credential('shopify_admin').access_token }}
```

## Two kinds

|                      | Value comes from     | Use it for                                          |
| -------------------- | -------------------- | --------------------------------------------------- |
| **Static**           | You type it in       | API keys, non-expiring tokens                       |
| **Refresher-backed** | A workflow you build | OAuth tokens, session logins, anything that expires |

Both are read exactly the same way in a workflow. The difference is only who produces the value.

## Creating one

Go to **Workflows → Credentials** and choose **Add credential**.

<Steps>
  <Step title="Name it">
    The name is the handle you use in expressions, so keep it short and stable: `shopify_admin`, `stripe`, `hubspot`. Letters, numbers, dots, dashes and underscores only.
  </Step>

  <Step title="Pick a refresher — or None">
    **None** makes it static: a **Value** section appears and you type the keys in.

    Picking a workflow makes it refresher-backed. See [Refresher workflows](/workflows/credentials/refreshers).
  </Step>

  <Step title="Fill in the value or the secrets">
    A static credential takes its value directly, as one or more named keys.

    A refresher-backed one takes the **secrets** its refresher needs (a client id, a client secret, a refresh token) — never the token itself, which the refresher fetches.
  </Step>

  <Step title="Save, then refresh">
    A refresher-backed credential has no value until its refresher runs once. Use the refresh button (↻) on its row, or pick a policy that runs it automatically.
  </Step>
</Steps>

## Using one in a workflow

`$credential()` works in any expression field — an HTTP step's URL, headers or body, a condition, a transform, a code step's input, an app step.

| Write                                                   | Get                        |
| ------------------------------------------------------- | -------------------------- |
| `{{ $credential('stripe').api_key }}`                   | one key of the value       |
| `{{ $credential('stripe', 'api_key') }}`                | the same, explicit form    |
| `{{ $credential('stripe') }}`                           | the whole value object     |
| `{{ 'Bearer ' & $credential('hubspot').access_token }}` | concatenated into a header |

You do not have to remember the names. In any smart value field, open the **Variables** tab — credentials appear as their own group, with each credential's keys underneath. Selecting one inserts the expression for you.

Credentials are organization-wide. Any workflow can name any credential; there is nothing to import or bind.

<Note>
  A credential's keys are whatever its value contains. A static one has the keys you typed; a refresher-backed one has whatever its refresher last produced, which is why the list is empty until the first successful refresh.
</Note>

## What you can and cannot see

The list shows the name, which keys exist, the expiry, and how the last refresh went. It never shows a value — not in the UI, not through the API, not to an administrator. Once saved, a value can only be replaced.

Editing a credential shows each key with an empty box next to it:

* **Leave it blank** — keep the stored value
* **Type a new value** — replace that key
* **Trash icon** — remove that key

A credential must keep at least one key. To get rid of it entirely, delete the credential.

## Credentials in run records

When a step uses a credential, the real value goes out on the wire and a placeholder is recorded:

```
Authorization: Bearer «credential:shopify_admin.access_token»
```

That applies to persisted run state, API responses, the HTTP step's recorded request, error messages, logs, and error reports. If a run looks like it sent the wrong header, this is why — it didn't.

<Warning>
  Redaction matches the value exactly, so it cannot follow a value you **transform**. If a code step base64-encodes a token, or an expression slices it, the result is recorded as-is. Derive auth material inside the refresher, not in the workflows that consume the credential.
</Warning>

## Expiry

A credential can carry an expiry, and the list warns you before it bites: **Expiring soon** inside the last 15 minutes, then **Expired**.

For a refresher-backed credential the expiry comes from the refresher and a policy can renew it automatically. For a static one nothing renews it — the date is there so a key with a known end date warns you rather than failing silently.

## Permissions

| Scope              | Can                                                    |
| ------------------ | ------------------------------------------------------ |
| `workflows:read`   | See the list: names, key names, expiry, refresh status |
| `workflows:manage` | Create, edit, rotate, delete, and refresh on demand    |

Setup secrets are stricter than the credential itself: they are readable only by that credential's own refresher run, never by an ordinary workflow. See [Refresher workflows](/workflows/credentials/refreshers).
