Reputation: 77
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":"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
--b670ec35bd824dff8c0eefe62035e0b2 Content-Type: application/pdf Content-Disposition: file; filename="ABC.pdf"; documentId=1
--b670ec35bd824dff8c0eefe62035e0b2-- --c17efb7771a64f688508187fee57c398--
Upvotes: 0
Views: 4004
Reputation: 9356
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--
Upvotes: 2