public static void ProcessChanges(string listID, ChangeToken lastChangeToken, DurableOrchestrationClient client, ILogger log) { using (var cc = new OfficeDevPnP.Core.AuthenticationManager().GetAppOnlyAuthenticatedContext(ConfigurationManager.AppSettings["siteUrl"], ConfigurationManager.AppSettings["clientId"], ConfigurationManager.AppSettings["clientSecret"])) { ChangeQuery changeQuery = new ChangeQuery(false, false); changeQuery.Item = true; changeQuery.Update = true; // could handle deletes too. Just need to know if approve or reject is assumed changeQuery.ChangeTokenStart = lastChangeToken; List changedList = cc.Web.GetListById(new Guid(listID)); var changes = changedList.GetChanges(changeQuery); cc.Load(changes); cc.ExecuteQuery(); foreach (Change change in changes) { if (change is ChangeItem) { ListItem task = changedList.GetItemById((change as ChangeItem).ItemId); ListItemVersionCollection taskVersions = task.Versions; cc.Load(taskVersions); cc.Load(task); cc.ExecuteQuery(); if (taskVersions.Count < 2) { return; } var currentStatus = (string)taskVersions[0]["Status"]; var priorStatus = (string)taskVersions[1]["Status"]; string wfid = (string)task["workflowId"]; Console.WriteLine($"Item # ${task.Id} current status is ${currentStatus} Prior status is ${priorStatus}"); switch ((string)task["Action"]) { case "DocOwnerApproval": if (currentStatus != priorStatus) { if (currentStatus == "Approve") { log.LogInformation("Sending event DocOwnerApproved"); client.RaiseEventAsync(wfid, "DocOwnerApproved"); } else { log.LogInformation("Sending event DocOwnerRejected"); client.RaiseEventAsync(wfid, "DocOwnerRejected"); } } break; case "StakeHolderApproval": if (currentStatus != priorStatus) { if (currentStatus == "Approve") { var eventName = "StakeHolderApproval:" + ((FieldUserValue)task["AssignedTo"]).LookupId; log.LogInformation($"Sending event '${eventName}'"); client.RaiseEventAsync(wfid, eventName, true); } else { log.LogInformation($"Sending event 'StakeHolderRejection'"); client.RaiseEventAsync(wfid, "StakeHolderRejection"); } } break; } } } }; }