From the Trenches: Composite templates

There is an unlimited variety of use cases for sending envelopes using the DocuSign eSignature REST API. The composite template is one of the most powerful tools in a developer’s toolkit for creating envelopes using the API, and along with that power comes a good deal of complexity. In this article I will describe a common use case and give JSON and C# (using our SDK) examples of how to use composite templates to code a solution. Composite templates give you more power when creating an envelope, including the ability to:

  1. Apply multiple templates to a single envelope.
  2. Replace the documents on your saved DocuSign server templates when creating the envelope, but still have the server template apply all the tabs to the recipients in your envelope.
  3. Write values at run time into the text tabs and other data fields on the server template.
  4. Add additional tabs at run time.
  5. Transform PDF fields into DocuSign tabs and assign them to recipients.

Let’s take as an example a Statement of Work where the description of the work provided varies and the hourly rate varies depending on the work provided. A DocuSign template could be created that includes all the tabs for a customer to initial and sign the document defined by auto-place text, or as we say in the eSignature API, anchorStrings. One of these tabs would be labeled HourlyRate. At run time we want to use our saved template, but swap in a new document, define a new customer and set the value of hourly rate.

To do this, we add an array of compositeTemplates to our envelope. In that array we define one composite template. We add a document to the composite template to replace the document saved on the server template. We also add a serverTemplates array consisting of one server template. This is the template you have saved in your DocuSign account. And finally, we add the inlineTemplates array, consisting of one inline template to provide the runtime information about recipients and tabs. Notice that to write a value to the HourlyRate tab, I only needed to match the tabLabel on the template to identify the tab, set the value and set the tab to locked. In JSON the complete envelope definition would look like the code below. There are only three envelope properties: compositeTemplates, emailSubject, and status.

  "compositeTemplates": [
      "compositeTemplateId": "1",
      "document": {
        "documentBase64": "PDF Bytes",
        "documentId": "1",
        "fileExtension": "pdf",
        "name": "Statement of Work"
      "inlineTemplates": [
          "recipients": {
            "signers": [
                "email": "",
                "name": "Geoff Test",
                "recipientId": "1",
                "roleName": "Customer",
                "routingOrder": "1",
                "tabs": {
                  "textTabs": [
                      "tabLabel": "HourlyRate",
                      "value": "$180.00",
                      "locked": "true"
          "sequence": "2"
      "serverTemplates": [
          "sequence": "1",
          "templateId": "57fd4752-xxxx-xxxx-xxxx-ecbfc7a43bef"
  "emailSubject": "CompositeTemplate Example",
  "status": "sent"

To generate this JSON using the C# SDK, the code would look like this:

public static string CompositeTemplateExample()
  // Instantiate ApiClient and configure authentication. Method not not shown.
  string accountId = GetAPIandAuthenticate(); 
  EnvelopesApi api = new EnvelopesApi(Configuration.Default);  
  // Create a list of composite templates
  List<CompositeTemplate> CompoTemplateList = new List<CompositeTemplate>();
  // Create one Composite Templates
  CompositeTemplate compoTemplate = new CompositeTemplate();
  // Create a document
  var documents = new List<Document>();
  byte[] fileBytes = null;
  Document doc = new Document(); 
  fileBytes = File.ReadAllBytes(@"C:\temp\SOW1.pdf");
  doc.Name = "Statement of Work";  
  doc.DocumentBase64 = System.Convert.ToBase64String(fileBytes);
  doc.DocumentId = "1";
  doc.FileExtension = "pdf";
  // Add to Composite template
  compoTemplate.Document = doc;
  // Create Envelope recipients, including them in the first template
  List<Signer> signers = new List<Signer>();
  // Create the tab for hourly rate
  Tabs tabs = new Tabs();
  Text textBox = new Text();
  textBox.TabLabel = "HourlyRate";
  textBox.Value = "$180.00";
  textBox.Locked = "true";
  tabs.TextTabs = new List<Text>();
  // Create the signer and add the tabs to pick up the HourlyRate
  Signer newRecipient = new Signer
       Email = "",
       Name = "Geoff Test",
       RecipientId = "1",
       RoleName = "Customer",
       RoutingOrder = "1",
       Tabs = tabs,
  // Create first list for InlineTemplates
  List<InlineTemplate> inlineTemplateList = new List<InlineTemplate>();
  InlineTemplate inlineTemplate = new InlineTemplate();
  inlineTemplate.Sequence = "2";
  inlineTemplate.Recipients = new Recipients();
  inlineTemplate.Recipients.Signers = signers;
  // Add it to the inlineTemplatesList
  // Create the reference to the template housed on your DocuSign account
  ServerTemplate serverTemplate = new ServerTemplate()
       Sequence = "1",
       TemplateId = "ce839909-xxxx-xxxx-xxxx-a05dbd8c7217" // Statement of Work
  List<ServerTemplate> serverTemplateList = new List<ServerTemplate>();
  // Add it to the templates List
  // Create the composite template, add the server / inline template lists.
  compoTemplate.CompositeTemplateId = "1";
  compoTemplate.ServerTemplates = serverTemplateList;
  compoTemplate.InlineTemplates = inlineTemplateList;
  // Take the Composite Template list, add both
  List<CompositeTemplate> compositList = new List<CompositeTemplate>();
  // Create the definition for the envelope
  EnvelopeDefinition envDefinition = new EnvelopeDefinition();
  // Add the Composite Template list
  envDefinition.CompositeTemplates = compositList;
  envDefinition.EmailSubject = "CompositeTemplate Example";
  envDefinition.Status = "sent";
  EnvelopesApi.CreateEnvelopeOptions options = null; //No query parameters
  // Create the envelope
  EnvelopeSummary Response = api.CreateEnvelope(accountId, envDefinition, options);
  string envelopeId = Response.EnvelopeId;
  return envelopeId;

The resulting envelope has been created with the new document of terms and conditions. All the Initial and SignHere tabs are placed on the anchor strings. The hourly rate has been written to the PDF and cannot be edited by the signer.


Additional resources


Geoff Pfander
Geoff Pfander
Senior Developer Support Engineer