Workflow Triggers
Triggers are the starting point of any workflow. They define when and how a workflow should be executed. This document covers the different types of triggers available in our system and how to configure them using YAML.
Types of Triggers
There are three main types of triggers:
- Entity Triggers
- Manual Triggers
- Scheduled Triggers
Entity Triggers
Entity triggers are used to execute workflows based on changes to specific entities in the system.
triggers:
- type: "Entity"
entityName: "Order"
eventType: "Modified"
position: "After"
conditions:
- expression: "[Order.Status] = 'Ready for Pickup'"
Configuration Options
type: Optional. Default is "Entity".entityName: Required. The name of the entity to watch (e.g., "Order", "Shipment").eventType: Required. Can be "Added", "Modified", or "Deleted".position: Optional. Can be "Before" or "After" database persistence. Default is "After".conditions: Optional. C# expressions to further filter when the trigger should fire.
Before vs After Position
The position attribute determines when the workflow executes relative to database persistence:
| Position | When It Fires | Entity Data State | Use Cases |
|---|---|---|---|
| Before | Before database save | Entity has pending changes, not yet committed | Data validation, field modification, approval gates |
| After | After database save (default) | Entity is committed to database | Notifications, audit logging, downstream integrations |
Important Considerations:
- Before triggers execute synchronously - exceptions will prevent the entity from being saved
- After triggers can execute asynchronously without blocking the save operation
- Modified events provide a
changesvariable in both positions showing field-level differences
Workflows with "Before" position triggers MUST use executionMode: Sync.
workflow:
name: "My Before Trigger Workflow"
executionMode: Sync # Required for Before triggers!
triggers:
- type: "Entity"
entityName: "Order"
eventType: "Modified"
position: "Before"
Why?
- "Before" triggers modify entities via
trackedEntitybeforeSaveChanges()is called - Async execution would run the workflow after the save completes, making modifications impossible
- Entity relationships contain circular references that cannot be serialized for async processing
The system will:
- Reject new workflows configured with
executionMode: Asyncand "Before" triggers - Force sync execution for existing misconfigured workflows (with a warning log)
Available Variables
Entity triggers provide several variables that can be used in your workflow:
| Variable | Description |
|---|---|
entity | The entity object that triggered the workflow (see entity-specific properties below) |
entityName | The type name of the entity (e.g., "Order", "Contact") |
organizationId | The organization ID |
eventType | The event type ("Added", "Modified", or "Deleted") |
position | The trigger position ("Before" or "After") |
changes | For "Modified" events only - contains field-level changes |
trackedEntity | For "Before" triggers only - the EF tracked entity for direct modification |
The changes Variable
For "Modified" events, a changes variable is available:
{
"field1": { "originalValue": "oldValue", "currentValue": "newValue" },
"field2": { "originalValue": "oldValue", "currentValue": "newValue" }
}
Entity Properties by Type
The entity variable contains different properties depending on the entity type. For performance and reliability, only scalar properties are included - collections and navigation properties are excluded to ensure efficient serialization.
Order Entity
When an Order triggers a workflow, the entity variable contains:
| Property | Type | Description |
|---|---|---|
OrderId | int | Primary key |
OrderNumber | string | Order number |
TrackingNumber | string? | Tracking number |
OrganizationId | int | Organization ID |
DivisionId | int | Division ID |
DivisionName | string? | Division name |
OrderType | enum | Order type (ParcelShipment, AirShipmentOrder, etc.) |
OrderTypeName | string | Order type as string |
OrderStatusId | int | Status ID |
OrderStatusName | string? | Status name |
LastOrderStatusModified | DateTime? | When status last changed |
BillToContactId | int? | Bill-to contact ID |
BillToContactName | string? | Bill-to contact name |
BillToContactAccountNumber | string? | Account number |
BillToContactType | enum? | Contact type |
EmployeeContactId | int? | Employee ID |
EmployeeContactName | string? | Employee name |
SalespersonContactId | int? | Salesperson ID |
SalespersonContactName | string? | Salesperson name |
EquipmentTypeId | int? | Equipment type ID |
EquipmentTypeName | string? | Equipment type name |
IsDraft | bool | Draft status |
Created | DateTime | Creation date |
CreatedBy | string | Created by user ID |
CreatedByUserName | string? | Created by username |
LastModified | DateTime | Last modified date |
LastModifiedBy | string | Modified by user ID |
LastModifiedByUserName | string? | Modified by username |
CustomValues | Dictionary | Custom field values |
Collections NOT included: Charges, Commodities, TrackingEvents, OrderDocuments, OrderEntities, Carriers, OrderCarriers, OrderCommodities
OrderCommodity Entity
When an OrderCommodity triggers a workflow, the entity variable contains:
| Property | Type | Description |
|---|---|---|
OrderId | int | Order ID |
CommodityId | int | Commodity ID |
OrderNumber | string? | Order number |
OrderTrackingNumber | string? | Order tracking number |
OrderOrganizationId | int? | Order's organization ID |
CommodityDescription | string? | Commodity description |
CommodityOrganizationId | int? | Commodity's organization ID |
CommodityStatusId | int? | Commodity status ID |
CommodityStatusName | string? | Commodity status name |
CommodityTypeId | int? | Commodity type ID |
CommodityTypeDescription | string? | Commodity type description |
CommodityTypeCode | string? | Commodity type code |
Pieces | int? | Number of pieces |
Weight | decimal? | Weight per piece |
WeightTotal | decimal? | Total weight |
WeightUnit | enum? | Weight unit |
Length | decimal? | Length |
Width | decimal? | Width |
Height | decimal? | Height |
DimensionsUnit | enum? | Dimensions unit |
VolumeTotal | decimal? | Total volume |
VolumeUnit | enum? | Volume unit |
Created | DateTime | Creation date |
CreatedBy | string | Created by user ID |
LastModified | DateTime | Last modified date |
LastModifiedBy | string | Modified by user ID |
CustomValues | Dictionary | OrderCommodity custom values |
CommodityCustomValues | Dictionary | Commodity custom values |
Navigation properties NOT included: Full Order object, full Commodity object with nested collections
Commodity Entity
When a Commodity triggers a workflow, the entity variable contains:
| Property | Type | Description |
|---|---|---|
CommodityId | int | Primary key |
OrganizationId | int | Organization ID |
Description | string | Commodity description |
Note | string? | Notes |
SerialNumber | string? | Serial number |
CommodityStatusId | int? | Status ID |
CommodityStatusName | string? | Status name |
CommodityTypeId | int? | Type ID |
CommodityTypeCode | string? | Type code |
CommodityTypeDescription | string? | Type description |
PackageTypeId | int? | Package type ID |
PackageTypeName | string? | Package type name |
Length | decimal? | Length |
Width | decimal? | Width |
Height | decimal? | Height |
DimensionsUnit | enum | Dimensions unit |
Weight | decimal? | Weight per piece |
WeightTotal | decimal? | Total weight |
WeightUnit | enum | Weight unit |
WeightByTotal | bool | Calculate weight by total |
VolumePiece | decimal? | Volume per piece |
VolumeTotal | decimal? | Total volume |
VolumeUnit | enum | Volume unit |
Pieces | int | Number of pieces |
Quantity | int? | Quantity |
Unit | string? | Unit of measure |
UnitaryValue | decimal? | Value per unit |
UnitaryValueTotal | decimal? | Total value |
ValueByTotal | bool | Calculate value by total |
WarehouseLocationId | int? | Location ID |
WarehouseLocationCode | string? | Location code |
ContainerCommodityId | int? | Parent container ID (no recursive object) |
JobId | Guid? | Job ID |
InventoryItemId | int? | Inventory item ID |
BillToContactId | int? | Bill-to contact ID |
BillToContactName | string? | Bill-to contact name |
IsDeleted | bool? | Deletion flag |
Created | DateTime | Creation date |
CreatedBy | string | Created by user ID |
LastModified | DateTime | Last modified date |
LastModifiedBy | string | Modified by user ID |
CustomValues | Dictionary | Custom field values |
Collections NOT included: OrderCommodities, ContainerCommodities, ContainerCommodity (recursive), CommodityTrackingNumbers, CommodityTags
AccountingTransaction Entity
When an AccountingTransaction triggers a workflow, the entity variable contains:
| Property | Type | Description |
|---|---|---|
AccountingTransactionId | int | Primary key |
OrganizationId | int | Organization ID |
TransactionNumber | string | Transaction number |
DivisionId | int | Division ID |
DivisionName | string? | Division name |
AccountId | int? | Account ID |
AccountName | string? | Account name |
AccountType | enum? | Account type |
AccountingTransactionStatus | enum | Transaction status |
AccountingTransactionType | enum | Transaction type (Invoice, Payment, CreditMemo) |
ApplyToContactId | int? | Contact ID |
ApplyToContactName | string? | Contact name |
ApplyToContactType | enum? | Contact type |
ApplyToContactAccountNumber | string? | Contact account number |
BillToContactAddressId | int? | Billing address ID |
BillToContactAddressLine | string? | Billing address line |
TransactionDate | DateTime | Transaction date |
DueDate | DateTime | Due date |
PaidDate | DateTime? | Payment date |
AmountDue | decimal | Amount due |
AmountPaid | decimal | Amount paid |
PaidAs | enum | Paid as (Receivable, Payable) |
PaymentTermsId | int? | Payment terms ID |
PaymentTermsDescription | string? | Payment terms description |
Note | string? | Notes |
IsDraft | bool | Draft status |
Created | DateTime | Creation date |
CreatedBy | string | Created by user ID |
LastModified | DateTime | Last modified date |
LastModifiedBy | string | Modified by user ID |
CustomValues | Dictionary | Custom field values |
Collections NOT included: Charges, Payments, AccountingTransactionCharges, AccountingTransactionPayments, Jobs
Fetching Related Data
To access related collections (charges, commodities, etc.), use GraphQL queries:
activities:
- name: getOrderData
steps:
- task: "Query/GraphQL"
name: "fetchOrder"
inputs:
query: |
query GetOrder($organizationId: Int!, $orderId: Int!) {
order(organizationId: $organizationId, orderId: $orderId) {
orderId
orderNumber
charges {
chargeId
description
amount
}
orderCommodities {
commodity {
commodityId
description
}
}
}
}
variables:
organizationId: "{{ organizationId }}"
orderId: "{{ entity.OrderId }}"
This approach:
- Ensures optimal performance with large orders (many charges, commodities, etc.)
- Allows fetching only the specific data needed
- Works reliably for both sync and async workflows
Example: Trigger on New High-Priority Order
triggers:
- type: "Entity"
entityName: "Order"
eventType: "Added"
position: "After"
conditions:
- expression: "[Order.Priority] = 'High'"
Example: Validate Order Before Save
Use a "Before" trigger to validate data or enforce business rules before the entity is persisted:
triggers:
- type: "Entity"
entityName: "Order"
eventType: "Modified"
position: "Before"
conditions:
- expression: "[changes.Status.currentValue] = 'Approved'"
This trigger fires before an Order's status change to "Approved" is saved, allowing the workflow to:
- Validate required fields are populated
- Check approval thresholds
- Modify related fields before persistence
Example: Before vs After for Status Changes
Before (Validation/Gate):
triggers:
- type: "Entity"
entityName: "Order"
eventType: "Modified"
position: "Before"
conditions:
- expression: "[changes.Status.currentValue] = 'Shipped'"
Use case: Verify all commodities have tracking numbers before allowing "Shipped" status.
After (Notification):
triggers:
- type: "Entity"
entityName: "Order"
eventType: "Modified"
position: "After"
conditions:
- expression: "[changes.Status.currentValue] = 'Shipped'"
Use case: Send shipment notification email after status is confirmed saved.
Modifying Entities with Before Triggers
A key capability of "Before" triggers is the ability to modify the entity before it's saved using the Entity/Change@1 task:
workflow:
triggers:
- type: "Entity"
entityName: "Order"
eventType: "Modified"
position: "Before"
conditions:
- expression: "[changes.Status.currentValue] = 'Ready for Pickup'"
activities:
- task: "Entity/Change@1"
name: setOrderPriority
inputs:
# Optional. If omitted, defaults to the entity from the trigger context.
entity: "{{ trigger.entity }}"
# Required. Properties to change (deep-merge with existing values).
values:
orderStatusId: 123
customValues:
priorityBucket: "HIGH"
This allows workflows to:
- Auto-populate fields based on business logic
- Set computed values before persistence
- Apply default values conditionally
- Enforce data standards across all saves
Manual Triggers
Manual triggers allow users to start workflows directly from the user interface.
triggers:
- type: "Manual"
displayName: "Process Rush Order"
additionalProperties:
silent: true
Configuration Options
type: Set to "Manual".displayName: Optional. The text shown on the trigger button in the UI.additionalProperties: Optional. Can includesilent: trueto suppress notifications.
Example: Manual Trigger for Inventory Audit
triggers:
- type: "Manual"
displayName: "Start Inventory Audit"
additionalProperties:
requireConfirmation: true
Scheduled Triggers
Scheduled triggers execute workflows at specified intervals using cron expressions.
schedules:
- cron: "0 0 * * 1"
displayName: "Weekly Report Generation"
Configuration Options
cron: Required. A cron expression defining the schedule.displayName: Optional. A human-readable name for the schedule.
Common Cron Patterns
- Every Monday at midnight:
0 0 * * 1 - Every 5 minutes:
*/5 * * * * - First day of every month at midnight:
0 0 1 * *
Example: Daily Shipment Summary
schedules:
- cron: "0 18 * * 1-5"
displayName: "Daily Shipment Summary (Weekdays at 6 PM)"
Best Practices
- Use meaningful names for your triggers, especially for manual and scheduled triggers.
- Keep conditions simple and focused. Complex conditions are better handled within the workflow logic.
- Choosing trigger position:
- Use
"After"(default) for notifications, logging, and integrations that don't need to block the save - Use
"Before"when you need to validate data, enforce business rules, or modify the entity before it's saved - Note: "Before" triggers run synchronously - errors will prevent the entity from saving
- Use
- Execution mode for Before triggers:
- Always use
executionMode: Syncwhen you have "Before" position triggers - The system will reject
executionMode: Asynccombined with "Before" triggers - This ensures entity modifications work correctly before persistence
- Always use
- Fetching related data:
- Entity trigger variables contain only scalar properties (no collections)
- Use GraphQL queries to fetch charges, commodities, and other related collections
- This ensures optimal performance for entities with large amounts of related data
- Use scheduled triggers sparingly to avoid overloading the system.
- Test your triggers thoroughly, especially when using complex cron expressions.
For more advanced cron expressions, use tools like CronTabGuru to ensure accuracy.