Ensemble Docs

Environments

Tenant variables and secrets that tool configurations reference, with per-signing-key overrides so one definition serves several callers.

An environment variable is a named value held for your tenant, which a tool or channel configuration refers to instead of containing it. Write ${secrets.STRIPE_KEY} in a tool's header and the real key lives here, once, where it can be rotated without touching the tool.

Two reasons this exists rather than putting values in the definitions:

  • A definition is versioned, diffed and synced between tenants. A credential in it travels with it, which is the last thing you want when promoting a tool from development to production.
  • The same definition needs different values per environment. One tool, pointed at the sandbox in your dev tenant and the live service in production, with nothing in the tool itself saying which.

Two kinds of reference

${vars.NAME}

Non-secret values. Readable back through the API, fine in a URL or a hostname.

${secrets.NAME}

Credentials. Encrypted at rest, and the API only ever returns a mask, never the value.

Which one a variable is, is a property of the variable, not of how you reference it. The two prefixes select from different pools.

Where they can be used

Anywhere a tool or channel configuration takes a string, alongside the other expression sources:

ReferenceResolves to
${vars.NAME}A non-secret tenant variable
${secrets.NAME}A secret tenant variable
${data.field}The tool's own input
${context.field}Context passed by the caller
${userContext.field}Who the call is running as

They compose, which is most of their usefulness:

baseUrl:     https://${vars.SUBDOMAIN}.example.com
authHeader:  Bearer ${secrets.TOKEN}
dynamicUrl:  ${vars.BASE_URL}/users/${data.userId}
username:    ${vars.TENANT_NAME}_user

Per-signing-key overrides

A variable is addressed by name plus an optional signing key. A row with no key is the tenant-wide default; a row with one overrides that default for callers whose JWT was signed with that key.

That is what lets one tenant serve several integrators from one set of tools. Each integrator holds its own signing key, and ${secrets.API_TOKEN} resolves to that integrator's token without a copy of the tool per integrator.

The lookup is name plus key first, then name alone. A variable with no override for the calling key is not an error; it falls back, which is why adding an override for one integrator cannot disturb anyone else.

Where to go next

On this page