Programmatically adding Survey participants and sending emails to the participants

SendSurveyData Class
     {
         String surveyCode; //Mandatory
         Boolean resend; // Optional, need to send incase of resend
         String fromAddress; // Optional, overrides survey level setting
         String emailService;//Optional, overrides survey level setting. Possible values 'SALESFORCE','GAINSIGHT' and 'MARKETO'
         String templateId; //Optional email template ID, overrides survey level setting
         List<SurveyParticipant__c> participants;//Situational, required while sending emails to existing participants
         List<String> contactIds;//Situational, required while adding new participants using contact IDs
    }

1) API to add participants using contact IDs

Map<String,Object> response = JBCXM.CEHandler.addParticipants(JBCXM.CEHandler.SendSurveyData  surveyData,Integer versionNumber);
Response Map
// success case
{"status":"SUCCESS","participantIds": [participant ID list]}
// failure case
{"status":"FAILURE","errMsg": "Failure reason"}

2) API to send emails to the participants

Map<String,Object> response = JBCXM.CEHandler.sendSurvey(JBCXM.CEHandler.SendSurveyData  surveyData,Integer versionNumber);
Response Map
// success case
{"status":"SUCCESS","msg": "Appropriate message"}
// failure case
{"status":"FAILURE","errMsg": "Failure reason"}

Example batches to add participants and send survey emails(Use case : Sending survey to all contacts whose Account annual revenue is more than 200K)

Note 1 : Survey should be in Publish status

Note 2 : We cannot add participants and send emails using Gainsight or Marketo email services in same batch context due to Salesforce limitation hence two batches. More details @ https://help.salesforce.com/apex/HTViewSolution?id=000079772&language=en_US

Note 3 : Contacts who are opted out of Salesforce emails or found in Gainsight survey unsubscribe list will not be added as participants.

Note 4 : addParticipants API will not check whether the Contact is already added to the survey or not. It is upto the caller.

Batch to add participants

public class ParticipantsBatch implements Database.Batchable<sObject>, Database.Stateful, Database.AllowsCallouts{
    
    private String surveyCode = '';
    private List<String> allParticipantIds = new List<String>();
    public ParticipantsBatch(String surveyCode){
        this.surveyCode = surveyCode;
    }
    
    public Database.QueryLocator start(Database.BatchableContext BC) {
        return Database.getQueryLocator('Select Id From Contact Where Account.AnnualRevenue > 200000' );
    }
    
     public void execute(Database.BatchableContext BC, List<sObject> recordInfo) {
        List<Contact> contacts = (List<Contact>)recordInfo;
         List<String> contactIds = new List<String>();
         for (Contact c : contacts){
            contactIds.add(c.Id);
         }
         JBCXM.CEHandler.SendSurveyData surveyData = new JBCXM.CEHandler.SendSurveyData();
         surveyData.surveyCode = surveyCode;
         surveyData.contactIds = contactIds; 
         Map<String,Object> response = JBCXM.CEHandler.addParticipants(surveyData,1);
         String status = (String) response.get('status');
         if ('SUCCESS'.equalsIgnoreCase(status)){
            List<String> participantIds = (List<String>) response.get('participantIds');
            allParticipantIds.addAll(participantIds);
         }else{
             System.debug('Error while adding participants :' + response.get('errMsg'));
         }
     }
     
     public void finish(Database.BatchableContext BC){
            if(allParticipantIds.size() > 0 )
            {
                //Sending emails through a separate batch to avoid salesforce limitation
                SurveyEmailBatch batchObj = new SurveyEmailBatch(surveyCode,allParticipantIds);
                Database.executeBatch(batchObj,100);
            }
     }

}

Batch to send emails to the participants

public class SurveyEmailBatch implements Database.Batchable<sObject>, Database.AllowsCallouts, Database.Stateful {
    private List<String> participantIds = new List<String>();
    private String surveyCode = '';

    public SurveyEmailBatch(String surveyCode, List<String>  participantIds){
        this.participantIds = participantIds;
        this.surveyCode = surveyCode;
    }
    
    public Database.QueryLocator start(Database.BatchableContext BC) {
        return Database.getQueryLocator('select id from JBCXM__SurveyParticipant__c where Id in : participantIds' );
    }
    
     public void execute(Database.BatchableContext BC, List<sObject> recordInfo) {
        List<JBCXM__SurveyParticipant__c> participants = (List<JBCXM__SurveyParticipant__c>)recordInfo;
        JBCXM.CEHandler.SendSurveyData surveyData = new JBCXM.CEHandler.SendSurveyData();
        surveyData.resend = false;
        surveyData.surveyCode = surveyCode;
        surveyData.participants = participants;
        Map<String,Object> emailResponse = JBCXM.CEHandler.sendSurvey(surveyData,1);
          String status = (String) emailResponse.get('status');
        If (!'SUCCESS'.equalsIgnoreCase(status)){
             System.debug('Error while sending emails to participants :' + emailResponse.get('errMsg'));
         }
     }
     
     public void finish(Database.BatchableContext BC){}
}