0
votes

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:

[EDITED]

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<Document> envelopeDocuments = new List<Document>();

                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<Tab>()
                                                                         {  new Tab()
                                                                            {
                                                                                documentId = 1.ToString(),
                                                                                pageNumber = 1.ToString(),
                                                                                //recipientId = 1.ToString(),
                                                                                xPosition = 100.ToString(),
                                                                                yPosition = 100.ToString()
                                                                            }
                                                                         }  
                                                      }
                                           };

                List<Recipient> recipients = new List<Recipient>();
                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)) > 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 --> \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();
            }
        } 
    } 

// Other classes used in object that is converted to JSON

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<Tab> 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; } 
}

[EDITED]

// Here is the request body from fiddler

POST https://demo.docusign.net/restapi/v2/accounts/295724/envelopes 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

--c17efb7771a64f688508187fee57c398 Content-Type: application/json Content-Disposition: form-data

{"emailBlurb":"EMAIL BODY HERE OK OK","emailSubject":"EMAIL SUBJECT HERE IS MANDATORY","status":"sent","documents":[{"documentId":1,"name":"ABC.pdf"}],"recipients":{"signers":[{"email":"[email protected]","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

--b670ec35bd824dff8c0eefe62035e0b2 Content-Type: application/pdf Content-Disposition: file; filename="ABC.pdf"; documentId=1

--b670ec35bd824dff8c0eefe62035e0b2-- --c17efb7771a64f688508187fee57c398--

1
Why do you manually form your json while you can use Json.Net ? Just do as in var objectCredentials = new { User....... BTW: you can also use HttpClient (available in .Net 4.5) to create multi-part request.L.B
Thanks for your recommendation about using Json.Net. I try with the HttpClient class too. Thanksdhernandez
I agree, that's a bad way of creating your JSON. Are you still receiving this error after changing that? THe error messages seems to indicate the problem is with the JSON and not the format of the multipart/form data request...Ergin
I change the code that create the JSON. I'm still having problem with the request, I also added the other classes that I use to create the JSON Object. Hope this can clarify the code.dhernandez
Can you post the JSON you are sending in your request separately? Just add a new code section in your question and put the JSON in there, otherwise it's very difficult to help debug.Ergin

1 Answers

2
votes

I believe the problem is with the JSON you are sending. It's valid JSON format you have but the value for your recipientId is being dropped or not set. You have this for the recipientId:

"recipientId": null,

To resolve try setting this to

"recipientId": "1",

Or whatever value you would like to set for it, since it's user configurable. For instance you can set it to "4321" if you wanted.

Also, DocuSign lets you set assign recipientIds as you would like, but if you don't specify the recipientId property at all, DocuSign should generate a GUID for the recipient. Therefore, I think another way to solve this issue is to not include the recipientId property at all, for instance:

"signHereTabs": [
    {
        "documentId": "1",
        "pageNumber": "1",
        "xPosition": "100",
        "yPosition": "100"
    }
]

I believe either solution should solve your issue.


[EDIT]

I see in the Fiddler output you added that you are missing CRLF characters between some of your boundaries. That might be causing your issue as well.

If you are sending TWO documents for instance it needs to be in this format. Each newline you see is a

CRLF (\r\n)

character. This is the format it needs to be in:

--AAA
Content-Type: application/json
Content-Disposition: form-data

<YOUR VALID JSON GOES HERE>
--AAA
Content-Disposition: form-data
Content-Type: multipart/mixed; boundary=BBB

--BBB
Content-Type:application/pdf
Content-Disposition: file; filename=\”document1.pdf"; documentid=1

<PDF Bytes for first document>
--BBB
Content-Type:application/pdf
Content-Disposition: file; filename=\”document2.pdf"; documentid=2

<PDF Bytes for second document>
--BBB--
--AAA--

If you are sending just ONE document then your spacing needs to be exactly like this:

--AAA
Content-Type: application/json
Content-Disposition: form-data

<YOUR VALID JSON GOES HERE>
--AAA
Content-Type:application/pdf
Content-Disposition: file; filename="document.pdf"; documentid=1 

<DOCUMENT BYTES GO HERE>
--AAA--