Skip to content

magmasystems/DocusignAPIDemo

Repository files navigation

DocuSign Development

Creating a New DocuSign Application

The first thing that you need to do is to add a new application through the DocuSign admin console. Let's say that this application is called Robyn. Go to the API and Keys section of the eSignature console. Clicking on the yellow “Add App/Integration Key” button brings up a new page where you can specify the details of the new app.

https://admindemo.docusign.com/api-integrator-key

Add Docusign App

Name your new app. Fill in something for the terms, the privacy policy, and the redirect URI (they can be any values, but they cannot be empty).

You will need to create a new RSA Keypair. Make sure that you download the private key file that is created. You will need this private key in your C# code when you make the call to the Docusign authorization API.

Also, copy down your Integration Key. This is a GUID that you will need in your C# code when you make the call to the Docusign authorization API.

Configure Docusign App

Giving Consent

We will be impersonating the admin user when we make API calls. There is a step that the Docusign admin has to go through in order to grant your application the permissions to make API calls on the admin user's behalf.

In your browser, enter the URL:

https://account-d.docusign.com/oauth/auth?response_type=code&scope=signature%20impersonation&client_id=xxxxxxxx-xxxx-xxxx-xxxx-9446ddb12063&redirect_uri=https://localhost:5000/Docusign

Make sure that the client_id is equal to the integration key that you set up in the step above.

When you enter this URL into your browser, a Docusign dialog box will appear and will prompt you to allow the app to impersonate you.

The redirect_uri must be the same Redirect URI that you chose when you set up the application in the Docusign sandbox.

Now that the application is set up, we can start coding.

Note: During the consent process, if you get a message saying that you are not a Docusign Admin, then go into the ESignature Admin dashboard and create a new organization and make sure that your existing account is linked to that new organization.

Create Docusign Org

Writing a Web App that uses DocuSign

We need to use a JWT authentication token for every request that we make to the DocuSign API. Before we make a call to the DocuSign API, we should call ConfigureApiClientAuth(ApiClient apiClient) in order to make sure that we have a valid token. The token will expire, so we need to refresh the token when it expires.

private static string AccessToken { get; set; }
private static DateTime ExpiresIn;

private void ConfigureApiClientAuth(ApiClient apiClient)
{
    this.CheckToken();
    apiClient.Configuration.AddDefaultHeader("Authorization", $"Bearer {AccessToken}");
}

private void CheckToken()
{
    if (AccessToken != null && DateTime.UtcNow <= ExpiresIn)
        return;

    this.UpdateToken();
}

private void UpdateToken()
{
    var clientId = this.Configuration["Docusign:clientId"];
    var impersonatedUserGuid = this.Configuration["Docusign:userId"];
    var authServer = this.Configuration["Docusign:authServer"];
    var privateKey = File.ReadAllBytes(this.Configuration["Docusign:privateKeyFile"]);

    var authToken = ApiClient.RequestJWTUserToken(
                clientId,
                impersonatedUserGuid,
                authServer,
                privateKey,
                1);

    AccessToken = authToken.access_token;
    if (authToken.expires_in != null)
        ExpiresIn = DateTime.UtcNow.AddSeconds(authToken.expires_in.Value);
}

As an example, here is a way that you can fetch the DocuSign template for the Robyn BAA.

The appsettings.json file has various configuration values that are associated with the DocuSign account.

In the constructor, we create the DocuSign ApiClient.

We will call the DocuSign API to list out all of the templates that our account owns. First, we make sure that we have a valid authentication token. Then we use the DocuSign TemplateAPI to get a list of the templates. Finally, we fetch the individual template.

private static ApiClient ApiClient { get; set; }

public DocusignController(ILogger<DocusignController> logger, IConfiguration config)
{
     this.Logger = logger;
     this.Configuration = config;

     var basePath = this.Configuration["Docusign:url"];
     ApiClient = new ApiClient(basePath);
}

public IActionResult Index()
{
    EnvelopeTemplate docusignTemplate = null;

    try
    {
        this.ConfigureApiClientAuth(ApiClient);

        var accountId = this.Configuration["Docusign:accountId"];
        var templatesApi = new TemplatesApi(ApiClient.Configuration);
        var templates = templatesApi.ListTemplates(accountId);

        foreach (var template in templates.EnvelopeTemplates)
        {
            docusignTemplate = template;
        }

        docusignTemplate = templatesApi.Get(accountId, docusignTemplate.TemplateId);
    }
    catch (Exception e)
    {
        this.Logger.LogError(e.Message);
        throw;
    }

    return View("Index", docusignTemplate);
}

Embedding vs Email

There are two ways to get a signature in DocuSign.

One way is to send a document to a signer through email. We can use a webhook to get a push notification as to the status of that document.

The other way is to embed the document signing process within the web app, and when the signer has completed the process, DocuSign redirects the user to a URL that you provide.

When using embedding as a signing method, you must use a signerId in both the RecipientViewRequest object and in the TemplateRole in the EnvelopeDefinition. The signerId can be any value, as long as it's in both objects and has the same value.

A good resource that discusses embedded signing is here.

Using DocuSign Connect to Get Notifications

This is a simple Webhook that you can use to process the callbacks from DocuSign when certain interesting events happen. We take the XML that Docusign puts in the payload, and deserialize it into a custom class that we created. We take the important fields from this payload, and we create a small object that we can pass to other functions. We would probably want to look up the Robyn user by the email address, and we want to store the “TimeSigned” value into their user record in the database.

using System.Xml.Serialization;
using Microsoft.AspNetCore.Mvc;
using DocusignDemo.Models;

namespace DocusignDemo.Controllers
{
    [ApiController]
    [Route("[controller]")]
    public class DocusignWebhookController : ControllerBase
    {
        [HttpPost]
        public ActionResult<RobynDocumentSignedCompletetionInfo> Index()  
              // IMPORTANT: DO NOT USE AN ARGUMENT TO THIS FUNCTION
        {
            if (!(new XmlSerializer(typeof(DocuSignEnvelopeInformation)).Deserialize(Request.Body)
                      is DocuSignEnvelopeInformation envelopeInformation))
                return null;

            var documentSignedCompletetionInfo = new RobynDocumentSignedCompletetionInfo
            {
                Email = envelopeInformation.EnvelopeStatus.RecipientStatuses[0].RecipientStatus.Email,
                DocumentId = envelopeInformation.EnvelopeStatus.EnvelopeID,
                Status = envelopeInformation.EnvelopeStatus.Status,
                TimeSigned = envelopeInformation.EnvelopeStatus.Completed,
            };

            return documentSignedCompletetionInfo;
        }
    }
}

In the appsettings.Development.json file, we have some settings that are important to our example.

"DocuSign":
{
    "authServer": "account-d.docusign.com",
    "url":        "https://demo.docusign.net/restapi",
    "accountId":  "[INSERT YOUR DOCUSIGN ACCOUNT ID HERE]",
    "clientId":   "[INSERT YOUR DOCUSIGN APP INTEGRATION KEY HERE]",
    "userId":     "[INSERT YOUR DOCUSIGN USER ID HERE]",
    "privateKeyFile": "Docusign.RSA.privatekey.txt",
}

Running the App and Using the Webhook

Go into your Terminal on your laptop, and start ngrok like this:

ngrok http https://localhost:5001

You will see ngrok respond with a message like this:

ngrok by @inconshreveable                                                                                                                       (Ctrl+C to quit)

Session Status                online
Account                       Marc Adler (Plan: Free)
Version                       2.3.35
Region                        United States (us)
Web Interface                 http://127.0.0.1:4040
Forwarding                    http://276d59629e7e.ngrok.io -> https://localhost:5001
Forwarding                    https://276d59629e7e.ngrok.io -> https://localhost:5001
Connections                   ttl     opn     rt1     rt5     p50     p90
                              0       0       0.00    0.00    0.00    0.00

Pay attention to the line that says:

https://276d59629e7e.ngrok.io -> https://localhost:5001

You will need to tell the DocuSign admin console that https://276d59629e7e.ngrok.io is the server where your webhook is. Note that this address will change every time that you restart ngrok.

You have to go into the DocuSign Connect dashboard, highlight the Robyn application, and change the URL of the webhook to the server that ngrok printed out.


Create Connection


Configure Connection


If you want to monitor the messages that ngrok processes, go into Chrome and go to localhost:4040.

Let’s say that the webhook can be reached at https://276d59629e7e.ngrok.io/DocusignWebhook

You can test the webhook using Postman:

Postman

If you have a breakpoint set at the webhook, the breakpoint should be hit. Also, the message should be seen in the ngrok console on Chrome (localhost:4040).

Now you can try DocuSign. Run your sample app, send out a document to be signed, wait for the recipient to sign it, and wait for the webhook to be called.

About

A small demo of how to use the DocuSign API within an ASP.NET Core 3.1 application

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published