BLOG

Automate Document Signing using the DocuSign API

Jan. 8, 2023

/

Adam Yue

DocuSign is a widely used document signing service. It provides an SDK for a range of programming languages that can achieve the automation of creating, sending and signing documents. The API provides more flexibility compare to using the DocuSign web portal, but requires a deeper understanding how DocuSign "thinks" about document signing. In this blog, we will go through how to use the DocuSign SDK in a Kotlin project with several common use cases.

Preparation

If you want to reproduce the following demo by yourself, please create a DocuSign developer account from here and upload some testing files as the templates. These IDs and credentials are required to send an Envelope:

  • accountId: your account ID which can be found in “General Settings”

  • userId: You can have multiple users under your DocuSign account. You can create users and find their id on “Settings -> Users”

  • clientId (Integration key): Is a UUID can be obtained in your developer account by accessing the “Settings -> Apps and Integration Keys” page

  • client secret (RSA private key): This is for the integration key you obtained above. It is also created on the “Apps and Integration Keys” page. The client secret can only be copied the first time it is displayed.

  • templateId: UUID of template files that can be found in editing templates page.

  • basePath: is https://demo.docusign.net/restapi for the DocuSign development environment

Key DocuSign Terminologies:

  • Envelope: is the final generated document sent to all recipients
  • Templates: files (pdf, doc, ppt, etc.) that makes up an Envelope
  • Tabs: Dynamically generated text fields that can be allocated on templates
  • Recipients: people who receive the envelopes

Let’s start with an example to demonstrate how to create and send an envelope using the DocuSign SDK:

Step one: Create EnvelopeDefinition

  1. Create a ServerTemplate object. A ServerTemplate represents a file you have uploaded to Docusign. The TemplateId can be found in edit template page.

Kotlin // Server template val demoTemplate = ServerTemplate() demoTemplate.sequence = "1" demoTemplate.templateId = "cd635318-aaad-4e63-ba2d-adb9edf06db3"

  1. Create Recipients and Signer Tabs

The SignHere object represents the location where a recipient has to sign the envelope. To determine the correct x and y position you can use the web portal UI.

``` Kotlin
// singer's tab
val signerTab = Tabs()
val signHere = SignHere()
signHere.pageNumber = "1"
signHere.documentId = "1"
signHere.xPosition = "125"
signHere.yPosition = "327"
signerTab.signHereTabs = listOf(signHere)
```

The Signer object is the signer's configuration which includes their email, name, recipientId and routingOrder. The recipientId is a unique string, you can use any string other than “1”. routingOrder defines the signing sequence. If there are two signers, the signer with smaller number will sign first.

```Kotlin
// signer's configuration
val signer = Signer()
signer.tabs(signerTab)
signer.email = signerEmail
signer.name = "Test Signer"
signer.recipientId = "1"
signer.routingOrder = "1"
```
Assign the signers to the Recipients object.
```Kotlin
//config recipients
val recipients = Recipients()
val signers = mutableListOf<Signer>()
signers.add(signer)
recipients.signers = signers
```
  1. Create InlineTemplate with Recipients Kotlin val recipientsTemplate = InlineTemplate() recipientsTemplate.sequence = "1" recipientsTemplate.recipients = recipients

  2. Create CompositeTemplate using both InlineTemplate and ServerTemplate

    Kotlin // composite template val compositeTemplate = CompositeTemplate() compositeTemplate.compositeTemplateId = "1" compositeTemplate.serverTemplates = listOf(demoTemplate) compositeTemplate.inlineTemplates = listOf(recipientsTemplate)

  3. Create EnvelopeDefinition

    Kotlin val envelopeDefinition = EnvelopeDefinition() envelopeDefinition.emailSubject = "DecoSignDemo" envelopeDefinition.compositeTemplates = listOf(compositeTemplate)

An EnvelopeDefinition is the core object which combines the templates (actual files) and signers together. This diagram outlines the EnvelopeDefinition object structure:

Step Two: Fill Tabs

DocuSign provides a variety of commonly used tabs such as: text, checkbox, dropdown etc. which can be added via Tab class in the SDK. For example: Let's add a text tab to capture the envelope’s creation date:

val formatter = DateTimeFormatter.ofPattern("dd MMMM yyyy")

val date = Text()
date.documentId = "1"
date.pageNumber = "1"
date.value =
    Instant.ofEpochMilli(System.currentTimeMillis())
        .atZone(ZoneId.systemDefault()).toLocalDate().format(formatter)
date.xPosition = "100"
date.yPosition = "354"
date.fontSize = "Size12"

val textTabs = listOf(date)

val prefilledTabs = PrefillTabs()
prefilledTabs.textTabs = textTabs

val tabs = Tabs()
tabs.prefillTabs = prefilledTabs

Note: To send an envelope, Tabs are always required. If no tabs are required, then create an empty Tabs object

Step Three: Send Envelope

After the EnvelopeDefinition and Tabs are prepared, the envelope is ready for sending.

  1. Create the ApiClient(check how to get basePath, clientId, userId, privateKey at Preparation):

    ```kotlin val apiClient = ApiClient(basePath) val jwtUserToken = apiClient.requestJWTUserToken( clientId, userId, listOf(OAuth.Scope_SIGNATURE), privateKey.toByteArray(Charsets.UTF_8), 300 )

    apiClient.setAccessToken(jwtUserToken.accessToken, 300) ```

  2. Create the EnvelopesApi kotlin val envelopesApi = EnvelopesApi(docuSignClient)

  3. Finally, Send the envelope with tabs: ```kotlin val envelopeSummary = envelopesApi.createEnvelope(accountId, envelopeDefinition)

    val tabs = fillTabs() envelopesApi.createDocumentTabs(accountId,envelopeSummary.envelopeId,"1",tabs) ```


Combining Multiple Templates

From the re-usability and management point of view, instead of having a big fixed template, it can be split into several small templates. It’s also one of the Best practices for using composite templates: “Create DocuSign templates around individual documents, rather than bundling multiple documents in a single template”

See Step One 'Creating the Envelope Definition' Part 5

envelopeDefinition.compositeTemplates = listOf(compositeTemplate)

An Envelope definition can take a list of composite templates, we can create another composite template (composite template Id must be different) in the same way as part 1 to 4 and add it to the list:

envelopeDefinition.compositeTemplates = listOf(
compositeTemplate, secondCompositeTemplate)

Notice: Page number of Tabs

The page number always points to the composite template page on which tabs will be added. For example, a singer A needs to sign on both compositeTemplate and a second CompositeTemplate above, both templates only have one page. When creating a Sign Here tab for the second composite template, the page number is still “1” even it’s the second page of the final envelope.

Multiple Signers and Signing Order

If there are multiple signers, each signer should have a unique recipient Id. They may have the same Routing Order, which means all signers will receive the envelope at the same time. If some signers are preferred to sign first, they should have smaller routing order.

Conclusion

This blog demonstrates the basic usage of the DocuSign SDK. DocuSign is a powerful document signing tool. It can greatly simplify business services processes. If you want to find out how Document Signing can help your organization to improve productivity don't hesitate to contact us.

sample code:

...
  private fun createEnvelope(): EnvelopeDefinition {
        // Server template
        val demoTemplate = ServerTemplate()
        demoTemplate.sequence = "1"
        demoTemplate.templateId = "cd635318-aaad-4e63-ba2d-adb9edf06db3"

        // singer's tab
        val signerTab = Tabs()
        val signHere = SignHere()
        signHere.pageNumber = "1"
        signHere.documentId = "1"
        signHere.xPosition = "125"
        signHere.yPosition = "327"
        signerTab.signHereTabs = listOf(signHere)

        // config signer
        val signer = Signer()
        signer.tabs(signerTab)
        signer.email = signerEmail
        signer.name = "Test Signer"
        signer.recipientId = "1"
        signer.routingOrder = "1"

        //config recipients
        val recipients = Recipients()
        val signers = mutableListOf<Signer>()
        signers.add(signer)
        recipients.signers = signers

        // inline template
        val recipientsTemplate = InlineTemplate()
        recipientsTemplate.sequence = "1"
        recipientsTemplate.recipients = recipients

        // composite template
        val compositeTemplate = CompositeTemplate()
        compositeTemplate.compositeTemplateId = "1"
        compositeTemplate.serverTemplates = listOf(demoTemplate)
        compositeTemplate.inlineTemplates = listOf(recipientsTemplate)

        // envelope
        val envelopeDefinition = EnvelopeDefinition()
        envelopeDefinition.emailSubject = "DecoSignDemo"
        envelopeDefinition.compositeTemplates = listOf(compositeTemplate)

        envelopeDefinition.status = "sent"
        return envelopeDefinition
    }

    private fun fillTabs(): Tabs {
        val formatter = DateTimeFormatter.ofPattern("dd MMMM yyyy")

        val date = Text()
        date.documentId = "1"
        date.pageNumber = "1"
        date.value =
            Instant.ofEpochMilli(System.currentTimeMillis())
                .atZone(ZoneId.systemDefault()).toLocalDate().format(formatter)
        date.xPosition = "100"
        date.yPosition = "354"
        date.fontSize = "Size12"

        val textTabs = listOf(date)

        val prefilledTabs = PrefillTabs()
        prefilledTabs.textTabs = textTabs

        val tabs = Tabs()
        tabs.prefillTabs = prefilledTabs

        return tabs
    }

    private fun createDocuSignApiClient(): ApiClient {
        val apiClient = ApiClient(basePath)
        val jwtUserToken = apiClient.requestJWTUserToken(
            clientId,
            userId,
            listOf(OAuth.Scope_SIGNATURE),
            privateKey.toByteArray(Charsets.UTF_8),
            300
        )

        apiClient.setAccessToken(jwtUserToken.accessToken, 300)
        return apiClient
    }

    @Test
    fun sendEnvelope(){
        val docuSignClient = createDocuSignApiClient()
        val envelopesApi = EnvelopesApi(docuSignClient)

        val envelopeDefinition = createEnvelope()
        val envelopeSummary = envelopesApi.createEnvelope(accountId, envelopeDefinition)

        val tabs = fillTabs()
        envelopesApi.createDocumentTabs(
            accountId,
            envelopeSummary.envelopeId,
            "1",
            tabs
        )

        println("envelope has been sent.")
    }
...

TAGS

API DocuSign

Share

Contact Us

Icon

Address
Level 8
11-17 York Street
Sydney NSW 2000

Icon

Phone Number
+61 2 8294 8067

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

© 2017-2024 Darumatic Pty Ltd. All Rights Reserved.