In Salesforce, you cannot directly trigger a Flow or Apex Trigger when a Sales Engagement Cadence is completed, because Salesforce does not expose a native “Cadence Completed” event or field out-of-the-box that Flows or Apex can monitor.
However, you can work around this limitation depending on what your goal is. Here is an overview of the solution using Change Data Capture and Apex trigger on CDC event:
STEP 1: Enable Change Data Capture for the ActionCadenceStepTracker
object as mentioned in the following screenshot.

STEP 2: Create an Apex Trigger on the ActionCadenceStepTrackerChangeEvent object
This Apex trigger runs on the ActionCadenceStepTracker
Change Event. It checks whether the State
field has been updated to 'Completed'
and verifies if the completed step is the last step in the cadence. If both conditions are met, it further checks if the cadence name is either "My Sample Cadence 1"
or "My Sample Cadence 2"
. If the cadence is related to an Opportunity, the trigger updates the Opportunity’s Description
field.
You can modify the logic and update different records based on your specific requirements.
trigger ActionCadenceStepTrackerCDCTrigger on ActionCadenceStepTrackerChangeEvent (after insert) {
set<Id> ActionCadenceStepTrackerIds = new set<Id>();
for(ActionCadenceStepTrackerChangeEvent event : Trigger.New) {
EventBus.ChangeEventHeader header = event.ChangeEventHeader;
System.debug('Received change event for ' +
header.entityName +
' for the ' +
header.changeType +
' operation.'
);
system.debug('event::'+event);
List<String> changedFields = event.ChangeEventHeader.getChangedFields();
Boolean isStateCompleted = 'Completed'.equals(event.State);
Boolean isStateFieldChanged = changedFields.contains('State');
if (header.changeType.equalsIgnoreCase('update') && isStateCompleted && isStateFieldChanged) {
for(Id recordId : header.getRecordIds()){
ActionCadenceStepTrackerIds.add(recordId);
}
}
}
Map<Id, ActionCadenceStepTracker> ActionCadenceStepTrackerMap = new Map<Id, ActionCadenceStepTracker>([SELECT Id, ActionCadenceName, ActionCadenceTrackerId, ActionCadenceTracker.State, ActionCadenceTracker.CurrentStepId, ActionCadenceTracker.RelatedToId, StepTitle, State, ActionCadenceId FROM ActionCadenceStepTracker WHERE ID IN :ActionCadenceStepTrackerIds]);
system.debug('ActionCadenceStepTrackerMap::'+ActionCadenceStepTrackerMap);
for(ActionCadenceStepTracker acst : ActionCadenceStepTrackerMap.values()){
if((acst.ActionCadenceName == 'My Sample Cadence 1' || acst.ActionCadenceName == 'My Sample Cadence 2') && acst.State == 'Completed' && acst.ActionCadenceTracker.CurrentStepId == NULL && acst.ActionCadenceTracker.State == 'Complete') {
system.debug(acst.ActionCadenceName+' cadence completed.');
//Example of Performing an action on the Opportunity
if(acst.ActionCadenceTracker.RelatedToId != NULL && String.valueOf(acst.ActionCadenceTracker.RelatedToId).StartsWith('006')){
Opportunity opp = new Opportunity(Id = acst.ActionCadenceTracker.RelatedToId);
opp.Description = acst.ActionCadenceName+' cadence completed.';
update opp;
}
}
}
}