Module Schema Reference
A comprehensive reference for all available options when building module schemas for Stacksync Workflows.
Schema Structure
Root Schema Object
{
"metadata": {
"workflows_module_schema_version": "1.0.0"
},
"fields": [...],
"ui_options": {...}
}
Required Properties:
metadata
- Schema metadata configurationfields
- Array of field definitions
Optional Properties:
ui_options
- Global UI configuration options
Metadata Configuration
workflows_module_schema_version
Type: String
Required: Yes
Default: "1.0.0"
Description: Specifies the schema version for compatibility
{
"metadata": {
"workflows_module_schema_version": "1.0.0"
}
}
Field Types
String Fields
Basic String Field:
{
"id": "field_name",
"type": "string",
"label": "Display Label",
"description": "Field description",
"default": "Default value"
}
Properties:
id
(string, required) - Unique field identifiertype
(string, required) - Must be "string"label
(string, optional) - Display label for the fielddescription
(string, optional) - Help text for usersdefault
(string, optional) - Default value
Number Fields
Basic Number Field:
{
"id": "count",
"type": "number",
"label": "Count",
"default": 0
}
Properties:
id
(string, required) - Unique field identifiertype
(string, required) - Must be "number"label
(string, optional) - Display labeldefault
(number, optional) - Default numeric value
Integer Fields
Basic Integer Field:
{
"id": "whole_number",
"type": "integer",
"label": "Whole Number",
"default": 1
}
Boolean Fields
Basic Boolean Field:
{
"id": "enable_feature",
"type": "boolean",
"label": "Enable Feature",
"default": false
}
Connection Fields
Connection Field:
{
"type": "connection",
"id": "api_connection",
"label": "API Connection",
"allowed_app_types": ["salesforce", "hubspot"],
"allowed_connection_management_types": ["managed", "custom"]
}
Properties:
allowed_app_types
(array, required) - List of supported connection typesallowed_connection_management_types
(array, required) - Connection management options
Supported App Types:
salesforce
- Salesforce CRMhubspot
- HubSpot CRMpostgres
- PostgreSQL databasemysql
- MySQL databasecustom_api
- Custom API connections
Connection Management Types:
managed
- Platform-managed connectionscustom
- User-provided credentials
Object Fields
Simple Object Field:
{
"type": "object",
"id": "settings",
"label": "Settings",
"fields": [
{
"id": "name",
"type": "string",
"label": "Name"
}
]
}
Object with Choices:
{
"type": "object",
"id": "platform",
"label": "Platform",
"choices": {
"values": [
{
"value": { "id": "linkedin", "label": "LinkedIn" },
"label": "LinkedIn"
}
]
}
}
Array Fields
String Array:
{
"type": "array",
"id": "tags",
"label": "Tags",
"items": {
"type": "string",
"label": "Tag"
}
}
Object Array:
{
"type": "array",
"id": "users",
"label": "Users",
"items": {
"type": "object",
"fields": [
{
"id": "name",
"type": "string",
"label": "Name"
}
]
}
}
UI Widgets
Available Widgets
input (default for strings)
{
"ui_options": {
"ui_widget": "input"
}
}
textarea (multi-line text)
{
"ui_options": {
"ui_widget": "textarea"
}
}
password (hidden text input)
{
"ui_options": {
"ui_widget": "password"
}
}
SelectWidget (dropdown selection)
{
"ui_options": {
"ui_widget": "SelectWidget"
}
}
checkbox (boolean checkbox)
{
"ui_options": {
"ui_widget": "checkbox"
}
}
CodeblockWidget (code editor)
{
"ui_options": {
"ui_widget": "CodeblockWidget",
"ui_options": {
"language": "json"
}
}
}
hidden (hidden field)
{
"ui_options": {
"ui_widget": "hidden"
}
}
CodeblockWidget Languages
Supported syntax highlighting languages:
json
- JSON formatsql
- SQL queriesjavascript
- JavaScript codepython
- Python codeyaml
- YAML configurationxml
- XML markuphtml
- HTML markupcss
- CSS styling
Validation Rules
Basic Validation
required - Field is mandatory
{
"validation": {
"required": true
}
}
min_length - Minimum string length
{
"validation": {
"min_length": 3
}
}
max_length - Maximum string length
{
"validation": {
"max_length": 100
}
}
minimum - Minimum numeric value
{
"validation": {
"minimum": 0
}
}
maximum - Maximum numeric value
{
"validation": {
"maximum": 1000
}
}
pattern - Regular expression validation
{
"validation": {
"pattern": "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$"
}
}
Format Validation
email - Email address format
{
"format": "email"
}
uri - URI format
{
"format": "uri"
}
date - Date format (YYYY-MM-DD)
{
"format": "date"
}
date-time - Date-time format (ISO 8601)
{
"format": "date-time"
}
uuid - UUID format
{
"format": "uuid"
}
Dynamic Content
Basic Content Configuration
{
"content": {
"type": ["managed"],
"content_objects": [
{
"id": "users"
}
]
}
}
Properties:
type
(array, required) - Content management typescontent_objects
(array, required) - List of content objects to fetch
Content Management Types:
managed
- Platform manages the content loadingcustom
- Custom content loading logic
Content Dependencies
Field-dependent content:
{
"content": {
"type": ["managed"],
"content_objects": [
{
"id": "users_in_channel",
"content_object_depends_on_fields": [
{
"id": "channel"
}
]
}
]
}
}
Array item dependencies:
{
"content_object_depends_on_fields": [
{
"id": "channels.items"
}
]
}
Choices Configuration
Static Choices
Simple string choices:
{
"choices": {
"values": [
{ "value": "option1", "label": "Option 1" },
{ "value": "option2", "label": "Option 2" }
]
}
}
Object choices:
{
"choices": {
"values": [
{
"value": { "id": "contact", "label": "Contact" },
"label": "Contact"
},
{
"value": { "id": "lead", "label": "Lead" },
"label": "Lead"
}
]
}
}
Dynamic Choices
Empty choices for dynamic loading:
{
"choices": {
"values": []
}
}
Schema Rules (Conditional Logic)
Basic Rules Structure
{
"rules": [
{
"if": {
"and": [
{
"id": "field_id",
"operator": "equal",
"value": "expected_value"
}
]
},
"then": {
"fields": [
{
"id": "target_field",
"ui_options": {
"ui_widget": "hidden"
},
"apply_as": "merge"
}
]
}
}
]
}
Condition Operators
equal - Exact match
{
"id": "status",
"operator": "equal",
"value": "active"
}
not_equal - Not equal to
{
"id": "status",
"operator": "not_equal",
"value": "inactive"
}
is_in - Value in array
{
"id": "category",
"operator": "is_in",
"value": ["premium", "enterprise"]
}
is_not_in - Value not in array
{
"id": "category",
"operator": "is_not_in",
"value": ["free", "trial"]
}
is_empty - Field is empty
{
"id": "optional_field",
"operator": "is_empty"
}
is_not_empty - Field has value
{
"id": "required_field",
"operator": "is_not_empty"
}
greater_than - Numeric comparison
{
"id": "count",
"operator": "greater_than",
"value": 10
}
less_than - Numeric comparison
{
"id": "count",
"operator": "less_than",
"value": 100
}
Logic Combinators
and - All conditions must be true
{
"and": [
{ "id": "field1", "operator": "equal", "value": "value1" },
{ "id": "field2", "operator": "equal", "value": "value2" }
]
}
or - Any condition must be true
{
"or": [
{ "id": "field1", "operator": "equal", "value": "value1" },
{ "id": "field2", "operator": "equal", "value": "value2" }
]
}
Rule Effects
apply_as options:
merge
- Merge with existing field configurationfully_replace
- Replace entire field configuration
Show/Hide Fields:
{
"then": {
"fields": [
{
"id": "conditional_field",
"ui_options": {
"ui_widget": null
},
"apply_as": "merge"
}
]
}
}
Hide Fields:
{
"then": {
"fields": [
{
"id": "conditional_field",
"ui_options": {
"ui_widget": "hidden"
},
"apply_as": "merge"
}
]
}
}
UI Layout Options
Global UI Options
Field Ordering:
{
"ui_options": {
"ui_order": ["field1", "field2", "field3"]
}
}
Field-Level UI Options
Horizontal Layout:
{
"ui_options": {
"ui_layout": {
"type": "horizontal",
"elements": ["first_name", "last_name"]
}
}
}
Advanced Features
Action Handlers
Action handlers define what should happen when users interact with fields. They trigger specific behaviors when field values change.
load_schema
Purpose: Triggers a schema reload when the field value changes, allowing for dynamic updates to other fields based on the new value.
Basic Usage:
{
"id": "country",
"type": "string",
"label": "Country",
"on_action": {
"load_schema": true
}
}
What happens when load_schema
is triggered:
You change the value of the field
country
A trigger sends an HTTP POST request to the module /schema endpoint with :
the full schema
the full form data
the full content objects
The module returns a new schema
The new schema is merged with the existing schema
The frontend updates the UI to reflect the new schema
Common Use Cases
Use Case 1: Cascading Dropdowns
{
"id": "country",
"type": "object",
"label": "Country",
"on_action": {
"load_schema": true
},
"choices": {
"values": [
{"value": {"id": "us", "label": "United States"}, "label": "United States"},
{"value": {"id": "ca", "label": "Canada"}, "label": "Canada"}
]
}
},
{
"id": "state",
"type": "object",
"label": "State/Province",
"content": {
"type": ["managed"],
"content_objects": [
{
"id": "states_by_country",
"content_object_depends_on_fields": [
{"id": "country"}
]
}
]
}
}
Use Case 2: Conditional Field Display
{
"id": "data_source",
"type": "string",
"label": "Data Source",
"on_action": {
"load_schema": true
},
"choices": {
"values": [
{"value": "database", "label": "Database"},
{"value": "api", "label": "API"},
{"value": "file", "label": "File"}
]
}
},
{
"id": "database_config",
"type": "object",
"label": "Database Configuration",
"rules": [
{
"if": {
"and": [
{
"id": "data_source",
"operator": "equal",
"value": "database"
}
]
},
"then": {
"fields": [
{
"id": "database_config",
"ui_options": {
"ui_widget": null
},
"apply_as": "merge"
}
]
}
}
]
}
Use Case 3: Dynamic Validation
{
"id": "field_type",
"type": "string",
"label": "Field Type",
"on_action": {
"load_schema": true
},
"choices": {
"values": [
{"value": "email", "label": "Email"},
{"value": "phone", "label": "Phone"},
{"value": "text", "label": "Text"}
]
}
},
{
"id": "field_value",
"type": "string",
"label": "Field Value",
"rules": [
{
"if": {
"and": [
{
"id": "field_type",
"operator": "equal",
"value": "email"
}
]
},
"then": {
"fields": [
{
"id": "field_value",
"format": "email",
"validation": {
"pattern": "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$"
},
"apply_as": "merge"
}
]
}
}
]
}
Backend Implementation
When load_schema: true
is triggered, your /content
endpoint receives the updated form data:
@router.route("/content", methods=["POST"])
def content():
try:
request = Request(flask_request)
data = request.data
# Get updated form data after field change
form_data = data.get("form_data", {})
content_object_names = data.get("content_object_names", [])
content_objects = []
for content_name in content_object_names:
if content_name == "states_by_country":
# Get the selected country from updated form data
selected_country = form_data.get("country", {})
country_id = selected_country.get("id") if selected_country else None
if country_id == "us":
states = [
{"value": {"id": "ca", "label": "California"}, "label": "California"},
{"value": {"id": "ny", "label": "New York"}, "label": "New York"}
]
elif country_id == "ca":
states = [
{"value": {"id": "on", "label": "Ontario"}, "label": "Ontario"},
{"value": {"id": "bc", "label": "British Columbia"}, "label": "British Columbia"}
]
else:
states = []
content_objects.append({
"content_object_name": "states_by_country",
"data": states
})
return Response(data={"content_objects": content_objects})
except Exception as e:
return Response.error(str(e))
Performance Considerations
Use Sparingly: Only add
load_schema: true
to fields that actually need to trigger updatesOptimize Backend: Ensure your
/content
endpoint responds quickly to avoid UI lagCache When Possible: Cache static data that doesn't change between requests
Batch Updates: If multiple fields need to trigger updates, consider grouping them
Best Practices
Clear User Feedback: Show loading indicators when schema is reloading
Preserve User Input: Ensure field values aren't lost during reload
Error Handling: Gracefully handle failures in content loading
Debouncing: Consider debouncing rapid field changes to avoid excessive requests
Debugging Tips
Check browser network tab to see
/content
requests when fields changeVerify that
content_object_depends_on_fields
references match your field IDs exactlyTest with browser console open to catch any JavaScript errors
Use simple test data first, then add complexity
Complete Field Example
Here's a comprehensive example showing most available options:
{
"id": "user_email",
"type": "string",
"label": "User Email",
"description": "Enter the user's email address",
"default": "",
"format": "email",
"validation": {
"required": true,
"pattern": "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$"
},
"validation_messages": {
"required": "Email is required for notifications",
"pattern": "Please enter a valid email address"
},
"ui_options": {
"ui_widget": "input"
},
"on_action": {
"load_schema": true
},
"rules": [
{
"if": {
"and": [
{
"id": "user_email",
"operator": "is_not_empty"
}
]
},
"then": {
"fields": [
{
"id": "send_notification",
"ui_options": {
"ui_widget": null
},
"apply_as": "merge"
}
]
}
}
]
}
This specification covers all major aspects of module schema configuration. Refer to this document when building your schemas to understand all available options and their proper usage.
Last updated