title: Trying to create DocuSign envelope with multiple documents
body: <p>I am trying to Create an Envelope with multiples documents using DocuSign REST API, I created a C# console application and wrote the envelope parameters in the request in JSON format. I'm getting error code "ENVELOPE IS INCOMPLETE", I been trying to compare my request with the one in the REST API Docusign Guide and I can't see what I am missing. Here is my sample code:</p>
  
  <p><strong>[EDITED]</strong></p>
  
  <pre><code>public class RequestSignature
      {
          // Enter your info here:
          static string email = "email";
          static string password = "password";
          static string integratorKey = "key";    
  
          public static void Main()
          {
              string url = "https://demo.docusign.net/restapi/v2/login_information";
              string baseURL = "";    // we will retrieve this
              string accountId = "";  // will retrieve
  
              var objectCredentials = new { Username = email, Password = password, IntegratorKey = integratorKey };
  
              string jSONCredentialsString = JsonConvert.SerializeObject(objectCredentials);
  
              // 
              // STEP 1 - Login
              //
              try
              {
                  HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
                  // request.Headers.Add("X-DocuSign-Authentication", authenticateStr);
  
                  request.Headers.Add("X-DocuSign-Authentication", jSONCredentialsString);
                  request.Accept = "application/json";
                  request.Method = "GET";
  
  
                  HttpWebResponse webResponse = (HttpWebResponse)request.GetResponse();
                  StreamReader sr = new StreamReader(webResponse.GetResponseStream());
                  string responseText = sr.ReadToEnd();
  
                  //  close stream reader
                  sr.Close();
                  JsonTextReader reader = new JsonTextReader(new StringReader(responseText));
                  JObject jObject = JObject.Parse(responseText);
  
                  // get the first User Account data
                  JToken jUserAccount = jObject["loginAccounts"].First;
                  // read values from JSON
                  accountId = (string)jUserAccount["accountId"];
                  baseURL = (string)jUserAccount["baseUrl"];
  
                  //
                  // STEP 2 - Send Envelope with Information
                  //
  
                  // construct an outgoing JSON request body that create the envelope
                  string formDataBoundary = String.Format("{0:N}", Guid.NewGuid());
                  StringBuilder requestBody = new StringBuilder();
  
                  string header = string.Format("--{0}\r\nContent-Type: application/json\r\nContent-Disposition: form-data\r\n\r\n", formDataBoundary);
  
                  // Documents list to send in the envelope
                  List&lt;Document&gt; envelopeDocuments = new List&lt;Document&gt;();
  
                  Document currentDocument = new Document(1, "ABC.pdf", "C:/Documents/ABC.pdf");
                  envelopeDocuments.Add(currentDocument);
  
                  DocuSignDocument[] documentsArray = (from doc in envelopeDocuments
                                                      select new DocuSignDocument()
                                                      {
                                                          documentId = doc.DocumentID.ToString(),
                                                          name = doc.Name
                                                      }).ToArray();
  
                  //currentDocument = new Document(2, "ABC.pdf", "D:/Documents/ABC.pdf");
                  //envelopeDocuments.Add(currentDocument);
  
                  // creaqte recipients
                  Recipient firstRecipient = new Recipient()
                                             {
                                                 email = "email",
                                                 name = "name",
                                                 recipientId = 1.ToString(),
                                                 routingOrder = 1.ToString(),
                                                 tabs = new Tabs()
                                                        {
                                                            signHereTabs = new List&lt;Tab&gt;()
                                                                           {  new Tab()
                                                                              {
                                                                                  documentId = 1.ToString(),
                                                                                  pageNumber = 1.ToString(),
                                                                                  //recipientId = 1.ToString(),
                                                                                  xPosition = 100.ToString(),
                                                                                  yPosition = 100.ToString()
                                                                              }
                                                                           }  
                                                        }
                                             };
  
                  List&lt;Recipient&gt; recipients = new List&lt;Recipient&gt;();
                  recipients.Add(firstRecipient);
                  // api json attributes setting by developer
  
                  // setting attributes for the envelope request 
  
                  var envelopeAttributes = new
                      {
                          //allowReassign = false,
                          emailBlurb = "EMAIL BODY HERE OK OK",
                          emailSubject = "EMAIL SUBJECT HERE IS MANDATORY",
                          // enableWetSign = false,
                          // messageLock = true,
  
                          // notification attributes                 
                          /*notifications = new
                              {
                                  useAccountDefaults = true,
  
                                  // reminder configuration attributes
                                  reminders = new object[]
                                                  {
                                                      new 
                                                      { 
                                                          reminderEnabled = true,
                                                          reminderDelay = 3,
                                                          reminderFrequency = 3
                                                      }
                                                  },
                                  // end reminder configuration attributes
  
                                  // expiration configuration attributes
                                  expirations = new object[] 
                                                    {
                                                        new 
                                                        {
                                                            expirationEnabled = true,
                                                            expirationAfter = 30,
                                                            expirationWarn = 5
                                                        }
                                                    }
                              }, */
                          // end notification attributes
                          status = "sent",
  
                          // start documents section
                          documents = documentsArray,
                          recipients = new 
                              {
                                  signers = recipients
                              }
  
                      };
  
                  // append "/envelopes" to baseURL and use in the request
                  request = (HttpWebRequest)WebRequest.Create(baseURL + "/envelopes");
                  request.Headers.Add("X-DocuSign-Authentication", jSONCredentialsString);
                  request.ContentType = "multipart/form-data; boundary=" + formDataBoundary;
                  request.Accept = "application/json";
                  request.Method = "POST";
                  request.KeepAlive = true;
                  request.Credentials = System.Net.CredentialCache.DefaultCredentials;
                  string requestBodyStartStr = header;
  
                  requestBodyStartStr += JsonConvert.SerializeObject(envelopeAttributes);
                  requestBodyStartStr += "\r\n--" + formDataBoundary + "\r\n";
                  // Write the body of the request
                  byte[] bodyStart = System.Text.Encoding.UTF8.GetBytes(requestBodyStartStr);
  
                  MemoryStream streamBufferData = new MemoryStream();
                  streamBufferData.Write(bodyStart, 0, bodyStart.Length);
  
                  // Read the file contents and write them to the request stream
                  byte[] buf = new byte[4096];
                  int length;
                  FileStream fileStream;
  
                  string mixedHeaderBoundary = String.Format("{0:N}", Guid.NewGuid());
                  // add multipart mixed header
                  string mixedHeader = "Content-Disposition: form-data\r\n";
                  mixedHeader += "Content-Type: multipart/mixed; boundary=" + mixedHeaderBoundary + "\r\n\r\n";
  
                  byte[] bodyMixedHeader = System.Text.Encoding.UTF8.GetBytes(mixedHeader);
                  streamBufferData.Write(bodyMixedHeader, 0, bodyMixedHeader.Length);
  
                  foreach (Document document in envelopeDocuments)
                  {
                      fileStream = null;
                      // load file from location
                      fileStream = File.OpenRead(document.PathName);
  
                      // write header of pdf
                      string headerOfDocumentStr = "--" + mixedHeaderBoundary + "\r\n" + 
                             "Content-Type: application/pdf\r\n" +
                          "Content-Disposition: file; filename=\"" + document.Name + "\";documentId=\"" + document.DocumentID + "\"\r\n\r\n";
  
                      byte[] headerDocBytes = System.Text.Encoding.UTF8.GetBytes(headerOfDocumentStr);
                      streamBufferData.Write(headerDocBytes, 0, headerDocBytes.Length);
  
                      length = 0;
                      while ((length = fileStream.Read(buf, 0, 4096)) &gt; 0)
                      {
                          streamBufferData.Write(buf, 0, length);
                      }
  
                      fileStream.Close();
  
                      //byte[] bottomMixedBoundaryForFDocument = System.Text.Encoding.UTF8.GetBytes("\r\n--" + mixedHeaderBoundary + "\r\n");
                      //streamBufferData.Write(bottomMixedBoundaryForFDocument, 0, bottomMixedBoundaryForFDocument.Length);
  
                  }
  
                  string requestBodyEndStr = "--" + mixedHeaderBoundary + "--\r\n";
  
                  byte[] requestBodyEndBytes = System.Text.Encoding.UTF8.GetBytes(requestBodyEndStr);
                  streamBufferData.Write(requestBodyEndBytes, 0, requestBodyEndBytes.Length);
  
                  // write end boundary
                  requestBodyEndStr = "--" + formDataBoundary + "--";
  
  
                  requestBodyEndBytes = System.Text.Encoding.UTF8.GetBytes(requestBodyEndStr);
                  streamBufferData.Write(requestBodyEndBytes, 0, requestBodyEndBytes.Length);
  
                  // pass temporary buffer data to WebRequestStream
                  request.ContentLength = streamBufferData.Length;
  
                  Stream dataStream = request.GetRequestStream();
                  byte[] byteArrayToSend = new byte[streamBufferData.Length];
  
                  streamBufferData.Seek(0, SeekOrigin.Begin);
                  streamBufferData.Read(byteArrayToSend, 0, (int)streamBufferData.Length);
  
                  dataStream.Write(byteArrayToSend, 0, (int)streamBufferData.Length);
  
                  streamBufferData.Close();
  
                  // read the response
                  webResponse = (HttpWebResponse)request.GetResponse();
                  responseText = "";
                  sr = new StreamReader(webResponse.GetResponseStream());
                  responseText = sr.ReadToEnd();
  
                  // display results
                  Console.WriteLine("Response of Action Create Envelope with Two Documents --&gt; \r\n " + responseText);
                  Console.ReadLine();
              }
              catch (WebException e)
              {
                  using (WebResponse response = e.Response)
                  {
                      HttpWebResponse httpResponse = (HttpWebResponse)response;
                      Console.WriteLine("Error code: {0}", httpResponse.StatusCode);
                      using (Stream data = response.GetResponseStream())
                      {
                          string text = new StreamReader(data).ReadToEnd();
                          Console.WriteLine(text);
                      }
                  }
                  Console.ReadLine();
              }
          } 
      } 
  </code></pre>
  
  <p>// Other classes used in object that is converted to JSON</p>
  
  <pre><code>public class Tab
  {
      public int documentId { get; set; }
      public int pageNumber { get; set; }
      public int recipientId { get; set; }
      public int xPosition { get; set; }
      public int yPosition { get; set; }
      public string name { get; set; }
      public string tabLabel { get; set; }
  }
  
  public class Tabs
  {
      public List&lt;Tab&gt; signHereTabs { get; set; }    
  }
  
  
  public class Recipient
  {
      public string email { get; set; }
      public string name { get; set; }
      // public int recipientId { get; set; }
      public int routingOrder { get; set; }
  
      public Tabs tabs { get; set; } 
  }
  </code></pre>
  
  <p><strong>[EDITED]</strong></p>
  
  <p>// Here is the request body from fiddler</p>
  
  <p>POST <a href="https://demo.docusign.net/restapi/v2/accounts/295724/envelopes" rel="nofollow">https://demo.docusign.net/restapi/v2/accounts/295724/envelopes</a> HTTP/1.1
  X-DocuSign-Authentication: {"Username":"email","Password":"username","IntegratorKey":"key"}
  Content-Type: multipart/form-data; boundary=c17efb7771a64f688508187fee57c398
  Accept: application/json
  Host: demo.docusign.net
  Content-Length: 147201
  Expect: 100-continue</p>
  
  <p>--c17efb7771a64f688508187fee57c398
  Content-Type: application/json
  Content-Disposition: form-data</p>
  
  <p>{"emailBlurb":"EMAIL BODY HERE OK OK","emailSubject":"EMAIL SUBJECT HERE IS MANDATORY","status":"sent","documents":[{"documentId":1,"name":"ABC.pdf"}],"recipients":{"signers":[{"email":"dn@brenock.com","name":"Dubhe","recipientId":"1","routingOrder":"1","tabs":{"signHereTabs":[{"documentId":"1","pageNumber":"1","xPosition":"100","yPosition":"100"}]}}]}}
  --c17efb7771a64f688508187fee57c398
  Content-Disposition: form-data
  Content-Type: multipart/mixed; boundary=b670ec35bd824dff8c0eefe62035e0b2</p>
  
  <p>--b670ec35bd824dff8c0eefe62035e0b2
  Content-Type: application/pdf
  Content-Disposition: file; filename="ABC.pdf"; documentId=1</p>
  
  <p>
  --b670ec35bd824dff8c0eefe62035e0b2--
  --c17efb7771a64f688508187fee57c398--</p>