Skip to main content

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:

  1. Entity Triggers
  2. Manual Triggers
  3. 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:

PositionWhen It FiresEntity Data StateUse Cases
BeforeBefore database saveEntity has pending changes, not yet committedData validation, field modification, approval gates
AfterAfter database save (default)Entity is committed to databaseNotifications, 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 changes variable in both positions showing field-level differences
Before Triggers Require Sync Execution Mode

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 trackedEntity before SaveChanges() 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:

  1. Reject new workflows configured with executionMode: Async and "Before" triggers
  2. 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:

VariableDescription
entityThe entity object that triggered the workflow (see entity-specific properties below)
entityNameThe type name of the entity (e.g., "Order", "Contact")
organizationIdThe organization ID
eventTypeThe event type ("Added", "Modified", or "Deleted")
positionThe trigger position ("Before" or "After")
changesFor "Modified" events only - contains field-level changes
trackedEntityFor "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:

PropertyTypeDescription
OrderIdintPrimary key
OrderNumberstringOrder number
TrackingNumberstring?Tracking number
OrganizationIdintOrganization ID
DivisionIdintDivision ID
DivisionNamestring?Division name
OrderTypeenumOrder type (ParcelShipment, AirShipmentOrder, etc.)
OrderTypeNamestringOrder type as string
OrderStatusIdintStatus ID
OrderStatusNamestring?Status name
LastOrderStatusModifiedDateTime?When status last changed
BillToContactIdint?Bill-to contact ID
BillToContactNamestring?Bill-to contact name
BillToContactAccountNumberstring?Account number
BillToContactTypeenum?Contact type
EmployeeContactIdint?Employee ID
EmployeeContactNamestring?Employee name
SalespersonContactIdint?Salesperson ID
SalespersonContactNamestring?Salesperson name
EquipmentTypeIdint?Equipment type ID
EquipmentTypeNamestring?Equipment type name
IsDraftboolDraft status
CreatedDateTimeCreation date
CreatedBystringCreated by user ID
CreatedByUserNamestring?Created by username
LastModifiedDateTimeLast modified date
LastModifiedBystringModified by user ID
LastModifiedByUserNamestring?Modified by username
CustomValuesDictionaryCustom 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:

PropertyTypeDescription
OrderIdintOrder ID
CommodityIdintCommodity ID
OrderNumberstring?Order number
OrderTrackingNumberstring?Order tracking number
OrderOrganizationIdint?Order's organization ID
CommodityDescriptionstring?Commodity description
CommodityOrganizationIdint?Commodity's organization ID
CommodityStatusIdint?Commodity status ID
CommodityStatusNamestring?Commodity status name
CommodityTypeIdint?Commodity type ID
CommodityTypeDescriptionstring?Commodity type description
CommodityTypeCodestring?Commodity type code
Piecesint?Number of pieces
Weightdecimal?Weight per piece
WeightTotaldecimal?Total weight
WeightUnitenum?Weight unit
Lengthdecimal?Length
Widthdecimal?Width
Heightdecimal?Height
DimensionsUnitenum?Dimensions unit
VolumeTotaldecimal?Total volume
VolumeUnitenum?Volume unit
CreatedDateTimeCreation date
CreatedBystringCreated by user ID
LastModifiedDateTimeLast modified date
LastModifiedBystringModified by user ID
CustomValuesDictionaryOrderCommodity custom values
CommodityCustomValuesDictionaryCommodity 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:

PropertyTypeDescription
CommodityIdintPrimary key
OrganizationIdintOrganization ID
DescriptionstringCommodity description
Notestring?Notes
SerialNumberstring?Serial number
CommodityStatusIdint?Status ID
CommodityStatusNamestring?Status name
CommodityTypeIdint?Type ID
CommodityTypeCodestring?Type code
CommodityTypeDescriptionstring?Type description
PackageTypeIdint?Package type ID
PackageTypeNamestring?Package type name
Lengthdecimal?Length
Widthdecimal?Width
Heightdecimal?Height
DimensionsUnitenumDimensions unit
Weightdecimal?Weight per piece
WeightTotaldecimal?Total weight
WeightUnitenumWeight unit
WeightByTotalboolCalculate weight by total
VolumePiecedecimal?Volume per piece
VolumeTotaldecimal?Total volume
VolumeUnitenumVolume unit
PiecesintNumber of pieces
Quantityint?Quantity
Unitstring?Unit of measure
UnitaryValuedecimal?Value per unit
UnitaryValueTotaldecimal?Total value
ValueByTotalboolCalculate value by total
WarehouseLocationIdint?Location ID
WarehouseLocationCodestring?Location code
ContainerCommodityIdint?Parent container ID (no recursive object)
JobIdGuid?Job ID
InventoryItemIdint?Inventory item ID
BillToContactIdint?Bill-to contact ID
BillToContactNamestring?Bill-to contact name
IsDeletedbool?Deletion flag
CreatedDateTimeCreation date
CreatedBystringCreated by user ID
LastModifiedDateTimeLast modified date
LastModifiedBystringModified by user ID
CustomValuesDictionaryCustom field values

Collections NOT included: OrderCommodities, ContainerCommodities, ContainerCommodity (recursive), CommodityTrackingNumbers, CommodityTags

AccountingTransaction Entity

When an AccountingTransaction triggers a workflow, the entity variable contains:

PropertyTypeDescription
AccountingTransactionIdintPrimary key
OrganizationIdintOrganization ID
TransactionNumberstringTransaction number
DivisionIdintDivision ID
DivisionNamestring?Division name
AccountIdint?Account ID
AccountNamestring?Account name
AccountTypeenum?Account type
AccountingTransactionStatusenumTransaction status
AccountingTransactionTypeenumTransaction type (Invoice, Payment, CreditMemo)
ApplyToContactIdint?Contact ID
ApplyToContactNamestring?Contact name
ApplyToContactTypeenum?Contact type
ApplyToContactAccountNumberstring?Contact account number
BillToContactAddressIdint?Billing address ID
BillToContactAddressLinestring?Billing address line
TransactionDateDateTimeTransaction date
DueDateDateTimeDue date
PaidDateDateTime?Payment date
AmountDuedecimalAmount due
AmountPaiddecimalAmount paid
PaidAsenumPaid as (Receivable, Payable)
PaymentTermsIdint?Payment terms ID
PaymentTermsDescriptionstring?Payment terms description
Notestring?Notes
IsDraftboolDraft status
CreatedDateTimeCreation date
CreatedBystringCreated by user ID
LastModifiedDateTimeLast modified date
LastModifiedBystringModified by user ID
CustomValuesDictionaryCustom field values

Collections NOT included: Charges, Payments, AccountingTransactionCharges, AccountingTransactionPayments, Jobs

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 include silent: true to 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

  1. Use meaningful names for your triggers, especially for manual and scheduled triggers.
  2. Keep conditions simple and focused. Complex conditions are better handled within the workflow logic.
  3. 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
  4. Execution mode for Before triggers:
    • Always use executionMode: Sync when you have "Before" position triggers
    • The system will reject executionMode: Async combined with "Before" triggers
    • This ensures entity modifications work correctly before persistence
  5. 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
  6. Use scheduled triggers sparingly to avoid overloading the system.
  7. Test your triggers thoroughly, especially when using complex cron expressions.

For more advanced cron expressions, use tools like CronTabGuru to ensure accuracy.