--- title: "Automatic Live Call Scheduling" slug: "salesforce-automatic-live-session-scheduling" description: "Learn how to sync Live Calls with ServiceAppointments using Apex classes and Process Builder for seamless scheduling and rescheduling in Field Service." updated: 2021-10-12T02:11:34Z published: 2021-10-12T02:11:34Z canonical: "docs.screenmeet.com/salesforce-automatic-live-session-scheduling" --- > ## Documentation Index > Fetch the complete documentation index at: https://docs.screenmeet.com/llms.txt > Use this file to discover all available pages before exploring further. # Example: Automatic Live Call Scheduling A common use case is wanting to add live calls to scheduled events. In this example, we'll explore how to add Live Calls to the ServiceAppointment object. A live call will be created automatically whenever a ServiceAppointment is scheduled, and we'll keep the Live session scheduled start time in sync if the appointment is rescheduled. ## The Setup For this example, the instance we will be using is pre-configured with Field Service and the Lightning Scheduler. We will be working with the ServiceAppointment object. 1. We will use the Process Builder to set up a process to keep our live calls in sync with our **ServiceAppointments.** 2. First, we will create three Apex classes to work with our *ServiceAppointment*based Process. - *HookCreateScheduledLiveSession* - For scheduling a new live session. - *HookRescheduleLiveSession* - For re-scheduling an existing live session - *HookCancelScheduledLiveSession* - For cancelling a scheduled live session 3. We will use a trigger on the *ScreenMeet Live Session* object to ensure our *ServiceAppointment* is associated with our live call. 4. Then, we will set up our process to execute the correct hook when the appropriate conditions are met. ## Apex Code ### Create Live Session - HookCreateScheduledLiveSession This class will make a call to the ScreenMeet API to create a new ScreenMeet Session with the type of 'live' for an audio/video call. ```java public with sharing class HookCreateScheduledLiveSession { //@InvocableMethod allows Flow Processes to use this method @InvocableMethod(label='SM Schedule Future Call') public static void demoAppointmentProcessHook(List apptLst) { //We will receive the apptList object from Flow System.debug('Appointment Created - Creating SM Session ' + apptLst); for (ServiceAppointment apt : apptLst) { //We will look up the owner of the appointment so that we can create the live call on their behalf with the service account User owner = [SELECT Name FROM User WHERE Id = :apt.OwnerId]; //format the desired date into an ISO Date String String isoDate = (String)JSON.deserializeUntyped(JSON.Serialize(apt.SchedStartTime)); System.debug('CREATING APPOINTMENT FOR DATE:' + isoDate); //Perform the @future callout to the ScreenMeet API futureCreateScheduledSessionCallout(apt.id, 'Live Call for Appointment ' + apt.AppointmentNumber, apt.OwnerId, owner.Name, isoDate); } } //Asyncronous @future callout that does ScreenMeet API call @future(Callout=true) public static void futureCreateScheduledSessionCallout(String id, string label, string ownerId, string ownerName, string isoDate) { screenmeet.ScreenMeetAPI.ScreenMeetSessionParams newSession = new screenmeet.ScreenMeetAPI.ScreenMeetSessionParams( 'live', //session type id, //parentObjectId - in this case, the Service Appointment ID 'serviceappointment', //owner object type which will show back up in the ScreenMeet Live Session table ownerId, //owner id to enable ScreenMeet ACL functionality label, //the description of the call ownerName //name of the owner ); //the actual REST callout        //This avoids running API callouts during test execution which will fail because no real data is available if (!Test.isRunningTest()) { screenmeet.ScreenMeetApi.scheduleSession(newSession, isoDate); } System.debug('Scheduled appointment successfully: ' + newSession); } } ``` ### Reschedule Live Session - HookRescheduleLiveSession Sometimes we have to re-schedule our appointments. In this case, we will also want to reschedule our Live Call together with the appointment. ```java public with sharing class HookRescheduleLiveSession { @InvocableMethod(label='SM Update Scheduled Call') public static void demoAppointmentProcessHook(List apptLst) { System.debug('Appointment UPDATE - UPDATING SM Session' + apptLst); for (ServiceAppointment apt : apptLst) { //prepare new ISO Date String with new Appointment scheduled start time String isoDate = (String)JSON.deserializeUntyped(JSON.Serialize(apt.SchedStartTime)); screenmeet__Live_Session__c smSession = [SELECT Id, screenmeet__Session_Id__c from screenmeet__Live_Session__c where Id = :apt.ScreenMeet_Live_Session__c]; futureRescheduleCallout(smSession.screenmeet__Session_Id__c, isoDate); } } @future(Callout=true) public static void futureRescheduleCallout(String SmSessionId, string isoDate) { //Make call to ScreenMeet API //This avoids running API callouts during test execution which will fail because no real data is available if (!Test.isRunningTest()) {                   screenmeet.ScreenMeetApi.rescheduleRemoteSession(SmSessionId, isoDate); } System.debug('Rescheduled live session ' + SmSessionId + ' for ' + isoDate); } } ``` ### Cancel Live Session - HookCancelScheduledLiveSession Finally, an example showing how to cancel a live session. ```java public with sharing class HookCancelScheduledLiveSession { @InvocableMethod(label='SM Cancel Scheduled Call') public static void demoHookCancelScheduledLiveSession(List apptLst) { System.debug('Appointment UPDATE - CLOSING SM Session' + apptLst); for (ServiceAppointment apt : apptLst) { //find the linked ScreenMeet Live Session object screenmeet__Live_Session__c smSession = [SELECT Id, screenmeet__Session_Id__c from screenmeet__Live_Session__c where Id = :apt.ScreenMeet_Live_Session__c]; futureCloseSessionCallout(smSession.screenmeet__Session_Id__c, apt.Id); } } @future(Callout=true) public static void futureCloseSessionCallout(String SmSessionId, String svcAptId) { screenmeet.ScreenMeetApi.closeRemoteSession(SmSessionId); //remove the related object reference from the appointment lookup when we cancel the appointment if (!Test.isRunningTest()) { ServiceAppointment apt = [SELECT Id, ScreenMeet_Live_Session__c from ServiceAppointment where Id = :svcAptId]; } //remove reference to closed object apt.ScreenMeet_Live_Session__c = null; update apt; System.debug('Close ScreenMeet live session ' + SmSessionId + ' for appt ' + svcAptId); } } ``` ## Update ServiceAppointment via Trigger - LinkScheduledServiceAppointment Because of the asynchronous nature of interacting with the ScreenMeet API, we won't instantly have the newly created *ScreenMeet Session* object to update our *ServiceAppointment* object. Instead, we will add a trigger to the *ScreenMeet Live Session* table to update our *ServiceAppointment*. Adding a Custom field to ServiceAppointmentNOTE: In order to track whether a ServiceAppointment has a live session associated with it or not, we are going to add two custom Lookup fields to ServiceAppointment called *ScreenMeet_Live_Session__c* and *ScreenMeet_Live_Session_URL__c.* ```java trigger LinkScheduledServiceAppointment on screenmeet__Live_Session__c (after insert) { if (Trigger.isInsert) { for (screenmeet__Live_Session__c ls: Trigger.new) { //only associate to service appointment when the parent object is a service appointment and the status is scheduled. if (ls.screenmeet__parentObjectType__c == 'serviceappointment' && ls.screenmeet__Status__c == 'scheduled') { System.debug('New service appointment being created'); ServiceAppointment svcApt = [SELECT ScreenMeet_Live_Session__c, Id FROM ServiceAppointment where Id = :ls.screenmeet__parentObjectId__c]; svcApt.ScreenMeet_Live_Session__c = ls.Id; svcApt.ScreenMeet_Live_Session_URL__c = ls.screenmeet__user_url__c; update svcApt; System.debug('Associated newly created SM session ' + svcApt.id + ' with SVC Appointment ' + svcApt.Id); } } } } ``` ## Configuring Flow Process Builder We are going to use the Process Builder from **Setup** to build our process to run our three Apex classes. Here is the general configuration we use for this example: | Let's take a look at what is happening our process here: **1. We have a rule based on ServiceAppointments to see if we need to Create a Live Call **to execute the *HookCreateScheduledLiveSession* Apex code.**** The rule set for creating a new session is:SchedStartTime is NOT NULL ScreenMeet_LiveSession__c IS NULL Status is NOT (Canceled, Cannot Complete, Completed)Basically, we want to make sure that there is a scheduled start time for the appointment, that no live session has already been created for this appointment, and that the status us valid. **2. We have a rule to determine if we need to reschedule the live call, which will execute *HookRescheduleLiveSession*.**SchedStartTime is NOT NULL AND HAS CHANGED ScreenMeet_LiveSession__c IS NOT NULL Status is NOT (Canceled, Cannot Complete, Completed)This rule is similar to the first rule, but since the live call has already been created, we need to reschedule it. **3. Finally, we have a rule to determine if we need to cancel the Live Session call in case the Appointment was cancelled. This will execute the code in *HookCancelScheduledLiveSession*.** SchedStartTime HAS CHANGED AND IS NULL OR (Status has changed to (Canceled, Completed, Cannot Complete) AND we have a Live Session) | ![](https://cdn.document360.io/9da39725-20e5-434f-83a4-d630456099dc/Images/Documentation/image-19.png) | | --- | --- |