Skip to content
PDF

Working with DocuSign

This guide includes the basic set of operations that can be used to setup a document signing process using the Module Suite Extension for DocuSign.

Creating a signing Envelope

One of the core concepts when setting up a DocuSign signing process is the "Envelope", which represents the overall container for a transaction.

When defining an envelope, you will be able to provide all details of the transaction. The minimal set of information to provide includes:

  • the documents to sign
  • the recipients of the signing request
  • the message they will receive

See the official DocuSign REST API guide for more details on this topic.

The docusign Content Script service includes methods to programmatically create and send signing envelopes.

EXAMPLE: Creating a simple envelope

def contract      = docman.getDocument(123456)
String contractID = contract.ID as String

definition = docusign.getNewEnvelopeDefinition()
                     .setEmailSubject("XYZ contract for signature")
                     .setEmailBody("Please sign the contract.")
                     .addRecipient('signers', 'Homer J. Simpson', 'homer@example.com', 'Manager')
                     .addSignHereTab("homer@example.com", contractID, "Sign here", 1, 89, 100)
                     .addDocuments(contract)
                     .notifyOnEnvelopeCompleted()
                     .notifyOnEnvelopeDeclined()
                     .notifyOnEnvelopeVoided()

envelope = docusign.createEnvelopeAndSend(null, definition)

docusign.registerEnvelope(envelope) // This command will register the envelope locally on Content Server, to track its status. 

EXAMPLE: Creating an envelope using a predefined template

When creating a new DocuSign envelope, it is possible to provide the envelope configuration in the form of a Map object. The structure of this map is compatible with the JSON format DocuSign uses to define Envelopes and Templates. For this reason, for complex envelope templates, a possible approach is to define the Template within your DocuSign account (using the visual editor to setup Recipients, Signing Tabs, etc.) and then export it and use it within your Content Script app.

def documentToSign      = docman.getDocument(123456)
def emailMessageSubject = "XYZ contract for signature"
def emailMessageBody    = "Please sign the contract." 
def documentsToSign     = [documentToSign]

def user = users.current


def envDefinition = [

    "documents"         : documentsToSign,
    "emailSubject"      : emailMessageSubject,
    "emailBlurb"        : emailMessageBody,
    "signingLocation"   : "Online",
    "authoritativeCopy" : "false",
    "notification": [
        "reminders": [
            "reminderEnabled"   : "false",
            "reminderDelay"     : "0",
            "reminderFrequency" : "0"
        ],
        "expirations": [
            "expireEnabled" : "true",
            "expireAfter"   : "120",
            "expireWarn"    : "0"
        ]
    ],
    "enforceSignerVisibility" : "false",
    "enableWetSign"           : "true",
    "allowMarkup"             : "false",
    "allowReassign"           : "false",
    "messageLock"             : "false",
    "recipientsLock"          : "false",
    "recipients": [
        "signers": [ user ],

        /* Alternatively, a map structure can be provided to define recipients (required for external users).

        "signers": [
            [
                "defaultRecipient"   : "false",
                "signInEachLocation" : "false",
                "name"  : "",
                "email" : "",
                "otuser":[
                           "name"  : user.displayName,
                           "email" : user.email,
                           "ID"    : user.ID
                         ],
                "accessCode"       : "",
                "requireIdLookup"  : "false",
                "routingOrder"     : "1",
                "note"             : "",
                "roleName"         : "Responder",
                "deliveryMethod"   : "email",
                "templateLocked"   : "false",
                "templateRequired" : "false",
                "inheritEmailNotificationConfiguration": "false",
                "tabs": [
                    //"signHereTabs": []
                ]
            ]
         ],
        */

        "agents"              : [],
        "editors"             : [],
        "intermediaries"      : [],
        "carbonCopies"        : [],
        "certifiedDeliveries" : [],
        "inPersonSigners"     : [],
        "recipientCount"      : "1"
    ],

    "envelopeIdStamping" : "true",
    "autoNavigation"     : "true"
]

def envDef = docusign.getNewEnvelopeDefinition(envDefinition)
                     .notifyOnEnvelopeSent()
                     .notifyOnRecipientCompleted()
                     .notifyOnEnvelopeCompleted()

def env =  docusign.createEnvelopeAndSend(null,  envDef) 

envelope = docusign.registerEnvelope(env).envelope // Register this envelope on Content Server. This is the ID of the signing envelope

Embedded recipients

Module Suite Extension for DocuSign supports embedded signing for authenticated OTCS users. When using this pattern, DocuSign delegates the task of identifying the recipients of the signing request to Content Server. Content Server is allowed to request the generation of a pre-signed signing url, which can be used by the recipient to sign the documents without having to authenticate with DocuSign. This approach avoids the context switching of the normal flow, which would require to open the system-generated email notification and access the DocuSign signing request from the provided link.

Refer to the official DocuSign REST API Guide - Embedding for further details on this topic.

When using the embedded signing pattern, recipients should be specified using a CSUser object.

EXAMPLE: Get a pre-authenticated signing URL for an OTCS internal user

In order to generate a signing URL for an embedded recipient, use the docusign.getRecipientUrl(...) API.

String envelopeID = 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'
String username = 'Admin'


def user = users.getUserByLoginName('Admin')
def env  = docusign.getEnvelope(envelopeID)

String profile               = null
String recipientUserName     = user.name
String recipientEmail        = user.email
String recipientClientUserID = user.ID as String
String recipientID           = env.recipients.find{ it.clientUserID == recipientClientUserID }.recipientID

String nextUrl               = "http://mycontentserver.example.com/otcs/cs.exe"

String signingUrl            = docusign.getRecipientUrl( profile, envelopeID, recipientUserName, recipientEmail, recipientID, recipientClientUserID, nextUrl )

redirect signingUrl

Envelope status update and signed document synch back

An important action to be performed when a signing workflow is concluded is to retrieve the signed documents and synchronize them back on your Content Server system. Module Suite Extension for DocuSign supports automating this task in different ways:

  • Subscribe to DocuSign push notifications when the envelopes change state (webhook pattern)

  • Poll the envelope status and update the local instance when a change is detected

The first approach (webhook) relies on the creation of an endpoint that can be invoked from DocuSign when changes happen. This pattern can be implemented by setting up the Script Console DocuSign Extension

The second approach (polling) can be implemented by using the getEnvelopeUpdates(...) API on the docusign service.

EXAMPLE: Poll DocuSign for Envelope updates and synch back documents

The following script can be scheduled to periodically update all active DocuSign envelopes.

Correct API usage

DocuSign monitors that the usage of the API is compliant with certain guidelines. Specifically, certain APIs cannot be invoked with a frequency that goes over a certain threshold. When scheduling polling scripts, make sure that the scheduling frequency complies with the DocuSign guidelines.

NOTE: This limitation can be overcome by using the webhook pattern, as described earlier.

res =  sql.runSQLFast("""SELECT AM_DocuSign.EnvelopeID ENVELOPEID 
                          from AM_DocuSign where 
                               AM_DocuSign.EnvelopeStatus not in ('completed', 'Completed')""", false, false, -1 ).rows.collect{it.ENVELOPEID}
if(res){
    docusign.getEnvelopesUpdates(null, res).each{

        docusign.updateEnvelope(docusign.getEnvelopeDetails(null, it.envelope))

        if(it.envelopeStatus == "completed"){
            docusign.getEnvelopeDocuments(null, it.envelope).each{ doc->
                doc.each{
                    if(it.key > 0){
                        docman.getNodeFast(it.key).addVersion(it.value)
                    }    
                }
            }   
        }
    }    
}