Skip to main content

Custom variables

Custom variables are user-defined template variables: a name → value map stored on a provider, customer, or location. Each entry becomes a {{<prefix>.custom.<name>}} placeholder that templates and connector models can reference, resolved at apply time. They extend the fixed catalog of built-in variables (provider.name, customer.id, and so on) with values you control: a DNS suffix per customer, a syslog host per location, a shared domain per provider.

Scopes and namespaces

Each of the three parent resources carries its own map, managed through its own sub-resource and exposed to templates under its own namespace:

ParentEndpointNamespaceExample token
Provider/providers/{providerId}/custom-variablesprovider.custom.*{{provider.custom.region}}
Customer/customers/{customerId}/custom-variablescustomer.custom.*{{customer.custom.webPort}}
Location/locations/{locationId}/custom-variableslocation.custom.*{{location.custom.rack}}

The levels are isolated namespaces, not a hierarchy. There is no precedence or shadowing between them. A provider variable resolves only as provider.custom.*, a customer variable only as customer.custom.*, and so on. A template field references whichever namespace it needs, subject to the namespaces in scope for that field (see Where variables resolve).

Operations

Each sub-resource supports the same three operations. The caller needs read permission on the parent resource for GET and update permission for PUT and PATCH.

  • GET: Returns the custom variables as a name → value map (empty when none are set).
  • PUT: Replaces the variables wholesale. Variables omitted from the body are removed, and an empty or omitted map clears them all.
  • PATCH: Applies a JSON Merge Patch (RFC 7386). A variable present in the body is added or updated, a variable mapped to null is removed (a no-op when it doesn't exist), and variables absent from the body are left untouched. The response returns the full resulting set.

Both request and response bodies wrap the map in a customVariables field. For example, this PATCH body updates one variable and removes another:

{
"customVariables": {
"region": "us-west-2",
"legacy_host": null
}
}

Responses are HAL documents whose _links carry self plus a link back to the parent resource (provider, customer, or location).

Validation

  • Names are 1–64 characters of letters, digits, hyphens, or underscores, and must start with a letter or digit (no leading hyphen or underscore, no dots). Note that the console is stricter: it accepts only letters, numbers, and underscores.
  • At most 50 variables are stored per level. A PATCH body may carry more entries than that (its null removal markers inflate the body without growing the stored map), but the merged result is still bounded to 50.
  • Values are strings of at most 1000 characters. They are stored verbatim and never re-rendered, so a value may not itself contain {{ or }} (rejected with a 400).

Violations are reported per entry, so a bad batch tells you every offending name at once.

Where variables resolve

Custom variables join the same substitution catalog as the built-in variables, so a <prefix>.custom.* token is usable anywhere its namespace is in scope:

  • Location and customer templates: The templated apply payload fields, with the same two-phase namespace scoping as the built-ins. See Variable substitution on the location template page for the field-by-field table.
  • Connector models: The templated application fields, resolved against the attaching connector's context when the model materializes. See Template variables in model applications.

Existence is not checked when a template or model is saved. A template may reference a custom variable that is only defined on some customers, or defined after the template is written. Resolution is strict at apply time instead: a placeholder that references an undefined variable fails the whole apply with a 4xx listing the offending variables, rather than emitting a blank or a literal {{…}}.

Custom variables vs. built-in variables

The built-in ("standard") variables are fixed keys resolved from the parent resource's own fields. They carry no .custom. segment and can't be edited:

NamespaceBuilt-in keys
provider.*provider.id, provider.name, provider.networkId, provider.networkGroupId, provider.organizationId
customer.*customer.id, customer.name
location.*location.id, location.name, location.description, location.address

A custom variable named after a built-in field doesn't collide with it. {{provider.name}} and {{provider.custom.name}} are distinct keys that resolve independently.

More info