title: How do I prefill fields in an envelope created from a template using Docusign's REST API?
body: <p>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.</p>
  
  <p>The workflow:  </p>
  
  <ul>
  <li>have a template with a bunch of fields  </li>
  <li><p>using the api:  </p>
  
  <ul>
  <li><p>create an envelope/document from the template, and assign a new user to sign (this document is going to be an agreement for signing up for a service)  </p>
  
  <ul>
  <li>create new role</li>
  <li>set roleName to fake signer on template (because I can't configure fields without at least one signer on the template)</li>
  <li>add textTabs to try to perfill some of the fields.</li>
  </ul></li>
  <li><p>retrieve the recipients   </p></li>
  <li>create a recipient view so that I get the URL to put in an iframe</li>
  </ul></li>
  </ul>
  
  <p>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).</p>
  
  <p>Here is the node.js code for the creation of the envelope (where I think my API usage is going wrong):</p>
  
  <pre><code>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 =&gt; {
      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;
  }
  </code></pre>
  
  <p>In the template editor on docusign, the  <code>Data Field Tag Properties</code> show the label of each of the corresponding fields as <code>field1</code>, <code>field2</code>, etc.</p>
  
  <p>These fields are now filled out with the provided values when I throw the new envelope in an iframe.</p>
  
  <p>just for reference here is the rest of the code that creates the api connection, and gets the view URL</p>
  
  <pre><code>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 =&gt; {
        const envelopeId = envelopeSummary.envelopeId;
  
        return createViewFromEnvelope(envelopeId);
      });
  }
  
  export function createViewFromEnvelope(envelopeId) {
    return getRecipients(envelopeId).then(recipients =&gt; {
      // 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 =&gt; [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 &amp;&amp; obj.length == k) removeNulls(obj);
    }
    return obj;
  };
  </code></pre>