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:
| Parent | Endpoint | Namespace | Example token |
|---|---|---|---|
| Provider | /providers/{providerId}/custom-variables | provider.custom.* | {{provider.custom.region}} |
| Customer | /customers/{customerId}/custom-variables | customer.custom.* | {{customer.custom.webPort}} |
| Location | /locations/{locationId}/custom-variables | location.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 tonullis 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
nullremoval 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 a400).
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:
| Namespace | Built-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.