NullVoxPopuli
NullVoxPopuli

Reputation: 65083

How do I prefill fields in an envelope created from a template using Docusign's REST API?

Note: I'm using the 'classic' experience because the new interface doesn't have a way for a template to set up required fields for future signers.

The workflow:

This is kind of obnoxious, because I don't care about having a first signer that isn't the user signing up for the service. I would however, like to have the the document be copied to someone after signing, but docusign doesn't appear to support this (that I've found anyway).

Here is the node.js code for the creation of the envelope (where I think my API usage is going wrong):

function createEnvelopeDefinition(templateId, userData) {
  var envDef = new docusign.EnvelopeDefinition();
  envDef.setEmailSubject('Signup Agreement');
  envDef.setTemplateId(templateId);

  var tRole = new docusign.TemplateRole();
  tRole.setRoleName('RoleOne');
  tRole.setName(userData.fullName);
  tRole.setEmail(userData.email);
  tRole.setClientUserId('2');
  tRole.setTabs(new docusign.Tabs());
  tRole.getTabs().setTextTabs([]);

  const fieldsToPreFill = [
    'field1',
    'field2',
    'field3',
    'field4'];

  fieldsToPreFill.forEach(fieldName => {
    let textTab = new docusign.Text();
    let value = userData[fieldName];
    if (value === null || value === undefined) { value = 'not null'; }
    textTab.setTabLabel(fieldName);
    textTab.setValue(value);
    tRole.getTabs().getTextTabs().push(textTab);
  });

  tRole = removeNulls(tRole);

  envDef.setTemplateRoles([tRole]);

  // send the envelope by setting |status| to 'sent'.
  // To save as a draft set to 'created'
  //   sent is required for getting view URLs
  envDef.setStatus('sent');

  return envDef;
}

In the template editor on docusign, the Data Field Tag Properties show the label of each of the corresponding fields as field1, field2, etc.

These fields are now filled out with the provided values when I throw the new envelope in an iframe.

just for reference here is the rest of the code that creates the api connection, and gets the view URL

import ENV from 'environment/backend';
const accountId = ENV.docusign.accountId;
var Promise = require('bluebird');

var docusign = require('docusign-esign');

export function newApiClient() {
  let apiClient = new docusign.ApiClient();
  apiClient.setBasePath(ENV.docusign.endpoint);

  // create JSON formatted auth header
  let creds = JSON.stringify({
    Username: ENV.docusign.email,
    Password: ENV.docusign.password,
    IntegratorKey: ENV.docusign.integratorKey
  });

  apiClient.addDefaultHeader('X-DocuSign-Authentication', creds);

  // assign api client to the Configuration object
  // this probably doesn't need to be set every time...
  docusign.Configuration.default.setDefaultApiClient(apiClient);

  return apiClient;
}

const defaultApiClient = newApiClient();
const envelopesApi = new docusign.EnvelopesApi();

const createEnvelope = Promise.promisify(envelopesApi.createEnvelope, { context: envelopesApi });
const listRecipients = Promise.promisify(envelopesApi.listRecipients, { context: envelopesApi });
const createRecipientView = Promise.promisify(envelopesApi.createRecipientView, { context: envelopesApi });

export default defaultApiClient;

// promise resolves to the view URL, envelopeId for the user.
// returns a recipientView
export function setupDocumentForEmbeddedSigning(templateId, userData) {
  let envDefinition = createEnvelopeDefinition(templateId, userData);

  return createEnvelope(accountId, envDefinition, null)
    .then(envelopeSummary => {
      const envelopeId = envelopeSummary.envelopeId;

      return createViewFromEnvelope(envelopeId);
    });
}

export function createViewFromEnvelope(envelopeId) {
  return getRecipients(envelopeId).then(recipients => {
    // the last signer is the one we added in the
    // createEnvelopeDefinition step
    let signers = recipients.signers;
    let lastSigner = signers[signers.length - 1];

    return createView(envelopeId, lastSigner)
      .then(recipientView => [recipientView.url, envelopeId]);
  });
}

function getRecipients(envelopeId) {
  return listRecipients(accountId, envelopeId);
}

function createView(envelopeId, signerData) {
  var viewRequest = new docusign.RecipientViewRequest();
  viewRequest.setReturnUrl(ENV.host);
  viewRequest.setAuthenticationMethod('email');

  // recipient information must match embedded recipient info
  // from the createEnvelopeDefinition method
  viewRequest.setEmail(signerData.email);
  viewRequest.setUserName(signerData.name);
  viewRequest.setRecipientId('2');
  viewRequest.setClientUserId('2');

  return createRecipientView(accountId, envelopeId, viewRequest);
}

// bug with the api wrapper
// https://github.com/docusign/docusign-node-client/issues/47
const removeNulls = function(obj) {
  var isArray = obj instanceof Array;
  for (var k in obj) {
    if (obj[k] === null) isArray ? obj.splice(k, 1) : delete obj[k];
    else if (typeof obj[k] == 'object') removeNulls(obj[k]);
    if (isArray && obj.length == k) removeNulls(obj);
  }
  return obj;
};

Upvotes: 2

Views: 3899

Answers (1)

Kim Brandl
Kim Brandl

Reputation: 13480

So, I may not fully understand where you're stuck, but I'll take a crack at this anyway...

Let's say I create a Template using the DocuSign UI and define two Recipient roles:

  • Signer1 (which will be the person who is signing up for your service) -- Action = "Sign"
  • CarbonCopy1 (which will be the person who gets a copy of the completed/signed documents once Signer1 signs) -- Action = "Receive a Copy"

(Note: these roles can be named whatever you want to name them -- I named them "Signer1" and "CarbonCopy1" so it'd be clear who each role represents.)

Assuming the above scenario, your Template's Recipient Roles (in the DocuSign UI) will look like this:

enter image description here

Next, let's assume that you define some fields (tabs) in the Template's document(s) (i.e., using the DocuSign UI) that the Signer1 recipient will need to populate when they sign the document(s). For this example, let's assume that the label (name) of one of those Text tabs is field1. Notice that the field is assigned to the Signer1 recipient:

enter image description here

Now, if I want to create an Envelope via the API that uses this Template, and pre-fill fields for one or more of the recipients, the key to doing that is using the "Composite Templates" structure in the API request. (See the Composite Templates section of this page for details.) In the example described above, your compositeTemplates object in the API request would contain a single serverTemplate object (which specifies the templateId and sequence=1), and a single inlineTemplate object (which specifies sequence=2 and the recipient info, including values for any tabs (fields) that you want to pre-fill).

In the example described above, the JSON API request to create the Envelope would look like this (assuming we're just pre-filling a single field for Signer1 -- obviously you could pre-fill additional fields by simply including them in the tabs object of the request along with field1):

POST https://{{env}}.docusign.net/restapi//v2/accounts/{{accountId}}/envelopes

{
    "emailSubject": "Test Pre-fill Tabs",
    "emailBlurb": "This is a test.",
    "compositeTemplates": [{
        "serverTemplates": [{
            "sequence": "1",
            "templateId": "CD0E6D53-3447-4A9E-BBAF-0EB2C78E8310"
        }],
        "inlineTemplates":[{
            "sequence": "2",
            "recipients": {
                "signers": [
                    {
                        "roleName": "Signer1",
                        "recipientId": "1",
                        "name": "John Doe",
                        "email": "[email protected]",
                        "clientUserId": "1234",
                        "tabs": {
                            "textTabs": [
                                {
                                    "tabLabel": "field1",
                                    "value": "TEST-123"
                                }
                            ]
                        }
                    },
                    {
                      "roleName": "CarbonCopy1",
                      "recipientId": "2",
                      "name": "Jane Doe",
                      "email": "[email protected]"
                    }
                ]
            }
        }]
    }],
    "status": "sent"
}

Once I create the Envelope using the above request, I execute a "POST Recipient View" request to get the signing URL for the first recipient (https://{{env}}.docusign.net/restapi//v2/accounts/{{accountId}}/envelopes/{{envelopeId/views/recipient).

Then, when I subsequently use the URL that's returned in that response to launch the signing session for Signer1 (John Doe), I see that the field1 tab is indeed pre-filled with the value that I specified in the "Create Envelope" API request (TEST-123):

enter image description here

Furthermore, once John Doe (Signer1) finishes signing and submits the completed documents, Jane Doe (CarbonCopy1) will be sent a copy.

I'm not familiar with the DocuSign Node SDK, but imagine you can figure out the syntax to use composite templates as shown in the above example. Hope this helps!

Upvotes: 7

Related Questions