| name | variable-creation |
| description | Create and manage Domo card variables (dropdowns, sliders, pills); function templates, control registration, card save flow, curl or CLI. |
Variable Creation
Create Domo card variables (interactive controls) and output curl commands or CLI commands to execute them.
Variables are user-adjustable values that feed into Beast Mode formulas, enabling dynamic what-if analysis. They appear as dropdown, pill, slider, textbox, or date picker controls on cards and dashboards.
When to Use This Skill
- User asks for a dropdown, slider, or interactive control on a card
- User mentions "variable", "parameter", or describes wanting dynamic/adjustable values
- A card needs what-if analysis or user-selectable inputs
- You're building a card and realize a beast mode needs a user-controlled input
Core Workflow — 3-Step Creation
Variable creation requires three sequential API calls. All three are mandatory — skipping the middle step causes a 400 error on the card save.
1. Check name uniqueness (GET /query/v1/functions/variables/uniqueName)
2. Create the function template WITH embedded control (POST /query/v1/functions/template)
3. Register the variable control (PUT /content/v1/variable/controls)
4. Read the current card definition (PUT /content/v3/cards/kpi/definition)
5. Save the card with the new control (PUT /content/v3/cards/kpi/{cardId})
Prerequisites
| Parameter | Source | Required |
|---|
instanceUrl | Domo instance (e.g., domo-gordon-pont.domo.com) | Always |
devToken | CLI auth / developer token | Always |
cardId | Card ID | Always |
dataSourceId | Dataset UUID (from card definition or columns) | For validation and card save |
Variable Data Types
| Data Type | Expression Examples | Compatible Controls |
|---|
string | 'TEST', 'Option A' | DROPDOWN, PILL, TEXTBOX |
numeric | 100, 0.5 | DROPDOWN, PILL, SLIDER, TEXTBOX |
date | CURRENT_DATE(), '2024-01-01' | DROPDOWN, DATE_PICKER |
Variable Control Types
| Type | Description | Best For |
|---|
DROPDOWN | Select from a list of predefined values | Categorical selections, string/numeric/date |
PILL | Inline toggle chips | Small number of options (2-5) |
SLIDER | Numeric range slider | Numeric ranges with min/max |
TEXTBOX | Free-text input | Open-ended string/numeric input |
DATE_PICKER | Calendar date selector | Date variables |
Expression Types by Data Type
| Data Type | exprType |
|---|
string | STRING_VALUE |
numeric | NUMERIC_VALUE |
date | DATE_VALUE |
Values Array
For DROPDOWN and PILL controls, the values array defines the selectable options:
{"expression": {"value": "Option Text", "exprType": "STRING_VALUE"}}
For SLIDER controls, values define the min/max range:
[
{"expression": {"value": "0", "exprType": "NUMERIC_VALUE"}},
{"expression": {"value": "100", "exprType": "NUMERIC_VALUE"}}
]
Step 1: Check Name Uniqueness
Endpoint: GET /api/query/v1/functions/variables/uniqueName?name={name}
curl -X GET "https://{instanceUrl}/api/query/v1/functions/variables/uniqueName?name={variableName}" \
-H "X-DOMO-Developer-Token: {devToken}"
Returns [] if the name is available. Returns an array of function template IDs if the name is already in use. Variable names must be globally unique across the entire Domo instance.
Step 2: Create the Function Template
Endpoint: POST /api/query/v1/functions/template
This creates the variable's function template. The request body must include an embedded control object — this is critical and differs from regular beast mode creation.
curl -X POST "https://{instanceUrl}/api/query/v1/functions/template" \
-H "X-DOMO-Developer-Token: {devToken}" \
-H "Content-Type: application/json" \
-d '{
"name": "{variableName}",
"formula": "{defaultExpression}",
"status": "VALID",
"dataType": "{dataType}",
"persistedOnDataSource": false,
"isAggregatable": true,
"bignumber": false,
"owner": null,
"nonAggregatedColumns": [],
"legacyId": "calculation_{uuid}",
"variable": true,
"isCalculation": true,
"initialPersistedOnDataSource": false,
"saved": true,
"query": "{defaultExpression}",
"control": {
"format": {"type": "default"},
"controlType": "VARIABLE",
"function": {
"name": "{variableName}",
"dataType": "{dataType}",
"expression": "{defaultExpression}",
"id": -201
},
"saveOverride": true,
"description": "",
"values": [
{"expression": {"value": "{value1}", "exprType": "{exprType}"}},
{"expression": {"value": "{value2}", "exprType": "{exprType}"}}
],
"type": "{controlType}",
"unsaved": true,
"name": "{variableName}",
"id": -101
},
"description": "",
"locked": false,
"cacheWindow": "non_dynamic",
"containsAggregation": false,
"containsAnalytic": false,
"invalidColumns": [],
"nonAggregatedExpressions": [],
"formulaTemplateDependencies": [],
"columnPositions": [],
"formulaId": "calculation_{another_uuid}",
"formulaDependencies": [],
"isControlled": false,
"global": true,
"unsaved": true,
"expression": "{defaultExpression}"
}'
Key fields:
variable: true — marks this as a variable function (not a regular beast mode)
control — the embedded control definition with placeholder IDs (-201, -101)
legacyId and formulaId — generate unique UUIDs in the format calculation_{uuid}
global: true — variables are instance-wide
owner: null — server assigns the owner
Response — save the id (numeric function template ID):
{
"id": 1172,
"name": "{variableName}",
"legacyId": "calculation_{uuid}",
"variable": true,
...
}
Step 3: Register the Variable Control
Endpoint: PUT /api/content/v1/variable/controls
This step registers the control with the Domo control system. Without this step, the card save will return 400.
curl -X PUT "https://{instanceUrl}/api/content/v1/variable/controls" \
-H "X-DOMO-Developer-Token: {devToken}" \
-H "Content-Type: application/json" \
-d '[
{
"format": {"type": "default"},
"controlType": "VARIABLE",
"function": {
"name": "{variableName}",
"dataType": "{dataType}",
"expression": "{defaultExpression}",
"id": {functionTemplateId from Step 2}
},
"saveOverride": true,
"description": "",
"values": [
{"expression": {"value": "{value1}", "exprType": "{exprType}"}},
{"expression": {"value": "{value2}", "exprType": "{exprType}"}}
],
"type": "{controlType}",
"unsaved": false,
"name": "{variableName}"
}
]'
Key differences from Step 2's control:
function.id is now the real template ID from Step 2 (not -201)
unsaved: false (not true)
- No
id: -101 at the control level
- Body is an array of control objects
Response — returns an array with the registered control, including server-assigned id:
[
{
"id": 145,
"function": {"id": 1172, ...},
"type": "DROPDOWN",
"values": [...],
"controlType": "VARIABLE",
...
}
]
Step 4: Read the Current Card Definition
curl -X PUT "https://{instanceUrl}/api/content/v3/cards/kpi/definition" \
-H "X-DOMO-Developer-Token: {devToken}" \
-H "Content-Type: application/json" \
-d '{
"dynamicText": true,
"variables": true,
"urn": "{cardId}"
}'
Save the full response. You need definition.subscriptions, definition.controls, definition.charts, definition.modified, etc.
Get the dataSourceId from columns[].sourceId in the response.
Step 5: Save the Card with the New Control
Endpoint: PUT /api/content/v3/cards/kpi/{cardId}
Build the update payload by merging the new control into the card definition.
curl -X PUT "https://{instanceUrl}/api/content/v3/cards/kpi/{cardId}" \
-H "X-DOMO-Developer-Token: {devToken}" \
-H "Content-Type: application/json" \
-d '{
"definition": {
"subscriptions": {existing subscriptions from card def — do NOT add dataSourceId here},
"formulas": {"dsUpdated": [], "dsDeleted": [], "card": []},
"annotations": {"new": [], "modified": [], "deleted": []},
"conditionalFormats": {"card": [], "datasource": []},
"controls": [{existing controls with saveOverride: true}, {new control}],
"segments": {"active": [], "create": [], "update": [], "delete": []},
"charts": {existing charts},
"dynamicTitle": {existing dynamicTitle},
"dynamicDescription": {"text": []},
"chartVersion": "{existing chartVersion}",
"allowTableDrill": true,
"inputTable": false,
"modified": {existing modified timestamp},
"title": "{card title}",
"description": ""
},
"dataProvider": {"dataSourceId": "{dataSourceId}"},
"variables": true,
"columns": false
}'
Critical payload notes:
variables: true and columns: false at the top level
dataSourceId goes in dataProvider only — NOT in subscriptions.main
formulas uses the {dsUpdated, dsDeleted, card} structure (not the array format from the read response)
- Existing controls must be passed in their full server format with
saveOverride: true added
- The new control uses the simplified format with
function.id = the template ID from Step 2
- The
modified timestamp must match the card definition's value
Optional: Validate the Variable Formula
Endpoint: POST /api/query/v1/functions/validateFormulas
Validation is optional but recommended before creating. The formula entry must have "variable": true.
curl -X POST "https://{instanceUrl}/api/query/v1/functions/validateFormulas" \
-H "X-DOMO-Developer-Token: {devToken}" \
-H "Content-Type: application/json" \
-d '{
"dataSourceId": "{dataSourceId}",
"columns": [{column schema array}],
"formulas": {
"{formulaId}": {
"id": "{formulaId}",
"name": "{variableName}",
"formula": "{defaultExpression}",
"status": "valid",
"dataType": "{dataType}",
"variable": true,
"templateId": null,
"legacyId": "{formulaId}",
"formulaDependencies": []
}
}
}'
Using the Variable in a Beast Mode
A variable has no effect on a card unless it's referenced in a Beast Mode formula:
CASE
WHEN `My Variable` = 'Option A' THEN `column_a`
WHEN `My Variable` = 'Option B' THEN `column_b`
ELSE `column_a`
END
Variables are referenced by name in backticks, just like dataset columns.
Three-Tier Control Hierarchy
Variables have three levels of override:
- Default Control — Set in Beast Mode Editor (or via API). Baseline value.
- Card Variable Control — Override in Analyzer for a specific card. Does NOT transfer to dashboards.
- Dashboard Variable Control — Override on a specific dashboard. Resets on page refresh.
Using the CLI
The community-domo-cli handles the full 3-step flow automatically:
community-domo-cli variables check-name "My Variable"
community-domo-cli variables list {cardId}
community-domo-cli variables create {cardId} --body-file variable.json
community-domo-cli variables validate --body-file validate-payload.json
community-domo-cli cards definition {cardId}
Example: Create a string dropdown variable via CLI
variable.json:
{
"name": "Region Selector",
"type": "DROPDOWN",
"function": {
"name": "Region Selector",
"dataType": "string",
"expression": "'North'"
},
"description": "Select a region to filter by",
"values": [
{"expression": {"value": "North", "exprType": "STRING_VALUE"}},
{"expression": {"value": "South", "exprType": "STRING_VALUE"}},
{"expression": {"value": "East", "exprType": "STRING_VALUE"}},
{"expression": {"value": "West", "exprType": "STRING_VALUE"}}
]
}
community-domo-cli variables create 1810280719 --body-file variable.json --yes
The CLI automatically:
- Checks name uniqueness
- Creates the function template with embedded control
- Registers the control via
PUT /content/v1/variable/controls
- Reads the card definition
- Merges and saves the card
Troubleshooting
| Problem | Cause | Fix |
|---|
| Variable not visible on card | Not referenced in any beast mode | Create a beast mode that uses the variable |
| Card save returns 400 | Missing PUT /content/v1/variable/controls step | Must register the control before saving the card |
| Card save returns 400 | dataSourceId in subscriptions.main | Remove it — only put dataSourceId in dataProvider |
| Card save returns 400 | Existing controls not in full server format | Pass existing controls as-is from card def with saveOverride: true |
| 500 Internal database error | Duplicate variable name | Check name with GET /query/v1/functions/variables/uniqueName first |
Validation returns INVALID | Bad expression syntax | Check quotes for strings, function syntax for dates |
| Dashboard doesn't show variable control | Card-level override doesn't propagate | Set the control at dashboard level |
| Variable resets on dashboard refresh | Expected behavior | Dashboard controls reset to default on page load |
Output Format
When generating commands for the user, provide:
- What it does — one sentence explaining the variable
- The variable definition — name, type, default, control type, options
- Numbered commands — in execution order (all 3 steps), ready to copy/paste
- What to do with each response — especially saving the function template ID from Step 2
- Beast mode integration — show the formula that references the variable
- Verify — tell them to check the card in Domo after running