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

# Account Variables

> Share typed, reusable configuration across flows and swap values on the fly without editing definitions

Account variables let you stop hard-coding the same configuration values into every [Flow Definition](/concepts/flow-definitions). Define a value once — a department's email address, a campaign's hours of operation, a company-wide sender name — reference it from any flow with `{{ account.<set>.<key> }}`, and change it later by updating one place. The **next** execution picks up the new value with no definition edits.

Account variables carry plain configuration only. They are **not** for secrets — credentials belong in [Connections](/concepts/connections), which handlers consume by reference so secret values never enter a flow's data. See [Variables vs. Connections](#variables-vs-connections) below.

## Two scopes: `var` and `account`

There are two variable scopes, addressed by two different [expression](/concepts/expressions) roots. They solve different problems:

| Scope                      | Root                    | Lives on                                          | Best for                                                                                                                                                      |
| -------------------------- | ----------------------- | ------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Flow-scope variable**    | `{{ var.name }}`        | A single definition (its `variables` list)        | A constant local to one flow — a threshold, a fixed label — that never needs to change from outside the definition.                                           |
| **Account-scope variable** | `{{ account.set.key }}` | Your whole account (a store shared by every flow) | Configuration reused across many flows, or values you want to change on the fly (per department, per campaign, per environment) without touching definitions. |

A flow-scope `var` is declared inline on the definition and resolves to its literal value every run. An account-scope `account` value is stored once at the account level and resolved fresh at the start of each execution, so editing it changes what the next run sees.

<Tip>
  **Rule of thumb:** if a value **varies per run**, make it a definition **input**. If it **varies per department, per campaign, or per environment** — but is stable within a run — make it an **account variable**. If it's a **secret**, make it a **Connection**.
</Tip>

## The model: sets and versions

Account variables use one model — **sets** with **versions** — that covers both the "many variants" case and the flat "one value everywhere" case.

* A **Variable Set** is a named, typed schema your account owns. It declares **keys**, each with a [`ValueType`](/concepts/expressions) (`string`, `number`, `boolean`, `object`, `array`, or `datetime`) and an optional **default value**. An account can hold many sets — for example `department`, `company`, and `campaign` — each modeling a different kind of configurable thing.
* A **Version** is a named instance of a set's schema — concrete values for its keys. The `department` set might have versions `sales`, `support`, and `billing`. A version is validated against the set's schema when you save it: every key that has no default must be supplied, and every value must match its key's declared type.

Expressions always address values **by set name, never by version name**: `{{ account.department.email }}`. Which version fills in the value is chosen separately (see [Selecting a version](#selecting-a-version)). A set with a single version is the flat case — one `support_email` everywhere — with no separate concept to learn.

```json theme={null}
{
  "name": "department",
  "keys": [
    { "name": "email", "type": "string" },
    { "name": "hours", "type": "string", "default": "9-5 ET" }
  ],
  "versions": [
    { "name": "sales",   "values": { "email": "sales@acme.com",   "hours": "8-6 ET" } },
    { "name": "support", "values": { "email": "support@acme.com" } }
  ]
}
```

Here `support` omits `hours`, so it resolves to the key default `"9-5 ET"`. Resolution order is always **version value → key default**. Adding a new key with a default to a set with a dozen versions is a single edit.

## Selecting a version

Which version supplies the values for a set is chosen in two places, per set and independently:

<Steps>
  <Step title="Definition default (variable_bindings)">
    A definition declares a default version for each set its expressions reference, via its `variable_bindings` map (`set_name → version_name`). For example `{"department": "sales"}` binds the `department` set to its `sales` version for that flow.
  </Step>

  <Step title="Trigger override (variable_overrides)">
    The manual trigger (`POST /definitions/{id}/trigger`) may override the version per set with a `variable_overrides` map on the trigger request. `{"department": "support"}` runs that one execution with the `support` version instead of the bound default. Selection is per-set and independent: you can override `department` while leaving `campaign` on its default. Non-manual triggers — [schedule](/concepts/schedules), [webhook](/concepts/webhooks), and [event](/concepts/event-subscriptions) — use the definition's bound defaults.
  </Step>
</Steps>

Values are **snapshotted once at the start of each execution**. A mid-run edit never half-applies within a single run, and every execution takes its own snapshot — so the next run always reflects the current stored values.

## Fail-early validation

Account variables are validated up front so a flow never starts half-resolvable:

* **At definition save (D-08):** every `{{ account.<set>.<key> }}` an expression references must resolve — the set must exist, the key must exist, and the definition must bind a default version for that set. Otherwise the create/update is rejected with `422`.
* **At trigger time:** a `variable_overrides` entry naming a version that doesn't exist is rejected with `400` before any workflow starts.

## Referential safety (409 guard)

Adding sets, keys, and versions is always free. But **removing or renaming** something a live definition references is blocked so you can't silently break a flow. Deleting or renaming a set, deleting or renaming a version a definition binds, or removing/renaming a key a definition's expressions use returns `409 Conflict` with the referencing definition IDs:

```json theme={null}
{
  "detail": {
    "message": "Variable set is referenced by live definitions; update them first",
    "definition_ids": ["def_a1b2c3d4", "def_e5f6g7h8"]
  }
}
```

Update or delete the referencing definitions first, then retry.

## Managing account variables

All endpoints operate only on your organization's variable store. Reads require authentication; every mutating endpoint requires an **admin-role** caller.

| Method   | Endpoint                                        | Purpose                                                                        |
| -------- | ----------------------------------------------- | ------------------------------------------------------------------------------ |
| `GET`    | `/variables`                                    | List variable sets. Paginate with `limit`/`skip`, sort with `sort_by`/`order`. |
| `POST`   | `/variables`                                    | Create a set (schema + versions). Returns `201`.                               |
| `GET`    | `/variables/{set_name}`                         | Fetch one set with its versions embedded.                                      |
| `PUT`    | `/variables/{set_name}`                         | Full-replace a set's name, keys, and versions.                                 |
| `DELETE` | `/variables/{set_name}`                         | Delete a set and all its versions. Returns `204`.                              |
| `POST`   | `/variables/{set_name}/versions`                | Add a version to an existing set. Returns `201`.                               |
| `PUT`    | `/variables/{set_name}/versions/{version_name}` | Replace a version's values or rename it.                                       |
| `DELETE` | `/variables/{set_name}/versions/{version_name}` | Delete a version. Returns `204`.                                               |

Set, key, and version names must be **expression-path-safe** — they must match `^[a-zA-Z_][a-zA-Z0-9_]*$` (a leading letter or underscore, then letters, digits, or underscores) so a name can never contain a `.` or break the `account.<set>.<key>` path. Storage caps apply: up to 200 sets per account, 100 keys and 100 versions per set, and 16 KB per individual value.

Creating a set:

```bash theme={null}
curl -X POST "$BASE_URL/variables" \
  -H "X-API-Key: $GETDIALED_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "department",
    "keys": [
      {"name": "email", "type": "string"},
      {"name": "hours", "type": "string", "default": "9-5 ET"}
    ],
    "versions": [
      {"name": "sales", "values": {"email": "sales@acme.com", "hours": "8-6 ET"}}
    ]
  }'
```

## Variables vs. Connections

Account-variable values are configuration, and by design they flow into step payloads, execution events, and logs — that is what makes them useful to reference from a flow. That same visibility is exactly why they must never hold a secret.

|                          | Account variables                                        | Connections                                                     |
| ------------------------ | -------------------------------------------------------- | --------------------------------------------------------------- |
| **Holds**                | Plain configuration (emails, hours, labels, flags)       | Credentials (passwords, API tokens, keys)                       |
| **Referenced by**        | `{{ account.<set>.<key> }}` in expressions               | `connection_id` on a task                                       |
| **Where the value goes** | Into step payloads, events, and logs — visible by design | Resolved server-side by reference; never enters the flow's data |
| **Change on the fly**    | Yes — update a version, next run picks it up             | Rotate credentials without editing flows                        |

<Warning>
  **If it's a secret, it's a Connection.** Account variables have no secret flag and never will — their values appear in payloads, events, and logs by design. Store any credential in a [Connection](/concepts/connections), where handlers consume it by reference and the secret never enters the expression context.
</Warning>

## Next steps

<CardGroup cols={2}>
  <Card title="Expressions" icon="code" href="/concepts/expressions">
    The `{{ }}` language and every context root, including `account` and `var`.
  </Card>

  <Card title="Connections" icon="key" href="/concepts/connections">
    Where credentials belong — referenced, never embedded.
  </Card>
</CardGroup>
