Workflows define object lifecycle states and transitions. Automations execute actions in response to triggers and conditions. Together they control how objects move through business processes.
Workflow Definition
A workflow in a package consists of three asset types:
| Asset type | Purpose |
|---|---|
workflows | Defines the workflow entity (key, name) |
workflowStates | Defines states within the workflow (draft, review, approved, archived) |
workflowTransitionTriggers | Defines what triggers transitions between states |
Workflow States
Each state declares a key, a display name, an optional color for visual identification, and a position value that controls the order in the workflow diagram.
{
"workflowStates": [
{
"key": "draft",
"name": "Draft",
"color": "#6B7280",
"position": 1
},
{
"key": "review",
"name": "In Review",
"color": "#F59E0B",
"position": 2
},
{
"key": "approved",
"name": "Approved",
"color": "#10B981",
"position": 3
}
]
}
States are not ordered by their array position in the JSON. The position property determines the sequence in the UI.
Transition Triggers
Transition triggers define which state changes are allowed and what initiates them. A trigger specifies the source state, the target state, and the conditions under which the transition is permitted.
{
"workflowTransitionTriggers": [
{
"key": "submit_for_review",
"name": "Submit for Review",
"fromStateKey": "draft",
"toStateKey": "review"
},
{
"key": "approve",
"name": "Approve",
"fromStateKey": "review",
"toStateKey": "approved"
}
]
}
State-Scoped Permissions
Permissions can be restricted to specific combinations of workflow state and user relation type. This controls who can perform which actions at each stage of the lifecycle.
Condition Model
Conditions bind a UserRelationTypeKey and a WorkflowStateKey to a permission grant:
{
"conditions": [
{
"userRelationTypeKey": "core_business_owner",
"workflowStateKey": "draft",
"editable": true,
"visible": true
},
{
"userRelationTypeKey": "core_steward",
"workflowStateKey": "review",
"editable": true,
"visible": true
}
]
}
This configuration allows business owners to edit the object in draft state and stewards to edit it during review. Users without a matching relation-state combination see the object as read-only (or hidden, depending on the visible flag).
Both userRelationTypeKey and workflowStateKey must reference valid, existing entities. A condition with an invalid key does not raise an error — it silently evaluates to false, effectively denying the permission to all users in that state.
Condition Evaluation Rules
- Multiple conditions combine with OR logic. Any matching condition grants the specified access.
- A condition with only
userRelationTypeKey(no state key) applies across all workflow states. - A condition with only
workflowStateKey(no relation key) applies to all users regardless of their relation. - No conditions on an asset means the default access applies (visible and editable by all).
Since version 2025.5, the userRelationTypeKeys property on workflow transitions has been removed. Migrate by removing userRelationTypeKeys from transition definitions and creating equivalent conditions with userRelationType scope instead.
Automation Pipeline
Cascading actions continue after failure. If one action in an automation chain fails (invalid state transition, permission denied), the remaining actions still execute. A failed “change workflow state” followed by a “send notification” still sends the notification. Design automations defensively — put the most critical action first and consider splitting complex chains into separate automations with explicit triggers.
Automations execute a three-stage pipeline: trigger, stream (filter), and action.
Stage 1: Trigger
The trigger determines when the automation fires. Two trigger categories exist.
Event-based triggers:
| Event | Fires when |
|---|---|
| Object created | A new object of the specified type is created |
| Attribute changed | A specific attribute value is modified |
| Relation added | A new relation is created on the object |
| Relation removed | A relation is deleted from the object |
| Object deleted | An object is removed from the system |
| Workflow state changed | An object transitions to a new workflow state |
Schedule-based triggers:
| Schedule | Behavior |
|---|---|
| Daily | Fires once per day at the configured time |
| Weekly | Fires on the configured day and time |
| Custom cron | Fires on the specified cron schedule |
Schedule-based automations evaluate the stream filter against all objects of the target type at execution time.
Stage 2: Stream (Filter)
The stream narrows which objects the automation acts on. Without a stream filter, the action applies to every object that matches the trigger.
Filter criteria:
- Object type — restricts to specific object types
- Workflow state — matches objects in a specific state
- Attribute values — filters by attribute content (equals, contains, greater than, etc.)
- Relations — matches objects with specific relation types or targets
An automation without an object type filter affects ALL object types in the system. Always set an object type filter as the first criterion.
A missing or overly broad stream filter combined with a destructive action (attribute deletion, workflow state change) causes irreversible bulk changes. There is no undo for automation-triggered modifications.
Stage 3: Action
One or more actions execute on each object that passes the stream filter.
| Action type | Effect |
|---|---|
| Set attribute value | Writes a value to the specified attribute |
| Change workflow state | Transitions the object to a target state |
| Send notification | Dispatches an email or in-app notification |
| Add relation | Creates a relation from the object to a target |
| Remove relation | Deletes an existing relation |
| Run script | Executes a custom script |
Actions execute in the order they are defined. If an action fails (invalid state transition, permission denied), subsequent actions in the chain still execute.
Dynamic Expressions
Automations support dynamic expressions that resolve at execution time based on the current object and context.
Context Variables
| Variable | Resolves to |
|---|---|
@objectId | The ID of the current object in the stream |
@objectTypeKey | The object type key of the current object |
@currentUserId | The ID of the user who triggered the event (or system user for scheduled triggers) |
@now | The current timestamp |
Selectors
Selectors navigate the object graph to retrieve related data:
- Attribute selectors — read attribute values from the current object
- Relation selectors — traverse relations to access attributes on related objects
- Metadata selectors — access system fields (created date, modified date, creator)
Functions
Expressions support built-in functions for data transformation:
- String functions — concatenate, substring, replace, uppercase, lowercase
- Date functions — add days, difference between dates, format
- Conditional logic — if/then/else based on attribute values or relation existence
Expressions are evaluated once per object in the stream. Each object provides its own context for variable resolution.
Notification Configuration
Automation actions can dispatch notifications using predefined templates.
Template Structure
Notification templates define the message format for email and in-app delivery. Each template specifies:
- Subject — the notification title (supports dynamic expressions)
- Body — the message content (supports HTML and dynamic expressions)
- Module_Id — determines which module context the notification references, controlling the link destination when the user clicks the notification
- Recipients — defined by user relation types or explicit user references
Author Self-Suppression
The user who triggered the automation event does not receive the notification by default. This prevents users from receiving notifications about their own actions. Override this behavior in the notification template configuration if self-notification is required.
Complete Automation Example
An automation that notifies the business owner when an object moves to “review” state:
{
"key": "notify_owner_on_review",
"name": "Notify Owner on Review Submission",
"trigger": {
"event": "workflowStateChanged",
"toStateKey": "review"
},
"stream": {
"objectTypeKey": "cust_recipe"
},
"actions": [
{
"type": "sendNotification",
"templateKey": "review_notification",
"recipientRelationType": "core_business_owner"
}
]
}
The trigger fires when any cust_recipe object transitions to the “review” state. The action sends a notification to users assigned as business owners of that object.
Workflow Transition Triggers
Transition triggers automate workflow state changes based on user relation events. They are defined as a separate asset type (workflowTransitionTriggers) in the package.
| Trigger type | Fires when | Example use case |
|---|---|---|
user_relation_changed | A user relation on the object changes | Auto-advance from “draft” to “review” when a reviewer is assigned |
object_moved | An object is moved to a different parent | Reset to “draft” when object is reorganized |
Each trigger specifies:
type— the trigger event typechangeUserRelationTypeKey— which user relation type activates the triggerchangeToValueUserRelationTypeKey— optional: the target user relation valuepipelineKey— optional: a DFA pipeline to executeorderNumber— execution order when multiple triggers fire
The object_moved trigger type was added in 2025. It enables workflow automation based on hierarchy changes — useful for governance processes where moving an object between domains requires re-approval.
Comment Type Categories
Comment types define structured annotations tied to workflow processes. They are defined in commentTypeCategories and linked to applications via commentTypeCategoryApplications.
Each category has:
key,name— identitydefaultCommentTypeKey— the comment type selected by defaultisVisible— whether the category appears in the comment UIcommentTypes[]— array of comment types with key, name, and optional features
Comment types enable structured feedback during workflow transitions — for example, requiring a “rejection reason” comment when transitioning from “review” back to “draft”.
Approval Modes
Workflow transitions support approval modes via the changeThresholdTypeKey property on transitions.
| Mode | Behavior |
|---|---|
any | Any authorized user can trigger the transition |
majority | More than 50% of authorized users must approve |
all | All authorized users must approve |
This enables multi-stakeholder approval workflows where a business term requires sign-off from multiple owners before publication.
Gotchas
Unfiltered automation = system-wide impact. An automation without an object type filter in its stream processes every object in the system that matches the trigger event. A “set attribute” action without a type filter overwrites that attribute on every object. Always define the narrowest possible stream filter.
Silent condition failure. A condition that references a nonexistent UserRelationTypeKey or WorkflowStateKey does not produce an error. It evaluates to false for every user and state combination, effectively disabling the permission grant. Verify all keys exist before deploying workflow configurations.
Cascading actions continue after failure. If one action in an automation chain fails, the remaining actions still execute. A failed “change workflow state” followed by a “send notification” still sends the notification, even though the state change did not occur.
Test automations with narrow filters first, then expand scope gradually. Start with a single object type and a specific workflow state. Verify the behavior, then broaden the filter criteria incrementally.
Use schedule-based automations for batch operations (weekly reports, SLA escalation checks). Use event-based automations for immediate responses (notifications, attribute calculations).