DocuSign Integration in Salesforce

Step 1: Create a DocuSign account using the below link.

https://www.docusign.com/

Step 2: After creating the account, Go to settings → apps and keys and create a new connected app for integration. After creating the app, save the integration key and private key.

Step 3: Create remote site settings in salesforce via setup → remote site settings

Step 4: Create a custom metadata record to store docusign credentials.

Step 5: Create an apex class to integrate DocuSign.

public with sharing class docuSignCtrl {

     @AuraEnabled

    public static docuSign__mdt docuSign_Credentials(){

        docuSign__mdt docuSign_metadata=[select 

  id,ClientId__c,ClientSecret__c,refresh_Token__c from docuSign__mdt where   

  DeveloperName='docuSign_auth' limit 1];

        return docuSign_metadata;

    }



    @AuraEnabled

    public static String getAccessToken(String authCode){


        auth_info docuSignAuth;

             

        if(String.isNotBlank(authCode)){

            docuSignAuth=getDocuSignToken(authCode);

           

            if(String.isNotBlank(docuSignAuth.access_token)){

                                   

              docuSign_accessToken=docuSignAuth.access_token;

                     }

        }      

        return docuSign_accessToken;

    }


    public static auth_info getDocuSignToken(string authCode) {

       

        docuSign__mdt docuSign_metadata=docuSign_Credentials();


        Http http = new Http();

        HttpRequest req = new HttpRequest();

        req.setEndpoint('https://account.docusign.com/oauth/token?grant_type=authorization_code&code='+authCode);

        req.setMethod('POST');

              req.setHeader('Authorization', 'Basic '+EncodingUtil.base64Encode(blob.valueOf(docuSign_metadata.ClientId__c+':'+docuSign_metadata.ClientSecret__c)));

        req.setHeader('Content-Type','application/json');

        req.setHeader('Content-Length', '0');

        HttpResponse rep = http.send(req);

        auth_info docuSign_auth=(auth_info)

                        Json.deserialize(rep.getBody(), auth_info.class);

        return docuSign_auth;


    }


    @AuraEnabled

    public static String sendDoc_for_sign(String documentId,String accessToken,String recipientEmail,string recipientName){

       

        contentVersion[] documentVersion=[select id,title,versionData from contentVersion where id=:documentId];


        try {

            String envelopBody='{}';


            String documentBase64 = EncodingUtil.base64Encode(documentVersion.get(0).versionData);

            String doc_Id ='001';

            String fileExtension = 'pdf';

            String name = documentVersion.get(0).title;

           

            String jsonString = '{'

            +'"documents": ['

                +'{'

                +'"documentBase64":"'+documentBase64+'",'

                +'"documentId": "'+doc_Id+'",'

                +'"fileExtension": "'+fileExtension+'",'

                +'"name": "'+name+'",'

                +'}'

            +'],'

            +'"emailSubject": "Simple Signing Example",'

            +'"recipients": {'

            +' "signers": ['

                +' {'

                +'  "email":"'+recipientEmail+'",'

                +'  "name": "'+recipientName+'",'

                +' "recipientId":"1001"'

                +'},'

                +']'

            +'},'

            +'"status": "sent"'

            +'}';


            Http httpTosent = new Http();

            HttpRequest httpReq = new HttpRequest();

            httpReq.setEndPoint('https://docusingBaseUrl/restapi/v2.1/accounts/docusignAccId/envelopes');

            httpReq.setMethod('POST');

            httpReq.setHeader('Authorization', 'Bearer '+accessToken);

            httpReq.setHeader('Content-Type','application/json');

            httpReq.setBody(jsonString);

            httpReq.setTimeout(60000);

            httpResponse res=httpTosent.send(httpReq);

            system.debug(res.getBody());

            return Json.serialize('{"recipient":"'+recipientEmail+'","envelope":'+res.getBody()+'}');

        } catch (Exception e) {

            throw new AuraHandledException(e.getMessage());

        }

    }



    public class auth_info{

        public string access_token{get;set;}

        public string refresh_token{get;set;}

        public string error_description{get;set;}

    }

}


Step 6: 
create a Lightning web component to upload the document.

docuSignFileuploader.Html

 <template>


    <lightning-spinner if:true={isLoading}></lightning-spinner>

    <lightning-card>

      <template lwc:if={showSignIn}>

        <div class='slds-align_absolute-center'>

          <lightning-button variant="brand" label="signIn" 

                          onclick={sign_docuSign}></lightning-button>

        </div>

      </template>

      <template lwc:else>

        <div>

         

 

  <div class='slds-align_absolute-center'style="width:fit-content">

 

            <div style="width:fit-content">

              {fileName}

              <lightning-file-upload name="fileUploader" accept='.pdf' 

                           onuploadfinished={handleUploadFinished}

                 

                  class="fileUploader">

              </lightning-file-upload>

 

 

            </div>

            <lightning-icon icon-name='action:approval' 

                                        class="uploadSuccess_icon"

              if:true={isUploaded_to_SF}></lightning-icon>

 

            <div style="margin-left:10%;width: 20pc;">

              <lightning-record-edit-form object-api-name="User">

                <label for="fieldid">select Recipient</label>

                <lightning-input-field field-name="ContactId" id="fieldid" 

                                variant="label-hidden"

                 

              onchange={handleRecipient_change}></lightning-input-field>

              </lightning-record-edit-form>

            </div>

 

          </div><br>

          <div class='slds-align_absolute-center' 

                                               style="width:fit-content">

            <lightning-button label="send document" variant="brand" 

                                     onclick={send_document_to_docuSign}

              disabled={isButtonEnable}></lightning-button>

          </div>

        </div>

      </template>

    </lightning-card>

 

    <div if:true={isUploaded}>

     

  <section class="slds-modal slds-fade-in-open">

        <div class="slds-modal__container">

          <button class="slds-button slds-button_icon slds-modal__close  

                                          slds-button_icon-inverse">

            <lightning-icon icon-name="utility:close" variant='inverse' 

                             onclick={closePopUp}></lightning-icon>

            <span class="slds-assistive-text">Cancel and close</span>

          </button>

          <div class="slds-modal__header">

            <h1 id="modal-heading-01" class="slds-modal__title

                                   slds-hyphenate">Success</h1>

            <lightning-icon icon-name="action:approval" 

                                    style="zoom:60%"></lightning-icon>

          </div>

          <div class="slds-modal__content slds-p-around_medium" 

                                       id="modal-content-id-1">

            <h3 style="text-align:center">Your Document SuccessFully Sent

                                         to DocuSign.</h3><br>

 

            <div>

              <table class="docuSign_table">

                <tr>

                  <td>Document Name: {uploaded_document.name}</td>

                  <td>Recipient: <lightning-formatted-email 

                       label={uploaded_document.recipient}             

                                 value={uploaded_document.recipient}>

              </lightning-formatted-email></td>

                </tr>

                <tr>

                  <td>Salesforce DocumentId:

                  <a>{uploaded_document.contentVersionId}</a></td>

                  <td>Status: {uploaded_document.status}</td>

                </tr>

                <tr>

                  <td>DocuSign EnvelopId:

                     <a>{uploaded_document.envelopeId}</a></td>

                </tr>

              </table>

            </div>


          </div>

          <div class="slds-modal__footer">

            <button class="slds-button slds-button_neutral" 

                               aria-label="Cancel and close"

              onclick={closePopUp}>Close</button>

          </div>

        </div>

      </section>

      <div class="slds-backdrop slds-backdrop_open" 

                                          role="presentation"></div>

    </div>

  </template>

docuSignFileuploader.Js

import { LightningElement, track, api, wire } from 'lwc';

 import { getRecord,createRecord } from 'lightning/uiRecordApi';

 import sendDoc from '@salesforce/apex/docuSignCtrl.sendDoc_for_sign';

 import docuSign_Credentials from 

                '@salesforce/apex/docuSignCtrl.docuSign_Credentials';


 import getAccessToken from 

                       '@salesforce/apex/docuSignCtrl.getDocuSignToken;

 export default class LightningUploader extends LightningElement {

    uploaded_document = {};

    AccessToken;

    showSignIn;

    isUploaded;

    isUploaded_to_SF;

    isLoading;

    fileName;

    @track recipientData;

    recipient_conId;

   

 signIn_url;



    @wire(getRecord, { recordId: '$recipient_conId', fields: 

 ['Contact.Id', 'Contact.Name', 'Contact.Email'] })

    recipientRecord({ error, data }) {

        if (data) {

            this.isLoading = false;

            this.recipientData = data;

        }

    }




    connectedCallback() {

                this.isLoading = true;

        let docuSign_authCode = new 

                   URL(window.location.href).searchParams.get('code');

        getAccessToken({ authCode: docuSign_authCode }).then((res) => {

                this.showSignIn = false;

                this.AccessToken = res;

                this.isLoading = false;

        })

    }


   

    handleUploadFinished(event){

        console.log('event>>>',event);

        this.uploaded_document = {};

        let uploadedDoc=event.detail.files[0];

        this.uploaded_document['contentVersionId'] = 

                                      uploadedDoc.contentVersionId;

        this.uploaded_document['name'] = uploadedDoc.name;

        this.fileName = uploadedDoc.name;

        this.isUploaded_to_SF=true;

    }





    handleRecipient_change(event) {

        this.recipient_conId = event.target.value;

        if (this.recipient_conId) {

            this.isLoading = true;

        } else {

            this.recipientData = null;

        }


    }


    get isButtonEnable() {


        if (this.recipientData && 

          this.uploaded_document.hasOwnProperty('contentVersionId')) {

            return false;

        } else {

            return true;

        }

    }


    send_document_to_docuSign() {

        this.isLoading = true;

        if (this.AccessToken && this.recipientData && 

              (this.uploaded_document.hasOwnProperty('contentVersionId')

            && this.uploaded_document['contentVersionId'])) {


            sendDoc({ documentId: 

          this.uploaded_document['contentVersionId'],

          accessToken: this.AccessToken, recipientEmail: 

          this.recipientData.fields.Email.value, recipientName: 

          this.recipientData.fields.Name.value })

          .then((res) => {

                  const documentRes = JSON.parse(JSON.parse(res));

                  this.uploaded_document['envelopeId'] = 

                  documentRes['envelope']['envelopeId'];

                  this.uploaded_document['recipient'] = 

                  documentRes['recipient'];

                  this.uploaded_document['status'] = 

                  documentRes['envelope']['status'];

               

                this.isUploaded = true;

                this.isLoading = false;

            })

        } else {

            let toastMessage = '';

            if (!this.AccessToken) {

                toastMessage += 'Authentication failure,check

                                      accessToken!';

            }

            if (!this.recipientData) {

                toastMessage += (toastMessage) ? ',No recipient Found' : 

                          'No recipient selected!';

            }

            if(!this.uploaded_document.hasOwnProperty('contentVersionId'))  

                 {

                toastMessage += (toastMessage) ? ',Please uploade the

                  Document' : 'Please uploaded Document!';

            }



            this.showToastMessage(toastMessage, 'info');

            this.isLoading = false;

        }

    }


    sign_docuSign() {

       

        docuSign_Credentials().then((res)=>{

            let signIn_url = 'https://account.docusign.com/oauth/auth?redirect_uri=https://YourEndPoint/democommunity/s/docusign&response_type=code&client_id='+res.ClientId__c+'&scope=signature';


            window.open(signIn_url, 'self');

        })

       

    }


   


    closePopUp() {

        this.isUploaded = false;

    }


    showToastMessage(message, variant) {

        this.dispatchEvent(

            new ShowToastEvent({

                title: variant,

                variant: variant,

                message: message

            })

        )

        this.isLoading = false;

    }


   }


Output:

We can see the envelope ID in the DocuSign just created from Salesforce.