Working with DocuSign, Authorization and Sending Document for Signature

Last Update: August 30, 2024
Table of Contents
Contributors
Picture of Nayeem Iqubal
Nayeem Iqubal
Tech Stack
0 +
Want to accelerate your software development company?

It has become a prerequisite for companies to develop custom software products to stay competitive.

DocuSign is a well known platform where users can send their document for signing via email or your app. I will try to show you how DocuSign authorize an user and how can we send a document to users for signing electronically and we will do that programmatically. To use DocuSign at first we need a free developer account. Go there and select Developer Account button in the top left then Create Account. Log into this account. After login you need to create an app for your integration. Go to My Apps and Keys there you will see your Integrations. Click ADD APP & INTEGRATION KEY button. Give a name and select Authorization Code Grant for User Application. In secret keys generate one and save them somewhere because you won’t be able to see it again. In Redirect URLs Add one which will be needed when we make URLs for authorization. An Integration key will be generated for your app we need this later. We will use Authorization Code Grant to authorize users. Authorization process has 2 steps first we need to obtain Authorization Code and 2nd using that Authorization Code we need to obtain access token using rest api call. To get Authorization Code we need to generate a url where we need to redirect ours users to that url. There user will login to their DocuSign Account and grant access to our app. After user authorizes our app user will be redirected to our whitelisted redirect url with a Authorization Code. Below is the URL format.
				
					https://account-d.docusign.com/oauth/auth?response_type=code&scope=signature&client_id=7c2b8d7e-xxxx-xxxx-xxxx-cda8a50dd73f&state=a39fh23hnf23&redirect_uri=http://example.com/callback/
				
			
client_id is the integration key and redirect_uri is the url where DocuSign will redirect users with a Authorization Code. After Redirected URL will contain a parameter called code. We need this code to generate access token. To Get Access Token we need to call a rest api and we need to set header. The authorization header will contain integration key and secret key separated by a colon and converted it to base64 with prefixed by a word Basic. We can generate this base64 easily by using browser console. In Console write this and enter
				
					btoa('INTEGRATION_KEY:SECRET_KEY')
				
			
it will show the base64 of the string. set this string in the Authorization Header. This is a POST method so I am using curl to request this endpoint.
				
					curl --header "Authorization: Basic BASE64_OF_YOUR_INTEGRATION_AND_SECRET_KEY"
--data "grant_type=authorization_code&code=AUTHORIZATION_CODE_FROM_DOCUSIGN" 
--request POST https://account-d.docusign.com/oauth/token
				
			
The response of this request will have access_token, refresh_token and expires_in . We need this access token to make every DocuSign API Call. I am using C# as an example for how to send a document for signing. We need to add a C# library to make DocuSign api call. Search and install eSignature API via  Nuget Package Manager Which is made by DocuSign. First we need to make an envelope here is the Code example to  make an Envelope.
				
					private EnvelopeDefinition MakeEnvelope(string signerEmail, string signerName, string ccEmail, string ccName)
{
    string doc2DocxBytes = Convert.ToBase64String(System.IO.File.ReadAllBytes(Config.docDocx));
    string doc3PdfBytes = Convert.ToBase64String(System.IO.File.ReadAllBytes(Config.docPdf)); 
    // Create the envelope definition
    EnvelopeDefinition env = new EnvelopeDefinition();
    env.EmailSubject = "Please sign this document set";
    Document doc1 = new Document();
    string b64 = Convert.ToBase64String(document1(signerEmail, signerName, ccEmail, ccName));
    doc1.DocumentBase64 = b64;
    doc1.Name = "Order acknowledgement"; // can be different from actual file name
    doc1.FileExtension = "html"; // Source data format. Signed docs are always pdf.
    doc1.DocumentId = "1"; // a label used to reference the doc
    Document doc2 = new Document {
        DocumentBase64 = doc2DocxBytes,
        Name = "Battle Plan", // can be different from actual file name
        FileExtension = "docx",
        DocumentId = "2"
    };

    Document doc3 = new Document
    {
        DocumentBase64 = doc3PdfBytes,
        Name = "Lorem Ipsum", // can be different from actual file name
        FileExtension = "pdf",
        DocumentId = "3"
    };


    // The order in the docs array determines the order in the envelope
    env.Documents =  new List<Document> { doc1, doc2, doc3};

    // create a signer recipient to sign the document, identified by name and email
    // We're setting the parameters via the object creation
    Signer signer1 = new Signer {
        Email = signerEmail,
        Name = signerName,
        RecipientId = "1",
        RoutingOrder = "1"
    };

    // routingOrder (lower means earlier) determines the order of deliveries
    // to the recipients. Parallel routing order is supported by using the
    // same integer as the order for two or more recipients.

    // create a cc recipient to receive a copy of the documents, identified by name and email
    // We're setting the parameters via setters
    CarbonCopy cc1 = new CarbonCopy
    {
        Email = ccEmail,
        Name = ccName,
        RecipientId = "2",
        RoutingOrder = "2"
    };

    // Create signHere fields (also known as tabs) on the documents,
    // We're using anchor (autoPlace) positioning
    //
    // The DocuSign platform searches throughout your envelope's
    // documents for matching anchor strings. So the
    // signHere2 tab will be used in both document 2 and 3 since they
    // use the same anchor string for their "signer 1" tabs.
    SignHere signHere1 = new SignHere
    {
        AnchorString = "**signature_1**",
        AnchorUnits = "pixels",
        AnchorYOffset = "10",
        AnchorXOffset = "20"
    };

    SignHere signHere2 = new SignHere
    {
        AnchorString = "/sn1/",
        AnchorUnits = "pixels",
        AnchorYOffset = "10",
        AnchorXOffset = "20"
    };
    

    // Tabs are set per recipient / signer
    Tabs signer1Tabs = new Tabs {
        SignHereTabs = new List<SignHere> { signHere1, signHere2}
    };
    
    signer1.Tabs = signer1Tabs;

    // Add the recipients to the envelope object
    Recipients recipients = new Recipients
    {
        Signers = new List<Signer> { signer1 },
        CarbonCopies = new List<CarbonCopy> { cc1 }
    };
    
    env.Recipients = recipients;

    // Request that the envelope be sent by setting |status| to "sent".
    // To request that the envelope be created as a draft, set to "created"
    env.Status = RequestItemsService.Status;

    return env;
}

// The HTML of the first document in the envelope used by our example is defined here
private byte[] document1(string signerEmail, string signerName, string ccEmail, string ccName)
{
    return Encoding.UTF8.GetBytes(
    " <!DOCTYPE html>\n" +
        "    <html>\n" +
        "        <head>\n" +
        "          <meta charset=\"UTF-8\">\n" +
        "        </head>\n" +
        "        <body style=\"font-family:sans-serif;margin-left:2em;\">\n" +
        "        <h1 style=\"font-family: 'Trebuchet MS', Helvetica, sans-serif;\n" +
        "            color: darkblue;margin-bottom: 0;\">World Wide Corp</h1>\n" +
        "        <h2 style=\"font-family: 'Trebuchet MS', Helvetica, sans-serif;\n" +
        "          margin-top: 0px;margin-bottom: 3.5em;font-size: 1em;\n" +
        "          color: darkblue;\">Order Processing Division</h2>\n" +
        "        <h4>Ordered by " + signerName + "</h4>\n" +
        "        <p style=\"margin-top:0em; margin-bottom:0em;\">Email: " + signerEmail + "</p>\n" +
        "        <p style=\"margin-top:0em; margin-bottom:0em;\">Copy to: " + ccName + ", " + ccEmail + "</p>\n" +
        "        <p style=\"margin-top:3em;\">\n" +
        "  Candy bonbon pastry jujubes lollipop wafer biscuit biscuit. Topping brownie sesame snaps sweet roll pie. Croissant danish biscuit soufflé caramels jujubes jelly. Dragée danish caramels lemon drops dragée. Gummi bears cupcake biscuit tiramisu sugar plum pastry. Dragée gummies applicake pudding liquorice. Donut jujubes oat cake jelly-o. Dessert bear claw chocolate cake gummies lollipop sugar plum ice cream gummies cheesecake.\n" +
        "        </p>\n" +
        "        \n" +
        "        <h3 style=\"margin-top:3em;\">Agreed: <span style=\"color:white;\">**signature_1**/</span></h3>\n" +
        "        <script>class RocketElementorAnimation{constructor(){this.deviceMode=document.createElement("span"),this.deviceMode.id="elementor-device-mode-wpr",this.deviceMode.setAttribute("class","elementor-screen-only"),document.body.appendChild(this.deviceMode)}_detectAnimations(){let t=getComputedStyle(this.deviceMode,":after").content.replace(/"/g,"");this.animationSettingKeys=this._listAnimationSettingsKeys(t),document.querySelectorAll(".elementor-invisible[data-settings]").forEach(t=>{const e=t.getBoundingClientRect();if(e.bottom>=0&&e.top<=window.innerHeight)try{this._animateElement(t)}catch(t){}})}_animateElement(t){const e=JSON.parse(t.dataset.settings),i=e._animation_delay||e.animation_delay||0,n=e[this.animationSettingKeys.find(t=>e[t])];if("none"===n)return void t.classList.remove("elementor-invisible");t.classList.remove(n),this.currentAnimation&&t.classList.remove(this.currentAnimation),this.currentAnimation=n;let s=setTimeout(()=>{t.classList.remove("elementor-invisible"),t.classList.add("animated",n),this._removeAnimationSettings(t,e)},i);window.addEventListener("rocket-startLoading",function(){clearTimeout(s)})}_listAnimationSettingsKeys(t="mobile"){const e=[""];switch(t){case"mobile":e.unshift("_mobile");case"tablet":e.unshift("_tablet");case"desktop":e.unshift("_desktop")}const i=[];return["animation","_animation"].forEach(t=>{e.forEach(e=>{i.push(t+e)})}),i}_removeAnimationSettings(t,e){this._listAnimationSettingsKeys().forEach(t=>delete e[t]),t.dataset.settings=JSON.stringify(e)}static run(){const t=new RocketElementorAnimation;requestAnimationFrame(t._detectAnimations.bind(t))}}document.addEventListener("DOMContentLoaded",RocketElementorAnimation.run);</script></body>\n" +
        "    </html>"
        );
}
				
			
And this is the code for sending this envelope to DocuSign.
				
					public EnvelopeSummary SendEnvelope(string signerEmail, string signerName, string ccEmail, string ccName)
        {
            var accessToken = ACCESS_TOKEN;
            var basePath = BASE_PATH + "/restapi";
            var accountId = ACCOUNT_ID;

            EnvelopeDefinition env = MakeEnvelope(signerEmail, signerName, ccEmail, ccName);
            var apiClient = new ApiClient(basePath);
            apiClient.Configuration.DefaultHeader.Add("Authorization", "Bearer " + accessToken);
            var envelopesApi = new EnvelopesApi(apiClient);
            EnvelopeSummary results = envelopesApi.CreateEnvelope(accountId, env);
            RequestItemsService.EnvelopeId = results.EnvelopeId;
            return results;
        }
				
			
ACCESS_TOKEN is the token we got from the authorization step. BASE_PATH will be https://demo.docusign.net as this is for development purpose and you will find it in the admin dashboard (My Apps and Keys) Page. ACCOUNT_ID is the API Account Id which is also in the dashboard.  If our SendEnvelope method is called successfully , Signers will be notified via email that he/she has a document to Sign. Go through their official doc if you want to dive deeply to know other features also.
Potential Developer
Tech Stack
0 +
Accelerate Your Software Development Potential with Us
With our innovative solutions and dedicated expertise, success is a guaranteed outcome. Let's accelerate together towards your goals and beyond.
Blogs You May Love

Don’t let understaffing hold you back. Maximize your team’s performance and reach your business goals with the best IT Staff Augmentation